From c8ecb4bd84f5f1528ed5c6a240e73871a62cc03c Mon Sep 17 00:00:00 2001 From: Kajsa Tunedal <kajtu36@liu.se> Date: Wed, 13 Nov 2024 21:18:13 +0100 Subject: [PATCH] added amici toolbox --- .gitignore | 2 - .../SuiteSparse/AMD/Demo/amd_demo.c | 177 + .../SuiteSparse/AMD/Demo/amd_demo2.c | 208 + .../SuiteSparse/AMD/Demo/amd_f77wrapper.c | 87 + .../SuiteSparse/AMD/Demo/amd_l_demo.c | 178 + .../SuiteSparse/AMD/Demo/amd_simple.c | 22 + .../ThirdParty/SuiteSparse/AMD/Include/amd.h | 400 + .../SuiteSparse/AMD/Include/amd_internal.h | 326 + .../SuiteSparse/AMD/MATLAB/amd_mex.c | 192 + .../ThirdParty/SuiteSparse/AMD/Source/amd_1.c | 180 + .../ThirdParty/SuiteSparse/AMD/Source/amd_2.c | 1842 ++++ .../SuiteSparse/AMD/Source/amd_aat.c | 184 + .../SuiteSparse/AMD/Source/amd_control.c | 64 + .../SuiteSparse/AMD/Source/amd_defaults.c | 37 + .../SuiteSparse/AMD/Source/amd_dump.c | 179 + .../SuiteSparse/AMD/Source/amd_global.c | 14 + .../SuiteSparse/AMD/Source/amd_info.c | 119 + .../SuiteSparse/AMD/Source/amd_order.c | 199 + .../SuiteSparse/AMD/Source/amd_post_tree.c | 120 + .../SuiteSparse/AMD/Source/amd_postorder.c | 206 + .../SuiteSparse/AMD/Source/amd_preprocess.c | 118 + .../SuiteSparse/AMD/Source/amd_valid.c | 92 + .../ThirdParty/SuiteSparse/BTF/Include/btf.h | 267 + .../SuiteSparse/BTF/Include/btf_internal.h | 64 + .../ThirdParty/SuiteSparse/BTF/MATLAB/btf.c | 145 + .../SuiteSparse/BTF/MATLAB/maxtrans.c | 102 + .../SuiteSparse/BTF/MATLAB/strongcomp.c | 180 + .../SuiteSparse/BTF/Source/btf_maxtrans.c | 387 + .../SuiteSparse/BTF/Source/btf_order.c | 132 + .../SuiteSparse/BTF/Source/btf_strongcomp.c | 593 ++ .../SuiteSparse/CAMD/Demo/camd_demo.c | 172 + .../SuiteSparse/CAMD/Demo/camd_demo2.c | 216 + .../SuiteSparse/CAMD/Demo/camd_l_demo.c | 173 + .../SuiteSparse/CAMD/Demo/camd_simple.c | 23 + .../SuiteSparse/CAMD/Include/camd.h | 407 + .../SuiteSparse/CAMD/Include/camd_internal.h | 317 + .../SuiteSparse/CAMD/MATLAB/camd_mex.c | 213 + .../SuiteSparse/CAMD/Source/camd_1.c | 183 + .../SuiteSparse/CAMD/Source/camd_2.c | 2012 ++++ .../SuiteSparse/CAMD/Source/camd_aat.c | 183 + .../SuiteSparse/CAMD/Source/camd_control.c | 64 + .../SuiteSparse/CAMD/Source/camd_defaults.c | 36 + .../SuiteSparse/CAMD/Source/camd_dump.c | 189 + .../SuiteSparse/CAMD/Source/camd_global.c | 14 + .../SuiteSparse/CAMD/Source/camd_info.c | 119 + .../SuiteSparse/CAMD/Source/camd_order.c | 200 + .../SuiteSparse/CAMD/Source/camd_postorder.c | 50 + .../SuiteSparse/CAMD/Source/camd_preprocess.c | 118 + .../SuiteSparse/CAMD/Source/camd_valid.c | 112 + .../SuiteSparse/COLAMD/Demo/colamd_example.c | 178 + .../COLAMD/Demo/colamd_l_example.c | 179 + .../SuiteSparse/COLAMD/Include/colamd.h | 237 + .../SuiteSparse/COLAMD/MATLAB/colamdmex.c | 210 + .../SuiteSparse/COLAMD/MATLAB/colamdtestmex.c | 567 ++ .../SuiteSparse/COLAMD/MATLAB/symamdmex.c | 192 + .../SuiteSparse/COLAMD/MATLAB/symamdtestmex.c | 533 + .../SuiteSparse/COLAMD/Source/colamd.c | 3590 +++++++ .../SuiteSparse/KLU/Demo/klu_simple.c | 27 + .../ThirdParty/SuiteSparse/KLU/Demo/kludemo.c | 326 + .../SuiteSparse/KLU/Demo/kluldemo.c | 329 + .../ThirdParty/SuiteSparse/KLU/Include/klu.h | 832 ++ .../SuiteSparse/KLU/Include/klu_internal.h | 243 + .../SuiteSparse/KLU/Include/klu_version.h | 694 ++ .../SuiteSparse/KLU/MATLAB/klu_mex.c | 1974 ++++ .../ThirdParty/SuiteSparse/KLU/Source/klu.c | 773 ++ .../SuiteSparse/KLU/Source/klu_analyze.c | 482 + .../KLU/Source/klu_analyze_given.c | 369 + .../SuiteSparse/KLU/Source/klu_defaults.c | 54 + .../SuiteSparse/KLU/Source/klu_diagnostics.c | 568 ++ .../SuiteSparse/KLU/Source/klu_dump.c | 147 + .../SuiteSparse/KLU/Source/klu_extract.c | 290 + .../SuiteSparse/KLU/Source/klu_factor.c | 543 + .../SuiteSparse/KLU/Source/klu_free_numeric.c | 71 + .../KLU/Source/klu_free_symbolic.c | 34 + .../SuiteSparse/KLU/Source/klu_kernel.c | 1010 ++ .../SuiteSparse/KLU/Source/klu_memory.c | 216 + .../SuiteSparse/KLU/Source/klu_refactor.c | 474 + .../SuiteSparse/KLU/Source/klu_scale.c | 159 + .../SuiteSparse/KLU/Source/klu_solve.c | 396 + .../SuiteSparse/KLU/Source/klu_sort.c | 156 + .../SuiteSparse/KLU/Source/klu_tsolve.c | 465 + .../ThirdParty/SuiteSparse/KLU/Tcov/klutest.c | 1384 +++ .../SuiteSparse/KLU/User/klu_cholmod.c | 108 + .../SuiteSparse/KLU/User/klu_cholmod.h | 7 + .../SuiteSparse/KLU/User/klu_l_cholmod.c | 108 + .../SuiteSparse_config/SuiteSparse_config.c | 531 + .../SuiteSparse_config/SuiteSparse_config.h | 247 + .../SuiteSparse_config/xerbla/xerbla.c | 12 + .../SuiteSparse_config/xerbla/xerbla.h | 2 + .../SuiteSparse/include/SuiteSparse_config.h | 247 + .../ThirdParty/SuiteSparse/include/amd.h | 400 + .../ThirdParty/SuiteSparse/include/btf.h | 267 + .../ThirdParty/SuiteSparse/include/camd.h | 407 + .../ThirdParty/SuiteSparse/include/colamd.h | 237 + .../ThirdParty/SuiteSparse/include/klu.h | 832 ++ .../sundials/include/arkode/arkode.h | 134 + .../sundials/include/arkode/arkode_arkstep.h | 368 + .../sundials/include/arkode/arkode_bandpre.h | 46 + .../sundials/include/arkode/arkode_bbdpre.h | 67 + .../sundials/include/arkode/arkode_butcher.h | 72 + .../include/arkode/arkode_butcher_dirk.h | 55 + .../include/arkode/arkode_butcher_erk.h | 56 + .../sundials/include/arkode/arkode_erkstep.h | 218 + .../sundials/include/arkode/arkode_ls.h | 97 + .../sundials/include/arkode/arkode_mristep.h | 139 + .../ThirdParty/sundials/include/cvode/cvode.h | 194 + .../sundials/include/cvode/cvode_bandpre.h | 48 + .../sundials/include/cvode/cvode_bbdpre.h | 65 + .../sundials/include/cvode/cvode_diag.h | 60 + .../sundials/include/cvode/cvode_direct.h | 60 + .../sundials/include/cvode/cvode_ls.h | 129 + .../sundials/include/cvode/cvode_spils.h | 78 + .../sundials/include/cvodes/cvodes.h | 573 ++ .../sundials/include/cvodes/cvodes_bandpre.h | 60 + .../sundials/include/cvodes/cvodes_bbdpre.h | 93 + .../sundials/include/cvodes/cvodes_diag.h | 73 + .../sundials/include/cvodes/cvodes_direct.h | 69 + .../sundials/include/cvodes/cvodes_ls.h | 234 + .../sundials/include/cvodes/cvodes_spils.h | 107 + .../ThirdParty/sundials/include/ida/ida.h | 207 + .../sundials/include/ida/ida_bbdpre.h | 65 + .../sundials/include/ida/ida_direct.h | 61 + .../ThirdParty/sundials/include/ida/ida_ls.h | 135 + .../sundials/include/ida/ida_spils.h | 80 + .../ThirdParty/sundials/include/idas/idas.h | 581 ++ .../sundials/include/idas/idas_bbdpre.h | 96 + .../sundials/include/idas/idas_direct.h | 70 + .../sundials/include/idas/idas_ls.h | 255 + .../sundials/include/idas/idas_spils.h | 111 + .../sundials/include/kinsol/kinsol.h | 149 + .../sundials/include/kinsol/kinsol_bbdpre.h | 66 + .../sundials/include/kinsol/kinsol_direct.h | 59 + .../sundials/include/kinsol/kinsol_ls.h | 119 + .../sundials/include/kinsol/kinsol_spils.h | 73 + .../sundials/include/nvector/nvector_cuda.h | 180 + .../include/nvector/nvector_mpicuda.h | 194 + .../include/nvector/nvector_mpiraja.h | 180 + .../sundials/include/nvector/nvector_openmp.h | 197 + .../include/nvector/nvector_openmpdev.h | 201 + .../include/nvector/nvector_parallel.h | 206 + .../sundials/include/nvector/nvector_parhyp.h | 183 + .../sundials/include/nvector/nvector_petsc.h | 175 + .../include/nvector/nvector_pthreads.h | 231 + .../sundials/include/nvector/nvector_raja.h | 162 + .../sundials/include/nvector/nvector_serial.h | 188 + .../include/nvector/nvector_trilinos.h | 125 + .../sundials/include/sundials/sundials_band.h | 181 + .../include/sundials/sundials_config.h | 118 + .../include/sundials/sundials_dense.h | 212 + .../include/sundials/sundials_direct.h | 339 + .../include/sundials/sundials_fnvector.h | 42 + .../include/sundials/sundials_iterative.h | 263 + .../include/sundials/sundials_klu_impl.h | 57 + .../include/sundials/sundials_lapack.h | 209 + .../include/sundials/sundials_linearsolver.h | 180 + .../sundials/include/sundials/sundials_math.h | 168 + .../include/sundials/sundials_matrix.h | 116 + .../sundials/include/sundials/sundials_mpi.h | 54 + .../include/sundials/sundials_mpi_types.h | 35 + .../sundials/sundials_nonlinearsolver.h | 191 + .../include/sundials/sundials_nvector.h | 229 + .../sundials/sundials_nvector_senswrapper.h | 104 + .../sundials/include/sundials/sundials_pcg.h | 164 + .../include/sundials/sundials_sparse.h | 91 + .../include/sundials/sundials_spbcgs.h | 204 + .../include/sundials/sundials_spfgmr.h | 294 + .../include/sundials/sundials_spgmr.h | 301 + .../include/sundials/sundials_sptfqmr.h | 259 + .../sundials/sundials_superlumt_impl.h | 61 + .../include/sundials/sundials_types.h | 145 + .../include/sundials/sundials_version.h | 38 + .../include/sunlinsol/sunlinsol_band.h | 75 + .../include/sunlinsol/sunlinsol_dense.h | 79 + .../include/sunlinsol/sunlinsol_klu.h | 138 + .../include/sunlinsol/sunlinsol_lapackband.h | 92 + .../include/sunlinsol/sunlinsol_lapackdense.h | 92 + .../include/sunlinsol/sunlinsol_pcg.h | 113 + .../include/sunlinsol/sunlinsol_spbcgs.h | 120 + .../include/sunlinsol/sunlinsol_spfgmr.h | 132 + .../include/sunlinsol/sunlinsol_spgmr.h | 131 + .../include/sunlinsol/sunlinsol_sptfqmr.h | 122 + .../include/sunlinsol/sunlinsol_superlumt.h | 125 + .../include/sunmatrix/sunmatrix_band.h | 129 + .../include/sunmatrix/sunmatrix_dense.h | 105 + .../include/sunmatrix/sunmatrix_sparse.h | 143 + .../sunnonlinsol/sunnonlinsol_fixedpoint.h | 113 + .../sunnonlinsol/sunnonlinsol_newton.h | 109 + .../ThirdParty/sundials/src/arkode/arkode.c | 2557 +++++ .../sundials/src/arkode/arkode_adapt.c | 427 + .../sundials/src/arkode/arkode_adapt_impl.h | 109 + .../sundials/src/arkode/arkode_arkstep.c | 2608 +++++ .../sundials/src/arkode/arkode_arkstep_impl.h | 203 + .../sundials/src/arkode/arkode_arkstep_io.c | 2619 +++++ .../sundials/src/arkode/arkode_arkstep_nls.c | 567 ++ .../sundials/src/arkode/arkode_bandpre.c | 542 + .../sundials/src/arkode/arkode_bandpre_impl.h | 72 + .../sundials/src/arkode/arkode_bbdpre.c | 666 ++ .../sundials/src/arkode/arkode_bbdpre_impl.h | 81 + .../sundials/src/arkode/arkode_butcher.c | 2140 ++++ .../sundials/src/arkode/arkode_butcher_dirk.c | 509 + .../sundials/src/arkode/arkode_butcher_erk.c | 607 ++ .../sundials/src/arkode/arkode_erkstep.c | 1242 +++ .../sundials/src/arkode/arkode_erkstep_impl.h | 108 + .../sundials/src/arkode/arkode_erkstep_io.c | 1529 +++ .../sundials/src/arkode/arkode_impl.h | 1085 ++ .../sundials/src/arkode/arkode_interp.c | 611 ++ .../sundials/src/arkode/arkode_interp_impl.h | 89 + .../sundials/src/arkode/arkode_io.c | 907 ++ .../sundials/src/arkode/arkode_ls.c | 2766 ++++++ .../sundials/src/arkode/arkode_ls_impl.h | 303 + .../sundials/src/arkode/arkode_mristep.c | 1146 +++ .../sundials/src/arkode/arkode_mristep_impl.h | 106 + .../sundials/src/arkode/arkode_mristep_io.c | 768 ++ .../sundials/src/arkode/arkode_root.c | 790 ++ .../sundials/src/arkode/arkode_root_impl.h | 86 + .../sundials/src/arkode/fcmix/farkadapt.c | 78 + .../sundials/src/arkode/fcmix/farkband.c | 96 + .../sundials/src/arkode/fcmix/farkbandmass.c | 85 + .../sundials/src/arkode/fcmix/farkbbd.c | 133 + .../sundials/src/arkode/fcmix/farkbbd.h | 83 + .../sundials/src/arkode/fcmix/farkbp.c | 51 + .../sundials/src/arkode/fcmix/farkbp.h | 71 + .../sundials/src/arkode/fcmix/farkdense.c | 92 + .../sundials/src/arkode/fcmix/farkdensemass.c | 77 + .../sundials/src/arkode/fcmix/farkewt.c | 72 + .../sundials/src/arkode/fcmix/farkexpstab.c | 73 + .../sundials/src/arkode/fcmix/farkjtimes.c | 121 + .../sundials/src/arkode/fcmix/farkmasspreco.c | 102 + .../sundials/src/arkode/fcmix/farkmtimes.c | 93 + .../src/arkode/fcmix/farknulllinsol.c | 43 + .../src/arkode/fcmix/farknullmatrix.c | 44 + .../src/arkode/fcmix/farknullnonlinsol.c | 41 + .../sundials/src/arkode/fcmix/farkode.c | 881 ++ .../sundials/src/arkode/fcmix/farkode.h | 404 + .../sundials/src/arkode/fcmix/farkpreco.c | 118 + .../sundials/src/arkode/fcmix/farkroot.c | 93 + .../sundials/src/arkode/fcmix/farkroot.h | 71 + .../sundials/src/arkode/fcmix/farksparse.c | 99 + .../src/arkode/fcmix/farksparsemass.c | 84 + .../ThirdParty/sundials/src/cvode/cvode.c | 4093 ++++++++ .../sundials/src/cvode/cvode_bandpre.c | 562 ++ .../sundials/src/cvode/cvode_bandpre_impl.h | 75 + .../sundials/src/cvode/cvode_bbdpre.c | 702 ++ .../sundials/src/cvode/cvode_bbdpre_impl.h | 83 + .../sundials/src/cvode/cvode_diag.c | 439 + .../sundials/src/cvode/cvode_diag_impl.h | 68 + .../sundials/src/cvode/cvode_direct.c | 55 + .../sundials/src/cvode/cvode_impl.h | 556 ++ .../ThirdParty/sundials/src/cvode/cvode_io.c | 1155 +++ .../ThirdParty/sundials/src/cvode/cvode_ls.c | 1522 +++ .../sundials/src/cvode/cvode_ls_impl.h | 175 + .../ThirdParty/sundials/src/cvode/cvode_nls.c | 325 + .../sundials/src/cvode/cvode_spils.c | 77 + .../sundials/src/cvode/fcmix/fcvband.c | 99 + .../sundials/src/cvode/fcmix/fcvbbd.c | 140 + .../sundials/src/cvode/fcmix/fcvbbd.h | 524 + .../sundials/src/cvode/fcmix/fcvbp.c | 54 + .../sundials/src/cvode/fcmix/fcvbp.h | 372 + .../sundials/src/cvode/fcmix/fcvdense.c | 91 + .../sundials/src/cvode/fcmix/fcvewt.c | 73 + .../sundials/src/cvode/fcmix/fcvjtimes.c | 124 + .../sundials/src/cvode/fcmix/fcvnulllinsol.c | 41 + .../sundials/src/cvode/fcmix/fcvnullmatrix.c | 41 + .../src/cvode/fcmix/fcvnullnonlinsol.c | 41 + .../sundials/src/cvode/fcmix/fcvode.c | 539 + .../sundials/src/cvode/fcmix/fcvode.h | 1084 ++ .../sundials/src/cvode/fcmix/fcvpreco.c | 130 + .../sundials/src/cvode/fcmix/fcvroot.c | 85 + .../sundials/src/cvode/fcmix/fcvroot.h | 141 + .../sundials/src/cvode/fcmix/fcvsparse.c | 93 + .../ThirdParty/sundials/src/cvodes/cvodea.c | 3075 ++++++ .../sundials/src/cvodes/cvodea_io.c | 747 ++ .../ThirdParty/sundials/src/cvodes/cvodes.c | 8813 +++++++++++++++++ .../sundials/src/cvodes/cvodes_bandpre.c | 623 ++ .../sundials/src/cvodes/cvodes_bandpre_impl.h | 77 + .../sundials/src/cvodes/cvodes_bbdpre.c | 912 ++ .../sundials/src/cvodes/cvodes_bbdpre_impl.h | 103 + .../sundials/src/cvodes/cvodes_diag.c | 509 + .../sundials/src/cvodes/cvodes_diag_impl.h | 69 + .../sundials/src/cvodes/cvodes_direct.c | 66 + .../sundials/src/cvodes/cvodes_impl.h | 1191 +++ .../sundials/src/cvodes/cvodes_io.c | 2017 ++++ .../sundials/src/cvodes/cvodes_ls.c | 2346 +++++ .../sundials/src/cvodes/cvodes_ls_impl.h | 226 + .../sundials/src/cvodes/cvodes_nls.c | 319 + .../sundials/src/cvodes/cvodes_nls_sim.c | 520 + .../sundials/src/cvodes/cvodes_nls_stg.c | 448 + .../sundials/src/cvodes/cvodes_nls_stg1.c | 372 + .../sundials/src/cvodes/cvodes_spils.c | 107 + .../ThirdParty/sundials/src/ida/fcmix/fida.c | 617 ++ .../ThirdParty/sundials/src/ida/fcmix/fida.h | 1107 +++ .../sundials/src/ida/fcmix/fidaband.c | 114 + .../sundials/src/ida/fcmix/fidabbd.c | 147 + .../sundials/src/ida/fcmix/fidabbd.h | 549 + .../sundials/src/ida/fcmix/fidadense.c | 110 + .../sundials/src/ida/fcmix/fidaewt.c | 89 + .../sundials/src/ida/fcmix/fidajtimes.c | 156 + .../sundials/src/ida/fcmix/fidanullmatrix.c | 41 + .../src/ida/fcmix/fidanullnonlinsol.c | 41 + .../sundials/src/ida/fcmix/fidapreco.c | 151 + .../sundials/src/ida/fcmix/fidaroot.c | 90 + .../sundials/src/ida/fcmix/fidaroot.h | 143 + .../sundials/src/ida/fcmix/fidasparse.c | 94 + .../ThirdParty/sundials/src/ida/ida.c | 3384 +++++++ .../ThirdParty/sundials/src/ida/ida_bbdpre.c | 667 ++ .../sundials/src/ida/ida_bbdpre_impl.h | 88 + .../ThirdParty/sundials/src/ida/ida_direct.c | 56 + .../ThirdParty/sundials/src/ida/ida_ic.c | 704 ++ .../ThirdParty/sundials/src/ida/ida_impl.h | 526 + .../ThirdParty/sundials/src/ida/ida_io.c | 1183 +++ .../ThirdParty/sundials/src/ida/ida_ls.c | 1548 +++ .../ThirdParty/sundials/src/ida/ida_ls_impl.h | 188 + .../ThirdParty/sundials/src/ida/ida_nls.c | 288 + .../ThirdParty/sundials/src/ida/ida_spils.c | 81 + .../ThirdParty/sundials/src/idas/idaa.c | 3343 +++++++ .../ThirdParty/sundials/src/idas/idaa_io.c | 782 ++ .../ThirdParty/sundials/src/idas/idas.c | 7416 ++++++++++++++ .../sundials/src/idas/idas_bbdpre.c | 908 ++ .../sundials/src/idas/idas_bbdpre_impl.h | 107 + .../sundials/src/idas/idas_direct.c | 66 + .../ThirdParty/sundials/src/idas/idas_ic.c | 1353 +++ .../ThirdParty/sundials/src/idas/idas_impl.h | 1157 +++ .../ThirdParty/sundials/src/idas/idas_io.c | 1986 ++++ .../ThirdParty/sundials/src/idas/idas_ls.c | 2416 +++++ .../sundials/src/idas/idas_ls_impl.h | 238 + .../ThirdParty/sundials/src/idas/idas_nls.c | 291 + .../sundials/src/idas/idas_nls_sim.c | 408 + .../sundials/src/idas/idas_nls_stg.c | 351 + .../ThirdParty/sundials/src/idas/idas_spils.c | 114 + .../sundials/src/kinsol/fcmix/fkinband.c | 117 + .../sundials/src/kinsol/fcmix/fkinbbd.c | 152 + .../sundials/src/kinsol/fcmix/fkinbbd.h | 317 + .../sundials/src/kinsol/fcmix/fkindense.c | 104 + .../sundials/src/kinsol/fcmix/fkinjtimes.c | 82 + .../src/kinsol/fcmix/fkinnulllinsol.c | 41 + .../src/kinsol/fcmix/fkinnullmatrix.c | 42 + .../sundials/src/kinsol/fcmix/fkinpreco.c | 142 + .../sundials/src/kinsol/fcmix/fkinsol.c | 401 + .../sundials/src/kinsol/fcmix/fkinsol.h | 783 ++ .../sundials/src/kinsol/fcmix/fkinsparse.c | 88 + .../ThirdParty/sundials/src/kinsol/kinsol.c | 2507 +++++ .../sundials/src/kinsol/kinsol_bbdpre.c | 582 ++ .../sundials/src/kinsol/kinsol_bbdpre_impl.h | 82 + .../sundials/src/kinsol/kinsol_direct.c | 55 + .../sundials/src/kinsol/kinsol_impl.h | 487 + .../sundials/src/kinsol/kinsol_io.c | 1060 ++ .../sundials/src/kinsol/kinsol_ls.c | 1335 +++ .../sundials/src/kinsol/kinsol_ls_impl.h | 180 + .../sundials/src/kinsol/kinsol_spils.c | 73 + .../src/nvector/openmp/fnvector_openmp.c | 154 + .../src/nvector/openmp/fnvector_openmp.h | 92 + .../src/nvector/openmp/nvector_openmp.c | 2586 +++++ .../src/nvector/openmpdev/nvector_openmpdev.c | 3057 ++++++ .../src/nvector/parallel/fnvector_parallel.c | 191 + .../src/nvector/parallel/fnvector_parallel.h | 96 + .../src/nvector/parallel/nvector_parallel.c | 2256 +++++ .../src/nvector/parhyp/nvector_parhyp.c | 1983 ++++ .../src/nvector/petsc/nvector_petsc.c | 1722 ++++ .../src/nvector/pthreads/fnvector_pthreads.c | 154 + .../src/nvector/pthreads/fnvector_pthreads.h | 92 + .../src/nvector/pthreads/nvector_pthreads.c | 5385 ++++++++++ .../src/nvector/serial/fnvector_serial.c | 154 + .../src/nvector/serial/fnvector_serial.h | 92 + .../src/nvector/serial/nvector_serial.c | 2147 ++++ .../sundials/src/sundials/sundials_band.c | 264 + .../sundials/src/sundials/sundials_dense.c | 400 + .../sundials/src/sundials/sundials_direct.c | 355 + .../src/sundials/sundials_iterative.c | 298 + .../src/sundials/sundials_linearsolver.c | 132 + .../sundials/src/sundials/sundials_math.c | 53 + .../sundials/src/sundials/sundials_matrix.c | 82 + .../sundials/src/sundials/sundials_mpi.c | 99 + .../src/sundials/sundials_nonlinearsolver.c | 161 + .../sundials/src/sundials/sundials_nvector.c | 495 + .../sundials/sundials_nvector_senswrapper.c | 544 + .../sundials/src/sundials/sundials_pcg.c | 223 + .../sundials/src/sundials/sundials_sparse.c | 870 ++ .../sundials/src/sundials/sundials_spbcgs.c | 384 + .../sundials/src/sundials/sundials_spfgmr.c | 374 + .../sundials/src/sundials/sundials_spgmr.c | 459 + .../sundials/src/sundials/sundials_sptfqmr.c | 521 + .../sundials/src/sundials/sundials_version.c | 48 + .../src/sunlinsol/band/fsunlinsol_band.c | 96 + .../src/sunlinsol/band/fsunlinsol_band.h | 62 + .../src/sunlinsol/band/sunlinsol_band.c | 286 + .../src/sunlinsol/dense/fsunlinsol_dense.c | 96 + .../src/sunlinsol/dense/fsunlinsol_dense.h | 62 + .../src/sunlinsol/dense/sunlinsol_dense.c | 271 + .../src/sunlinsol/klu/fsunlinsol_klu.c | 157 + .../src/sunlinsol/klu/fsunlinsol_klu.h | 81 + .../src/sunlinsol/klu/sunlinsol_klu.c | 457 + .../lapackband/fsunlinsol_lapackband.c | 94 + .../lapackband/fsunlinsol_lapackband.h | 62 + .../lapackband/sunlinsol_lapackband.c | 280 + .../lapackdense/fsunlinsol_lapackdense.c | 92 + .../lapackdense/fsunlinsol_lapackdense.h | 62 + .../lapackdense/sunlinsol_lapackdense.c | 271 + .../src/sunlinsol/pcg/fsunlinsol_pcg.c | 191 + .../src/sunlinsol/pcg/fsunlinsol_pcg.h | 80 + .../src/sunlinsol/pcg/sunlinsol_pcg.c | 481 + .../src/sunlinsol/spbcgs/fsunlinsol_spbcgs.c | 191 + .../src/sunlinsol/spbcgs/fsunlinsol_spbcgs.h | 80 + .../src/sunlinsol/spbcgs/sunlinsol_spbcgs.c | 649 ++ .../src/sunlinsol/spfgmr/fsunlinsol_spfgmr.c | 241 + .../src/sunlinsol/spfgmr/fsunlinsol_spfgmr.h | 88 + .../src/sunlinsol/spfgmr/sunlinsol_spfgmr.c | 719 ++ .../src/sunlinsol/spgmr/fsunlinsol_spgmr.c | 241 + .../src/sunlinsol/spgmr/fsunlinsol_spgmr.h | 88 + .../src/sunlinsol/spgmr/sunlinsol_spgmr.c | 763 ++ .../sunlinsol/sptfqmr/fsunlinsol_sptfqmr.c | 191 + .../sunlinsol/sptfqmr/fsunlinsol_sptfqmr.h | 80 + .../src/sunlinsol/sptfqmr/sunlinsol_sptfqmr.c | 767 ++ .../superlumt/fsunlinsol_superlumt.c | 132 + .../superlumt/fsunlinsol_superlumt.h | 70 + .../sunlinsol/superlumt/sunlinsol_superlumt.c | 431 + .../src/sunmatrix/band/fsunmatrix_band.c | 80 + .../src/sunmatrix/band/fsunmatrix_band.h | 62 + .../src/sunmatrix/band/sunmatrix_band.c | 488 + .../src/sunmatrix/dense/fsunmatrix_dense.c | 78 + .../src/sunmatrix/dense/fsunmatrix_dense.h | 62 + .../src/sunmatrix/dense/sunmatrix_dense.c | 348 + .../src/sunmatrix/sparse/fsunmatrix_sparse.c | 79 + .../src/sunmatrix/sparse/fsunmatrix_sparse.h | 65 + .../src/sunmatrix/sparse/sunmatrix_sparse.c | 1132 +++ .../fixedpoint/fsunnonlinsol_fixedpoint.c | 95 + .../fixedpoint/fsunnonlinsol_fixedpoint.h | 56 + .../fixedpoint/sunnonlinsol_fixedpoint.c | 660 ++ .../newton/fsunnonlinsol_newton.c | 95 + .../newton/fsunnonlinsol_newton.h | 56 + .../sunnonlinsol/newton/sunnonlinsol_newton.c | 453 + .../include/amici/abstract_model.h | 720 ++ .../include/amici/amici.h | 79 + .../include/amici/backwardproblem.h | 153 + .../include/amici/cblas.h | 73 + .../include/amici/defines.h | 163 + .../include/amici/edata.h | 535 + .../include/amici/exception.h | 169 + .../include/amici/forwardproblem.h | 351 + .../include/amici/hdf5.h | 213 + .../include/amici/interface_matlab.h | 68 + .../include/amici/misc.h | 102 + .../include/amici/model.h | 1780 ++++ .../include/amici/model_dae.h | 436 + .../include/amici/model_ode.h | 462 + .../include/amici/newton_solver.h | 296 + .../include/amici/rdata.h | 362 + .../include/amici/returndata_matlab.h | 135 + .../include/amici/serialization.h | 323 + .../include/amici/solver.h | 1477 +++ .../include/amici/solver_cvodes.h | 209 + .../include/amici/solver_idas.h | 196 + .../include/amici/spline.h | 18 + .../include/amici/steadystateproblem.h | 152 + .../include/amici/sundials_linsol_wrapper.h | 859 ++ .../include/amici/sundials_matrix_wrapper.h | 191 + .../include/amici/symbolic_functions.h | 34 + .../include/amici/vector.h | 313 + .../include/amici/version.in.h | 6 + .../matlab/auxiliary/CalcMD5/CalcMD5.c | 650 ++ .../src/model_header.ODE_template.h | 810 ++ .../src/wrapfunctions.ODE_template.h | 11 + .../swig/stdvec2numpy.h | 128 + .../tests/cpputest/testfunctions.h | 205 + 463 files changed, 201537 insertions(+), 2 deletions(-) create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Demo/amd_demo.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Demo/amd_demo2.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Demo/amd_f77wrapper.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Demo/amd_l_demo.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Demo/amd_simple.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Include/amd.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Include/amd_internal.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/MATLAB/amd_mex.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_1.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_2.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_aat.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_control.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_defaults.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_dump.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_global.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_info.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_order.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_post_tree.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_postorder.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_preprocess.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_valid.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/Include/btf.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/Include/btf_internal.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/MATLAB/btf.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/MATLAB/maxtrans.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/MATLAB/strongcomp.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/Source/btf_maxtrans.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/Source/btf_order.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/Source/btf_strongcomp.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Demo/camd_demo.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Demo/camd_demo2.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Demo/camd_l_demo.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Demo/camd_simple.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Include/camd.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Include/camd_internal.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/MATLAB/camd_mex.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_1.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_2.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_aat.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_control.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_defaults.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_dump.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_global.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_info.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_order.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_postorder.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_preprocess.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_valid.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/Demo/colamd_example.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/Demo/colamd_l_example.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/Include/colamd.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/MATLAB/colamdmex.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/MATLAB/colamdtestmex.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/MATLAB/symamdmex.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/MATLAB/symamdtestmex.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/Source/colamd.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Demo/klu_simple.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Demo/kludemo.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Demo/kluldemo.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Include/klu.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Include/klu_internal.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Include/klu_version.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/MATLAB/klu_mex.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_analyze.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_analyze_given.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_defaults.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_diagnostics.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_dump.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_extract.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_factor.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_free_numeric.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_free_symbolic.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_kernel.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_memory.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_refactor.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_scale.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_solve.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_sort.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_tsolve.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Tcov/klutest.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/User/klu_cholmod.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/User/klu_cholmod.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/User/klu_l_cholmod.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/SuiteSparse_config/xerbla/xerbla.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/SuiteSparse_config/xerbla/xerbla.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/SuiteSparse_config.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/amd.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/btf.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/camd.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/colamd.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/klu.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_arkstep.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_bandpre.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_bbdpre.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_butcher.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_butcher_dirk.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_butcher_erk.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_erkstep.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_ls.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_mristep.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_bandpre.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_bbdpre.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_diag.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_direct.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_ls.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_spils.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_bandpre.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_bbdpre.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_diag.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_direct.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_ls.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_spils.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/ida/ida.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/ida/ida_bbdpre.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/ida/ida_direct.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/ida/ida_ls.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/ida/ida_spils.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/idas/idas.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/idas/idas_bbdpre.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/idas/idas_direct.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/idas/idas_ls.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/idas/idas_spils.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/kinsol/kinsol.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/kinsol/kinsol_bbdpre.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/kinsol/kinsol_direct.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/kinsol/kinsol_ls.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/kinsol/kinsol_spils.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_cuda.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_mpicuda.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_mpiraja.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_openmp.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_openmpdev.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_parallel.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_parhyp.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_petsc.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_pthreads.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_raja.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_serial.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_trilinos.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_band.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_config.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_dense.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_direct.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_fnvector.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_iterative.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_klu_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_lapack.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_linearsolver.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_math.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_matrix.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_mpi.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_mpi_types.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_nonlinearsolver.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_nvector.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_nvector_senswrapper.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_pcg.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_sparse.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_spbcgs.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_spfgmr.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_spgmr.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_sptfqmr.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_superlumt_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_types.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_version.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_band.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_dense.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_klu.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_lapackband.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_lapackdense.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_pcg.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_spbcgs.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_spfgmr.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_spgmr.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_sptfqmr.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_superlumt.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunmatrix/sunmatrix_band.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunmatrix/sunmatrix_dense.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunmatrix/sunmatrix_sparse.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunnonlinsol/sunnonlinsol_fixedpoint.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunnonlinsol/sunnonlinsol_newton.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_adapt.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_adapt_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_arkstep.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_arkstep_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_arkstep_io.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_arkstep_nls.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_bandpre.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_bandpre_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_bbdpre.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_bbdpre_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_butcher.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_butcher_dirk.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_butcher_erk.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_erkstep.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_erkstep_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_erkstep_io.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_interp.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_interp_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_io.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_ls.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_ls_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_mristep.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_mristep_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_mristep_io.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_root.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_root_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkadapt.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkband.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkbandmass.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkbbd.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkbbd.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkbp.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkbp.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkdense.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkdensemass.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkewt.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkexpstab.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkjtimes.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkmasspreco.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkmtimes.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farknulllinsol.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farknullmatrix.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farknullnonlinsol.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkode.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkode.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkpreco.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkroot.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkroot.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farksparse.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farksparsemass.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_bandpre.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_bandpre_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_bbdpre.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_bbdpre_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_diag.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_diag_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_direct.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_io.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_ls.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_ls_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_nls.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_spils.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvband.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvbbd.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvbbd.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvbp.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvbp.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvdense.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvewt.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvjtimes.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvnulllinsol.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvnullmatrix.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvnullnonlinsol.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvode.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvode.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvpreco.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvroot.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvroot.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvsparse.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodea.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodea_io.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_bandpre.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_bandpre_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_bbdpre.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_bbdpre_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_diag.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_diag_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_direct.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_io.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_ls.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_ls_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_nls.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_nls_sim.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_nls_stg.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_nls_stg1.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_spils.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fida.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fida.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidaband.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidabbd.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidabbd.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidadense.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidaewt.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidajtimes.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidanullmatrix.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidanullnonlinsol.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidapreco.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidaroot.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidaroot.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidasparse.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_bbdpre.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_bbdpre_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_direct.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_ic.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_io.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_ls.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_ls_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_nls.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_spils.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idaa.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idaa_io.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_bbdpre.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_bbdpre_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_direct.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_ic.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_io.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_ls.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_ls_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_nls.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_nls_sim.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_nls_stg.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_spils.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinband.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinbbd.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinbbd.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkindense.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinjtimes.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinnulllinsol.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinnullmatrix.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinpreco.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinsol.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinsol.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinsparse.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_bbdpre.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_bbdpre_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_direct.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_io.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_ls.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_ls_impl.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_spils.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/openmp/fnvector_openmp.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/openmp/fnvector_openmp.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/openmp/nvector_openmp.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/openmpdev/nvector_openmpdev.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/parallel/fnvector_parallel.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/parallel/fnvector_parallel.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/parallel/nvector_parallel.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/parhyp/nvector_parhyp.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/petsc/nvector_petsc.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/pthreads/fnvector_pthreads.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/pthreads/fnvector_pthreads.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/pthreads/nvector_pthreads.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/serial/fnvector_serial.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/serial/fnvector_serial.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/serial/nvector_serial.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_band.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_dense.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_direct.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_iterative.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_linearsolver.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_math.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_matrix.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_mpi.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_nonlinearsolver.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_nvector.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_nvector_senswrapper.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_pcg.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_sparse.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_spbcgs.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_spfgmr.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_spgmr.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_sptfqmr.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_version.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/band/fsunlinsol_band.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/band/fsunlinsol_band.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/band/sunlinsol_band.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/dense/fsunlinsol_dense.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/dense/fsunlinsol_dense.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/dense/sunlinsol_dense.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/klu/fsunlinsol_klu.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/klu/fsunlinsol_klu.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/klu/sunlinsol_klu.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackband/fsunlinsol_lapackband.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackband/fsunlinsol_lapackband.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackband/sunlinsol_lapackband.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackdense/fsunlinsol_lapackdense.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackdense/fsunlinsol_lapackdense.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackdense/sunlinsol_lapackdense.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/pcg/fsunlinsol_pcg.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/pcg/fsunlinsol_pcg.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/pcg/sunlinsol_pcg.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spbcgs/fsunlinsol_spbcgs.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spbcgs/fsunlinsol_spbcgs.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spbcgs/sunlinsol_spbcgs.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spfgmr/fsunlinsol_spfgmr.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spfgmr/fsunlinsol_spfgmr.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spfgmr/sunlinsol_spfgmr.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spgmr/fsunlinsol_spgmr.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spgmr/fsunlinsol_spgmr.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spgmr/sunlinsol_spgmr.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/sptfqmr/fsunlinsol_sptfqmr.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/sptfqmr/fsunlinsol_sptfqmr.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/sptfqmr/sunlinsol_sptfqmr.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/superlumt/fsunlinsol_superlumt.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/superlumt/fsunlinsol_superlumt.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/superlumt/sunlinsol_superlumt.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/band/fsunmatrix_band.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/band/fsunmatrix_band.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/band/sunmatrix_band.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/dense/fsunmatrix_dense.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/dense/fsunmatrix_dense.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/dense/sunmatrix_dense.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/sparse/fsunmatrix_sparse.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/sparse/fsunmatrix_sparse.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/sparse/sunmatrix_sparse.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/fsunnonlinsol_fixedpoint.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/fsunnonlinsol_fixedpoint.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/sunnonlinsol_fixedpoint.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/newton/fsunnonlinsol_newton.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/newton/fsunnonlinsol_newton.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/newton/sunnonlinsol_newton.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/abstract_model.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/amici.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/backwardproblem.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/cblas.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/defines.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/edata.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/exception.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/forwardproblem.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/hdf5.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/interface_matlab.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/misc.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/model.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/model_dae.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/model_ode.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/newton_solver.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/rdata.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/returndata_matlab.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/serialization.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/solver.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/solver_cvodes.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/solver_idas.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/spline.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/steadystateproblem.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/sundials_linsol_wrapper.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/sundials_matrix_wrapper.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/symbolic_functions.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/vector.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/include/amici/version.in.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/matlab/auxiliary/CalcMD5/CalcMD5.c create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/src/model_header.ODE_template.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/src/wrapfunctions.ODE_template.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/swig/stdvec2numpy.h create mode 100644 Requirements/AMICI-0.10.11_SS_eventFix/tests/cpputest/testfunctions.h diff --git a/.gitignore b/.gitignore index ba0543c..fdedf6c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,8 +6,6 @@ *.png *.fig *.pdf -*.h -*.c *.slxc *.out *.log diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Demo/amd_demo.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Demo/amd_demo.c new file mode 100644 index 0000000..70d9007 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Demo/amd_demo.c @@ -0,0 +1,177 @@ +/* ========================================================================= */ +/* === AMD demo main program =============================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* AMD Copyright (c) by Timothy A. Davis, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* DrTimothyAldenDavis@gmail.com, http://www.suitesparse.com */ +/* ------------------------------------------------------------------------- */ + +/* A simple C main program that illustrates the use of the ANSI C interface + * to AMD. + */ + +#include "amd.h" +#include <stdio.h> +#include <stdlib.h> + +int main (void) +{ + /* The symmetric can_24 Harwell/Boeing matrix, including upper and lower + * triangular parts, and the diagonal entries. Note that this matrix is + * 0-based, with row and column indices in the range 0 to n-1. */ + int n = 24, nz, + Ap [ ] = { 0, 9, 15, 21, 27, 33, 39, 48, 57, 61, 70, 76, 82, 88, 94, 100, + 106, 110, 119, 128, 137, 143, 152, 156, 160 }, + Ai [ ] = { + /* column 0: */ 0, 5, 6, 12, 13, 17, 18, 19, 21, + /* column 1: */ 1, 8, 9, 13, 14, 17, + /* column 2: */ 2, 6, 11, 20, 21, 22, + /* column 3: */ 3, 7, 10, 15, 18, 19, + /* column 4: */ 4, 7, 9, 14, 15, 16, + /* column 5: */ 0, 5, 6, 12, 13, 17, + /* column 6: */ 0, 2, 5, 6, 11, 12, 19, 21, 23, + /* column 7: */ 3, 4, 7, 9, 14, 15, 16, 17, 18, + /* column 8: */ 1, 8, 9, 14, + /* column 9: */ 1, 4, 7, 8, 9, 13, 14, 17, 18, + /* column 10: */ 3, 10, 18, 19, 20, 21, + /* column 11: */ 2, 6, 11, 12, 21, 23, + /* column 12: */ 0, 5, 6, 11, 12, 23, + /* column 13: */ 0, 1, 5, 9, 13, 17, + /* column 14: */ 1, 4, 7, 8, 9, 14, + /* column 15: */ 3, 4, 7, 15, 16, 18, + /* column 16: */ 4, 7, 15, 16, + /* column 17: */ 0, 1, 5, 7, 9, 13, 17, 18, 19, + /* column 18: */ 0, 3, 7, 9, 10, 15, 17, 18, 19, + /* column 19: */ 0, 3, 6, 10, 17, 18, 19, 20, 21, + /* column 20: */ 2, 10, 19, 20, 21, 22, + /* column 21: */ 0, 2, 6, 10, 11, 19, 20, 21, 22, + /* column 22: */ 2, 20, 21, 22, + /* column 23: */ 6, 11, 12, 23 } ; + + int P [24], Pinv [24], i, j, k, jnew, p, inew, result ; + double Control [AMD_CONTROL], Info [AMD_INFO] ; + char A [24][24] ; + + /* here is an example of how to use AMD_VERSION. This code will work in + * any version of AMD. */ +#if defined(AMD_VERSION) && (AMD_VERSION >= AMD_VERSION_CODE(1,2)) + printf ("AMD version %d.%d.%d, date: %s\n", + AMD_MAIN_VERSION, AMD_SUB_VERSION, AMD_SUBSUB_VERSION, AMD_DATE) ; +#else + printf ("AMD version: 1.1 or earlier\n") ; +#endif + + printf ("AMD demo, with the 24-by-24 Harwell/Boeing matrix, can_24:\n") ; + + /* get the default parameters, and print them */ + amd_defaults (Control) ; + amd_control (Control) ; + + /* print the input matrix */ + nz = Ap [n] ; + printf ("\nInput matrix: %d-by-%d, with %d entries.\n" + " Note that for a symmetric matrix such as this one, only the\n" + " strictly lower or upper triangular parts would need to be\n" + " passed to AMD, since AMD computes the ordering of A+A'. The\n" + " diagonal entries are also not needed, since AMD ignores them.\n" + , n, n, nz) ; + for (j = 0 ; j < n ; j++) + { + printf ("\nColumn: %d, number of entries: %d, with row indices in" + " Ai [%d ... %d]:\n row indices:", + j, Ap [j+1] - Ap [j], Ap [j], Ap [j+1]-1) ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + i = Ai [p] ; + printf (" %d", i) ; + } + printf ("\n") ; + } + + /* print a character plot of the input matrix. This is only reasonable + * because the matrix is small. */ + printf ("\nPlot of input matrix pattern:\n") ; + for (j = 0 ; j < n ; j++) + { + for (i = 0 ; i < n ; i++) A [i][j] = '.' ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + i = Ai [p] ; + A [i][j] = 'X' ; + } + } + printf (" ") ; + for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ; + printf ("\n") ; + for (i = 0 ; i < n ; i++) + { + printf ("%2d: ", i) ; + for (j = 0 ; j < n ; j++) + { + printf (" %c", A [i][j]) ; + } + printf ("\n") ; + } + + /* order the matrix */ + result = amd_order (n, Ap, Ai, P, Control, Info) ; + printf ("return value from amd_order: %d (should be %d)\n", + result, AMD_OK) ; + + /* print the statistics */ + amd_info (Info) ; + + if (result != AMD_OK) + { + printf ("AMD failed\n") ; + exit (1) ; + } + + /* print the permutation vector, P, and compute the inverse permutation */ + printf ("Permutation vector:\n") ; + for (k = 0 ; k < n ; k++) + { + /* row/column j is the kth row/column in the permuted matrix */ + j = P [k] ; + Pinv [j] = k ; + printf (" %2d", j) ; + } + printf ("\n\n") ; + + printf ("Inverse permutation vector:\n") ; + for (j = 0 ; j < n ; j++) + { + k = Pinv [j] ; + printf (" %2d", k) ; + } + printf ("\n\n") ; + + /* print a character plot of the permuted matrix. */ + printf ("\nPlot of permuted matrix pattern:\n") ; + for (jnew = 0 ; jnew < n ; jnew++) + { + j = P [jnew] ; + for (inew = 0 ; inew < n ; inew++) A [inew][jnew] = '.' ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + inew = Pinv [Ai [p]] ; + A [inew][jnew] = 'X' ; + } + } + printf (" ") ; + for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ; + printf ("\n") ; + for (i = 0 ; i < n ; i++) + { + printf ("%2d: ", i) ; + for (j = 0 ; j < n ; j++) + { + printf (" %c", A [i][j]) ; + } + printf ("\n") ; + } + + return (0) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Demo/amd_demo2.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Demo/amd_demo2.c new file mode 100644 index 0000000..68c1e9e --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Demo/amd_demo2.c @@ -0,0 +1,208 @@ +/* ========================================================================= */ +/* === AMD demo main program (jumbled matrix version) ====================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* AMD Copyright (c) by Timothy A. Davis, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* DrTimothyAldenDavis@gmail.com, http://www.suitesparse.com */ +/* ------------------------------------------------------------------------- */ + +/* A simple C main program that illustrates the use of the ANSI C interface + * to AMD. + * + * Identical to amd_demo.c, except that it operates on an input matrix that has + * unsorted columns and duplicate entries. + */ + +#include "amd.h" +#include <stdio.h> +#include <stdlib.h> + +int main (void) +{ + /* The symmetric can_24 Harwell/Boeing matrix (jumbled, and not symmetric). + * Since AMD operates on A+A', only A(i,j) or A(j,i) need to be specified, + * or both. The diagonal entries are optional (some are missing). + * There are many duplicate entries, which must be removed. */ + int n = 24, nz, + Ap [ ] = { 0, 9, 14, 20, 28, 33, 37, 44, 53, 58, 63, 63, 66, 69, 72, 75, + 78, 82, 86, 91, 97, 101, 112, 112, 116 }, + Ai [ ] = { + /* column 0: */ 0, 17, 18, 21, 5, 12, 5, 0, 13, + /* column 1: */ 14, 1, 8, 13, 17, + /* column 2: */ 2, 20, 11, 6, 11, 22, + /* column 3: */ 3, 3, 10, 7, 18, 18, 15, 19, + /* column 4: */ 7, 9, 15, 14, 16, + /* column 5: */ 5, 13, 6, 17, + /* column 6: */ 5, 0, 11, 6, 12, 6, 23, + /* column 7: */ 3, 4, 9, 7, 14, 16, 15, 17, 18, + /* column 8: */ 1, 9, 14, 14, 14, + /* column 9: */ 7, 13, 8, 1, 17, + /* column 10: */ + /* column 11: */ 2, 12, 23, + /* column 12: */ 5, 11, 12, + /* column 13: */ 0, 13, 17, + /* column 14: */ 1, 9, 14, + /* column 15: */ 3, 15, 16, + /* column 16: */ 16, 4, 4, 15, + /* column 17: */ 13, 17, 19, 17, + /* column 18: */ 15, 17, 19, 9, 10, + /* column 19: */ 17, 19, 20, 0, 6, 10, + /* column 20: */ 22, 10, 20, 21, + /* column 21: */ 6, 2, 10, 19, 20, 11, 21, 22, 22, 22, 22, + /* column 22: */ + /* column 23: */ 12, 11, 12, 23 } ; + + int P [24], Pinv [24], i, j, k, jnew, p, inew, result ; + double Control [AMD_CONTROL], Info [AMD_INFO] ; + char A [24][24] ; + + printf ("AMD demo, with a jumbled version of the 24-by-24\n") ; + printf ("Harwell/Boeing matrix, can_24:\n") ; + + /* get the default parameters, and print them */ + amd_defaults (Control) ; + amd_control (Control) ; + + /* print the input matrix */ + nz = Ap [n] ; + printf ("\nJumbled input matrix: %d-by-%d, with %d entries.\n" + " Note that for a symmetric matrix such as this one, only the\n" + " strictly lower or upper triangular parts would need to be\n" + " passed to AMD, since AMD computes the ordering of A+A'. The\n" + " diagonal entries are also not needed, since AMD ignores them.\n" + " This version of the matrix has jumbled columns and duplicate\n" + " row indices.\n", n, n, nz) ; + for (j = 0 ; j < n ; j++) + { + printf ("\nColumn: %d, number of entries: %d, with row indices in" + " Ai [%d ... %d]:\n row indices:", + j, Ap [j+1] - Ap [j], Ap [j], Ap [j+1]-1) ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + i = Ai [p] ; + printf (" %d", i) ; + } + printf ("\n") ; + } + + /* print a character plot of the input matrix. This is only reasonable + * because the matrix is small. */ + printf ("\nPlot of (jumbled) input matrix pattern:\n") ; + for (j = 0 ; j < n ; j++) + { + for (i = 0 ; i < n ; i++) A [i][j] = '.' ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + i = Ai [p] ; + A [i][j] = 'X' ; + } + } + printf (" ") ; + for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ; + printf ("\n") ; + for (i = 0 ; i < n ; i++) + { + printf ("%2d: ", i) ; + for (j = 0 ; j < n ; j++) + { + printf (" %c", A [i][j]) ; + } + printf ("\n") ; + } + + /* print a character plot of the matrix A+A'. */ + printf ("\nPlot of symmetric matrix to be ordered by amd_order:\n") ; + for (j = 0 ; j < n ; j++) + { + for (i = 0 ; i < n ; i++) A [i][j] = '.' ; + } + for (j = 0 ; j < n ; j++) + { + A [j][j] = 'X' ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + i = Ai [p] ; + A [i][j] = 'X' ; + A [j][i] = 'X' ; + } + } + printf (" ") ; + for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ; + printf ("\n") ; + for (i = 0 ; i < n ; i++) + { + printf ("%2d: ", i) ; + for (j = 0 ; j < n ; j++) + { + printf (" %c", A [i][j]) ; + } + printf ("\n") ; + } + + /* order the matrix */ + result = amd_order (n, Ap, Ai, P, Control, Info) ; + printf ("return value from amd_order: %d (should be %d)\n", + result, AMD_OK_BUT_JUMBLED) ; + + /* print the statistics */ + amd_info (Info) ; + + if (result != AMD_OK_BUT_JUMBLED) + { + printf ("AMD failed\n") ; + exit (1) ; + } + + /* print the permutation vector, P, and compute the inverse permutation */ + printf ("Permutation vector:\n") ; + for (k = 0 ; k < n ; k++) + { + /* row/column j is the kth row/column in the permuted matrix */ + j = P [k] ; + Pinv [j] = k ; + printf (" %2d", j) ; + } + printf ("\n\n") ; + + printf ("Inverse permutation vector:\n") ; + for (j = 0 ; j < n ; j++) + { + k = Pinv [j] ; + printf (" %2d", k) ; + } + printf ("\n\n") ; + + /* print a character plot of the permuted matrix. */ + printf ("\nPlot of (symmetrized) permuted matrix pattern:\n") ; + for (j = 0 ; j < n ; j++) + { + for (i = 0 ; i < n ; i++) A [i][j] = '.' ; + } + for (jnew = 0 ; jnew < n ; jnew++) + { + j = P [jnew] ; + A [jnew][jnew] = 'X' ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + inew = Pinv [Ai [p]] ; + A [inew][jnew] = 'X' ; + A [jnew][inew] = 'X' ; + } + } + printf (" ") ; + for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ; + printf ("\n") ; + for (i = 0 ; i < n ; i++) + { + printf ("%2d: ", i) ; + for (j = 0 ; j < n ; j++) + { + printf (" %c", A [i][j]) ; + } + printf ("\n") ; + } + + return (0) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Demo/amd_f77wrapper.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Demo/amd_f77wrapper.c new file mode 100644 index 0000000..d918845 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Demo/amd_f77wrapper.c @@ -0,0 +1,87 @@ +/* ========================================================================= */ +/* === amd_f77wrapper ====================================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* AMD Copyright (c) by Timothy A. Davis, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* Fortran interface for the C-callable AMD library (int version only). This + * is HIGHLY non-portable. You will need to modify this depending on how your + * Fortran and C compilers behave. Two examples are provided. + * + * To avoid using I/O, and to avoid the extra porting step of a Fortran + * function, the status code is returned as the first entry in P (P [0] in C + * and P (1) in Fortran) if an error occurs. The error codes are negative + * (-1: out of memory, -2: invalid matrix). + * + * For some C and Fortran compilers, the Fortran compiler appends a single "_" + * after each routine name. C doesn't do this, so the translation is made + * here. Some Fortran compilers don't append an underscore (xlf on IBM AIX, + * for * example). + */ + +#include "amd.h" +#include <stdio.h> + +/* ------------------------------------------------------------------------- */ +/* Linux, Solaris, SGI */ +/* ------------------------------------------------------------------------- */ + +void amdorder_ (int *n, const int *Ap, const int *Ai, int *P, + double *Control, double *Info) +{ + int result = amd_order (*n, Ap, Ai, P, Control, Info) ; + if (result != AMD_OK && P) P [0] = result ; +} + +void amddefaults_ (double *Control) +{ + amd_defaults (Control) ; +} + +void amdcontrol_ (double *Control) +{ + fflush (stdout) ; + amd_control (Control) ; + fflush (stdout) ; +} + +void amdinfo_ (double *Info) +{ + fflush (stdout) ; + amd_info (Info) ; + fflush (stdout) ; +} + +/* ------------------------------------------------------------------------- */ +/* IBM AIX. Probably Windows, Compaq Alpha, and HP Unix as well. */ +/* ------------------------------------------------------------------------- */ + +void amdorder (int *n, const int *Ap, const int *Ai, int *P, + double *Control, double *Info) +{ + int result = amd_order (*n, Ap, Ai, P, Control, Info) ; + if (result != AMD_OK && P) P [0] = result ; +} + +void amddefaults (double *Control) +{ + amd_defaults (Control) ; +} + +void amdcontrol (double *Control) +{ + fflush (stdout) ; + amd_control (Control) ; + fflush (stdout) ; +} + +void amdinfo (double *Info) +{ + fflush (stdout) ; + amd_info (Info) ; + fflush (stdout) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Demo/amd_l_demo.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Demo/amd_l_demo.c new file mode 100644 index 0000000..62a0591 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Demo/amd_l_demo.c @@ -0,0 +1,178 @@ +/* ========================================================================= */ +/* === AMD demo main program (long integer version) ======================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* AMD Copyright (c) by Timothy A. Davis, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* A simple C main program that illustrates the use of the ANSI C interface + * to AMD. + */ + +#include "amd.h" +#include <stdio.h> +#include <stdlib.h> +#define Long SuiteSparse_long + +int main (void) +{ + /* The symmetric can_24 Harwell/Boeing matrix, including upper and lower + * triangular parts, and the diagonal entries. Note that this matrix is + * 0-based, with row and column indices in the range 0 to n-1. */ + Long n = 24, nz, + Ap [ ] = { 0, 9, 15, 21, 27, 33, 39, 48, 57, 61, 70, 76, 82, 88, 94, 100, + 106, 110, 119, 128, 137, 143, 152, 156, 160 }, + Ai [ ] = { + /* column 0: */ 0, 5, 6, 12, 13, 17, 18, 19, 21, + /* column 1: */ 1, 8, 9, 13, 14, 17, + /* column 2: */ 2, 6, 11, 20, 21, 22, + /* column 3: */ 3, 7, 10, 15, 18, 19, + /* column 4: */ 4, 7, 9, 14, 15, 16, + /* column 5: */ 0, 5, 6, 12, 13, 17, + /* column 6: */ 0, 2, 5, 6, 11, 12, 19, 21, 23, + /* column 7: */ 3, 4, 7, 9, 14, 15, 16, 17, 18, + /* column 8: */ 1, 8, 9, 14, + /* column 9: */ 1, 4, 7, 8, 9, 13, 14, 17, 18, + /* column 10: */ 3, 10, 18, 19, 20, 21, + /* column 11: */ 2, 6, 11, 12, 21, 23, + /* column 12: */ 0, 5, 6, 11, 12, 23, + /* column 13: */ 0, 1, 5, 9, 13, 17, + /* column 14: */ 1, 4, 7, 8, 9, 14, + /* column 15: */ 3, 4, 7, 15, 16, 18, + /* column 16: */ 4, 7, 15, 16, + /* column 17: */ 0, 1, 5, 7, 9, 13, 17, 18, 19, + /* column 18: */ 0, 3, 7, 9, 10, 15, 17, 18, 19, + /* column 19: */ 0, 3, 6, 10, 17, 18, 19, 20, 21, + /* column 20: */ 2, 10, 19, 20, 21, 22, + /* column 21: */ 0, 2, 6, 10, 11, 19, 20, 21, 22, + /* column 22: */ 2, 20, 21, 22, + /* column 23: */ 6, 11, 12, 23 } ; + + Long P [24], Pinv [24], i, j, k, jnew, p, inew, result ; + double Control [AMD_CONTROL], Info [AMD_INFO] ; + char A [24][24] ; + + /* here is an example of how to use AMD_VERSION. This code will work in + * any version of AMD. */ +#if defined(AMD_VERSION) && (AMD_VERSION >= AMD_VERSION_CODE(1,2)) + printf ("AMD version %d.%d.%d, date: %s\n", + AMD_MAIN_VERSION, AMD_SUB_VERSION, AMD_SUBSUB_VERSION, AMD_DATE) ; +#else + printf ("AMD version: 1.1 or earlier\n") ; +#endif + + printf ("AMD demo, with the 24-by-24 Harwell/Boeing matrix, can_24:\n") ; + + /* get the default parameters, and print them */ + amd_l_defaults (Control) ; + amd_l_control (Control) ; + + /* print the input matrix */ + nz = Ap [n] ; + printf ("\nInput matrix: %ld-by-%ld, with %ld entries.\n" + " Note that for a symmetric matrix such as this one, only the\n" + " strictly lower or upper triangular parts would need to be\n" + " passed to AMD, since AMD computes the ordering of A+A'. The\n" + " diagonal entries are also not needed, since AMD ignores them.\n" + , n, n, nz) ; + for (j = 0 ; j < n ; j++) + { + printf ("\nColumn: %ld, number of entries: %ld, with row indices in" + " Ai [%ld ... %ld]:\n row indices:", + j, Ap [j+1] - Ap [j], Ap [j], Ap [j+1]-1) ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + i = Ai [p] ; + printf (" %ld", i) ; + } + printf ("\n") ; + } + + /* print a character plot of the input matrix. This is only reasonable + * because the matrix is small. */ + printf ("\nPlot of input matrix pattern:\n") ; + for (j = 0 ; j < n ; j++) + { + for (i = 0 ; i < n ; i++) A [i][j] = '.' ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + i = Ai [p] ; + A [i][j] = 'X' ; + } + } + printf (" ") ; + for (j = 0 ; j < n ; j++) printf (" %1ld", j % 10) ; + printf ("\n") ; + for (i = 0 ; i < n ; i++) + { + printf ("%2ld: ", i) ; + for (j = 0 ; j < n ; j++) + { + printf (" %c", A [i][j]) ; + } + printf ("\n") ; + } + + /* order the matrix */ + result = amd_l_order (n, Ap, Ai, P, Control, Info) ; + printf ("return value from amd_l_order: %ld (should be %d)\n", + result, AMD_OK) ; + + /* print the statistics */ + amd_l_info (Info) ; + + if (result != AMD_OK) + { + printf ("AMD failed\n") ; + exit (1) ; + } + + /* print the permutation vector, P, and compute the inverse permutation */ + printf ("Permutation vector:\n") ; + for (k = 0 ; k < n ; k++) + { + /* row/column j is the kth row/column in the permuted matrix */ + j = P [k] ; + Pinv [j] = k ; + printf (" %2ld", j) ; + } + printf ("\n\n") ; + + printf ("Inverse permutation vector:\n") ; + for (j = 0 ; j < n ; j++) + { + k = Pinv [j] ; + printf (" %2ld", k) ; + } + printf ("\n\n") ; + + /* print a character plot of the permuted matrix. */ + printf ("\nPlot of permuted matrix pattern:\n") ; + for (jnew = 0 ; jnew < n ; jnew++) + { + j = P [jnew] ; + for (inew = 0 ; inew < n ; inew++) A [inew][jnew] = '.' ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + inew = Pinv [Ai [p]] ; + A [inew][jnew] = 'X' ; + } + } + printf (" ") ; + for (j = 0 ; j < n ; j++) printf (" %1ld", j % 10) ; + printf ("\n") ; + for (i = 0 ; i < n ; i++) + { + printf ("%2ld: ", i) ; + for (j = 0 ; j < n ; j++) + { + printf (" %c", A [i][j]) ; + } + printf ("\n") ; + } + + return (0) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Demo/amd_simple.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Demo/amd_simple.c new file mode 100644 index 0000000..5241fb1 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Demo/amd_simple.c @@ -0,0 +1,22 @@ +/* ------------------------------------------------------------------------- */ +/* AMD Copyright (c) by Timothy A. Davis, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +#include <stdio.h> +#include "amd.h" + +int n = 5 ; +int Ap [ ] = { 0, 2, 6, 10, 12, 14} ; +int Ai [ ] = { 0,1, 0,1,2,4, 1,2,3,4, 2,3, 1,4 } ; +int P [5] ; + +int main (void) +{ + int k ; + (void) amd_order (n, Ap, Ai, P, (double *) NULL, (double *) NULL) ; + for (k = 0 ; k < n ; k++) printf ("P [%d] = %d\n", k, P [k]) ; + return (0) ; +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Include/amd.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Include/amd.h new file mode 100644 index 0000000..a72851f --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Include/amd.h @@ -0,0 +1,400 @@ +/* ========================================================================= */ +/* === AMD: approximate minimum degree ordering =========================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* AMD Version 2.4, Copyright (c) 1996-2013 by Timothy A. Davis, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* AMD finds a symmetric ordering P of a matrix A so that the Cholesky + * factorization of P*A*P' has fewer nonzeros and takes less work than the + * Cholesky factorization of A. If A is not symmetric, then it performs its + * ordering on the matrix A+A'. Two sets of user-callable routines are + * provided, one for int integers and the other for SuiteSparse_long integers. + * + * The method is based on the approximate minimum degree algorithm, discussed + * in Amestoy, Davis, and Duff, "An approximate degree ordering algorithm", + * SIAM Journal of Matrix Analysis and Applications, vol. 17, no. 4, pp. + * 886-905, 1996. This package can perform both the AMD ordering (with + * aggressive absorption), and the AMDBAR ordering (without aggressive + * absorption) discussed in the above paper. This package differs from the + * Fortran codes discussed in the paper: + * + * (1) it can ignore "dense" rows and columns, leading to faster run times + * (2) it computes the ordering of A+A' if A is not symmetric + * (3) it is followed by a depth-first post-ordering of the assembly tree + * (or supernodal elimination tree) + * + * For historical reasons, the Fortran versions, amd.f and amdbar.f, have + * been left (nearly) unchanged. They compute the identical ordering as + * described in the above paper. + */ + +#ifndef AMD_H +#define AMD_H + +/* make it easy for C++ programs to include AMD */ +#ifdef __cplusplus +extern "C" { +#endif + +/* get the definition of size_t: */ +#include <stddef.h> + +#include "SuiteSparse_config.h" + +int amd_order /* returns AMD_OK, AMD_OK_BUT_JUMBLED, + * AMD_INVALID, or AMD_OUT_OF_MEMORY */ +( + int n, /* A is n-by-n. n must be >= 0. */ + const int Ap [ ], /* column pointers for A, of size n+1 */ + const int Ai [ ], /* row indices of A, of size nz = Ap [n] */ + int P [ ], /* output permutation, of size n */ + double Control [ ], /* input Control settings, of size AMD_CONTROL */ + double Info [ ] /* output Info statistics, of size AMD_INFO */ +) ; + +SuiteSparse_long amd_l_order /* see above for description of arguments */ +( + SuiteSparse_long n, + const SuiteSparse_long Ap [ ], + const SuiteSparse_long Ai [ ], + SuiteSparse_long P [ ], + double Control [ ], + double Info [ ] +) ; + +/* Input arguments (not modified): + * + * n: the matrix A is n-by-n. + * Ap: an int/SuiteSparse_long array of size n+1, containing column + * pointers of A. + * Ai: an int/SuiteSparse_long array of size nz, containing the row + * indices of A, where nz = Ap [n]. + * Control: a double array of size AMD_CONTROL, containing control + * parameters. Defaults are used if Control is NULL. + * + * Output arguments (not defined on input): + * + * P: an int/SuiteSparse_long array of size n, containing the output + * permutation. If row i is the kth pivot row, then P [k] = i. In + * MATLAB notation, the reordered matrix is A (P,P). + * Info: a double array of size AMD_INFO, containing statistical + * information. Ignored if Info is NULL. + * + * On input, the matrix A is stored in column-oriented form. The row indices + * of nonzero entries in column j are stored in Ai [Ap [j] ... Ap [j+1]-1]. + * + * If the row indices appear in ascending order in each column, and there + * are no duplicate entries, then amd_order is slightly more efficient in + * terms of time and memory usage. If this condition does not hold, a copy + * of the matrix is created (where these conditions do hold), and the copy is + * ordered. This feature is new to v2.0 (v1.2 and earlier required this + * condition to hold for the input matrix). + * + * Row indices must be in the range 0 to + * n-1. Ap [0] must be zero, and thus nz = Ap [n] is the number of nonzeros + * in A. The array Ap is of size n+1, and the array Ai is of size nz = Ap [n]. + * The matrix does not need to be symmetric, and the diagonal does not need to + * be present (if diagonal entries are present, they are ignored except for + * the output statistic Info [AMD_NZDIAG]). The arrays Ai and Ap are not + * modified. This form of the Ap and Ai arrays to represent the nonzero + * pattern of the matrix A is the same as that used internally by MATLAB. + * If you wish to use a more flexible input structure, please see the + * umfpack_*_triplet_to_col routines in the UMFPACK package, at + * http://www.suitesparse.com. + * + * Restrictions: n >= 0. Ap [0] = 0. Ap [j] <= Ap [j+1] for all j in the + * range 0 to n-1. nz = Ap [n] >= 0. Ai [0..nz-1] must be in the range 0 + * to n-1. Finally, Ai, Ap, and P must not be NULL. If any of these + * restrictions are not met, AMD returns AMD_INVALID. + * + * AMD returns: + * + * AMD_OK if the matrix is valid and sufficient memory can be allocated to + * perform the ordering. + * + * AMD_OUT_OF_MEMORY if not enough memory can be allocated. + * + * AMD_INVALID if the input arguments n, Ap, Ai are invalid, or if P is + * NULL. + * + * AMD_OK_BUT_JUMBLED if the matrix had unsorted columns, and/or duplicate + * entries, but was otherwise valid. + * + * The AMD routine first forms the pattern of the matrix A+A', and then + * computes a fill-reducing ordering, P. If P [k] = i, then row/column i of + * the original is the kth pivotal row. In MATLAB notation, the permuted + * matrix is A (P,P), except that 0-based indexing is used instead of the + * 1-based indexing in MATLAB. + * + * The Control array is used to set various parameters for AMD. If a NULL + * pointer is passed, default values are used. The Control array is not + * modified. + * + * Control [AMD_DENSE]: controls the threshold for "dense" rows/columns. + * A dense row/column in A+A' can cause AMD to spend a lot of time in + * ordering the matrix. If Control [AMD_DENSE] >= 0, rows/columns + * with more than Control [AMD_DENSE] * sqrt (n) entries are ignored + * during the ordering, and placed last in the output order. The + * default value of Control [AMD_DENSE] is 10. If negative, no + * rows/columns are treated as "dense". Rows/columns with 16 or + * fewer off-diagonal entries are never considered "dense". + * + * Control [AMD_AGGRESSIVE]: controls whether or not to use aggressive + * absorption, in which a prior element is absorbed into the current + * element if is a subset of the current element, even if it is not + * adjacent to the current pivot element (refer to Amestoy, Davis, + * & Duff, 1996, for more details). The default value is nonzero, + * which means to perform aggressive absorption. This nearly always + * leads to a better ordering (because the approximate degrees are + * more accurate) and a lower execution time. There are cases where + * it can lead to a slightly worse ordering, however. To turn it off, + * set Control [AMD_AGGRESSIVE] to 0. + * + * Control [2..4] are not used in the current version, but may be used in + * future versions. + * + * The Info array provides statistics about the ordering on output. If it is + * not present, the statistics are not returned. This is not an error + * condition. + * + * Info [AMD_STATUS]: the return value of AMD, either AMD_OK, + * AMD_OK_BUT_JUMBLED, AMD_OUT_OF_MEMORY, or AMD_INVALID. + * + * Info [AMD_N]: n, the size of the input matrix + * + * Info [AMD_NZ]: the number of nonzeros in A, nz = Ap [n] + * + * Info [AMD_SYMMETRY]: the symmetry of the matrix A. It is the number + * of "matched" off-diagonal entries divided by the total number of + * off-diagonal entries. An entry A(i,j) is matched if A(j,i) is also + * an entry, for any pair (i,j) for which i != j. In MATLAB notation, + * S = spones (A) ; + * B = tril (S, -1) + triu (S, 1) ; + * symmetry = nnz (B & B') / nnz (B) ; + * + * Info [AMD_NZDIAG]: the number of entries on the diagonal of A. + * + * Info [AMD_NZ_A_PLUS_AT]: the number of nonzeros in A+A', excluding the + * diagonal. If A is perfectly symmetric (Info [AMD_SYMMETRY] = 1) + * with a fully nonzero diagonal, then Info [AMD_NZ_A_PLUS_AT] = nz-n + * (the smallest possible value). If A is perfectly unsymmetric + * (Info [AMD_SYMMETRY] = 0, for an upper triangular matrix, for + * example) with no diagonal, then Info [AMD_NZ_A_PLUS_AT] = 2*nz + * (the largest possible value). + * + * Info [AMD_NDENSE]: the number of "dense" rows/columns of A+A' that were + * removed from A prior to ordering. These are placed last in the + * output order P. + * + * Info [AMD_MEMORY]: the amount of memory used by AMD, in bytes. In the + * current version, this is 1.2 * Info [AMD_NZ_A_PLUS_AT] + 9*n + * times the size of an integer. This is at most 2.4nz + 9n. This + * excludes the size of the input arguments Ai, Ap, and P, which have + * a total size of nz + 2*n + 1 integers. + * + * Info [AMD_NCMPA]: the number of garbage collections performed. + * + * Info [AMD_LNZ]: the number of nonzeros in L (excluding the diagonal). + * This is a slight upper bound because mass elimination is combined + * with the approximate degree update. It is a rough upper bound if + * there are many "dense" rows/columns. The rest of the statistics, + * below, are also slight or rough upper bounds, for the same reasons. + * The post-ordering of the assembly tree might also not exactly + * correspond to a true elimination tree postordering. + * + * Info [AMD_NDIV]: the number of divide operations for a subsequent LDL' + * or LU factorization of the permuted matrix A (P,P). + * + * Info [AMD_NMULTSUBS_LDL]: the number of multiply-subtract pairs for a + * subsequent LDL' factorization of A (P,P). + * + * Info [AMD_NMULTSUBS_LU]: the number of multiply-subtract pairs for a + * subsequent LU factorization of A (P,P), assuming that no numerical + * pivoting is required. + * + * Info [AMD_DMAX]: the maximum number of nonzeros in any column of L, + * including the diagonal. + * + * Info [14..19] are not used in the current version, but may be used in + * future versions. + */ + +/* ------------------------------------------------------------------------- */ +/* direct interface to AMD */ +/* ------------------------------------------------------------------------- */ + +/* amd_2 is the primary AMD ordering routine. It is not meant to be + * user-callable because of its restrictive inputs and because it destroys + * the user's input matrix. It does not check its inputs for errors, either. + * However, if you can work with these restrictions it can be faster than + * amd_order and use less memory (assuming that you can create your own copy + * of the matrix for AMD to destroy). Refer to AMD/Source/amd_2.c for a + * description of each parameter. */ + +void amd_2 +( + int n, + int Pe [ ], + int Iw [ ], + int Len [ ], + int iwlen, + int pfree, + int Nv [ ], + int Next [ ], + int Last [ ], + int Head [ ], + int Elen [ ], + int Degree [ ], + int W [ ], + double Control [ ], + double Info [ ] +) ; + +void amd_l2 +( + SuiteSparse_long n, + SuiteSparse_long Pe [ ], + SuiteSparse_long Iw [ ], + SuiteSparse_long Len [ ], + SuiteSparse_long iwlen, + SuiteSparse_long pfree, + SuiteSparse_long Nv [ ], + SuiteSparse_long Next [ ], + SuiteSparse_long Last [ ], + SuiteSparse_long Head [ ], + SuiteSparse_long Elen [ ], + SuiteSparse_long Degree [ ], + SuiteSparse_long W [ ], + double Control [ ], + double Info [ ] +) ; + +/* ------------------------------------------------------------------------- */ +/* amd_valid */ +/* ------------------------------------------------------------------------- */ + +/* Returns AMD_OK or AMD_OK_BUT_JUMBLED if the matrix is valid as input to + * amd_order; the latter is returned if the matrix has unsorted and/or + * duplicate row indices in one or more columns. Returns AMD_INVALID if the + * matrix cannot be passed to amd_order. For amd_order, the matrix must also + * be square. The first two arguments are the number of rows and the number + * of columns of the matrix. For its use in AMD, these must both equal n. + * + * NOTE: this routine returned TRUE/FALSE in v1.2 and earlier. + */ + +int amd_valid +( + int n_row, /* # of rows */ + int n_col, /* # of columns */ + const int Ap [ ], /* column pointers, of size n_col+1 */ + const int Ai [ ] /* row indices, of size Ap [n_col] */ +) ; + +SuiteSparse_long amd_l_valid +( + SuiteSparse_long n_row, + SuiteSparse_long n_col, + const SuiteSparse_long Ap [ ], + const SuiteSparse_long Ai [ ] +) ; + +/* ------------------------------------------------------------------------- */ +/* AMD memory manager and printf routines */ +/* ------------------------------------------------------------------------- */ + + /* moved to SuiteSparse_config.c */ + +/* ------------------------------------------------------------------------- */ +/* AMD Control and Info arrays */ +/* ------------------------------------------------------------------------- */ + +/* amd_defaults: sets the default control settings */ +void amd_defaults (double Control [ ]) ; +void amd_l_defaults (double Control [ ]) ; + +/* amd_control: prints the control settings */ +void amd_control (double Control [ ]) ; +void amd_l_control (double Control [ ]) ; + +/* amd_info: prints the statistics */ +void amd_info (double Info [ ]) ; +void amd_l_info (double Info [ ]) ; + +#define AMD_CONTROL 5 /* size of Control array */ +#define AMD_INFO 20 /* size of Info array */ + +/* contents of Control */ +#define AMD_DENSE 0 /* "dense" if degree > Control [0] * sqrt (n) */ +#define AMD_AGGRESSIVE 1 /* do aggressive absorption if Control [1] != 0 */ + +/* default Control settings */ +#define AMD_DEFAULT_DENSE 10.0 /* default "dense" degree 10*sqrt(n) */ +#define AMD_DEFAULT_AGGRESSIVE 1 /* do aggressive absorption by default */ + +/* contents of Info */ +#define AMD_STATUS 0 /* return value of amd_order and amd_l_order */ +#define AMD_N 1 /* A is n-by-n */ +#define AMD_NZ 2 /* number of nonzeros in A */ +#define AMD_SYMMETRY 3 /* symmetry of pattern (1 is sym., 0 is unsym.) */ +#define AMD_NZDIAG 4 /* # of entries on diagonal */ +#define AMD_NZ_A_PLUS_AT 5 /* nz in A+A' */ +#define AMD_NDENSE 6 /* number of "dense" rows/columns in A */ +#define AMD_MEMORY 7 /* amount of memory used by AMD */ +#define AMD_NCMPA 8 /* number of garbage collections in AMD */ +#define AMD_LNZ 9 /* approx. nz in L, excluding the diagonal */ +#define AMD_NDIV 10 /* number of fl. point divides for LU and LDL' */ +#define AMD_NMULTSUBS_LDL 11 /* number of fl. point (*,-) pairs for LDL' */ +#define AMD_NMULTSUBS_LU 12 /* number of fl. point (*,-) pairs for LU */ +#define AMD_DMAX 13 /* max nz. in any column of L, incl. diagonal */ + +/* ------------------------------------------------------------------------- */ +/* return values of AMD */ +/* ------------------------------------------------------------------------- */ + +#define AMD_OK 0 /* success */ +#define AMD_OUT_OF_MEMORY -1 /* malloc failed, or problem too large */ +#define AMD_INVALID -2 /* input arguments are not valid */ +#define AMD_OK_BUT_JUMBLED 1 /* input matrix is OK for amd_order, but + * columns were not sorted, and/or duplicate entries were present. AMD had + * to do extra work before ordering the matrix. This is a warning, not an + * error. */ + +/* ========================================================================== */ +/* === AMD version ========================================================== */ +/* ========================================================================== */ + +/* AMD Version 1.2 and later include the following definitions. + * As an example, to test if the version you are using is 1.2 or later: + * + * #ifdef AMD_VERSION + * if (AMD_VERSION >= AMD_VERSION_CODE (1,2)) ... + * #endif + * + * This also works during compile-time: + * + * #if defined(AMD_VERSION) && (AMD_VERSION >= AMD_VERSION_CODE (1,2)) + * printf ("This is version 1.2 or later\n") ; + * #else + * printf ("This is an early version\n") ; + * #endif + * + * Versions 1.1 and earlier of AMD do not include a #define'd version number. + */ + +#define AMD_DATE "May 4, 2016" +#define AMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) +#define AMD_MAIN_VERSION 2 +#define AMD_SUB_VERSION 4 +#define AMD_SUBSUB_VERSION 6 +#define AMD_VERSION AMD_VERSION_CODE(AMD_MAIN_VERSION,AMD_SUB_VERSION) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Include/amd_internal.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Include/amd_internal.h new file mode 100644 index 0000000..6730527 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Include/amd_internal.h @@ -0,0 +1,326 @@ +/* ========================================================================= */ +/* === amd_internal.h ====================================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* AMD, Copyright (c) Timothy A. Davis, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* This file is for internal use in AMD itself, and does not normally need to + * be included in user code (it is included in UMFPACK, however). All others + * should use amd.h instead. + */ + +/* ========================================================================= */ +/* === NDEBUG ============================================================== */ +/* ========================================================================= */ + +/* + * Turning on debugging takes some work (see below). If you do not edit this + * file, then debugging is always turned off, regardless of whether or not + * -DNDEBUG is specified in your compiler options. + * + * If AMD is being compiled as a mexFunction, then MATLAB_MEX_FILE is defined, + * and mxAssert is used instead of assert. If debugging is not enabled, no + * MATLAB include files or functions are used. Thus, the AMD library libamd.a + * can be safely used in either a stand-alone C program or in another + * mexFunction, without any change. + */ + +/* + AMD will be exceedingly slow when running in debug mode. The next three + lines ensure that debugging is turned off. +*/ +#ifndef NDEBUG +#define NDEBUG +#endif + +/* + To enable debugging, uncomment the following line: +#undef NDEBUG +*/ + +/* ------------------------------------------------------------------------- */ +/* ANSI include files */ +/* ------------------------------------------------------------------------- */ + +/* from stdlib.h: size_t, malloc, free, realloc, and calloc */ +#include <stdlib.h> + +#if !defined(NPRINT) || !defined(NDEBUG) +/* from stdio.h: printf. Not included if NPRINT is defined at compile time. + * fopen and fscanf are used when debugging. */ +#include <stdio.h> +#endif + +/* from limits.h: INT_MAX and LONG_MAX */ +#include <limits.h> + +/* from math.h: sqrt */ +#include <math.h> + +/* ------------------------------------------------------------------------- */ +/* MATLAB include files (only if being used in or via MATLAB) */ +/* ------------------------------------------------------------------------- */ + +#ifdef MATLAB_MEX_FILE +#include "matrix.h" +#include "mex.h" +#endif + +/* ------------------------------------------------------------------------- */ +/* basic definitions */ +/* ------------------------------------------------------------------------- */ + +#ifdef FLIP +#undef FLIP +#endif + +#ifdef MAX +#undef MAX +#endif + +#ifdef MIN +#undef MIN +#endif + +#ifdef EMPTY +#undef EMPTY +#endif + +#ifdef GLOBAL +#undef GLOBAL +#endif + +#ifdef PRIVATE +#undef PRIVATE +#endif + +/* FLIP is a "negation about -1", and is used to mark an integer i that is + * normally non-negative. FLIP (EMPTY) is EMPTY. FLIP of a number > EMPTY + * is negative, and FLIP of a number < EMTPY is positive. FLIP (FLIP (i)) = i + * for all integers i. UNFLIP (i) is >= EMPTY. */ +#define EMPTY (-1) +#define FLIP(i) (-(i)-2) +#define UNFLIP(i) ((i < EMPTY) ? FLIP (i) : (i)) + +/* for integer MAX/MIN, or for doubles when we don't care how NaN's behave: */ +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +/* logical expression of p implies q: */ +#define IMPLIES(p,q) (!(p) || (q)) + +/* Note that the IBM RS 6000 xlc predefines TRUE and FALSE in <types.h>. */ +/* The Compaq Alpha also predefines TRUE and FALSE. */ +#ifdef TRUE +#undef TRUE +#endif +#ifdef FALSE +#undef FALSE +#endif + +#define TRUE (1) +#define FALSE (0) +#define PRIVATE static +#define GLOBAL +#define EMPTY (-1) + +/* Note that Linux's gcc 2.96 defines NULL as ((void *) 0), but other */ +/* compilers (even gcc 2.95.2 on Solaris) define NULL as 0 or (0). We */ +/* need to use the ANSI standard value of 0. */ +#ifdef NULL +#undef NULL +#endif + +#define NULL 0 + +/* largest value of size_t */ +#ifndef SIZE_T_MAX +#ifdef SIZE_MAX +/* C99 only */ +#define SIZE_T_MAX SIZE_MAX +#else +#define SIZE_T_MAX ((size_t) (-1)) +#endif +#endif + +/* ------------------------------------------------------------------------- */ +/* integer type for AMD: int or SuiteSparse_long */ +/* ------------------------------------------------------------------------- */ + +#include "amd.h" + +#if defined (DLONG) || defined (ZLONG) + +#define Int SuiteSparse_long +#define ID SuiteSparse_long_id +#define Int_MAX SuiteSparse_long_max + +#define AMD_order amd_l_order +#define AMD_defaults amd_l_defaults +#define AMD_control amd_l_control +#define AMD_info amd_l_info +#define AMD_1 amd_l1 +#define AMD_2 amd_l2 +#define AMD_valid amd_l_valid +#define AMD_aat amd_l_aat +#define AMD_postorder amd_l_postorder +#define AMD_post_tree amd_l_post_tree +#define AMD_dump amd_l_dump +#define AMD_debug amd_l_debug +#define AMD_debug_init amd_l_debug_init +#define AMD_preprocess amd_l_preprocess + +#else + +#define Int int +#define ID "%d" +#define Int_MAX INT_MAX + +#define AMD_order amd_order +#define AMD_defaults amd_defaults +#define AMD_control amd_control +#define AMD_info amd_info +#define AMD_1 amd_1 +#define AMD_2 amd_2 +#define AMD_valid amd_valid +#define AMD_aat amd_aat +#define AMD_postorder amd_postorder +#define AMD_post_tree amd_post_tree +#define AMD_dump amd_dump +#define AMD_debug amd_debug +#define AMD_debug_init amd_debug_init +#define AMD_preprocess amd_preprocess + +#endif + +/* ------------------------------------------------------------------------- */ +/* AMD routine definitions (not user-callable) */ +/* ------------------------------------------------------------------------- */ + +GLOBAL size_t AMD_aat +( + Int n, + const Int Ap [ ], + const Int Ai [ ], + Int Len [ ], + Int Tp [ ], + double Info [ ] +) ; + +GLOBAL void AMD_1 +( + Int n, + const Int Ap [ ], + const Int Ai [ ], + Int P [ ], + Int Pinv [ ], + Int Len [ ], + Int slen, + Int S [ ], + double Control [ ], + double Info [ ] +) ; + +GLOBAL void AMD_postorder +( + Int nn, + Int Parent [ ], + Int Npiv [ ], + Int Fsize [ ], + Int Order [ ], + Int Child [ ], + Int Sibling [ ], + Int Stack [ ] +) ; + +GLOBAL Int AMD_post_tree +( + Int root, + Int k, + Int Child [ ], + const Int Sibling [ ], + Int Order [ ], + Int Stack [ ] +#ifndef NDEBUG + , Int nn +#endif +) ; + +GLOBAL void AMD_preprocess +( + Int n, + const Int Ap [ ], + const Int Ai [ ], + Int Rp [ ], + Int Ri [ ], + Int W [ ], + Int Flag [ ] +) ; + +/* ------------------------------------------------------------------------- */ +/* debugging definitions */ +/* ------------------------------------------------------------------------- */ + +#ifndef NDEBUG + +/* from assert.h: assert macro */ +#include <assert.h> + +#ifndef EXTERN +#define EXTERN extern +#endif + +EXTERN Int AMD_debug ; + +GLOBAL void AMD_debug_init ( char *s ) ; + +GLOBAL void AMD_dump +( + Int n, + Int Pe [ ], + Int Iw [ ], + Int Len [ ], + Int iwlen, + Int pfree, + Int Nv [ ], + Int Next [ ], + Int Last [ ], + Int Head [ ], + Int Elen [ ], + Int Degree [ ], + Int W [ ], + Int nel +) ; + +#ifdef ASSERT +#undef ASSERT +#endif + +/* Use mxAssert if AMD is compiled into a mexFunction */ +#ifdef MATLAB_MEX_FILE +#define ASSERT(expression) (mxAssert ((expression), "")) +#else +#define ASSERT(expression) (assert (expression)) +#endif + +#define AMD_DEBUG0(params) { SUITESPARSE_PRINTF (params) ; } +#define AMD_DEBUG1(params) { if (AMD_debug >= 1) SUITESPARSE_PRINTF (params) ; } +#define AMD_DEBUG2(params) { if (AMD_debug >= 2) SUITESPARSE_PRINTF (params) ; } +#define AMD_DEBUG3(params) { if (AMD_debug >= 3) SUITESPARSE_PRINTF (params) ; } +#define AMD_DEBUG4(params) { if (AMD_debug >= 4) SUITESPARSE_PRINTF (params) ; } + +#else + +/* no debugging */ +#define ASSERT(expression) +#define AMD_DEBUG0(params) +#define AMD_DEBUG1(params) +#define AMD_DEBUG2(params) +#define AMD_DEBUG3(params) +#define AMD_DEBUG4(params) + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/MATLAB/amd_mex.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/MATLAB/amd_mex.c new file mode 100644 index 0000000..89fdc9b --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/MATLAB/amd_mex.c @@ -0,0 +1,192 @@ +/* ========================================================================= */ +/* === AMD mexFunction ===================================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* AMD, Copyright (c) Timothy A. Davis, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* + * Usage: + * p = amd (A) + * p = amd (A, Control) + * [p, Info] = amd (A) + * [p, Info] = amd (A, Control) + * Control = amd ; % return the default Control settings for AMD + * amd ; % print the default Control settings for AMD + * + * Given a square matrix A, compute a permutation P suitable for a Cholesky + * factorization of the matrix B (P,P), where B = spones (A) + spones (A'). + * The method used is the approximate minimum degree ordering method. See + * amd.m and amd.h for more information. + * + * The input matrix need not have sorted columns, and can have duplicate + * entries. + */ + +#include "amd.h" +#include "mex.h" +#include "matrix.h" +#define Long SuiteSparse_long + +void mexFunction +( + int nargout, + mxArray *pargout [ ], + int nargin, + const mxArray *pargin [ ] +) +{ + Long i, m, n, *Ap, *Ai, *P, nc, result, spumoni, full ; + double *Pout, *InfoOut, Control [AMD_CONTROL], Info [AMD_INFO], *ControlIn ; + mxArray *A ; + + /* --------------------------------------------------------------------- */ + /* get control parameters */ + /* --------------------------------------------------------------------- */ + + spumoni = 0 ; + if (nargin == 0) + { + /* get the default control parameters, and return */ + pargout [0] = mxCreateDoubleMatrix (AMD_CONTROL, 1, mxREAL) ; + amd_l_defaults (mxGetPr (pargout [0])) ; + if (nargout == 0) + { + amd_l_control (mxGetPr (pargout [0])) ; + } + return ; + } + + amd_l_defaults (Control) ; + if (nargin > 1) + { + ControlIn = mxGetPr (pargin [1]) ; + nc = mxGetM (pargin [1]) * mxGetN (pargin [1]) ; + Control [AMD_DENSE] + = (nc > 0) ? ControlIn [AMD_DENSE] : AMD_DEFAULT_DENSE ; + Control [AMD_AGGRESSIVE] + = (nc > 1) ? ControlIn [AMD_AGGRESSIVE] : AMD_DEFAULT_AGGRESSIVE ; + spumoni = (nc > 2) ? (ControlIn [2] != 0) : 0 ; + } + + if (spumoni > 0) + { + amd_l_control (Control) ; + } + + /* --------------------------------------------------------------------- */ + /* get inputs */ + /* --------------------------------------------------------------------- */ + + if (nargout > 2 || nargin > 2) + { + mexErrMsgTxt ("Usage: p = amd (A)\nor [p, Info] = amd (A, Control)") ; + } + + A = (mxArray *) pargin [0] ; + n = mxGetN (A) ; + m = mxGetM (A) ; + if (spumoni > 0) + { + mexPrintf (" input matrix A is %d-by-%d\n", m, n) ; + } + if (mxGetNumberOfDimensions (A) != 2) + { + mexErrMsgTxt ("amd: A must be 2-dimensional") ; + } + if (m != n) + { + mexErrMsgTxt ("amd: A must be square") ; + } + + /* --------------------------------------------------------------------- */ + /* allocate workspace for output permutation */ + /* --------------------------------------------------------------------- */ + + P = mxMalloc ((n+1) * sizeof (Long)) ; + + /* --------------------------------------------------------------------- */ + /* if A is full, convert to a sparse matrix */ + /* --------------------------------------------------------------------- */ + + full = !mxIsSparse (A) ; + if (full) + { + if (spumoni > 0) + { + mexPrintf ( + " input matrix A is full (sparse copy of A will be created)\n"); + } + mexCallMATLAB (1, &A, 1, (mxArray **) pargin, "sparse") ; + } + Ap = (Long *) mxGetJc (A) ; + Ai = (Long *) mxGetIr (A) ; + if (spumoni > 0) + { + mexPrintf (" input matrix A has %d nonzero entries\n", Ap [n]) ; + } + + /* --------------------------------------------------------------------- */ + /* order the matrix */ + /* --------------------------------------------------------------------- */ + + result = amd_l_order (n, Ap, Ai, P, Control, Info) ; + + /* --------------------------------------------------------------------- */ + /* if A is full, free the sparse copy of A */ + /* --------------------------------------------------------------------- */ + + if (full) + { + mxDestroyArray (A) ; + } + + /* --------------------------------------------------------------------- */ + /* print results (including return value) */ + /* --------------------------------------------------------------------- */ + + if (spumoni > 0) + { + amd_l_info (Info) ; + } + + /* --------------------------------------------------------------------- */ + /* check error conditions */ + /* --------------------------------------------------------------------- */ + + if (result == AMD_OUT_OF_MEMORY) + { + mexErrMsgTxt ("amd: out of memory") ; + } + else if (result == AMD_INVALID) + { + mexErrMsgTxt ("amd: input matrix A is corrupted") ; + } + + /* --------------------------------------------------------------------- */ + /* copy the outputs to MATLAB */ + /* --------------------------------------------------------------------- */ + + /* output permutation, P */ + pargout [0] = mxCreateDoubleMatrix (1, n, mxREAL) ; + Pout = mxGetPr (pargout [0]) ; + for (i = 0 ; i < n ; i++) + { + Pout [i] = P [i] + 1 ; /* change to 1-based indexing for MATLAB */ + } + mxFree (P) ; + + /* Info */ + if (nargout > 1) + { + pargout [1] = mxCreateDoubleMatrix (AMD_INFO, 1, mxREAL) ; + InfoOut = mxGetPr (pargout [1]) ; + for (i = 0 ; i < AMD_INFO ; i++) + { + InfoOut [i] = Info [i] ; + } + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_1.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_1.c new file mode 100644 index 0000000..2be486e --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_1.c @@ -0,0 +1,180 @@ +/* ========================================================================= */ +/* === AMD_1 =============================================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* AMD, Copyright (c) Timothy A. Davis, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* AMD_1: Construct A+A' for a sparse matrix A and perform the AMD ordering. + * + * The n-by-n sparse matrix A can be unsymmetric. It is stored in MATLAB-style + * compressed-column form, with sorted row indices in each column, and no + * duplicate entries. Diagonal entries may be present, but they are ignored. + * Row indices of column j of A are stored in Ai [Ap [j] ... Ap [j+1]-1]. + * Ap [0] must be zero, and nz = Ap [n] is the number of entries in A. The + * size of the matrix, n, must be greater than or equal to zero. + * + * This routine must be preceded by a call to AMD_aat, which computes the + * number of entries in each row/column in A+A', excluding the diagonal. + * Len [j], on input, is the number of entries in row/column j of A+A'. This + * routine constructs the matrix A+A' and then calls AMD_2. No error checking + * is performed (this was done in AMD_valid). + */ + +#include "amd_internal.h" + +GLOBAL void AMD_1 +( + Int n, /* n > 0 */ + const Int Ap [ ], /* input of size n+1, not modified */ + const Int Ai [ ], /* input of size nz = Ap [n], not modified */ + Int P [ ], /* size n output permutation */ + Int Pinv [ ], /* size n output inverse permutation */ + Int Len [ ], /* size n input, undefined on output */ + Int slen, /* slen >= sum (Len [0..n-1]) + 7n, + * ideally slen = 1.2 * sum (Len) + 8n */ + Int S [ ], /* size slen workspace */ + double Control [ ], /* input array of size AMD_CONTROL */ + double Info [ ] /* output array of size AMD_INFO */ +) +{ + Int i, j, k, p, pfree, iwlen, pj, p1, p2, pj2, *Iw, *Pe, *Nv, *Head, + *Elen, *Degree, *s, *W, *Sp, *Tp ; + + /* --------------------------------------------------------------------- */ + /* construct the matrix for AMD_2 */ + /* --------------------------------------------------------------------- */ + + ASSERT (n > 0) ; + + iwlen = slen - 6*n ; + s = S ; + Pe = s ; s += n ; + Nv = s ; s += n ; + Head = s ; s += n ; + Elen = s ; s += n ; + Degree = s ; s += n ; + W = s ; s += n ; + Iw = s ; s += iwlen ; + + ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ; + + /* construct the pointers for A+A' */ + Sp = Nv ; /* use Nv and W as workspace for Sp and Tp [ */ + Tp = W ; + pfree = 0 ; + for (j = 0 ; j < n ; j++) + { + Pe [j] = pfree ; + Sp [j] = pfree ; + pfree += Len [j] ; + } + + /* Note that this restriction on iwlen is slightly more restrictive than + * what is strictly required in AMD_2. AMD_2 can operate with no elbow + * room at all, but it will be very slow. For better performance, at + * least size-n elbow room is enforced. */ + ASSERT (iwlen >= pfree + n) ; + +#ifndef NDEBUG + for (p = 0 ; p < iwlen ; p++) Iw [p] = EMPTY ; +#endif + + for (k = 0 ; k < n ; k++) + { + AMD_DEBUG1 (("Construct row/column k= "ID" of A+A'\n", k)) ; + p1 = Ap [k] ; + p2 = Ap [k+1] ; + + /* construct A+A' */ + for (p = p1 ; p < p2 ; ) + { + /* scan the upper triangular part of A */ + j = Ai [p] ; + ASSERT (j >= 0 && j < n) ; + if (j < k) + { + /* entry A (j,k) in the strictly upper triangular part */ + ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ; + ASSERT (Sp [k] < (k == n-1 ? pfree : Pe [k+1])) ; + Iw [Sp [j]++] = k ; + Iw [Sp [k]++] = j ; + p++ ; + } + else if (j == k) + { + /* skip the diagonal */ + p++ ; + break ; + } + else /* j > k */ + { + /* first entry below the diagonal */ + break ; + } + /* scan lower triangular part of A, in column j until reaching + * row k. Start where last scan left off. */ + ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ; + pj2 = Ap [j+1] ; + for (pj = Tp [j] ; pj < pj2 ; ) + { + i = Ai [pj] ; + ASSERT (i >= 0 && i < n) ; + if (i < k) + { + /* A (i,j) is only in the lower part, not in upper */ + ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ; + ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ; + Iw [Sp [i]++] = j ; + Iw [Sp [j]++] = i ; + pj++ ; + } + else if (i == k) + { + /* entry A (k,j) in lower part and A (j,k) in upper */ + pj++ ; + break ; + } + else /* i > k */ + { + /* consider this entry later, when k advances to i */ + break ; + } + } + Tp [j] = pj ; + } + Tp [k] = p ; + } + + /* clean up, for remaining mismatched entries */ + for (j = 0 ; j < n ; j++) + { + for (pj = Tp [j] ; pj < Ap [j+1] ; pj++) + { + i = Ai [pj] ; + ASSERT (i >= 0 && i < n) ; + /* A (i,j) is only in the lower part, not in upper */ + ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ; + ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ; + Iw [Sp [i]++] = j ; + Iw [Sp [j]++] = i ; + } + } + +#ifndef NDEBUG + for (j = 0 ; j < n-1 ; j++) ASSERT (Sp [j] == Pe [j+1]) ; + ASSERT (Sp [n-1] == pfree) ; +#endif + + /* Tp and Sp no longer needed ] */ + + /* --------------------------------------------------------------------- */ + /* order the matrix */ + /* --------------------------------------------------------------------- */ + + AMD_2 (n, Pe, Iw, Len, iwlen, pfree, + Nv, Pinv, P, Head, Elen, Degree, W, Control, Info) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_2.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_2.c new file mode 100644 index 0000000..f144722 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_2.c @@ -0,0 +1,1842 @@ +/* ========================================================================= */ +/* === AMD_2 =============================================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* AMD, Copyright (c) Timothy A. Davis, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* AMD_2: performs the AMD ordering on a symmetric sparse matrix A, followed + * by a postordering (via depth-first search) of the assembly tree using the + * AMD_postorder routine. + */ + +#include "amd_internal.h" + +/* ========================================================================= */ +/* === clear_flag ========================================================== */ +/* ========================================================================= */ + +static Int clear_flag (Int wflg, Int wbig, Int W [ ], Int n) +{ + Int x ; + if (wflg < 2 || wflg >= wbig) + { + for (x = 0 ; x < n ; x++) + { + if (W [x] != 0) W [x] = 1 ; + } + wflg = 2 ; + } + /* at this point, W [0..n-1] < wflg holds */ + return (wflg) ; +} + + +/* ========================================================================= */ +/* === AMD_2 =============================================================== */ +/* ========================================================================= */ + +GLOBAL void AMD_2 +( + Int n, /* A is n-by-n, where n > 0 */ + Int Pe [ ], /* Pe [0..n-1]: index in Iw of row i on input */ + Int Iw [ ], /* workspace of size iwlen. Iw [0..pfree-1] + * holds the matrix on input */ + Int Len [ ], /* Len [0..n-1]: length for row/column i on input */ + Int iwlen, /* length of Iw. iwlen >= pfree + n */ + Int pfree, /* Iw [pfree ... iwlen-1] is empty on input */ + + /* 7 size-n workspaces, not defined on input: */ + Int Nv [ ], /* the size of each supernode on output */ + Int Next [ ], /* the output inverse permutation */ + Int Last [ ], /* the output permutation */ + Int Head [ ], + Int Elen [ ], /* the size columns of L for each supernode */ + Int Degree [ ], + Int W [ ], + + /* control parameters and output statistics */ + double Control [ ], /* array of size AMD_CONTROL */ + double Info [ ] /* array of size AMD_INFO */ +) +{ + +/* + * Given a representation of the nonzero pattern of a symmetric matrix, A, + * (excluding the diagonal) perform an approximate minimum (UMFPACK/MA38-style) + * degree ordering to compute a pivot order such that the introduction of + * nonzeros (fill-in) in the Cholesky factors A = LL' is kept low. At each + * step, the pivot selected is the one with the minimum UMFAPACK/MA38-style + * upper-bound on the external degree. This routine can optionally perform + * aggresive absorption (as done by MC47B in the Harwell Subroutine + * Library). + * + * The approximate degree algorithm implemented here is the symmetric analog of + * the degree update algorithm in MA38 and UMFPACK (the Unsymmetric-pattern + * MultiFrontal PACKage, both by Davis and Duff). The routine is based on the + * MA27 minimum degree ordering algorithm by Iain Duff and John Reid. + * + * This routine is a translation of the original AMDBAR and MC47B routines, + * in Fortran, with the following modifications: + * + * (1) dense rows/columns are removed prior to ordering the matrix, and placed + * last in the output order. The presence of a dense row/column can + * increase the ordering time by up to O(n^2), unless they are removed + * prior to ordering. + * + * (2) the minimum degree ordering is followed by a postordering (depth-first + * search) of the assembly tree. Note that mass elimination (discussed + * below) combined with the approximate degree update can lead to the mass + * elimination of nodes with lower exact degree than the current pivot + * element. No additional fill-in is caused in the representation of the + * Schur complement. The mass-eliminated nodes merge with the current + * pivot element. They are ordered prior to the current pivot element. + * Because they can have lower exact degree than the current element, the + * merger of two or more of these nodes in the current pivot element can + * lead to a single element that is not a "fundamental supernode". The + * diagonal block can have zeros in it. Thus, the assembly tree used here + * is not guaranteed to be the precise supernodal elemination tree (with + * "funadmental" supernodes), and the postordering performed by this + * routine is not guaranteed to be a precise postordering of the + * elimination tree. + * + * (3) input parameters are added, to control aggressive absorption and the + * detection of "dense" rows/columns of A. + * + * (4) additional statistical information is returned, such as the number of + * nonzeros in L, and the flop counts for subsequent LDL' and LU + * factorizations. These are slight upper bounds, because of the mass + * elimination issue discussed above. + * + * (5) additional routines are added to interface this routine to MATLAB + * to provide a simple C-callable user-interface, to check inputs for + * errors, compute the symmetry of the pattern of A and the number of + * nonzeros in each row/column of A+A', to compute the pattern of A+A', + * to perform the assembly tree postordering, and to provide debugging + * ouput. Many of these functions are also provided by the Fortran + * Harwell Subroutine Library routine MC47A. + * + * (6) both int and SuiteSparse_long versions are provided. In the + * descriptions below and integer is and int or SuiteSparse_long depending + * on which version is being used. + + ********************************************************************** + ***** CAUTION: ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT. ****** + ********************************************************************** + ** If you want error checking, a more versatile input format, and a ** + ** simpler user interface, use amd_order or amd_l_order instead. ** + ** This routine is not meant to be user-callable. ** + ********************************************************************** + + * ---------------------------------------------------------------------------- + * References: + * ---------------------------------------------------------------------------- + * + * [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern multifrontal + * method for sparse LU factorization", SIAM J. Matrix Analysis and + * Applications, vol. 18, no. 1, pp. 140-158. Discusses UMFPACK / MA38, + * which first introduced the approximate minimum degree used by this + * routine. + * + * [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An approximate + * minimum degree ordering algorithm," SIAM J. Matrix Analysis and + * Applications, vol. 17, no. 4, pp. 886-905, 1996. Discusses AMDBAR and + * MC47B, which are the Fortran versions of this routine. + * + * [3] Alan George and Joseph Liu, "The evolution of the minimum degree + * ordering algorithm," SIAM Review, vol. 31, no. 1, pp. 1-19, 1989. + * We list below the features mentioned in that paper that this code + * includes: + * + * mass elimination: + * Yes. MA27 relied on supervariable detection for mass elimination. + * + * indistinguishable nodes: + * Yes (we call these "supervariables"). This was also in the MA27 + * code - although we modified the method of detecting them (the + * previous hash was the true degree, which we no longer keep track + * of). A supervariable is a set of rows with identical nonzero + * pattern. All variables in a supervariable are eliminated together. + * Each supervariable has as its numerical name that of one of its + * variables (its principal variable). + * + * quotient graph representation: + * Yes. We use the term "element" for the cliques formed during + * elimination. This was also in the MA27 code. The algorithm can + * operate in place, but it will work more efficiently if given some + * "elbow room." + * + * element absorption: + * Yes. This was also in the MA27 code. + * + * external degree: + * Yes. The MA27 code was based on the true degree. + * + * incomplete degree update and multiple elimination: + * No. This was not in MA27, either. Our method of degree update + * within MC47B is element-based, not variable-based. It is thus + * not well-suited for use with incomplete degree update or multiple + * elimination. + * + * Authors, and Copyright (C) 2004 by: + * Timothy A. Davis, Patrick Amestoy, Iain S. Duff, John K. Reid. + * + * Acknowledgements: This work (and the UMFPACK package) was supported by the + * National Science Foundation (ASC-9111263, DMS-9223088, and CCR-0203270). + * The UMFPACK/MA38 approximate degree update algorithm, the unsymmetric analog + * which forms the basis of AMD, was developed while Tim Davis was supported by + * CERFACS (Toulouse, France) in a post-doctoral position. This C version, and + * the etree postorder, were written while Tim Davis was on sabbatical at + * Stanford University and Lawrence Berkeley National Laboratory. + + * ---------------------------------------------------------------------------- + * INPUT ARGUMENTS (unaltered): + * ---------------------------------------------------------------------------- + + * n: The matrix order. Restriction: n >= 1. + * + * iwlen: The size of the Iw array. On input, the matrix is stored in + * Iw [0..pfree-1]. However, Iw [0..iwlen-1] should be slightly larger + * than what is required to hold the matrix, at least iwlen >= pfree + n. + * Otherwise, excessive compressions will take place. The recommended + * value of iwlen is 1.2 * pfree + n, which is the value used in the + * user-callable interface to this routine (amd_order.c). The algorithm + * will not run at all if iwlen < pfree. Restriction: iwlen >= pfree + n. + * Note that this is slightly more restrictive than the actual minimum + * (iwlen >= pfree), but AMD_2 will be very slow with no elbow room. + * Thus, this routine enforces a bare minimum elbow room of size n. + * + * pfree: On input the tail end of the array, Iw [pfree..iwlen-1], is empty, + * and the matrix is stored in Iw [0..pfree-1]. During execution, + * additional data is placed in Iw, and pfree is modified so that + * Iw [pfree..iwlen-1] is always the unused part of Iw. + * + * Control: A double array of size AMD_CONTROL containing input parameters + * that affect how the ordering is computed. If NULL, then default + * settings are used. + * + * Control [AMD_DENSE] is used to determine whether or not a given input + * row is "dense". A row is "dense" if the number of entries in the row + * exceeds Control [AMD_DENSE] times sqrt (n), except that rows with 16 or + * fewer entries are never considered "dense". To turn off the detection + * of dense rows, set Control [AMD_DENSE] to a negative number, or to a + * number larger than sqrt (n). The default value of Control [AMD_DENSE] + * is AMD_DEFAULT_DENSE, which is defined in amd.h as 10. + * + * Control [AMD_AGGRESSIVE] is used to determine whether or not aggressive + * absorption is to be performed. If nonzero, then aggressive absorption + * is performed (this is the default). + + * ---------------------------------------------------------------------------- + * INPUT/OUPUT ARGUMENTS: + * ---------------------------------------------------------------------------- + * + * Pe: An integer array of size n. On input, Pe [i] is the index in Iw of + * the start of row i. Pe [i] is ignored if row i has no off-diagonal + * entries. Thus Pe [i] must be in the range 0 to pfree-1 for non-empty + * rows. + * + * During execution, it is used for both supervariables and elements: + * + * Principal supervariable i: index into Iw of the description of + * supervariable i. A supervariable represents one or more rows of + * the matrix with identical nonzero pattern. In this case, + * Pe [i] >= 0. + * + * Non-principal supervariable i: if i has been absorbed into another + * supervariable j, then Pe [i] = FLIP (j), where FLIP (j) is defined + * as (-(j)-2). Row j has the same pattern as row i. Note that j + * might later be absorbed into another supervariable j2, in which + * case Pe [i] is still FLIP (j), and Pe [j] = FLIP (j2) which is + * < EMPTY, where EMPTY is defined as (-1) in amd_internal.h. + * + * Unabsorbed element e: the index into Iw of the description of element + * e, if e has not yet been absorbed by a subsequent element. Element + * e is created when the supervariable of the same name is selected as + * the pivot. In this case, Pe [i] >= 0. + * + * Absorbed element e: if element e is absorbed into element e2, then + * Pe [e] = FLIP (e2). This occurs when the pattern of e (which we + * refer to as Le) is found to be a subset of the pattern of e2 (that + * is, Le2). In this case, Pe [i] < EMPTY. If element e is "null" + * (it has no nonzeros outside its pivot block), then Pe [e] = EMPTY, + * and e is the root of an assembly subtree (or the whole tree if + * there is just one such root). + * + * Dense variable i: if i is "dense", then Pe [i] = EMPTY. + * + * On output, Pe holds the assembly tree/forest, which implicitly + * represents a pivot order with identical fill-in as the actual order + * (via a depth-first search of the tree), as follows. If Nv [i] > 0, + * then i represents a node in the assembly tree, and the parent of i is + * Pe [i], or EMPTY if i is a root. If Nv [i] = 0, then (i, Pe [i]) + * represents an edge in a subtree, the root of which is a node in the + * assembly tree. Note that i refers to a row/column in the original + * matrix, not the permuted matrix. + * + * Info: A double array of size AMD_INFO. If present, (that is, not NULL), + * then statistics about the ordering are returned in the Info array. + * See amd.h for a description. + + * ---------------------------------------------------------------------------- + * INPUT/MODIFIED (undefined on output): + * ---------------------------------------------------------------------------- + * + * Len: An integer array of size n. On input, Len [i] holds the number of + * entries in row i of the matrix, excluding the diagonal. The contents + * of Len are undefined on output. + * + * Iw: An integer array of size iwlen. On input, Iw [0..pfree-1] holds the + * description of each row i in the matrix. The matrix must be symmetric, + * and both upper and lower triangular parts must be present. The + * diagonal must not be present. Row i is held as follows: + * + * Len [i]: the length of the row i data structure in the Iw array. + * Iw [Pe [i] ... Pe [i] + Len [i] - 1]: + * the list of column indices for nonzeros in row i (simple + * supervariables), excluding the diagonal. All supervariables + * start with one row/column each (supervariable i is just row i). + * If Len [i] is zero on input, then Pe [i] is ignored on input. + * + * Note that the rows need not be in any particular order, and there + * may be empty space between the rows. + * + * During execution, the supervariable i experiences fill-in. This is + * represented by placing in i a list of the elements that cause fill-in + * in supervariable i: + * + * Len [i]: the length of supervariable i in the Iw array. + * Iw [Pe [i] ... Pe [i] + Elen [i] - 1]: + * the list of elements that contain i. This list is kept short + * by removing absorbed elements. + * Iw [Pe [i] + Elen [i] ... Pe [i] + Len [i] - 1]: + * the list of supervariables in i. This list is kept short by + * removing nonprincipal variables, and any entry j that is also + * contained in at least one of the elements (j in Le) in the list + * for i (e in row i). + * + * When supervariable i is selected as pivot, we create an element e of + * the same name (e=i): + * + * Len [e]: the length of element e in the Iw array. + * Iw [Pe [e] ... Pe [e] + Len [e] - 1]: + * the list of supervariables in element e. + * + * An element represents the fill-in that occurs when supervariable i is + * selected as pivot (which represents the selection of row i and all + * non-principal variables whose principal variable is i). We use the + * term Le to denote the set of all supervariables in element e. Absorbed + * supervariables and elements are pruned from these lists when + * computationally convenient. + * + * CAUTION: THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION. + * The contents of Iw are undefined on output. + + * ---------------------------------------------------------------------------- + * OUTPUT (need not be set on input): + * ---------------------------------------------------------------------------- + * + * Nv: An integer array of size n. During execution, ABS (Nv [i]) is equal to + * the number of rows that are represented by the principal supervariable + * i. If i is a nonprincipal or dense variable, then Nv [i] = 0. + * Initially, Nv [i] = 1 for all i. Nv [i] < 0 signifies that i is a + * principal variable in the pattern Lme of the current pivot element me. + * After element me is constructed, Nv [i] is set back to a positive + * value. + * + * On output, Nv [i] holds the number of pivots represented by super + * row/column i of the original matrix, or Nv [i] = 0 for non-principal + * rows/columns. Note that i refers to a row/column in the original + * matrix, not the permuted matrix. + * + * Elen: An integer array of size n. See the description of Iw above. At the + * start of execution, Elen [i] is set to zero for all rows i. During + * execution, Elen [i] is the number of elements in the list for + * supervariable i. When e becomes an element, Elen [e] = FLIP (esize) is + * set, where esize is the size of the element (the number of pivots, plus + * the number of nonpivotal entries). Thus Elen [e] < EMPTY. + * Elen (i) = EMPTY set when variable i becomes nonprincipal. + * + * For variables, Elen (i) >= EMPTY holds until just before the + * postordering and permutation vectors are computed. For elements, + * Elen [e] < EMPTY holds. + * + * On output, Elen [i] is the degree of the row/column in the Cholesky + * factorization of the permuted matrix, corresponding to the original row + * i, if i is a super row/column. It is equal to EMPTY if i is + * non-principal. Note that i refers to a row/column in the original + * matrix, not the permuted matrix. + * + * Note that the contents of Elen on output differ from the Fortran + * version (Elen holds the inverse permutation in the Fortran version, + * which is instead returned in the Next array in this C version, + * described below). + * + * Last: In a degree list, Last [i] is the supervariable preceding i, or EMPTY + * if i is the head of the list. In a hash bucket, Last [i] is the hash + * key for i. + * + * Last [Head [hash]] is also used as the head of a hash bucket if + * Head [hash] contains a degree list (see the description of Head, + * below). + * + * On output, Last [0..n-1] holds the permutation. That is, if + * i = Last [k], then row i is the kth pivot row (where k ranges from 0 to + * n-1). Row Last [k] of A is the kth row in the permuted matrix, PAP'. + * + * Next: Next [i] is the supervariable following i in a link list, or EMPTY if + * i is the last in the list. Used for two kinds of lists: degree lists + * and hash buckets (a supervariable can be in only one kind of list at a + * time). + * + * On output Next [0..n-1] holds the inverse permutation. That is, if + * k = Next [i], then row i is the kth pivot row. Row i of A appears as + * the (Next[i])-th row in the permuted matrix, PAP'. + * + * Note that the contents of Next on output differ from the Fortran + * version (Next is undefined on output in the Fortran version). + + * ---------------------------------------------------------------------------- + * LOCAL WORKSPACE (not input or output - used only during execution): + * ---------------------------------------------------------------------------- + * + * Degree: An integer array of size n. If i is a supervariable, then + * Degree [i] holds the current approximation of the external degree of + * row i (an upper bound). The external degree is the number of nonzeros + * in row i, minus ABS (Nv [i]), the diagonal part. The bound is equal to + * the exact external degree if Elen [i] is less than or equal to two. + * + * We also use the term "external degree" for elements e to refer to + * |Le \ Lme|. If e is an element, then Degree [e] is |Le|, which is the + * degree of the off-diagonal part of the element e (not including the + * diagonal part). + * + * Head: An integer array of size n. Head is used for degree lists. + * Head [deg] is the first supervariable in a degree list. All + * supervariables i in a degree list Head [deg] have the same approximate + * degree, namely, deg = Degree [i]. If the list Head [deg] is empty then + * Head [deg] = EMPTY. + * + * During supervariable detection Head [hash] also serves as a pointer to + * a hash bucket. If Head [hash] >= 0, there is a degree list of degree + * hash. The hash bucket head pointer is Last [Head [hash]]. If + * Head [hash] = EMPTY, then the degree list and hash bucket are both + * empty. If Head [hash] < EMPTY, then the degree list is empty, and + * FLIP (Head [hash]) is the head of the hash bucket. After supervariable + * detection is complete, all hash buckets are empty, and the + * (Last [Head [hash]] = EMPTY) condition is restored for the non-empty + * degree lists. + * + * W: An integer array of size n. The flag array W determines the status of + * elements and variables, and the external degree of elements. + * + * for elements: + * if W [e] = 0, then the element e is absorbed. + * if W [e] >= wflg, then W [e] - wflg is the size of the set + * |Le \ Lme|, in terms of nonzeros (the sum of ABS (Nv [i]) for + * each principal variable i that is both in the pattern of + * element e and NOT in the pattern of the current pivot element, + * me). + * if wflg > W [e] > 0, then e is not absorbed and has not yet been + * seen in the scan of the element lists in the computation of + * |Le\Lme| in Scan 1 below. + * + * for variables: + * during supervariable detection, if W [j] != wflg then j is + * not in the pattern of variable i. + * + * The W array is initialized by setting W [i] = 1 for all i, and by + * setting wflg = 2. It is reinitialized if wflg becomes too large (to + * ensure that wflg+n does not cause integer overflow). + + * ---------------------------------------------------------------------------- + * LOCAL INTEGERS: + * ---------------------------------------------------------------------------- + */ + + Int deg, degme, dext, lemax, e, elenme, eln, i, ilast, inext, j, + jlast, jnext, k, knt1, knt2, knt3, lenj, ln, me, mindeg, nel, nleft, + nvi, nvj, nvpiv, slenme, wbig, we, wflg, wnvi, ok, ndense, ncmpa, + dense, aggressive ; + + unsigned Int hash ; /* unsigned, so that hash % n is well defined.*/ + +/* + * deg: the degree of a variable or element + * degme: size, |Lme|, of the current element, me (= Degree [me]) + * dext: external degree, |Le \ Lme|, of some element e + * lemax: largest |Le| seen so far (called dmax in Fortran version) + * e: an element + * elenme: the length, Elen [me], of element list of pivotal variable + * eln: the length, Elen [...], of an element list + * hash: the computed value of the hash function + * i: a supervariable + * ilast: the entry in a link list preceding i + * inext: the entry in a link list following i + * j: a supervariable + * jlast: the entry in a link list preceding j + * jnext: the entry in a link list, or path, following j + * k: the pivot order of an element or variable + * knt1: loop counter used during element construction + * knt2: loop counter used during element construction + * knt3: loop counter used during compression + * lenj: Len [j] + * ln: length of a supervariable list + * me: current supervariable being eliminated, and the current + * element created by eliminating that supervariable + * mindeg: current minimum degree + * nel: number of pivots selected so far + * nleft: n - nel, the number of nonpivotal rows/columns remaining + * nvi: the number of variables in a supervariable i (= Nv [i]) + * nvj: the number of variables in a supervariable j (= Nv [j]) + * nvpiv: number of pivots in current element + * slenme: number of variables in variable list of pivotal variable + * wbig: = (INT_MAX - n) for the int version, (SuiteSparse_long_max - n) + * for the SuiteSparse_long version. wflg is not allowed to + * be >= wbig. + * we: W [e] + * wflg: used for flagging the W array. See description of Iw. + * wnvi: wflg - Nv [i] + * x: either a supervariable or an element + * + * ok: true if supervariable j can be absorbed into i + * ndense: number of "dense" rows/columns + * dense: rows/columns with initial degree > dense are considered "dense" + * aggressive: true if aggressive absorption is being performed + * ncmpa: number of garbage collections + + * ---------------------------------------------------------------------------- + * LOCAL DOUBLES, used for statistical output only (except for alpha): + * ---------------------------------------------------------------------------- + */ + + double f, r, ndiv, s, nms_lu, nms_ldl, dmax, alpha, lnz, lnzme ; + +/* + * f: nvpiv + * r: degme + nvpiv + * ndiv: number of divisions for LU or LDL' factorizations + * s: number of multiply-subtract pairs for LU factorization, for the + * current element me + * nms_lu number of multiply-subtract pairs for LU factorization + * nms_ldl number of multiply-subtract pairs for LDL' factorization + * dmax: the largest number of entries in any column of L, including the + * diagonal + * alpha: "dense" degree ratio + * lnz: the number of nonzeros in L (excluding the diagonal) + * lnzme: the number of nonzeros in L (excl. the diagonal) for the + * current element me + + * ---------------------------------------------------------------------------- + * LOCAL "POINTERS" (indices into the Iw array) + * ---------------------------------------------------------------------------- +*/ + + Int p, p1, p2, p3, p4, pdst, pend, pj, pme, pme1, pme2, pn, psrc ; + +/* + * Any parameter (Pe [...] or pfree) or local variable starting with "p" (for + * Pointer) is an index into Iw, and all indices into Iw use variables starting + * with "p." The only exception to this rule is the iwlen input argument. + * + * p: pointer into lots of things + * p1: Pe [i] for some variable i (start of element list) + * p2: Pe [i] + Elen [i] - 1 for some variable i + * p3: index of first supervariable in clean list + * p4: + * pdst: destination pointer, for compression + * pend: end of memory to compress + * pj: pointer into an element or variable + * pme: pointer into the current element (pme1...pme2) + * pme1: the current element, me, is stored in Iw [pme1...pme2] + * pme2: the end of the current element + * pn: pointer into a "clean" variable, also used to compress + * psrc: source pointer, for compression +*/ + +/* ========================================================================= */ +/* INITIALIZATIONS */ +/* ========================================================================= */ + + /* Note that this restriction on iwlen is slightly more restrictive than + * what is actually required in AMD_2. AMD_2 can operate with no elbow + * room at all, but it will be slow. For better performance, at least + * size-n elbow room is enforced. */ + ASSERT (iwlen >= pfree + n) ; + ASSERT (n > 0) ; + + /* initialize output statistics */ + lnz = 0 ; + ndiv = 0 ; + nms_lu = 0 ; + nms_ldl = 0 ; + dmax = 1 ; + me = EMPTY ; + + mindeg = 0 ; + ncmpa = 0 ; + nel = 0 ; + lemax = 0 ; + + /* get control parameters */ + if (Control != (double *) NULL) + { + alpha = Control [AMD_DENSE] ; + aggressive = (Control [AMD_AGGRESSIVE] != 0) ; + } + else + { + alpha = AMD_DEFAULT_DENSE ; + aggressive = AMD_DEFAULT_AGGRESSIVE ; + } + /* Note: if alpha is NaN, this is undefined: */ + if (alpha < 0) + { + /* only remove completely dense rows/columns */ + dense = n-2 ; + } + else + { + dense = alpha * sqrt ((double) n) ; + } + dense = MAX (16, dense) ; + dense = MIN (n, dense) ; + AMD_DEBUG1 (("\n\nAMD (debug), alpha %g, aggr. "ID"\n", + alpha, aggressive)) ; + + for (i = 0 ; i < n ; i++) + { + Last [i] = EMPTY ; + Head [i] = EMPTY ; + Next [i] = EMPTY ; + /* if separate Hhead array is used for hash buckets: * + Hhead [i] = EMPTY ; + */ + Nv [i] = 1 ; + W [i] = 1 ; + Elen [i] = 0 ; + Degree [i] = Len [i] ; + } + +#ifndef NDEBUG + AMD_DEBUG1 (("\n======Nel "ID" initial\n", nel)) ; + AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next, Last, + Head, Elen, Degree, W, -1) ; +#endif + + /* initialize wflg */ + wbig = Int_MAX - n ; + wflg = clear_flag (0, wbig, W, n) ; + + /* --------------------------------------------------------------------- */ + /* initialize degree lists and eliminate dense and empty rows */ + /* --------------------------------------------------------------------- */ + + ndense = 0 ; + + for (i = 0 ; i < n ; i++) + { + deg = Degree [i] ; + ASSERT (deg >= 0 && deg < n) ; + if (deg == 0) + { + + /* ------------------------------------------------------------- + * we have a variable that can be eliminated at once because + * there is no off-diagonal non-zero in its row. Note that + * Nv [i] = 1 for an empty variable i. It is treated just + * the same as an eliminated element i. + * ------------------------------------------------------------- */ + + Elen [i] = FLIP (1) ; + nel++ ; + Pe [i] = EMPTY ; + W [i] = 0 ; + + } + else if (deg > dense) + { + + /* ------------------------------------------------------------- + * Dense variables are not treated as elements, but as unordered, + * non-principal variables that have no parent. They do not take + * part in the postorder, since Nv [i] = 0. Note that the Fortran + * version does not have this option. + * ------------------------------------------------------------- */ + + AMD_DEBUG1 (("Dense node "ID" degree "ID"\n", i, deg)) ; + ndense++ ; + Nv [i] = 0 ; /* do not postorder this node */ + Elen [i] = EMPTY ; + nel++ ; + Pe [i] = EMPTY ; + + } + else + { + + /* ------------------------------------------------------------- + * place i in the degree list corresponding to its degree + * ------------------------------------------------------------- */ + + inext = Head [deg] ; + ASSERT (inext >= EMPTY && inext < n) ; + if (inext != EMPTY) Last [inext] = i ; + Next [i] = inext ; + Head [deg] = i ; + + } + } + +/* ========================================================================= */ +/* WHILE (selecting pivots) DO */ +/* ========================================================================= */ + + while (nel < n) + { + +#ifndef NDEBUG + AMD_DEBUG1 (("\n======Nel "ID"\n", nel)) ; + if (AMD_debug >= 2) + { + AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next, + Last, Head, Elen, Degree, W, nel) ; + } +#endif + +/* ========================================================================= */ +/* GET PIVOT OF MINIMUM DEGREE */ +/* ========================================================================= */ + + /* ----------------------------------------------------------------- */ + /* find next supervariable for elimination */ + /* ----------------------------------------------------------------- */ + + ASSERT (mindeg >= 0 && mindeg < n) ; + for (deg = mindeg ; deg < n ; deg++) + { + me = Head [deg] ; + if (me != EMPTY) break ; + } + mindeg = deg ; + ASSERT (me >= 0 && me < n) ; + AMD_DEBUG1 (("=================me: "ID"\n", me)) ; + + /* ----------------------------------------------------------------- */ + /* remove chosen variable from link list */ + /* ----------------------------------------------------------------- */ + + inext = Next [me] ; + ASSERT (inext >= EMPTY && inext < n) ; + if (inext != EMPTY) Last [inext] = EMPTY ; + Head [deg] = inext ; + + /* ----------------------------------------------------------------- */ + /* me represents the elimination of pivots nel to nel+Nv[me]-1. */ + /* place me itself as the first in this set. */ + /* ----------------------------------------------------------------- */ + + elenme = Elen [me] ; + nvpiv = Nv [me] ; + ASSERT (nvpiv > 0) ; + nel += nvpiv ; + +/* ========================================================================= */ +/* CONSTRUCT NEW ELEMENT */ +/* ========================================================================= */ + + /* ----------------------------------------------------------------- + * At this point, me is the pivotal supervariable. It will be + * converted into the current element. Scan list of the pivotal + * supervariable, me, setting tree pointers and constructing new list + * of supervariables for the new element, me. p is a pointer to the + * current position in the old list. + * ----------------------------------------------------------------- */ + + /* flag the variable "me" as being in Lme by negating Nv [me] */ + Nv [me] = -nvpiv ; + degme = 0 ; + ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ; + + if (elenme == 0) + { + + /* ------------------------------------------------------------- */ + /* construct the new element in place */ + /* ------------------------------------------------------------- */ + + pme1 = Pe [me] ; + pme2 = pme1 - 1 ; + + for (p = pme1 ; p <= pme1 + Len [me] - 1 ; p++) + { + i = Iw [p] ; + ASSERT (i >= 0 && i < n && Nv [i] >= 0) ; + nvi = Nv [i] ; + if (nvi > 0) + { + + /* ----------------------------------------------------- */ + /* i is a principal variable not yet placed in Lme. */ + /* store i in new list */ + /* ----------------------------------------------------- */ + + /* flag i as being in Lme by negating Nv [i] */ + degme += nvi ; + Nv [i] = -nvi ; + Iw [++pme2] = i ; + + /* ----------------------------------------------------- */ + /* remove variable i from degree list. */ + /* ----------------------------------------------------- */ + + ilast = Last [i] ; + inext = Next [i] ; + ASSERT (ilast >= EMPTY && ilast < n) ; + ASSERT (inext >= EMPTY && inext < n) ; + if (inext != EMPTY) Last [inext] = ilast ; + if (ilast != EMPTY) + { + Next [ilast] = inext ; + } + else + { + /* i is at the head of the degree list */ + ASSERT (Degree [i] >= 0 && Degree [i] < n) ; + Head [Degree [i]] = inext ; + } + } + } + } + else + { + + /* ------------------------------------------------------------- */ + /* construct the new element in empty space, Iw [pfree ...] */ + /* ------------------------------------------------------------- */ + + p = Pe [me] ; + pme1 = pfree ; + slenme = Len [me] - elenme ; + + for (knt1 = 1 ; knt1 <= elenme + 1 ; knt1++) + { + + if (knt1 > elenme) + { + /* search the supervariables in me. */ + e = me ; + pj = p ; + ln = slenme ; + AMD_DEBUG2 (("Search sv: "ID" "ID" "ID"\n", me,pj,ln)) ; + } + else + { + /* search the elements in me. */ + e = Iw [p++] ; + ASSERT (e >= 0 && e < n) ; + pj = Pe [e] ; + ln = Len [e] ; + AMD_DEBUG2 (("Search element e "ID" in me "ID"\n", e,me)) ; + ASSERT (Elen [e] < EMPTY && W [e] > 0 && pj >= 0) ; + } + ASSERT (ln >= 0 && (ln == 0 || (pj >= 0 && pj < iwlen))) ; + + /* --------------------------------------------------------- + * search for different supervariables and add them to the + * new list, compressing when necessary. this loop is + * executed once for each element in the list and once for + * all the supervariables in the list. + * --------------------------------------------------------- */ + + for (knt2 = 1 ; knt2 <= ln ; knt2++) + { + i = Iw [pj++] ; + ASSERT (i >= 0 && i < n && (i == me || Elen [i] >= EMPTY)); + nvi = Nv [i] ; + AMD_DEBUG2 ((": "ID" "ID" "ID" "ID"\n", + i, Elen [i], Nv [i], wflg)) ; + + if (nvi > 0) + { + + /* ------------------------------------------------- */ + /* compress Iw, if necessary */ + /* ------------------------------------------------- */ + + if (pfree >= iwlen) + { + + AMD_DEBUG1 (("GARBAGE COLLECTION\n")) ; + + /* prepare for compressing Iw by adjusting pointers + * and lengths so that the lists being searched in + * the inner and outer loops contain only the + * remaining entries. */ + + Pe [me] = p ; + Len [me] -= knt1 ; + /* check if nothing left of supervariable me */ + if (Len [me] == 0) Pe [me] = EMPTY ; + Pe [e] = pj ; + Len [e] = ln - knt2 ; + /* nothing left of element e */ + if (Len [e] == 0) Pe [e] = EMPTY ; + + ncmpa++ ; /* one more garbage collection */ + + /* store first entry of each object in Pe */ + /* FLIP the first entry in each object */ + for (j = 0 ; j < n ; j++) + { + pn = Pe [j] ; + if (pn >= 0) + { + ASSERT (pn >= 0 && pn < iwlen) ; + Pe [j] = Iw [pn] ; + Iw [pn] = FLIP (j) ; + } + } + + /* psrc/pdst point to source/destination */ + psrc = 0 ; + pdst = 0 ; + pend = pme1 - 1 ; + + while (psrc <= pend) + { + /* search for next FLIP'd entry */ + j = FLIP (Iw [psrc++]) ; + if (j >= 0) + { + AMD_DEBUG2 (("Got object j: "ID"\n", j)) ; + Iw [pdst] = Pe [j] ; + Pe [j] = pdst++ ; + lenj = Len [j] ; + /* copy from source to destination */ + for (knt3 = 0 ; knt3 <= lenj - 2 ; knt3++) + { + Iw [pdst++] = Iw [psrc++] ; + } + } + } + + /* move the new partially-constructed element */ + p1 = pdst ; + for (psrc = pme1 ; psrc <= pfree-1 ; psrc++) + { + Iw [pdst++] = Iw [psrc] ; + } + pme1 = p1 ; + pfree = pdst ; + pj = Pe [e] ; + p = Pe [me] ; + + } + + /* ------------------------------------------------- */ + /* i is a principal variable not yet placed in Lme */ + /* store i in new list */ + /* ------------------------------------------------- */ + + /* flag i as being in Lme by negating Nv [i] */ + degme += nvi ; + Nv [i] = -nvi ; + Iw [pfree++] = i ; + AMD_DEBUG2 ((" s: "ID" nv "ID"\n", i, Nv [i])); + + /* ------------------------------------------------- */ + /* remove variable i from degree link list */ + /* ------------------------------------------------- */ + + ilast = Last [i] ; + inext = Next [i] ; + ASSERT (ilast >= EMPTY && ilast < n) ; + ASSERT (inext >= EMPTY && inext < n) ; + if (inext != EMPTY) Last [inext] = ilast ; + if (ilast != EMPTY) + { + Next [ilast] = inext ; + } + else + { + /* i is at the head of the degree list */ + ASSERT (Degree [i] >= 0 && Degree [i] < n) ; + Head [Degree [i]] = inext ; + } + } + } + + if (e != me) + { + /* set tree pointer and flag to indicate element e is + * absorbed into new element me (the parent of e is me) */ + AMD_DEBUG1 ((" Element "ID" => "ID"\n", e, me)) ; + Pe [e] = FLIP (me) ; + W [e] = 0 ; + } + } + + pme2 = pfree - 1 ; + } + + /* ----------------------------------------------------------------- */ + /* me has now been converted into an element in Iw [pme1..pme2] */ + /* ----------------------------------------------------------------- */ + + /* degme holds the external degree of new element */ + Degree [me] = degme ; + Pe [me] = pme1 ; + Len [me] = pme2 - pme1 + 1 ; + ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ; + + Elen [me] = FLIP (nvpiv + degme) ; + /* FLIP (Elen (me)) is now the degree of pivot (including + * diagonal part). */ + +#ifndef NDEBUG + AMD_DEBUG2 (("New element structure: length= "ID"\n", pme2-pme1+1)) ; + for (pme = pme1 ; pme <= pme2 ; pme++) AMD_DEBUG3 ((" "ID"", Iw[pme])); + AMD_DEBUG3 (("\n")) ; +#endif + + /* ----------------------------------------------------------------- */ + /* make sure that wflg is not too large. */ + /* ----------------------------------------------------------------- */ + + /* With the current value of wflg, wflg+n must not cause integer + * overflow */ + + wflg = clear_flag (wflg, wbig, W, n) ; + +/* ========================================================================= */ +/* COMPUTE (W [e] - wflg) = |Le\Lme| FOR ALL ELEMENTS */ +/* ========================================================================= */ + + /* ----------------------------------------------------------------- + * Scan 1: compute the external degrees of previous elements with + * respect to the current element. That is: + * (W [e] - wflg) = |Le \ Lme| + * for each element e that appears in any supervariable in Lme. The + * notation Le refers to the pattern (list of supervariables) of a + * previous element e, where e is not yet absorbed, stored in + * Iw [Pe [e] + 1 ... Pe [e] + Len [e]]. The notation Lme + * refers to the pattern of the current element (stored in + * Iw [pme1..pme2]). If aggressive absorption is enabled, and + * (W [e] - wflg) becomes zero, then the element e will be absorbed + * in Scan 2. + * ----------------------------------------------------------------- */ + + AMD_DEBUG2 (("me: ")) ; + for (pme = pme1 ; pme <= pme2 ; pme++) + { + i = Iw [pme] ; + ASSERT (i >= 0 && i < n) ; + eln = Elen [i] ; + AMD_DEBUG3 ((""ID" Elen "ID": \n", i, eln)) ; + if (eln > 0) + { + /* note that Nv [i] has been negated to denote i in Lme: */ + nvi = -Nv [i] ; + ASSERT (nvi > 0 && Pe [i] >= 0 && Pe [i] < iwlen) ; + wnvi = wflg - nvi ; + for (p = Pe [i] ; p <= Pe [i] + eln - 1 ; p++) + { + e = Iw [p] ; + ASSERT (e >= 0 && e < n) ; + we = W [e] ; + AMD_DEBUG4 ((" e "ID" we "ID" ", e, we)) ; + if (we >= wflg) + { + /* unabsorbed element e has been seen in this loop */ + AMD_DEBUG4 ((" unabsorbed, first time seen")) ; + we -= nvi ; + } + else if (we != 0) + { + /* e is an unabsorbed element */ + /* this is the first we have seen e in all of Scan 1 */ + AMD_DEBUG4 ((" unabsorbed")) ; + we = Degree [e] + wnvi ; + } + AMD_DEBUG4 (("\n")) ; + W [e] = we ; + } + } + } + AMD_DEBUG2 (("\n")) ; + +/* ========================================================================= */ +/* DEGREE UPDATE AND ELEMENT ABSORPTION */ +/* ========================================================================= */ + + /* ----------------------------------------------------------------- + * Scan 2: for each i in Lme, sum up the degree of Lme (which is + * degme), plus the sum of the external degrees of each Le for the + * elements e appearing within i, plus the supervariables in i. + * Place i in hash list. + * ----------------------------------------------------------------- */ + + for (pme = pme1 ; pme <= pme2 ; pme++) + { + i = Iw [pme] ; + ASSERT (i >= 0 && i < n && Nv [i] < 0 && Elen [i] >= 0) ; + AMD_DEBUG2 (("Updating: i "ID" "ID" "ID"\n", i, Elen[i], Len [i])); + p1 = Pe [i] ; + p2 = p1 + Elen [i] - 1 ; + pn = p1 ; + hash = 0 ; + deg = 0 ; + ASSERT (p1 >= 0 && p1 < iwlen && p2 >= -1 && p2 < iwlen) ; + + /* ------------------------------------------------------------- */ + /* scan the element list associated with supervariable i */ + /* ------------------------------------------------------------- */ + + /* UMFPACK/MA38-style approximate degree: */ + if (aggressive) + { + for (p = p1 ; p <= p2 ; p++) + { + e = Iw [p] ; + ASSERT (e >= 0 && e < n) ; + we = W [e] ; + if (we != 0) + { + /* e is an unabsorbed element */ + /* dext = | Le \ Lme | */ + dext = we - wflg ; + if (dext > 0) + { + deg += dext ; + Iw [pn++] = e ; + hash += e ; + AMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ; + } + else + { + /* external degree of e is zero, absorb e into me*/ + AMD_DEBUG1 ((" Element "ID" =>"ID" (aggressive)\n", + e, me)) ; + ASSERT (dext == 0) ; + Pe [e] = FLIP (me) ; + W [e] = 0 ; + } + } + } + } + else + { + for (p = p1 ; p <= p2 ; p++) + { + e = Iw [p] ; + ASSERT (e >= 0 && e < n) ; + we = W [e] ; + if (we != 0) + { + /* e is an unabsorbed element */ + dext = we - wflg ; + ASSERT (dext >= 0) ; + deg += dext ; + Iw [pn++] = e ; + hash += e ; + AMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ; + } + } + } + + /* count the number of elements in i (including me): */ + Elen [i] = pn - p1 + 1 ; + + /* ------------------------------------------------------------- */ + /* scan the supervariables in the list associated with i */ + /* ------------------------------------------------------------- */ + + /* The bulk of the AMD run time is typically spent in this loop, + * particularly if the matrix has many dense rows that are not + * removed prior to ordering. */ + p3 = pn ; + p4 = p1 + Len [i] ; + for (p = p2 + 1 ; p < p4 ; p++) + { + j = Iw [p] ; + ASSERT (j >= 0 && j < n) ; + nvj = Nv [j] ; + if (nvj > 0) + { + /* j is unabsorbed, and not in Lme. */ + /* add to degree and add to new list */ + deg += nvj ; + Iw [pn++] = j ; + hash += j ; + AMD_DEBUG4 ((" s: "ID" hash "ID" Nv[j]= "ID"\n", + j, hash, nvj)) ; + } + } + + /* ------------------------------------------------------------- */ + /* update the degree and check for mass elimination */ + /* ------------------------------------------------------------- */ + + /* with aggressive absorption, deg==0 is identical to the + * Elen [i] == 1 && p3 == pn test, below. */ + ASSERT (IMPLIES (aggressive, (deg==0) == (Elen[i]==1 && p3==pn))) ; + + if (Elen [i] == 1 && p3 == pn) + { + + /* --------------------------------------------------------- */ + /* mass elimination */ + /* --------------------------------------------------------- */ + + /* There is nothing left of this node except for an edge to + * the current pivot element. Elen [i] is 1, and there are + * no variables adjacent to node i. Absorb i into the + * current pivot element, me. Note that if there are two or + * more mass eliminations, fillin due to mass elimination is + * possible within the nvpiv-by-nvpiv pivot block. It is this + * step that causes AMD's analysis to be an upper bound. + * + * The reason is that the selected pivot has a lower + * approximate degree than the true degree of the two mass + * eliminated nodes. There is no edge between the two mass + * eliminated nodes. They are merged with the current pivot + * anyway. + * + * No fillin occurs in the Schur complement, in any case, + * and this effect does not decrease the quality of the + * ordering itself, just the quality of the nonzero and + * flop count analysis. It also means that the post-ordering + * is not an exact elimination tree post-ordering. */ + + AMD_DEBUG1 ((" MASS i "ID" => parent e "ID"\n", i, me)) ; + Pe [i] = FLIP (me) ; + nvi = -Nv [i] ; + degme -= nvi ; + nvpiv += nvi ; + nel += nvi ; + Nv [i] = 0 ; + Elen [i] = EMPTY ; + + } + else + { + + /* --------------------------------------------------------- */ + /* update the upper-bound degree of i */ + /* --------------------------------------------------------- */ + + /* the following degree does not yet include the size + * of the current element, which is added later: */ + + Degree [i] = MIN (Degree [i], deg) ; + + /* --------------------------------------------------------- */ + /* add me to the list for i */ + /* --------------------------------------------------------- */ + + /* move first supervariable to end of list */ + Iw [pn] = Iw [p3] ; + /* move first element to end of element part of list */ + Iw [p3] = Iw [p1] ; + /* add new element, me, to front of list. */ + Iw [p1] = me ; + /* store the new length of the list in Len [i] */ + Len [i] = pn - p1 + 1 ; + + /* --------------------------------------------------------- */ + /* place in hash bucket. Save hash key of i in Last [i]. */ + /* --------------------------------------------------------- */ + + /* NOTE: this can fail if hash is negative, because the ANSI C + * standard does not define a % b when a and/or b are negative. + * That's why hash is defined as an unsigned Int, to avoid this + * problem. */ + hash = hash % n ; + ASSERT (((Int) hash) >= 0 && ((Int) hash) < n) ; + + /* if the Hhead array is not used: */ + j = Head [hash] ; + if (j <= EMPTY) + { + /* degree list is empty, hash head is FLIP (j) */ + Next [i] = FLIP (j) ; + Head [hash] = FLIP (i) ; + } + else + { + /* degree list is not empty, use Last [Head [hash]] as + * hash head. */ + Next [i] = Last [j] ; + Last [j] = i ; + } + + /* if a separate Hhead array is used: * + Next [i] = Hhead [hash] ; + Hhead [hash] = i ; + */ + + Last [i] = hash ; + } + } + + Degree [me] = degme ; + + /* ----------------------------------------------------------------- */ + /* Clear the counter array, W [...], by incrementing wflg. */ + /* ----------------------------------------------------------------- */ + + /* make sure that wflg+n does not cause integer overflow */ + lemax = MAX (lemax, degme) ; + wflg += lemax ; + wflg = clear_flag (wflg, wbig, W, n) ; + /* at this point, W [0..n-1] < wflg holds */ + +/* ========================================================================= */ +/* SUPERVARIABLE DETECTION */ +/* ========================================================================= */ + + AMD_DEBUG1 (("Detecting supervariables:\n")) ; + for (pme = pme1 ; pme <= pme2 ; pme++) + { + i = Iw [pme] ; + ASSERT (i >= 0 && i < n) ; + AMD_DEBUG2 (("Consider i "ID" nv "ID"\n", i, Nv [i])) ; + if (Nv [i] < 0) + { + /* i is a principal variable in Lme */ + + /* --------------------------------------------------------- + * examine all hash buckets with 2 or more variables. We do + * this by examing all unique hash keys for supervariables in + * the pattern Lme of the current element, me + * --------------------------------------------------------- */ + + /* let i = head of hash bucket, and empty the hash bucket */ + ASSERT (Last [i] >= 0 && Last [i] < n) ; + hash = Last [i] ; + + /* if Hhead array is not used: */ + j = Head [hash] ; + if (j == EMPTY) + { + /* hash bucket and degree list are both empty */ + i = EMPTY ; + } + else if (j < EMPTY) + { + /* degree list is empty */ + i = FLIP (j) ; + Head [hash] = EMPTY ; + } + else + { + /* degree list is not empty, restore Last [j] of head j */ + i = Last [j] ; + Last [j] = EMPTY ; + } + + /* if separate Hhead array is used: * + i = Hhead [hash] ; + Hhead [hash] = EMPTY ; + */ + + ASSERT (i >= EMPTY && i < n) ; + AMD_DEBUG2 (("----i "ID" hash "ID"\n", i, hash)) ; + + while (i != EMPTY && Next [i] != EMPTY) + { + + /* ----------------------------------------------------- + * this bucket has one or more variables following i. + * scan all of them to see if i can absorb any entries + * that follow i in hash bucket. Scatter i into w. + * ----------------------------------------------------- */ + + ln = Len [i] ; + eln = Elen [i] ; + ASSERT (ln >= 0 && eln >= 0) ; + ASSERT (Pe [i] >= 0 && Pe [i] < iwlen) ; + /* do not flag the first element in the list (me) */ + for (p = Pe [i] + 1 ; p <= Pe [i] + ln - 1 ; p++) + { + ASSERT (Iw [p] >= 0 && Iw [p] < n) ; + W [Iw [p]] = wflg ; + } + + /* ----------------------------------------------------- */ + /* scan every other entry j following i in bucket */ + /* ----------------------------------------------------- */ + + jlast = i ; + j = Next [i] ; + ASSERT (j >= EMPTY && j < n) ; + + while (j != EMPTY) + { + /* ------------------------------------------------- */ + /* check if j and i have identical nonzero pattern */ + /* ------------------------------------------------- */ + + AMD_DEBUG3 (("compare i "ID" and j "ID"\n", i,j)) ; + + /* check if i and j have the same Len and Elen */ + ASSERT (Len [j] >= 0 && Elen [j] >= 0) ; + ASSERT (Pe [j] >= 0 && Pe [j] < iwlen) ; + ok = (Len [j] == ln) && (Elen [j] == eln) ; + /* skip the first element in the list (me) */ + for (p = Pe [j] + 1 ; ok && p <= Pe [j] + ln - 1 ; p++) + { + ASSERT (Iw [p] >= 0 && Iw [p] < n) ; + if (W [Iw [p]] != wflg) ok = 0 ; + } + if (ok) + { + /* --------------------------------------------- */ + /* found it! j can be absorbed into i */ + /* --------------------------------------------- */ + + AMD_DEBUG1 (("found it! j "ID" => i "ID"\n", j,i)); + Pe [j] = FLIP (i) ; + /* both Nv [i] and Nv [j] are negated since they */ + /* are in Lme, and the absolute values of each */ + /* are the number of variables in i and j: */ + Nv [i] += Nv [j] ; + Nv [j] = 0 ; + Elen [j] = EMPTY ; + /* delete j from hash bucket */ + ASSERT (j != Next [j]) ; + j = Next [j] ; + Next [jlast] = j ; + + } + else + { + /* j cannot be absorbed into i */ + jlast = j ; + ASSERT (j != Next [j]) ; + j = Next [j] ; + } + ASSERT (j >= EMPTY && j < n) ; + } + + /* ----------------------------------------------------- + * no more variables can be absorbed into i + * go to next i in bucket and clear flag array + * ----------------------------------------------------- */ + + wflg++ ; + i = Next [i] ; + ASSERT (i >= EMPTY && i < n) ; + + } + } + } + AMD_DEBUG2 (("detect done\n")) ; + +/* ========================================================================= */ +/* RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVARIABLES FROM ELEMENT */ +/* ========================================================================= */ + + p = pme1 ; + nleft = n - nel ; + for (pme = pme1 ; pme <= pme2 ; pme++) + { + i = Iw [pme] ; + ASSERT (i >= 0 && i < n) ; + nvi = -Nv [i] ; + AMD_DEBUG3 (("Restore i "ID" "ID"\n", i, nvi)) ; + if (nvi > 0) + { + /* i is a principal variable in Lme */ + /* restore Nv [i] to signify that i is principal */ + Nv [i] = nvi ; + + /* --------------------------------------------------------- */ + /* compute the external degree (add size of current element) */ + /* --------------------------------------------------------- */ + + deg = Degree [i] + degme - nvi ; + deg = MIN (deg, nleft - nvi) ; + ASSERT (IMPLIES (aggressive, deg > 0) && deg >= 0 && deg < n) ; + + /* --------------------------------------------------------- */ + /* place the supervariable at the head of the degree list */ + /* --------------------------------------------------------- */ + + inext = Head [deg] ; + ASSERT (inext >= EMPTY && inext < n) ; + if (inext != EMPTY) Last [inext] = i ; + Next [i] = inext ; + Last [i] = EMPTY ; + Head [deg] = i ; + + /* --------------------------------------------------------- */ + /* save the new degree, and find the minimum degree */ + /* --------------------------------------------------------- */ + + mindeg = MIN (mindeg, deg) ; + Degree [i] = deg ; + + /* --------------------------------------------------------- */ + /* place the supervariable in the element pattern */ + /* --------------------------------------------------------- */ + + Iw [p++] = i ; + + } + } + AMD_DEBUG2 (("restore done\n")) ; + +/* ========================================================================= */ +/* FINALIZE THE NEW ELEMENT */ +/* ========================================================================= */ + + AMD_DEBUG2 (("ME = "ID" DONE\n", me)) ; + Nv [me] = nvpiv ; + /* save the length of the list for the new element me */ + Len [me] = p - pme1 ; + if (Len [me] == 0) + { + /* there is nothing left of the current pivot element */ + /* it is a root of the assembly tree */ + Pe [me] = EMPTY ; + W [me] = 0 ; + } + if (elenme != 0) + { + /* element was not constructed in place: deallocate part of */ + /* it since newly nonprincipal variables may have been removed */ + pfree = p ; + } + + /* The new element has nvpiv pivots and the size of the contribution + * block for a multifrontal method is degme-by-degme, not including + * the "dense" rows/columns. If the "dense" rows/columns are included, + * the frontal matrix is no larger than + * (degme+ndense)-by-(degme+ndense). + */ + + if (Info != (double *) NULL) + { + f = nvpiv ; + r = degme + ndense ; + dmax = MAX (dmax, f + r) ; + + /* number of nonzeros in L (excluding the diagonal) */ + lnzme = f*r + (f-1)*f/2 ; + lnz += lnzme ; + + /* number of divide operations for LDL' and for LU */ + ndiv += lnzme ; + + /* number of multiply-subtract pairs for LU */ + s = f*r*r + r*(f-1)*f + (f-1)*f*(2*f-1)/6 ; + nms_lu += s ; + + /* number of multiply-subtract pairs for LDL' */ + nms_ldl += (s + lnzme)/2 ; + } + +#ifndef NDEBUG + AMD_DEBUG2 (("finalize done nel "ID" n "ID"\n ::::\n", nel, n)) ; + for (pme = Pe [me] ; pme <= Pe [me] + Len [me] - 1 ; pme++) + { + AMD_DEBUG3 ((" "ID"", Iw [pme])) ; + } + AMD_DEBUG3 (("\n")) ; +#endif + + } + +/* ========================================================================= */ +/* DONE SELECTING PIVOTS */ +/* ========================================================================= */ + + if (Info != (double *) NULL) + { + + /* count the work to factorize the ndense-by-ndense submatrix */ + f = ndense ; + dmax = MAX (dmax, (double) ndense) ; + + /* number of nonzeros in L (excluding the diagonal) */ + lnzme = (f-1)*f/2 ; + lnz += lnzme ; + + /* number of divide operations for LDL' and for LU */ + ndiv += lnzme ; + + /* number of multiply-subtract pairs for LU */ + s = (f-1)*f*(2*f-1)/6 ; + nms_lu += s ; + + /* number of multiply-subtract pairs for LDL' */ + nms_ldl += (s + lnzme)/2 ; + + /* number of nz's in L (excl. diagonal) */ + Info [AMD_LNZ] = lnz ; + + /* number of divide ops for LU and LDL' */ + Info [AMD_NDIV] = ndiv ; + + /* number of multiply-subtract pairs for LDL' */ + Info [AMD_NMULTSUBS_LDL] = nms_ldl ; + + /* number of multiply-subtract pairs for LU */ + Info [AMD_NMULTSUBS_LU] = nms_lu ; + + /* number of "dense" rows/columns */ + Info [AMD_NDENSE] = ndense ; + + /* largest front is dmax-by-dmax */ + Info [AMD_DMAX] = dmax ; + + /* number of garbage collections in AMD */ + Info [AMD_NCMPA] = ncmpa ; + + /* successful ordering */ + Info [AMD_STATUS] = AMD_OK ; + } + +/* ========================================================================= */ +/* POST-ORDERING */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- + * Variables at this point: + * + * Pe: holds the elimination tree. The parent of j is FLIP (Pe [j]), + * or EMPTY if j is a root. The tree holds both elements and + * non-principal (unordered) variables absorbed into them. + * Dense variables are non-principal and unordered. + * + * Elen: holds the size of each element, including the diagonal part. + * FLIP (Elen [e]) > 0 if e is an element. For unordered + * variables i, Elen [i] is EMPTY. + * + * Nv: Nv [e] > 0 is the number of pivots represented by the element e. + * For unordered variables i, Nv [i] is zero. + * + * Contents no longer needed: + * W, Iw, Len, Degree, Head, Next, Last. + * + * The matrix itself has been destroyed. + * + * n: the size of the matrix. + * No other scalars needed (pfree, iwlen, etc.) + * ------------------------------------------------------------------------- */ + + /* restore Pe */ + for (i = 0 ; i < n ; i++) + { + Pe [i] = FLIP (Pe [i]) ; + } + + /* restore Elen, for output information, and for postordering */ + for (i = 0 ; i < n ; i++) + { + Elen [i] = FLIP (Elen [i]) ; + } + +/* Now the parent of j is Pe [j], or EMPTY if j is a root. Elen [e] > 0 + * is the size of element e. Elen [i] is EMPTY for unordered variable i. */ + +#ifndef NDEBUG + AMD_DEBUG2 (("\nTree:\n")) ; + for (i = 0 ; i < n ; i++) + { + AMD_DEBUG2 ((" "ID" parent: "ID" ", i, Pe [i])) ; + ASSERT (Pe [i] >= EMPTY && Pe [i] < n) ; + if (Nv [i] > 0) + { + /* this is an element */ + e = i ; + AMD_DEBUG2 ((" element, size is "ID"\n", Elen [i])) ; + ASSERT (Elen [e] > 0) ; + } + AMD_DEBUG2 (("\n")) ; + } + AMD_DEBUG2 (("\nelements:\n")) ; + for (e = 0 ; e < n ; e++) + { + if (Nv [e] > 0) + { + AMD_DEBUG3 (("Element e= "ID" size "ID" nv "ID" \n", e, + Elen [e], Nv [e])) ; + } + } + AMD_DEBUG2 (("\nvariables:\n")) ; + for (i = 0 ; i < n ; i++) + { + Int cnt ; + if (Nv [i] == 0) + { + AMD_DEBUG3 (("i unordered: "ID"\n", i)) ; + j = Pe [i] ; + cnt = 0 ; + AMD_DEBUG3 ((" j: "ID"\n", j)) ; + if (j == EMPTY) + { + AMD_DEBUG3 ((" i is a dense variable\n")) ; + } + else + { + ASSERT (j >= 0 && j < n) ; + while (Nv [j] == 0) + { + AMD_DEBUG3 ((" j : "ID"\n", j)) ; + j = Pe [j] ; + AMD_DEBUG3 ((" j:: "ID"\n", j)) ; + cnt++ ; + if (cnt > n) break ; + } + e = j ; + AMD_DEBUG3 ((" got to e: "ID"\n", e)) ; + } + } + } +#endif + +/* ========================================================================= */ +/* compress the paths of the variables */ +/* ========================================================================= */ + + for (i = 0 ; i < n ; i++) + { + if (Nv [i] == 0) + { + + /* ------------------------------------------------------------- + * i is an un-ordered row. Traverse the tree from i until + * reaching an element, e. The element, e, was the principal + * supervariable of i and all nodes in the path from i to when e + * was selected as pivot. + * ------------------------------------------------------------- */ + + AMD_DEBUG1 (("Path compression, i unordered: "ID"\n", i)) ; + j = Pe [i] ; + ASSERT (j >= EMPTY && j < n) ; + AMD_DEBUG3 ((" j: "ID"\n", j)) ; + if (j == EMPTY) + { + /* Skip a dense variable. It has no parent. */ + AMD_DEBUG3 ((" i is a dense variable\n")) ; + continue ; + } + + /* while (j is a variable) */ + while (Nv [j] == 0) + { + AMD_DEBUG3 ((" j : "ID"\n", j)) ; + j = Pe [j] ; + AMD_DEBUG3 ((" j:: "ID"\n", j)) ; + ASSERT (j >= 0 && j < n) ; + } + /* got to an element e */ + e = j ; + AMD_DEBUG3 (("got to e: "ID"\n", e)) ; + + /* ------------------------------------------------------------- + * traverse the path again from i to e, and compress the path + * (all nodes point to e). Path compression allows this code to + * compute in O(n) time. + * ------------------------------------------------------------- */ + + j = i ; + /* while (j is a variable) */ + while (Nv [j] == 0) + { + jnext = Pe [j] ; + AMD_DEBUG3 (("j "ID" jnext "ID"\n", j, jnext)) ; + Pe [j] = e ; + j = jnext ; + ASSERT (j >= 0 && j < n) ; + } + } + } + +/* ========================================================================= */ +/* postorder the assembly tree */ +/* ========================================================================= */ + + AMD_postorder (n, Pe, Nv, Elen, + W, /* output order */ + Head, Next, Last) ; /* workspace */ + +/* ========================================================================= */ +/* compute output permutation and inverse permutation */ +/* ========================================================================= */ + + /* W [e] = k means that element e is the kth element in the new + * order. e is in the range 0 to n-1, and k is in the range 0 to + * the number of elements. Use Head for inverse order. */ + + for (k = 0 ; k < n ; k++) + { + Head [k] = EMPTY ; + Next [k] = EMPTY ; + } + for (e = 0 ; e < n ; e++) + { + k = W [e] ; + ASSERT ((k == EMPTY) == (Nv [e] == 0)) ; + if (k != EMPTY) + { + ASSERT (k >= 0 && k < n) ; + Head [k] = e ; + } + } + + /* construct output inverse permutation in Next, + * and permutation in Last */ + nel = 0 ; + for (k = 0 ; k < n ; k++) + { + e = Head [k] ; + if (e == EMPTY) break ; + ASSERT (e >= 0 && e < n && Nv [e] > 0) ; + Next [e] = nel ; + nel += Nv [e] ; + } + ASSERT (nel == n - ndense) ; + + /* order non-principal variables (dense, & those merged into supervar's) */ + for (i = 0 ; i < n ; i++) + { + if (Nv [i] == 0) + { + e = Pe [i] ; + ASSERT (e >= EMPTY && e < n) ; + if (e != EMPTY) + { + /* This is an unordered variable that was merged + * into element e via supernode detection or mass + * elimination of i when e became the pivot element. + * Place i in order just before e. */ + ASSERT (Next [i] == EMPTY && Nv [e] > 0) ; + Next [i] = Next [e] ; + Next [e]++ ; + } + else + { + /* This is a dense unordered variable, with no parent. + * Place it last in the output order. */ + Next [i] = nel++ ; + } + } + } + ASSERT (nel == n) ; + + AMD_DEBUG2 (("\n\nPerm:\n")) ; + for (i = 0 ; i < n ; i++) + { + k = Next [i] ; + ASSERT (k >= 0 && k < n) ; + Last [k] = i ; + AMD_DEBUG2 ((" perm ["ID"] = "ID"\n", k, i)) ; + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_aat.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_aat.c new file mode 100644 index 0000000..67c03f7 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_aat.c @@ -0,0 +1,184 @@ +/* ========================================================================= */ +/* === AMD_aat ============================================================= */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* AMD, Copyright (c) Timothy A. Davis, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* AMD_aat: compute the symmetry of the pattern of A, and count the number of + * nonzeros each column of A+A' (excluding the diagonal). Assumes the input + * matrix has no errors, with sorted columns and no duplicates + * (AMD_valid (n, n, Ap, Ai) must be AMD_OK, but this condition is not + * checked). + */ + +#include "amd_internal.h" + +GLOBAL size_t AMD_aat /* returns nz in A+A' */ +( + Int n, + const Int Ap [ ], + const Int Ai [ ], + Int Len [ ], /* Len [j]: length of column j of A+A', excl diagonal*/ + Int Tp [ ], /* workspace of size n */ + double Info [ ] +) +{ + Int p1, p2, p, i, j, pj, pj2, k, nzdiag, nzboth, nz ; + double sym ; + size_t nzaat ; + +#ifndef NDEBUG + AMD_debug_init ("AMD AAT") ; + for (k = 0 ; k < n ; k++) Tp [k] = EMPTY ; + ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ; +#endif + + if (Info != (double *) NULL) + { + /* clear the Info array, if it exists */ + for (i = 0 ; i < AMD_INFO ; i++) + { + Info [i] = EMPTY ; + } + Info [AMD_STATUS] = AMD_OK ; + } + + for (k = 0 ; k < n ; k++) + { + Len [k] = 0 ; + } + + nzdiag = 0 ; + nzboth = 0 ; + nz = Ap [n] ; + + for (k = 0 ; k < n ; k++) + { + p1 = Ap [k] ; + p2 = Ap [k+1] ; + AMD_DEBUG2 (("\nAAT Column: "ID" p1: "ID" p2: "ID"\n", k, p1, p2)) ; + + /* construct A+A' */ + for (p = p1 ; p < p2 ; ) + { + /* scan the upper triangular part of A */ + j = Ai [p] ; + if (j < k) + { + /* entry A (j,k) is in the strictly upper triangular part, + * add both A (j,k) and A (k,j) to the matrix A+A' */ + Len [j]++ ; + Len [k]++ ; + AMD_DEBUG3 ((" upper ("ID","ID") ("ID","ID")\n", j,k, k,j)); + p++ ; + } + else if (j == k) + { + /* skip the diagonal */ + p++ ; + nzdiag++ ; + break ; + } + else /* j > k */ + { + /* first entry below the diagonal */ + break ; + } + /* scan lower triangular part of A, in column j until reaching + * row k. Start where last scan left off. */ + ASSERT (Tp [j] != EMPTY) ; + ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ; + pj2 = Ap [j+1] ; + for (pj = Tp [j] ; pj < pj2 ; ) + { + i = Ai [pj] ; + if (i < k) + { + /* A (i,j) is only in the lower part, not in upper. + * add both A (i,j) and A (j,i) to the matrix A+A' */ + Len [i]++ ; + Len [j]++ ; + AMD_DEBUG3 ((" lower ("ID","ID") ("ID","ID")\n", + i,j, j,i)) ; + pj++ ; + } + else if (i == k) + { + /* entry A (k,j) in lower part and A (j,k) in upper */ + pj++ ; + nzboth++ ; + break ; + } + else /* i > k */ + { + /* consider this entry later, when k advances to i */ + break ; + } + } + Tp [j] = pj ; + } + /* Tp [k] points to the entry just below the diagonal in column k */ + Tp [k] = p ; + } + + /* clean up, for remaining mismatched entries */ + for (j = 0 ; j < n ; j++) + { + for (pj = Tp [j] ; pj < Ap [j+1] ; pj++) + { + i = Ai [pj] ; + /* A (i,j) is only in the lower part, not in upper. + * add both A (i,j) and A (j,i) to the matrix A+A' */ + Len [i]++ ; + Len [j]++ ; + AMD_DEBUG3 ((" lower cleanup ("ID","ID") ("ID","ID")\n", + i,j, j,i)) ; + } + } + + /* --------------------------------------------------------------------- */ + /* compute the symmetry of the nonzero pattern of A */ + /* --------------------------------------------------------------------- */ + + /* Given a matrix A, the symmetry of A is: + * B = tril (spones (A), -1) + triu (spones (A), 1) ; + * sym = nnz (B & B') / nnz (B) ; + * or 1 if nnz (B) is zero. + */ + + if (nz == nzdiag) + { + sym = 1 ; + } + else + { + sym = (2 * (double) nzboth) / ((double) (nz - nzdiag)) ; + } + + nzaat = 0 ; + for (k = 0 ; k < n ; k++) + { + nzaat += Len [k] ; + } + + AMD_DEBUG1 (("AMD nz in A+A', excluding diagonal (nzaat) = %g\n", + (double) nzaat)) ; + AMD_DEBUG1 ((" nzboth: "ID" nz: "ID" nzdiag: "ID" symmetry: %g\n", + nzboth, nz, nzdiag, sym)) ; + + if (Info != (double *) NULL) + { + Info [AMD_STATUS] = AMD_OK ; + Info [AMD_N] = n ; + Info [AMD_NZ] = nz ; + Info [AMD_SYMMETRY] = sym ; /* symmetry of pattern of A */ + Info [AMD_NZDIAG] = nzdiag ; /* nonzeros on diagonal of A */ + Info [AMD_NZ_A_PLUS_AT] = nzaat ; /* nonzeros in A+A' */ + } + + return (nzaat) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_control.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_control.c new file mode 100644 index 0000000..f6a5e9a --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_control.c @@ -0,0 +1,64 @@ +/* ========================================================================= */ +/* === AMD_control ========================================================= */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* AMD, Copyright (c) Timothy A. Davis, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* User-callable. Prints the control parameters for AMD. See amd.h + * for details. If the Control array is not present, the defaults are + * printed instead. + */ + +#include "amd_internal.h" + +GLOBAL void AMD_control +( + double Control [ ] +) +{ + double alpha ; + Int aggressive ; + + if (Control != (double *) NULL) + { + alpha = Control [AMD_DENSE] ; + aggressive = Control [AMD_AGGRESSIVE] != 0 ; + } + else + { + alpha = AMD_DEFAULT_DENSE ; + aggressive = AMD_DEFAULT_AGGRESSIVE ; + } + + SUITESPARSE_PRINTF (( + "\nAMD version %d.%d.%d, %s: approximate minimum degree ordering\n" + " dense row parameter: %g\n", AMD_MAIN_VERSION, AMD_SUB_VERSION, + AMD_SUBSUB_VERSION, AMD_DATE, alpha)) ; + + if (alpha < 0) + { + SUITESPARSE_PRINTF ((" no rows treated as dense\n")) ; + } + else + { + SUITESPARSE_PRINTF (( + " (rows with more than max (%g * sqrt (n), 16) entries are\n" + " considered \"dense\", and placed last in output permutation)\n", + alpha)) ; + } + + if (aggressive) + { + SUITESPARSE_PRINTF ((" aggressive absorption: yes\n")) ; + } + else + { + SUITESPARSE_PRINTF ((" aggressive absorption: no\n")) ; + } + + SUITESPARSE_PRINTF ((" size of AMD integer: %d\n\n", sizeof (Int))) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_defaults.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_defaults.c new file mode 100644 index 0000000..b9a9079 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_defaults.c @@ -0,0 +1,37 @@ +/* ========================================================================= */ +/* === AMD_defaults ======================================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* AMD, Copyright (c) Timothy A. Davis, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* User-callable. Sets default control parameters for AMD. See amd.h + * for details. + */ + +#include "amd_internal.h" + +/* ========================================================================= */ +/* === AMD defaults ======================================================== */ +/* ========================================================================= */ + +GLOBAL void AMD_defaults +( + double Control [ ] +) +{ + Int i ; + + if (Control != (double *) NULL) + { + for (i = 0 ; i < AMD_CONTROL ; i++) + { + Control [i] = 0 ; + } + Control [AMD_DENSE] = AMD_DEFAULT_DENSE ; + Control [AMD_AGGRESSIVE] = AMD_DEFAULT_AGGRESSIVE ; + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_dump.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_dump.c new file mode 100644 index 0000000..e58aaf5 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_dump.c @@ -0,0 +1,179 @@ +/* ========================================================================= */ +/* === AMD_dump ============================================================ */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* AMD, Copyright (c) Timothy A. Davis, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* Debugging routines for AMD. Not used if NDEBUG is not defined at compile- + * time (the default). See comments in amd_internal.h on how to enable + * debugging. Not user-callable. + */ + +#include "amd_internal.h" + +#ifndef NDEBUG + +/* This global variable is present only when debugging */ +GLOBAL Int AMD_debug = -999 ; /* default is no debug printing */ + +/* ========================================================================= */ +/* === AMD_debug_init ====================================================== */ +/* ========================================================================= */ + +/* Sets the debug print level, by reading the file debug.amd (if it exists) */ + +GLOBAL void AMD_debug_init ( char *s ) +{ + FILE *f ; + f = fopen ("debug.amd", "r") ; + if (f == (FILE *) NULL) + { + AMD_debug = -999 ; + } + else + { + fscanf (f, ID, &AMD_debug) ; + fclose (f) ; + } + if (AMD_debug >= 0) + { + printf ("%s: AMD_debug_init, D= "ID"\n", s, AMD_debug) ; + } +} + +/* ========================================================================= */ +/* === AMD_dump ============================================================ */ +/* ========================================================================= */ + +/* Dump AMD's data structure, except for the hash buckets. This routine + * cannot be called when the hash buckets are non-empty. + */ + +GLOBAL void AMD_dump ( + Int n, /* A is n-by-n */ + Int Pe [ ], /* pe [0..n-1]: index in iw of start of row i */ + Int Iw [ ], /* workspace of size iwlen, iwlen [0..pfree-1] + * holds the matrix on input */ + Int Len [ ], /* len [0..n-1]: length for row i */ + Int iwlen, /* length of iw */ + Int pfree, /* iw [pfree ... iwlen-1] is empty on input */ + Int Nv [ ], /* nv [0..n-1] */ + Int Next [ ], /* next [0..n-1] */ + Int Last [ ], /* last [0..n-1] */ + Int Head [ ], /* head [0..n-1] */ + Int Elen [ ], /* size n */ + Int Degree [ ], /* size n */ + Int W [ ], /* size n */ + Int nel +) +{ + Int i, pe, elen, nv, len, e, p, k, j, deg, w, cnt, ilast ; + + if (AMD_debug < 0) return ; + ASSERT (pfree <= iwlen) ; + AMD_DEBUG3 (("\nAMD dump, pfree: "ID"\n", pfree)) ; + for (i = 0 ; i < n ; i++) + { + pe = Pe [i] ; + elen = Elen [i] ; + nv = Nv [i] ; + len = Len [i] ; + w = W [i] ; + + if (elen >= EMPTY) + { + if (nv == 0) + { + AMD_DEBUG3 (("\nI "ID": nonprincipal: ", i)) ; + ASSERT (elen == EMPTY) ; + if (pe == EMPTY) + { + AMD_DEBUG3 ((" dense node\n")) ; + ASSERT (w == 1) ; + } + else + { + ASSERT (pe < EMPTY) ; + AMD_DEBUG3 ((" i "ID" -> parent "ID"\n", i, FLIP (Pe[i]))); + } + } + else + { + AMD_DEBUG3 (("\nI "ID": active principal supervariable:\n",i)); + AMD_DEBUG3 ((" nv(i): "ID" Flag: %d\n", nv, (nv < 0))) ; + ASSERT (elen >= 0) ; + ASSERT (nv > 0 && pe >= 0) ; + p = pe ; + AMD_DEBUG3 ((" e/s: ")) ; + if (elen == 0) AMD_DEBUG3 ((" : ")) ; + ASSERT (pe + len <= pfree) ; + for (k = 0 ; k < len ; k++) + { + j = Iw [p] ; + AMD_DEBUG3 ((" "ID"", j)) ; + ASSERT (j >= 0 && j < n) ; + if (k == elen-1) AMD_DEBUG3 ((" : ")) ; + p++ ; + } + AMD_DEBUG3 (("\n")) ; + } + } + else + { + e = i ; + if (w == 0) + { + AMD_DEBUG3 (("\nE "ID": absorbed element: w "ID"\n", e, w)) ; + ASSERT (nv > 0 && pe < 0) ; + AMD_DEBUG3 ((" e "ID" -> parent "ID"\n", e, FLIP (Pe [e]))) ; + } + else + { + AMD_DEBUG3 (("\nE "ID": unabsorbed element: w "ID"\n", e, w)) ; + ASSERT (nv > 0 && pe >= 0) ; + p = pe ; + AMD_DEBUG3 ((" : ")) ; + ASSERT (pe + len <= pfree) ; + for (k = 0 ; k < len ; k++) + { + j = Iw [p] ; + AMD_DEBUG3 ((" "ID"", j)) ; + ASSERT (j >= 0 && j < n) ; + p++ ; + } + AMD_DEBUG3 (("\n")) ; + } + } + } + + /* this routine cannot be called when the hash buckets are non-empty */ + AMD_DEBUG3 (("\nDegree lists:\n")) ; + if (nel >= 0) + { + cnt = 0 ; + for (deg = 0 ; deg < n ; deg++) + { + if (Head [deg] == EMPTY) continue ; + ilast = EMPTY ; + AMD_DEBUG3 ((ID": \n", deg)) ; + for (i = Head [deg] ; i != EMPTY ; i = Next [i]) + { + AMD_DEBUG3 ((" "ID" : next "ID" last "ID" deg "ID"\n", + i, Next [i], Last [i], Degree [i])) ; + ASSERT (i >= 0 && i < n && ilast == Last [i] && + deg == Degree [i]) ; + cnt += Nv [i] ; + ilast = i ; + } + AMD_DEBUG3 (("\n")) ; + } + ASSERT (cnt == n - nel) ; + } + +} + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_global.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_global.c new file mode 100644 index 0000000..453e970 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_global.c @@ -0,0 +1,14 @@ +/* ========================================================================= */ +/* === amd_global ========================================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* AMD, Copyright (c) Timothy A. Davis, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* In prior versions of AMD, this file declared the amd_malloc, amd_free, + amd_realloc, amd_calloc, and amd_printf functions. They are now replaced + by functions defined in SuiteSparse_config/SuiteSparse_config.c. + */ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_info.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_info.c new file mode 100644 index 0000000..062651f --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_info.c @@ -0,0 +1,119 @@ +/* ========================================================================= */ +/* === AMD_info ============================================================ */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* AMD, Copyright (c) Timothy A. Davis, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* User-callable. Prints the output statistics for AMD. See amd.h + * for details. If the Info array is not present, nothing is printed. + */ + +#include "amd_internal.h" + +#define PRI(format,x) { if (x >= 0) { SUITESPARSE_PRINTF ((format, x)) ; }} + +GLOBAL void AMD_info +( + double Info [ ] +) +{ + double n, ndiv, nmultsubs_ldl, nmultsubs_lu, lnz, lnzd ; + + SUITESPARSE_PRINTF (("\nAMD version %d.%d.%d, %s, results:\n", + AMD_MAIN_VERSION, AMD_SUB_VERSION, AMD_SUBSUB_VERSION, AMD_DATE)) ; + + if (!Info) + { + return ; + } + + n = Info [AMD_N] ; + ndiv = Info [AMD_NDIV] ; + nmultsubs_ldl = Info [AMD_NMULTSUBS_LDL] ; + nmultsubs_lu = Info [AMD_NMULTSUBS_LU] ; + lnz = Info [AMD_LNZ] ; + lnzd = (n >= 0 && lnz >= 0) ? (n + lnz) : (-1) ; + + /* AMD return status */ + SUITESPARSE_PRINTF ((" status: ")) ; + if (Info [AMD_STATUS] == AMD_OK) + { + SUITESPARSE_PRINTF (("OK\n")) ; + } + else if (Info [AMD_STATUS] == AMD_OUT_OF_MEMORY) + { + SUITESPARSE_PRINTF (("out of memory\n")) ; + } + else if (Info [AMD_STATUS] == AMD_INVALID) + { + SUITESPARSE_PRINTF (("invalid matrix\n")) ; + } + else if (Info [AMD_STATUS] == AMD_OK_BUT_JUMBLED) + { + SUITESPARSE_PRINTF (("OK, but jumbled\n")) ; + } + else + { + SUITESPARSE_PRINTF (("unknown\n")) ; + } + + /* statistics about the input matrix */ + PRI (" n, dimension of A: %.20g\n", n); + PRI (" nz, number of nonzeros in A: %.20g\n", + Info [AMD_NZ]) ; + PRI (" symmetry of A: %.4f\n", + Info [AMD_SYMMETRY]) ; + PRI (" number of nonzeros on diagonal: %.20g\n", + Info [AMD_NZDIAG]) ; + PRI (" nonzeros in pattern of A+A' (excl. diagonal): %.20g\n", + Info [AMD_NZ_A_PLUS_AT]) ; + PRI (" # dense rows/columns of A+A': %.20g\n", + Info [AMD_NDENSE]) ; + + /* statistics about AMD's behavior */ + PRI (" memory used, in bytes: %.20g\n", + Info [AMD_MEMORY]) ; + PRI (" # of memory compactions: %.20g\n", + Info [AMD_NCMPA]) ; + + /* statistics about the ordering quality */ + SUITESPARSE_PRINTF (("\n" + " The following approximate statistics are for a subsequent\n" + " factorization of A(P,P) + A(P,P)'. They are slight upper\n" + " bounds if there are no dense rows/columns in A+A', and become\n" + " looser if dense rows/columns exist.\n\n")) ; + + PRI (" nonzeros in L (excluding diagonal): %.20g\n", + lnz) ; + PRI (" nonzeros in L (including diagonal): %.20g\n", + lnzd) ; + PRI (" # divide operations for LDL' or LU: %.20g\n", + ndiv) ; + PRI (" # multiply-subtract operations for LDL': %.20g\n", + nmultsubs_ldl) ; + PRI (" # multiply-subtract operations for LU: %.20g\n", + nmultsubs_lu) ; + PRI (" max nz. in any column of L (incl. diagonal): %.20g\n", + Info [AMD_DMAX]) ; + + /* total flop counts for various factorizations */ + + if (n >= 0 && ndiv >= 0 && nmultsubs_ldl >= 0 && nmultsubs_lu >= 0) + { + SUITESPARSE_PRINTF (("\n" + " chol flop count for real A, sqrt counted as 1 flop: %.20g\n" + " LDL' flop count for real A: %.20g\n" + " LDL' flop count for complex A: %.20g\n" + " LU flop count for real A (with no pivoting): %.20g\n" + " LU flop count for complex A (with no pivoting): %.20g\n\n", + n + ndiv + 2*nmultsubs_ldl, + ndiv + 2*nmultsubs_ldl, + 9*ndiv + 8*nmultsubs_ldl, + ndiv + 2*nmultsubs_lu, + 9*ndiv + 8*nmultsubs_lu)) ; + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_order.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_order.c new file mode 100644 index 0000000..7f199ae --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_order.c @@ -0,0 +1,199 @@ +/* ========================================================================= */ +/* === AMD_order =========================================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* AMD, Copyright (c) Timothy A. Davis, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* User-callable AMD minimum degree ordering routine. See amd.h for + * documentation. + */ + +#include "amd_internal.h" + +/* ========================================================================= */ +/* === AMD_order =========================================================== */ +/* ========================================================================= */ + +GLOBAL Int AMD_order +( + Int n, + const Int Ap [ ], + const Int Ai [ ], + Int P [ ], + double Control [ ], + double Info [ ] +) +{ + Int *Len, *S, nz, i, *Pinv, info, status, *Rp, *Ri, *Cp, *Ci, ok ; + size_t nzaat, slen ; + double mem = 0 ; + +#ifndef NDEBUG + AMD_debug_init ("amd") ; +#endif + + /* clear the Info array, if it exists */ + info = Info != (double *) NULL ; + if (info) + { + for (i = 0 ; i < AMD_INFO ; i++) + { + Info [i] = EMPTY ; + } + Info [AMD_N] = n ; + Info [AMD_STATUS] = AMD_OK ; + } + + /* make sure inputs exist and n is >= 0 */ + if (Ai == (Int *) NULL || Ap == (Int *) NULL || P == (Int *) NULL || n < 0) + { + if (info) Info [AMD_STATUS] = AMD_INVALID ; + return (AMD_INVALID) ; /* arguments are invalid */ + } + + if (n == 0) + { + return (AMD_OK) ; /* n is 0 so there's nothing to do */ + } + + nz = Ap [n] ; + if (info) + { + Info [AMD_NZ] = nz ; + } + if (nz < 0) + { + if (info) Info [AMD_STATUS] = AMD_INVALID ; + return (AMD_INVALID) ; + } + + /* check if n or nz will cause size_t overflow */ + if (((size_t) n) >= SIZE_T_MAX / sizeof (Int) + || ((size_t) nz) >= SIZE_T_MAX / sizeof (Int)) + { + if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ; + return (AMD_OUT_OF_MEMORY) ; /* problem too large */ + } + + /* check the input matrix: AMD_OK, AMD_INVALID, or AMD_OK_BUT_JUMBLED */ + status = AMD_valid (n, n, Ap, Ai) ; + + if (status == AMD_INVALID) + { + if (info) Info [AMD_STATUS] = AMD_INVALID ; + return (AMD_INVALID) ; /* matrix is invalid */ + } + + /* allocate two size-n integer workspaces */ + Len = SuiteSparse_malloc (n, sizeof (Int)) ; + Pinv = SuiteSparse_malloc (n, sizeof (Int)) ; + mem += n ; + mem += n ; + if (!Len || !Pinv) + { + /* :: out of memory :: */ + SuiteSparse_free (Len) ; + SuiteSparse_free (Pinv) ; + if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ; + return (AMD_OUT_OF_MEMORY) ; + } + + if (status == AMD_OK_BUT_JUMBLED) + { + /* sort the input matrix and remove duplicate entries */ + AMD_DEBUG1 (("Matrix is jumbled\n")) ; + Rp = SuiteSparse_malloc (n+1, sizeof (Int)) ; + Ri = SuiteSparse_malloc (nz, sizeof (Int)) ; + mem += (n+1) ; + mem += MAX (nz,1) ; + if (!Rp || !Ri) + { + /* :: out of memory :: */ + SuiteSparse_free (Rp) ; + SuiteSparse_free (Ri) ; + SuiteSparse_free (Len) ; + SuiteSparse_free (Pinv) ; + if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ; + return (AMD_OUT_OF_MEMORY) ; + } + /* use Len and Pinv as workspace to create R = A' */ + AMD_preprocess (n, Ap, Ai, Rp, Ri, Len, Pinv) ; + Cp = Rp ; + Ci = Ri ; + } + else + { + /* order the input matrix as-is. No need to compute R = A' first */ + Rp = NULL ; + Ri = NULL ; + Cp = (Int *) Ap ; + Ci = (Int *) Ai ; + } + + /* --------------------------------------------------------------------- */ + /* determine the symmetry and count off-diagonal nonzeros in A+A' */ + /* --------------------------------------------------------------------- */ + + nzaat = AMD_aat (n, Cp, Ci, Len, P, Info) ; + AMD_DEBUG1 (("nzaat: %g\n", (double) nzaat)) ; + ASSERT ((MAX (nz-n, 0) <= nzaat) && (nzaat <= 2 * (size_t) nz)) ; + + /* --------------------------------------------------------------------- */ + /* allocate workspace for matrix, elbow room, and 6 size-n vectors */ + /* --------------------------------------------------------------------- */ + + S = NULL ; + slen = nzaat ; /* space for matrix */ + ok = ((slen + nzaat/5) >= slen) ; /* check for size_t overflow */ + slen += nzaat/5 ; /* add elbow room */ + for (i = 0 ; ok && i < 7 ; i++) + { + ok = ((slen + n) > slen) ; /* check for size_t overflow */ + slen += n ; /* size-n elbow room, 6 size-n work */ + } + mem += slen ; + ok = ok && (slen < SIZE_T_MAX / sizeof (Int)) ; /* check for overflow */ + ok = ok && (slen < Int_MAX) ; /* S[i] for Int i must be OK */ + if (ok) + { + S = SuiteSparse_malloc (slen, sizeof (Int)) ; + } + AMD_DEBUG1 (("slen %g\n", (double) slen)) ; + if (!S) + { + /* :: out of memory :: (or problem too large) */ + SuiteSparse_free (Rp) ; + SuiteSparse_free (Ri) ; + SuiteSparse_free (Len) ; + SuiteSparse_free (Pinv) ; + if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ; + return (AMD_OUT_OF_MEMORY) ; + } + if (info) + { + /* memory usage, in bytes. */ + Info [AMD_MEMORY] = mem * sizeof (Int) ; + } + + /* --------------------------------------------------------------------- */ + /* order the matrix */ + /* --------------------------------------------------------------------- */ + + AMD_1 (n, Cp, Ci, P, Pinv, Len, slen, S, Control, Info) ; + + /* --------------------------------------------------------------------- */ + /* free the workspace */ + /* --------------------------------------------------------------------- */ + + SuiteSparse_free (Rp) ; + SuiteSparse_free (Ri) ; + SuiteSparse_free (Len) ; + SuiteSparse_free (Pinv) ; + SuiteSparse_free (S) ; + if (info) Info [AMD_STATUS] = status ; + return (status) ; /* successful ordering */ +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_post_tree.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_post_tree.c new file mode 100644 index 0000000..516c95c --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_post_tree.c @@ -0,0 +1,120 @@ +/* ========================================================================= */ +/* === AMD_post_tree ======================================================= */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* AMD, Copyright (c) Timothy A. Davis, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* Post-ordering of a supernodal elimination tree. */ + +#include "amd_internal.h" + +GLOBAL Int AMD_post_tree +( + Int root, /* root of the tree */ + Int k, /* start numbering at k */ + Int Child [ ], /* input argument of size nn, undefined on + * output. Child [i] is the head of a link + * list of all nodes that are children of node + * i in the tree. */ + const Int Sibling [ ], /* input argument of size nn, not modified. + * If f is a node in the link list of the + * children of node i, then Sibling [f] is the + * next child of node i. + */ + Int Order [ ], /* output order, of size nn. Order [i] = k + * if node i is the kth node of the reordered + * tree. */ + Int Stack [ ] /* workspace of size nn */ +#ifndef NDEBUG + , Int nn /* nodes are in the range 0..nn-1. */ +#endif +) +{ + Int f, head, h, i ; + +#if 0 + /* --------------------------------------------------------------------- */ + /* recursive version (Stack [ ] is not used): */ + /* --------------------------------------------------------------------- */ + + /* this is simple, but can caouse stack overflow if nn is large */ + i = root ; + for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) + { + k = AMD_post_tree (f, k, Child, Sibling, Order, Stack, nn) ; + } + Order [i] = k++ ; + return (k) ; +#endif + + /* --------------------------------------------------------------------- */ + /* non-recursive version, using an explicit stack */ + /* --------------------------------------------------------------------- */ + + /* push root on the stack */ + head = 0 ; + Stack [0] = root ; + + while (head >= 0) + { + /* get head of stack */ + ASSERT (head < nn) ; + i = Stack [head] ; + AMD_DEBUG1 (("head of stack "ID" \n", i)) ; + ASSERT (i >= 0 && i < nn) ; + + if (Child [i] != EMPTY) + { + /* the children of i are not yet ordered */ + /* push each child onto the stack in reverse order */ + /* so that small ones at the head of the list get popped first */ + /* and the biggest one at the end of the list gets popped last */ + for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) + { + head++ ; + ASSERT (head < nn) ; + ASSERT (f >= 0 && f < nn) ; + } + h = head ; + ASSERT (head < nn) ; + for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) + { + ASSERT (h > 0) ; + Stack [h--] = f ; + AMD_DEBUG1 (("push "ID" on stack\n", f)) ; + ASSERT (f >= 0 && f < nn) ; + } + ASSERT (Stack [h] == i) ; + + /* delete child list so that i gets ordered next time we see it */ + Child [i] = EMPTY ; + } + else + { + /* the children of i (if there were any) are already ordered */ + /* remove i from the stack and order it. Front i is kth front */ + head-- ; + AMD_DEBUG1 (("pop "ID" order "ID"\n", i, k)) ; + Order [i] = k++ ; + ASSERT (k <= nn) ; + } + +#ifndef NDEBUG + AMD_DEBUG1 (("\nStack:")) ; + for (h = head ; h >= 0 ; h--) + { + Int j = Stack [h] ; + AMD_DEBUG1 ((" "ID, j)) ; + ASSERT (j >= 0 && j < nn) ; + } + AMD_DEBUG1 (("\n\n")) ; + ASSERT (head < nn) ; +#endif + + } + return (k) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_postorder.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_postorder.c new file mode 100644 index 0000000..e5aea7b --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_postorder.c @@ -0,0 +1,206 @@ +/* ========================================================================= */ +/* === AMD_postorder ======================================================= */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* AMD, Copyright (c) Timothy A. Davis, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* Perform a postordering (via depth-first search) of an assembly tree. */ + +#include "amd_internal.h" + +GLOBAL void AMD_postorder +( + /* inputs, not modified on output: */ + Int nn, /* nodes are in the range 0..nn-1 */ + Int Parent [ ], /* Parent [j] is the parent of j, or EMPTY if root */ + Int Nv [ ], /* Nv [j] > 0 number of pivots represented by node j, + * or zero if j is not a node. */ + Int Fsize [ ], /* Fsize [j]: size of node j */ + + /* output, not defined on input: */ + Int Order [ ], /* output post-order */ + + /* workspaces of size nn: */ + Int Child [ ], + Int Sibling [ ], + Int Stack [ ] +) +{ + Int i, j, k, parent, frsize, f, fprev, maxfrsize, bigfprev, bigf, fnext ; + + for (j = 0 ; j < nn ; j++) + { + Child [j] = EMPTY ; + Sibling [j] = EMPTY ; + } + + /* --------------------------------------------------------------------- */ + /* place the children in link lists - bigger elements tend to be last */ + /* --------------------------------------------------------------------- */ + + for (j = nn-1 ; j >= 0 ; j--) + { + if (Nv [j] > 0) + { + /* this is an element */ + parent = Parent [j] ; + if (parent != EMPTY) + { + /* place the element in link list of the children its parent */ + /* bigger elements will tend to be at the end of the list */ + Sibling [j] = Child [parent] ; + Child [parent] = j ; + } + } + } + +#ifndef NDEBUG + { + Int nels, ff, nchild ; + AMD_DEBUG1 (("\n\n================================ AMD_postorder:\n")); + nels = 0 ; + for (j = 0 ; j < nn ; j++) + { + if (Nv [j] > 0) + { + AMD_DEBUG1 (( ""ID" : nels "ID" npiv "ID" size "ID + " parent "ID" maxfr "ID"\n", j, nels, + Nv [j], Fsize [j], Parent [j], Fsize [j])) ; + /* this is an element */ + /* dump the link list of children */ + nchild = 0 ; + AMD_DEBUG1 ((" Children: ")) ; + for (ff = Child [j] ; ff != EMPTY ; ff = Sibling [ff]) + { + AMD_DEBUG1 ((ID" ", ff)) ; + ASSERT (Parent [ff] == j) ; + nchild++ ; + ASSERT (nchild < nn) ; + } + AMD_DEBUG1 (("\n")) ; + parent = Parent [j] ; + if (parent != EMPTY) + { + ASSERT (Nv [parent] > 0) ; + } + nels++ ; + } + } + } + AMD_DEBUG1 (("\n\nGo through the children of each node, and put\n" + "the biggest child last in each list:\n")) ; +#endif + + /* --------------------------------------------------------------------- */ + /* place the largest child last in the list of children for each node */ + /* --------------------------------------------------------------------- */ + + for (i = 0 ; i < nn ; i++) + { + if (Nv [i] > 0 && Child [i] != EMPTY) + { + +#ifndef NDEBUG + Int nchild ; + AMD_DEBUG1 (("Before partial sort, element "ID"\n", i)) ; + nchild = 0 ; + for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) + { + ASSERT (f >= 0 && f < nn) ; + AMD_DEBUG1 ((" f: "ID" size: "ID"\n", f, Fsize [f])) ; + nchild++ ; + ASSERT (nchild <= nn) ; + } +#endif + + /* find the biggest element in the child list */ + fprev = EMPTY ; + maxfrsize = EMPTY ; + bigfprev = EMPTY ; + bigf = EMPTY ; + for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) + { + ASSERT (f >= 0 && f < nn) ; + frsize = Fsize [f] ; + if (frsize >= maxfrsize) + { + /* this is the biggest seen so far */ + maxfrsize = frsize ; + bigfprev = fprev ; + bigf = f ; + } + fprev = f ; + } + ASSERT (bigf != EMPTY) ; + + fnext = Sibling [bigf] ; + + AMD_DEBUG1 (("bigf "ID" maxfrsize "ID" bigfprev "ID" fnext "ID + " fprev " ID"\n", bigf, maxfrsize, bigfprev, fnext, fprev)) ; + + if (fnext != EMPTY) + { + /* if fnext is EMPTY then bigf is already at the end of list */ + + if (bigfprev == EMPTY) + { + /* delete bigf from the element of the list */ + Child [i] = fnext ; + } + else + { + /* delete bigf from the middle of the list */ + Sibling [bigfprev] = fnext ; + } + + /* put bigf at the end of the list */ + Sibling [bigf] = EMPTY ; + ASSERT (Child [i] != EMPTY) ; + ASSERT (fprev != bigf) ; + ASSERT (fprev != EMPTY) ; + Sibling [fprev] = bigf ; + } + +#ifndef NDEBUG + AMD_DEBUG1 (("After partial sort, element "ID"\n", i)) ; + for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) + { + ASSERT (f >= 0 && f < nn) ; + AMD_DEBUG1 ((" "ID" "ID"\n", f, Fsize [f])) ; + ASSERT (Nv [f] > 0) ; + nchild-- ; + } + ASSERT (nchild == 0) ; +#endif + + } + } + + /* --------------------------------------------------------------------- */ + /* postorder the assembly tree */ + /* --------------------------------------------------------------------- */ + + for (i = 0 ; i < nn ; i++) + { + Order [i] = EMPTY ; + } + + k = 0 ; + + for (i = 0 ; i < nn ; i++) + { + if (Parent [i] == EMPTY && Nv [i] > 0) + { + AMD_DEBUG1 (("Root of assembly tree "ID"\n", i)) ; + k = AMD_post_tree (i, k, Child, Sibling, Order, Stack +#ifndef NDEBUG + , nn +#endif + ) ; + } + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_preprocess.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_preprocess.c new file mode 100644 index 0000000..a8139c3 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_preprocess.c @@ -0,0 +1,118 @@ +/* ========================================================================= */ +/* === AMD_preprocess ====================================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* AMD, Copyright (c) Timothy A. Davis, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* Sorts, removes duplicate entries, and transposes from the nonzero pattern of + * a column-form matrix A, to obtain the matrix R. The input matrix can have + * duplicate entries and/or unsorted columns (AMD_valid (n,Ap,Ai) must not be + * AMD_INVALID). + * + * This input condition is NOT checked. This routine is not user-callable. + */ + +#include "amd_internal.h" + +/* ========================================================================= */ +/* === AMD_preprocess ====================================================== */ +/* ========================================================================= */ + +/* AMD_preprocess does not check its input for errors or allocate workspace. + * On input, the condition (AMD_valid (n,n,Ap,Ai) != AMD_INVALID) must hold. + */ + +GLOBAL void AMD_preprocess +( + Int n, /* input matrix: A is n-by-n */ + const Int Ap [ ], /* size n+1 */ + const Int Ai [ ], /* size nz = Ap [n] */ + + /* output matrix R: */ + Int Rp [ ], /* size n+1 */ + Int Ri [ ], /* size nz (or less, if duplicates present) */ + + Int W [ ], /* workspace of size n */ + Int Flag [ ] /* workspace of size n */ +) +{ + + /* --------------------------------------------------------------------- */ + /* local variables */ + /* --------------------------------------------------------------------- */ + + Int i, j, p, p2 ; + + ASSERT (AMD_valid (n, n, Ap, Ai) != AMD_INVALID) ; + + /* --------------------------------------------------------------------- */ + /* count the entries in each row of A (excluding duplicates) */ + /* --------------------------------------------------------------------- */ + + for (i = 0 ; i < n ; i++) + { + W [i] = 0 ; /* # of nonzeros in row i (excl duplicates) */ + Flag [i] = EMPTY ; /* Flag [i] = j if i appears in column j */ + } + for (j = 0 ; j < n ; j++) + { + p2 = Ap [j+1] ; + for (p = Ap [j] ; p < p2 ; p++) + { + i = Ai [p] ; + if (Flag [i] != j) + { + /* row index i has not yet appeared in column j */ + W [i]++ ; /* one more entry in row i */ + Flag [i] = j ; /* flag row index i as appearing in col j*/ + } + } + } + + /* --------------------------------------------------------------------- */ + /* compute the row pointers for R */ + /* --------------------------------------------------------------------- */ + + Rp [0] = 0 ; + for (i = 0 ; i < n ; i++) + { + Rp [i+1] = Rp [i] + W [i] ; + } + for (i = 0 ; i < n ; i++) + { + W [i] = Rp [i] ; + Flag [i] = EMPTY ; + } + + /* --------------------------------------------------------------------- */ + /* construct the row form matrix R */ + /* --------------------------------------------------------------------- */ + + /* R = row form of pattern of A */ + for (j = 0 ; j < n ; j++) + { + p2 = Ap [j+1] ; + for (p = Ap [j] ; p < p2 ; p++) + { + i = Ai [p] ; + if (Flag [i] != j) + { + /* row index i has not yet appeared in column j */ + Ri [W [i]++] = j ; /* put col j in row i */ + Flag [i] = j ; /* flag row index i as appearing in col j*/ + } + } + } + +#ifndef NDEBUG + ASSERT (AMD_valid (n, n, Rp, Ri) == AMD_OK) ; + for (j = 0 ; j < n ; j++) + { + ASSERT (W [j] == Rp [j+1]) ; + } +#endif +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_valid.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_valid.c new file mode 100644 index 0000000..609abca --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/AMD/Source/amd_valid.c @@ -0,0 +1,92 @@ +/* ========================================================================= */ +/* === AMD_valid =========================================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* AMD, Copyright (c) Timothy A. Davis, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* Check if a column-form matrix is valid or not. The matrix A is + * n_row-by-n_col. The row indices of entries in column j are in + * Ai [Ap [j] ... Ap [j+1]-1]. Required conditions are: + * + * n_row >= 0 + * n_col >= 0 + * nz = Ap [n_col] >= 0 number of entries in the matrix + * Ap [0] == 0 + * Ap [j] <= Ap [j+1] for all j in the range 0 to n_col. + * Ai [0 ... nz-1] must be in the range 0 to n_row-1. + * + * If any of the above conditions hold, AMD_INVALID is returned. If the + * following condition holds, AMD_OK_BUT_JUMBLED is returned (a warning, + * not an error): + * + * row indices in Ai [Ap [j] ... Ap [j+1]-1] are not sorted in ascending + * order, and/or duplicate entries exist. + * + * Otherwise, AMD_OK is returned. + * + * In v1.2 and earlier, this function returned TRUE if the matrix was valid + * (now returns AMD_OK), or FALSE otherwise (now returns AMD_INVALID or + * AMD_OK_BUT_JUMBLED). + */ + +#include "amd_internal.h" + +GLOBAL Int AMD_valid +( + /* inputs, not modified on output: */ + Int n_row, /* A is n_row-by-n_col */ + Int n_col, + const Int Ap [ ], /* column pointers of A, of size n_col+1 */ + const Int Ai [ ] /* row indices of A, of size nz = Ap [n_col] */ +) +{ + Int nz, j, p1, p2, ilast, i, p, result = AMD_OK ; + + if (n_row < 0 || n_col < 0 || Ap == NULL || Ai == NULL) + { + return (AMD_INVALID) ; + } + nz = Ap [n_col] ; + if (Ap [0] != 0 || nz < 0) + { + /* column pointers must start at Ap [0] = 0, and Ap [n] must be >= 0 */ + AMD_DEBUG0 (("column 0 pointer bad or nz < 0\n")) ; + return (AMD_INVALID) ; + } + for (j = 0 ; j < n_col ; j++) + { + p1 = Ap [j] ; + p2 = Ap [j+1] ; + AMD_DEBUG2 (("\nColumn: "ID" p1: "ID" p2: "ID"\n", j, p1, p2)) ; + if (p1 > p2) + { + /* column pointers must be ascending */ + AMD_DEBUG0 (("column "ID" pointer bad\n", j)) ; + return (AMD_INVALID) ; + } + ilast = EMPTY ; + for (p = p1 ; p < p2 ; p++) + { + i = Ai [p] ; + AMD_DEBUG3 (("row: "ID"\n", i)) ; + if (i < 0 || i >= n_row) + { + /* row index out of range */ + AMD_DEBUG0 (("index out of range, col "ID" row "ID"\n", j, i)); + return (AMD_INVALID) ; + } + if (i <= ilast) + { + /* row index unsorted, or duplicate entry present */ + AMD_DEBUG1 (("index unsorted/dupl col "ID" row "ID"\n", j, i)); + result = AMD_OK_BUT_JUMBLED ; + } + ilast = i ; + } + } + return (result) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/Include/btf.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/Include/btf.h new file mode 100644 index 0000000..c36de94 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/Include/btf.h @@ -0,0 +1,267 @@ +/* ========================================================================== */ +/* === BTF package ========================================================== */ +/* ========================================================================== */ + +/* BTF_MAXTRANS: find a column permutation Q to give A*Q a zero-free diagonal + * BTF_STRONGCOMP: find a symmetric permutation P to put P*A*P' into block + * upper triangular form. + * BTF_ORDER: do both of the above (btf_maxtrans then btf_strongcomp). + * + * By Tim Davis. Copyright (c) 2004-2007, University of Florida. + * with support from Sandia National Laboratories. All Rights Reserved. + */ + + +/* ========================================================================== */ +/* === BTF_MAXTRANS ========================================================= */ +/* ========================================================================== */ + +/* BTF_MAXTRANS: finds a permutation of the columns of a matrix so that it has a + * zero-free diagonal. The input is an m-by-n sparse matrix in compressed + * column form. The array Ap of size n+1 gives the starting and ending + * positions of the columns in the array Ai. Ap[0] must be zero. The array Ai + * contains the row indices of the nonzeros of the matrix A, and is of size + * Ap[n]. The row indices of column j are located in Ai[Ap[j] ... Ap[j+1]-1]. + * Row indices must be in the range 0 to m-1. Duplicate entries may be present + * in any given column. The input matrix is not checked for validity (row + * indices out of the range 0 to m-1 will lead to an undeterminate result - + * possibly a core dump, for example). Row indices in any given column need + * not be in sorted order. However, if they are sorted and the matrix already + * has a zero-free diagonal, then the identity permutation is returned. + * + * The output of btf_maxtrans is an array Match of size n. If row i is matched + * with column j, then A(i,j) is nonzero, and then Match[i] = j. If the matrix + * is structurally nonsingular, all entries in the Match array are unique, and + * Match can be viewed as a column permutation if A is square. That is, column + * k of the original matrix becomes column Match[k] of the permuted matrix. In + * MATLAB, this can be expressed as (for non-structurally singular matrices): + * + * Match = maxtrans (A) ; + * B = A (:, Match) ; + * + * except of course here the A matrix and Match vector are all 0-based (rows + * and columns in the range 0 to n-1), not 1-based (rows/cols in range 1 to n). + * The MATLAB dmperm routine returns a row permutation. See the maxtrans + * mexFunction for more details. + * + * If row i is not matched to any column, then Match[i] is == -1. The + * btf_maxtrans routine returns the number of nonzeros on diagonal of the + * permuted matrix. + * + * In the MATLAB mexFunction interface to btf_maxtrans, 1 is added to the Match + * array to obtain a 1-based permutation. Thus, in MATLAB where A is m-by-n: + * + * q = maxtrans (A) ; % has entries in the range 0:n + * q % a column permutation (only if sprank(A)==n) + * B = A (:, q) ; % permuted matrix (only if sprank(A)==n) + * sum (q > 0) ; % same as "sprank (A)" + * + * This behaviour differs from p = dmperm (A) in MATLAB, which returns the + * matching as p(j)=i if row i and column j are matched, and p(j)=0 if column j + * is unmatched. + * + * p = dmperm (A) ; % has entries in the range 0:m + * p % a row permutation (only if sprank(A)==m) + * B = A (p, :) ; % permuted matrix (only if sprank(A)==m) + * sum (p > 0) ; % definition of sprank (A) + * + * This algorithm is based on the paper "On Algorithms for obtaining a maximum + * transversal" by Iain Duff, ACM Trans. Mathematical Software, vol 7, no. 1, + * pp. 315-330, and "Algorithm 575: Permutations for a zero-free diagonal", + * same issue, pp. 387-390. Algorithm 575 is MC21A in the Harwell Subroutine + * Library. This code is not merely a translation of the Fortran code into C. + * It is a completely new implementation of the basic underlying method (depth + * first search over a subgraph with nodes corresponding to columns matched so + * far, and cheap matching). This code was written with minimal observation of + * the MC21A/B code itself. See comments below for a comparison between the + * maxtrans and MC21A/B codes. + * + * This routine operates on a column-form matrix and produces a column + * permutation. MC21A uses a row-form matrix and produces a row permutation. + * The difference is merely one of convention in the comments and interpretation + * of the inputs and outputs. If you want a row permutation, simply pass a + * compressed-row sparse matrix to this routine and you will get a row + * permutation (just like MC21A). Similarly, you can pass a column-oriented + * matrix to MC21A and it will happily return a column permutation. + */ + +#ifndef _BTF_H +#define _BTF_H + +/* make it easy for C++ programs to include BTF */ +#ifdef __cplusplus +extern "C" { +#endif + +#include "SuiteSparse_config.h" + +int btf_maxtrans /* returns # of columns matched */ +( + /* --- input, not modified: --- */ + int nrow, /* A is nrow-by-ncol in compressed column form */ + int ncol, + int Ap [ ], /* size ncol+1 */ + int Ai [ ], /* size nz = Ap [ncol] */ + double maxwork, /* maximum amount of work to do is maxwork*nnz(A); no limit + * if <= 0 */ + + /* --- output, not defined on input --- */ + double *work, /* work = -1 if maxwork > 0 and the total work performed + * reached the maximum of maxwork*nnz(A). + * Otherwise, work = the total work performed. */ + + int Match [ ], /* size nrow. Match [i] = j if column j matched to row i + * (see above for the singular-matrix case) */ + + /* --- workspace, not defined on input or output --- */ + int Work [ ] /* size 5*ncol */ +) ; + +/* long integer version (all "int" parameters become "SuiteSparse_long") */ +SuiteSparse_long btf_l_maxtrans (SuiteSparse_long, SuiteSparse_long, + SuiteSparse_long *, SuiteSparse_long *, double, double *, + SuiteSparse_long *, SuiteSparse_long *) ; + + +/* ========================================================================== */ +/* === BTF_STRONGCOMP ======================================================= */ +/* ========================================================================== */ + +/* BTF_STRONGCOMP finds the strongly connected components of a graph, returning + * a symmetric permutation. The matrix A must be square, and is provided on + * input in compressed-column form (see BTF_MAXTRANS, above). The diagonal of + * the input matrix A (or A*Q if Q is provided on input) is ignored. + * + * If Q is not NULL on input, then the strongly connected components of A*Q are + * found. Q may be flagged on input, where Q[k] < 0 denotes a flagged column k. + * The permutation is j = BTF_UNFLIP (Q [k]). On output, Q is modified (the + * flags are preserved) so that P*A*Q is in block upper triangular form. + * + * If Q is NULL, then the permutation P is returned so that P*A*P' is in upper + * block triangular form. + * + * The vector R gives the block boundaries, where block b is in rows/columns + * R[b] to R[b+1]-1 of the permuted matrix, and where b ranges from 1 to the + * number of strongly connected components found. + */ + +int btf_strongcomp /* return # of strongly connected components */ +( + /* input, not modified: */ + int n, /* A is n-by-n in compressed column form */ + int Ap [ ], /* size n+1 */ + int Ai [ ], /* size nz = Ap [n] */ + + /* optional input, modified (if present) on output: */ + int Q [ ], /* size n, input column permutation */ + + /* output, not defined on input */ + int P [ ], /* size n. P [k] = j if row and column j are kth row/col + * in permuted matrix. */ + + int R [ ], /* size n+1. block b is in rows/cols R[b] ... R[b+1]-1 */ + + /* workspace, not defined on input or output */ + int Work [ ] /* size 4n */ +) ; + +SuiteSparse_long btf_l_strongcomp (SuiteSparse_long, SuiteSparse_long *, + SuiteSparse_long *, SuiteSparse_long *, SuiteSparse_long *, + SuiteSparse_long *, SuiteSparse_long *) ; + + +/* ========================================================================== */ +/* === BTF_ORDER ============================================================ */ +/* ========================================================================== */ + +/* BTF_ORDER permutes a square matrix into upper block triangular form. It + * does this by first finding a maximum matching (or perhaps a limited matching + * if the work is limited), via the btf_maxtrans function. If a complete + * matching is not found, BTF_ORDER completes the permutation, but flags the + * columns of P*A*Q to denote which columns are not matched. If the matrix is + * structurally rank deficient, some of the entries on the diagonal of the + * permuted matrix will be zero. BTF_ORDER then calls btf_strongcomp to find + * the strongly-connected components. + * + * On output, P and Q are the row and column permutations, where i = P[k] if + * row i of A is the kth row of P*A*Q, and j = BTF_UNFLIP(Q[k]) if column j of + * A is the kth column of P*A*Q. If Q[k] < 0, then the (k,k)th entry in P*A*Q + * is structurally zero. + * + * The vector R gives the block boundaries, where block b is in rows/columns + * R[b] to R[b+1]-1 of the permuted matrix, and where b ranges from 1 to the + * number of strongly connected components found. + */ + +int btf_order /* returns number of blocks found */ +( + /* --- input, not modified: --- */ + int n, /* A is n-by-n in compressed column form */ + int Ap [ ], /* size n+1 */ + int Ai [ ], /* size nz = Ap [n] */ + double maxwork, /* do at most maxwork*nnz(A) work in the maximum + * transversal; no limit if <= 0 */ + + /* --- output, not defined on input --- */ + double *work, /* return value from btf_maxtrans */ + int P [ ], /* size n, row permutation */ + int Q [ ], /* size n, column permutation */ + int R [ ], /* size n+1. block b is in rows/cols R[b] ... R[b+1]-1 */ + int *nmatch, /* # nonzeros on diagonal of P*A*Q */ + + /* --- workspace, not defined on input or output --- */ + int Work [ ] /* size 5n */ +) ; + +SuiteSparse_long btf_l_order (SuiteSparse_long, SuiteSparse_long *, + SuiteSparse_long *, double , double *, SuiteSparse_long *, + SuiteSparse_long *, SuiteSparse_long *, SuiteSparse_long *, + SuiteSparse_long *) ; + + +/* ========================================================================== */ +/* === BTF marking of singular columns ====================================== */ +/* ========================================================================== */ + +/* BTF_FLIP is a "negation about -1", and is used to mark an integer j + * that is normally non-negative. BTF_FLIP (-1) is -1. BTF_FLIP of + * a number > -1 is negative, and BTF_FLIP of a number < -1 is positive. + * BTF_FLIP (BTF_FLIP (j)) = j for all integers j. UNFLIP (j) acts + * like an "absolute value" operation, and is always >= -1. You can test + * whether or not an integer j is "flipped" with the BTF_ISFLIPPED (j) + * macro. + */ + +#define BTF_FLIP(j) (-(j)-2) +#define BTF_ISFLIPPED(j) ((j) < -1) +#define BTF_UNFLIP(j) ((BTF_ISFLIPPED (j)) ? BTF_FLIP (j) : (j)) + +/* ========================================================================== */ +/* === BTF version ========================================================== */ +/* ========================================================================== */ + +/* All versions of BTF include these definitions. + * As an example, to test if the version you are using is 1.2 or later: + * + * if (BTF_VERSION >= BTF_VERSION_CODE (1,2)) ... + * + * This also works during compile-time: + * + * #if (BTF >= BTF_VERSION_CODE (1,2)) + * printf ("This is version 1.2 or later\n") ; + * #else + * printf ("This is an early version\n") ; + * #endif + */ + +#define BTF_DATE "May 4, 2016" +#define BTF_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) +#define BTF_MAIN_VERSION 1 +#define BTF_SUB_VERSION 2 +#define BTF_SUBSUB_VERSION 6 +#define BTF_VERSION BTF_VERSION_CODE(BTF_MAIN_VERSION,BTF_SUB_VERSION) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/Include/btf_internal.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/Include/btf_internal.h new file mode 100644 index 0000000..fc0426d --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/Include/btf_internal.h @@ -0,0 +1,64 @@ +/* ========================================================================== */ +/* === btf_internal include file ============================================ */ +/* ========================================================================== */ + +#ifndef _BTF_INTERNAL_H +#define _BTF_INTERNAL_H + +/* + * By Tim Davis. Copyright (c) 2004-2007, University of Florida. + * with support from Sandia National Laboratories. All Rights Reserved. + */ + +/* Not to be included in any user program. */ + +#ifdef DLONG +#define Int SuiteSparse_long +#define Int_id SuiteSparse_long_id +#define BTF(name) btf_l_ ## name +#else +#define Int int +#define Int_id "%d" +#define BTF(name) btf_ ## name +#endif + +/* ========================================================================== */ +/* make sure debugging and printing is turned off */ + +#ifndef NDEBUG +#define NDEBUG +#endif +#ifndef NPRINT +#define NPRINT +#endif + +/* To enable debugging and assertions, uncomment this line: + #undef NDEBUG +*/ +/* To enable diagnostic printing, uncomment this line: + #undef NPRINT +*/ + +/* ========================================================================== */ + +#include <stdio.h> +#include <assert.h> +#define ASSERT(a) assert(a) + +#undef TRUE +#undef FALSE +#undef PRINTF +#undef MIN + +#ifndef NPRINT +#define PRINTF(s) { printf s ; } ; +#else +#define PRINTF(s) +#endif + +#define TRUE 1 +#define FALSE 0 +#define EMPTY (-1) +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/MATLAB/btf.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/MATLAB/btf.c new file mode 100644 index 0000000..45dcf75 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/MATLAB/btf.c @@ -0,0 +1,145 @@ +/* ========================================================================== */ +/* === btf mexFunction ====================================================== */ +/* ========================================================================== */ + +/* BTF: Permute a square matrix to upper block triangular form with a zero-free + * diagonal, or with a maximum number of nonzeros along the diagonal if a + * zero-free permutation does not exist. + * + * Usage: + * + * [p,q,r] = btf (A) ; + * [p,q,r] = btf (A, maxwork) ; + * + * If the matrix has structural full rank, this is essentially identical to + * + * [p,q,r] = dmperm (A) + * + * except that p, q, and r will differ in trivial ways. Both return an upper + * block triangular form with a zero-free diagonal, if the matrix is + * structurally non-singular. The number and sizes of the blocks will be + * identical, but the order of the blocks, and the ordering within the blocks, + * can be different. + * + * If the matrix is structurally singular, q will contain negative entries. + * The permuted matrix is C = A(p,abs(q)), and find(q<0) gives a list of + * indices of the diagonal of C that are equal to zero. This differs from + * dmperm, which does not place the maximum matching along the main diagonal + * of C=A(p,q), but places it above the diagonal instead. + * + * See maxtrans, or btf.m, for a description of maxwork. + * + * An optional fourth output [p,q,r,work] = btf (...) returns the amount of + * work performed, or -1 if the maximum work limit is reached (in which case + * the maximum matching might not have been found). + * + * By Tim Davis. Copyright (c) 2004-2007, University of Florida. + * with support from Sandia National Laboratories. All Rights Reserved. + * + * See also maxtrans, strongcomp, dmperm + */ + +/* ========================================================================== */ + +#include "mex.h" +#include "btf.h" +#define Long SuiteSparse_long + +void mexFunction +( + int nargout, + mxArray *pargout [ ], + int nargin, + const mxArray *pargin [ ] +) +{ + double work, maxwork ; + Long b, n, k, *Ap, *Ai, *P, *R, nblocks, *Work, *Q, nmatch ; + double *Px, *Rx, *Qx, *w ; + + /* ---------------------------------------------------------------------- */ + /* get inputs and allocate workspace */ + /* ---------------------------------------------------------------------- */ + + if (nargin < 1 || nargin > 2 || nargout > 4) + { + mexErrMsgTxt ("Usage: [p,q,r] = btf (A)") ; + } + n = mxGetM (pargin [0]) ; + if (!mxIsSparse (pargin [0]) || n != mxGetN (pargin [0])) + { + mexErrMsgTxt ("btf: A must be sparse, square, and non-empty") ; + } + + /* get sparse matrix A */ + Ap = (Long *) mxGetJc (pargin [0]) ; + Ai = (Long *) mxGetIr (pargin [0]) ; + + /* get output arrays */ + Q = mxMalloc (n * sizeof (Long)) ; + P = mxMalloc (n * sizeof (Long)) ; + R = mxMalloc ((n+1) * sizeof (Long)) ; + + /* get workspace */ + Work = mxMalloc (5*n * sizeof (Long)) ; + + maxwork = 0 ; + if (nargin > 1) + { + maxwork = mxGetScalar (pargin [1]) ; + } + work = 0 ; + + /* ---------------------------------------------------------------------- */ + /* find the permutation to BTF */ + /* ---------------------------------------------------------------------- */ + + nblocks = btf_l_order (n, Ap, Ai, maxwork, &work, P, Q, R, &nmatch, Work) ; + + /* ---------------------------------------------------------------------- */ + /* create outputs and free workspace */ + /* ---------------------------------------------------------------------- */ + + /* create P */ + pargout [0] = mxCreateDoubleMatrix (1, n, mxREAL) ; + Px = mxGetPr (pargout [0]) ; + for (k = 0 ; k < n ; k++) + { + Px [k] = P [k] + 1 ; /* convert to 1-based */ + } + + /* create Q */ + if (nargout > 1) + { + pargout [1] = mxCreateDoubleMatrix (1, n, mxREAL) ; + Qx = mxGetPr (pargout [1]) ; + for (k = 0 ; k < n ; k++) + { + Qx [k] = Q [k] + 1 ; /* convert to 1-based */ + } + } + + /* create R */ + if (nargout > 2) + { + pargout [2] = mxCreateDoubleMatrix (1, nblocks+1, mxREAL) ; + Rx = mxGetPr (pargout [2]) ; + for (b = 0 ; b <= nblocks ; b++) + { + Rx [b] = R [b] + 1 ; /* convert to 1-based */ + } + } + + /* create work output */ + if (nargout > 3) + { + pargout [3] = mxCreateDoubleMatrix (1, 1, mxREAL) ; + w = mxGetPr (pargout [3]) ; + w [0] = work ; + } + + mxFree (P) ; + mxFree (R) ; + mxFree (Work) ; + mxFree (Q) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/MATLAB/maxtrans.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/MATLAB/maxtrans.c new file mode 100644 index 0000000..8219981 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/MATLAB/maxtrans.c @@ -0,0 +1,102 @@ +/* ========================================================================== */ +/* === maxtrans mexFunction ================================================= */ +/* ========================================================================== */ + +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +/* MAXTRANS: Find a column permutation for a zero-free diagonal. + * + * Usage: + * + * q = maxtrans (A) ; + * q = maxtrans (A,maxwork) ; + * + * A (:,q) has a zero-free diagonal if sprank(A) == n. + * If the matrix is structurally singular, q will contain zeros. Similar + * to p = dmperm (A), except that dmperm returns a row permutation. + * + * An optional second output [q,work] = maxtrans (...) returns the amount of + * work performed, or -1 if the maximum work limit is reached (in which case + * the maximum matching might not have been found). + * + * By Tim Davis. Copyright (c) 2004-2007, University of Florida. + * with support from Sandia National Laboratories. All Rights Reserved. + */ + +/* ========================================================================== */ + +#include "mex.h" +#include "btf.h" +#define Long SuiteSparse_long + +void mexFunction +( + int nargout, + mxArray *pargout [ ], + int nargin, + const mxArray *pargin [ ] +) +{ + double maxwork, work ; + Long nrow, ncol, i, *Ap, *Ai, *Match, nmatch, *Work ; + double *Matchx, *w ; + + /* ---------------------------------------------------------------------- */ + /* get inputs and allocate workspace */ + /* ---------------------------------------------------------------------- */ + + if (nargin < 1 || nargin > 2 || nargout > 2) + { + mexErrMsgTxt ("Usage: q = maxtrans (A)") ; + } + nrow = mxGetM (pargin [0]) ; + ncol = mxGetN (pargin [0]) ; + if (!mxIsSparse (pargin [0])) + { + mexErrMsgTxt ("maxtrans: A must be sparse, and non-empty") ; + } + + /* get sparse matrix A */ + Ap = (Long *) mxGetJc (pargin [0]) ; + Ai = (Long *) mxGetIr (pargin [0]) ; + + /* get output array */ + Match = mxMalloc (nrow * sizeof (Long)) ; + + /* get workspace of size 5n (recursive version needs only 2n) */ + Work = mxMalloc (5*ncol * sizeof (Long)) ; + + maxwork = 0 ; + if (nargin > 1) + { + maxwork = mxGetScalar (pargin [1]) ; + } + work = 0 ; + + /* ---------------------------------------------------------------------- */ + /* perform the maximum transversal */ + /* ---------------------------------------------------------------------- */ + + nmatch = btf_l_maxtrans (nrow, ncol, Ap, Ai, maxwork, &work, Match, Work) ; + + /* ---------------------------------------------------------------------- */ + /* create outputs and free workspace */ + /* ---------------------------------------------------------------------- */ + + pargout [0] = mxCreateDoubleMatrix (1, nrow, mxREAL) ; + Matchx = mxGetPr (pargout [0]) ; + for (i = 0 ; i < nrow ; i++) + { + Matchx [i] = Match [i] + 1 ; /* convert to 1-based */ + } + + if (nargout > 1) + { + pargout [1] = mxCreateDoubleMatrix (1, 1, mxREAL) ; + w = mxGetPr (pargout [1]) ; + w [0] = work ; + } + + mxFree (Work) ; + mxFree (Match) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/MATLAB/strongcomp.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/MATLAB/strongcomp.c new file mode 100644 index 0000000..0e15735 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/MATLAB/strongcomp.c @@ -0,0 +1,180 @@ +/* ========================================================================== */ +/* === stongcomp mexFunction ================================================ */ +/* ========================================================================== */ + +/* STRONGCOMP: Find a symmetric permutation to upper block triangular form of + * a sparse square matrix. + * + * Usage: + * + * [p,r] = strongcomp (A) ; + * + * [p,q,r] = strongcomp (A,qin) ; + * + * In the first usage, the permuted matrix is C = A (p,p). In the second usage, + * the matrix A (:,qin) is symmetrically permuted to upper block triangular + * form, where qin is an input column permutation, and the final permuted + * matrix is C = A (p,q). This second usage is equivalent to + * + * [p,r] = strongcomp (A (:,qin)) ; + * q = qin (p) ; + * + * That is, if qin is not present it is assumed to be qin = 1:n. + * + * C is the permuted matrix, with a number of blocks equal to length(r)-1. + * The kth block is from row/col r(k) to row/col r(k+1)-1 of C. + * r(1) is one and the last entry in r is equal to n+1. + * The diagonal of A (or A (:,qin)) is ignored. + * + * strongcomp is normally proceeded by a maximum transversal: + * + * [p,q,r] = strongcomp (A, maxtrans (A)) + * + * if the matrix has full structural rank. This is identical to + * + * [p,q,r] = btf (A) + * + * (except that btf handles the case when A is structurally rank-deficient). + * It essentially the same as + * + * [p,q,r] = dmperm (A) + * + * except that p, q, and r will differ between btf and dmperm. Both return an + * upper block triangular form with a zero-free diagonal. The number and sizes + * of the blocks will be identical, but the order of the blocks, and the + * ordering within the blocks, can be different. For structurally rank + * deficient matrices, dmpmerm returns the maximum matching as a zero-free + * diagonal that is above the main diagonal; btf always returns the matching as + * the main diagonal (which will thus contain zeros). + * + * By Tim Davis. Copyright (c) 2004-2007, University of Florida. + * with support from Sandia National Laboratories. All Rights Reserved. + * + * See also maxtrans, btf, dmperm + */ + +/* ========================================================================== */ + +#include "mex.h" +#include "btf.h" +#define Long SuiteSparse_long + +void mexFunction +( + int nargout, + mxArray *pargout[], + int nargin, + const mxArray *pargin[] +) +{ + Long b, n, i, k, j, *Ap, *Ai, *P, *R, nblocks, *Work, *Q, jj ; + double *Px, *Rx, *Qx ; + + /* ---------------------------------------------------------------------- */ + /* get inputs and allocate workspace */ + /* ---------------------------------------------------------------------- */ + + if (!((nargin == 1 && nargout <= 2) || (nargin == 2 && nargout <= 3))) + { + mexErrMsgTxt ("Usage: [p,r] = strongcomp (A)" + " or [p,q,r] = strongcomp (A,qin)") ; + } + n = mxGetM (pargin [0]) ; + if (!mxIsSparse (pargin [0]) || n != mxGetN (pargin [0])) + { + mexErrMsgTxt ("strongcomp: A must be sparse, square, and non-empty") ; + } + + /* get sparse matrix A */ + Ap = (Long *) mxGetJc (pargin [0]) ; + Ai = (Long *) mxGetIr (pargin [0]) ; + + /* get output arrays */ + P = mxMalloc (n * sizeof (Long)) ; + R = mxMalloc ((n+1) * sizeof (Long)) ; + + /* get workspace of size 4n (recursive code only needs 2n) */ + Work = mxMalloc (4*n * sizeof (Long)) ; + + /* get the input column permutation Q */ + if (nargin == 2) + { + if (mxGetNumberOfElements (pargin [1]) != n) + { + mexErrMsgTxt + ("strongcomp: qin must be a permutation vector of size n") ; + } + Qx = mxGetPr (pargin [1]) ; + Q = mxMalloc (n * sizeof (Long)) ; + /* connvert Qin to 0-based and check validity */ + for (i = 0 ; i < n ; i++) + { + Work [i] = 0 ; + } + for (k = 0 ; k < n ; k++) + { + j = Qx [k] - 1 ; /* convert to 0-based */ + jj = BTF_UNFLIP (j) ; + if (jj < 0 || jj >= n || Work [jj] == 1) + { + mexErrMsgTxt + ("strongcomp: qin must be a permutation vector of size n") ; + } + Work [jj] = 1 ; + Q [k] = j ; + } + } + else + { + /* no input column permutation */ + Q = (Long *) NULL ; + } + + /* ---------------------------------------------------------------------- */ + /* find the strongly-connected components of A */ + /* ---------------------------------------------------------------------- */ + + nblocks = btf_l_strongcomp (n, Ap, Ai, Q, P, R, Work) ; + + /* ---------------------------------------------------------------------- */ + /* create outputs and free workspace */ + /* ---------------------------------------------------------------------- */ + + /* create P */ + pargout [0] = mxCreateDoubleMatrix (1, n, mxREAL) ; + Px = mxGetPr (pargout [0]) ; + for (k = 0 ; k < n ; k++) + { + Px [k] = P [k] + 1 ; /* convert to 1-based */ + } + + /* create Q */ + if (nargin == 2 && nargout > 1) + { + pargout [1] = mxCreateDoubleMatrix (1, n, mxREAL) ; + Qx = mxGetPr (pargout [1]) ; + for (k = 0 ; k < n ; k++) + { + Qx [k] = Q [k] + 1 ; /* convert to 1-based */ + } + } + + /* create R */ + if (nargout == nargin + 1) + { + pargout [nargin] = mxCreateDoubleMatrix (1, nblocks+1, mxREAL) ; + Rx = mxGetPr (pargout [nargin]) ; + for (b = 0 ; b <= nblocks ; b++) + { + Rx [b] = R [b] + 1 ; /* convert to 1-based */ + } + } + + mxFree (P) ; + mxFree (R) ; + mxFree (Work) ; + if (nargin == 2) + { + mxFree (Q) ; + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/Source/btf_maxtrans.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/Source/btf_maxtrans.c new file mode 100644 index 0000000..3f44b26 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/Source/btf_maxtrans.c @@ -0,0 +1,387 @@ +/* ========================================================================== */ +/* === BTF_MAXTRANS ========================================================= */ +/* ========================================================================== */ + +/* Finds a column permutation that maximizes the number of entries on the + * diagonal of a sparse matrix. See btf.h for more information. + * + * This function is identical to cs_maxtrans in CSparse, with the following + * exceptions: + * + * (1) cs_maxtrans finds both jmatch and imatch, where jmatch [i] = j and + * imatch [j] = i if row i is matched to column j. This function returns + * just jmatch (the Match array). The MATLAB interface to cs_maxtrans + * (the single-output cs_dmperm) returns imatch, not jmatch to the MATLAB + * caller. + * + * (2) cs_maxtrans includes a pre-pass that counts the number of non-empty + * rows and columns (m2 and n2, respectively), and computes the matching + * using the transpose of A if m2 < n2. cs_maxtrans also returns quickly + * if the diagonal of the matrix is already zero-free. This pre-pass + * allows cs_maxtrans to be much faster than maxtrans, if the use of the + * transpose is warranted. + * + * However, for square structurally non-singular matrices with one or more + * zeros on the diagonal, the pre-pass is a waste of time, and for these + * matrices, maxtrans can be twice as fast as cs_maxtrans. Since the + * maxtrans function is intended primarily for square matrices that are + * typically structurally nonsingular, the pre-pass is not included here. + * If this maxtrans function is used on a matrix with many more columns + * than rows, consider passing the transpose to this function, or use + * cs_maxtrans instead. + * + * (3) cs_maxtrans can operate as a randomized algorithm, to help avoid + * rare cases of excessive run-time. + * + * (4) this maxtrans function includes an option that limits the total work + * performed. If this limit is reached, the maximum transveral might not + * be found. + * + * Thus, for general usage, cs_maxtrans is preferred. For square matrices that + * are typically structurally non-singular, maxtrans is preferred. A partial + * maxtrans can still be very useful when solving a sparse linear system. + * + * By Tim Davis. Copyright (c) 2004-2007, University of Florida. + * with support from Sandia National Laboratories. All Rights Reserved. + */ + +#include "btf.h" +#include "btf_internal.h" + + +/* ========================================================================== */ +/* === augment ============================================================== */ +/* ========================================================================== */ + +/* Perform a depth-first-search starting at column k, to find an augmenting + * path. An augmenting path is a sequence of row/column pairs (i1,k), (i2,j1), + * (i3,j2), ..., (i(s+1), js), such that all of the following properties hold: + * + * * column k is not matched to any row + * * entries in the path are nonzero + * * the pairs (i1,j1), (i2,j2), (i3,j3) ..., (is,js) have been + * previously matched to each other + * * (i(s+1), js) is nonzero, and row i(s+1) is not matched to any column + * + * Once this path is found, the matching can be changed to the set of pairs + * path. An augmenting path is a sequence of row/column pairs + * + * (i1,k), (i2,j1), (i3,j2), ..., (i(s+1), js) + * + * Once a row is matched with a column it remains matched with some column, but + * not necessarily the column it was first matched with. + * + * In the worst case, this function can examine every nonzero in A. Since it + * is called n times by maxtrans, the total time of maxtrans can be as high as + * O(n*nnz(A)). To limit this work, pass a value of maxwork > 0. Then at + * most O((maxwork+1)*nnz(A)) work will be performed; the maximum matching might + * not be found, however. + * + * This routine is very similar to the dfs routine in klu_kernel.c, in the + * KLU sparse LU factorization package. It is essentially identical to the + * cs_augment routine in CSparse, and its recursive version (augment function + * in cs_maxtransr_mex.c), except that this routine allows for the search to be + * terminated early if too much work is being performed. + * + * The algorithm is based on the paper "On Algorithms for obtaining a maximum + * transversal" by Iain Duff, ACM Trans. Mathematical Software, vol 7, no. 1, + * pp. 315-330, and "Algorithm 575: Permutations for a zero-free diagonal", + * same issue, pp. 387-390. The code here is a new implementation of that + * algorithm, with different data structures and control flow. After writing + * this code, I carefully compared my algorithm with MC21A/B (ACM Algorithm 575) + * Some of the comparisons are partial because I didn't dig deeply into all of + * the details of MC21A/B, such as how the stack is maintained. The following + * arguments are essentially identical between this code and MC21A: + * + * maxtrans MC21A,B + * -------- ------- + * n N identical + * k JORD identical + * Ap IP column / row pointers + * Ai ICN row / column indices + * Ap[n] LICN length of index array (# of nonzeros in A) + * Match IPERM output column / row permutation + * nmatch NUMNZ # of nonzeros on diagonal of permuted matrix + * Flag CV mark a node as visited by the depth-first-search + * + * The following are different, but analogous: + * + * Cheap ARP indicates what part of the a column / row has + * already been matched. + * + * The following arguments are very different: + * + * - LENR # of entries in each row/column (unused in maxtrans) + * Pstack OUT Pstack keeps track of where we are in the depth- + * first-search scan of column j. I think that OUT + * plays a similar role in MC21B, but I'm unsure. + * Istack PR keeps track of the rows in the path. PR is a link + * list, though, whereas Istack is a stack. Maxtrans + * does not use any link lists. + * Jstack OUT? PR? the stack for nodes in the path (unsure) + * + * The following control structures are roughly comparable: + * + * maxtrans MC21B + * -------- ----- + * for (k = 0 ; k < n ; k++) DO 100 JORD=1,N + * while (head >= 0) DO 70 K=1,JORD + * for (p = Cheap [j] ; ...) DO 20 II=IN1,IN2 + * for (p = head ; ...) DO 90 K=1,JORD + */ + +static Int augment +( + Int k, /* which stage of the main loop we're in */ + Int Ap [ ], /* column pointers, size n+1 */ + Int Ai [ ], /* row indices, size nz = Ap [n] */ + Int Match [ ], /* size n, Match [i] = j if col j matched to i */ + Int Cheap [ ], /* rows Ai [Ap [j] .. Cheap [j]-1] alread matched */ + Int Flag [ ], /* Flag [j] = k if j already visited this stage */ + Int Istack [ ], /* size n. Row index stack. */ + Int Jstack [ ], /* size n. Column index stack. */ + Int Pstack [ ], /* size n. Keeps track of position in adjacency list */ + double *work, /* work performed by the depth-first-search */ + double maxwork /* maximum work allowed */ +) +{ + /* local variables, but "global" to all DFS levels: */ + Int found ; /* true if match found. */ + Int head ; /* top of stack */ + + /* variables that are purely local to any one DFS level: */ + Int j2 ; /* the next DFS goes to node j2 */ + Int pend ; /* one past the end of the adjacency list for node j */ + Int pstart ; + Int quick ; + + /* variables that need to be pushed then popped from the stack: */ + Int i ; /* the row tentatively matched to i if DFS successful */ + Int j ; /* the DFS is at the current node j */ + Int p ; /* current index into the adj. list for node j */ + /* the variables i, j, and p are stacked in Istack, Jstack, and Pstack */ + + quick = (maxwork > 0) ; + + /* start a DFS to find a match for column k */ + found = FALSE ; + i = EMPTY ; + head = 0 ; + Jstack [0] = k ; + ASSERT (Flag [k] != k) ; + + while (head >= 0) + { + j = Jstack [head] ; + pend = Ap [j+1] ; + + if (Flag [j] != k) /* a node is not yet visited */ + { + + /* -------------------------------------------------------------- */ + /* prework for node j */ + /* -------------------------------------------------------------- */ + + /* first time that j has been visited */ + Flag [j] = k ; + /* cheap assignment: find the next unmatched row in col j. This + * loop takes at most O(nnz(A)) time for the sum total of all + * calls to augment. */ + for (p = Cheap [j] ; p < pend && !found ; p++) + { + i = Ai [p] ; + found = (Match [i] == EMPTY) ; + } + Cheap [j] = p ; + + /* -------------------------------------------------------------- */ + + /* prepare for DFS */ + if (found) + { + /* end of augmenting path, column j matched with row i */ + Istack [head] = i ; + break ; + } + /* set Pstack [head] to the first entry in column j to scan */ + Pstack [head] = Ap [j] ; + } + + /* ------------------------------------------------------------------ */ + /* quick return if too much work done */ + /* ------------------------------------------------------------------ */ + + if (quick && *work > maxwork) + { + /* too much work has been performed; abort the search */ + return (EMPTY) ; + } + + /* ------------------------------------------------------------------ */ + /* DFS for nodes adjacent to j */ + /* ------------------------------------------------------------------ */ + + /* If cheap assignment not made, continue the depth-first search. All + * rows in column j are already matched. Add the adjacent nodes to the + * stack by iterating through until finding another non-visited node. + * + * It is the following loop that can force maxtrans to take + * O(n*nnz(A)) time. */ + + pstart = Pstack [head] ; + for (p = pstart ; p < pend ; p++) + { + i = Ai [p] ; + j2 = Match [i] ; + ASSERT (j2 != EMPTY) ; + if (Flag [j2] != k) + { + /* Node j2 is not yet visited, start a depth-first search on + * node j2. Keep track of where we left off in the scan of adj + * list of node j so we can restart j where we left off. */ + Pstack [head] = p + 1 ; + /* Push j2 onto the stack and immediately break so we can + * recurse on node j2. Also keep track of row i which (if this + * search for an augmenting path works) will be matched with the + * current node j. */ + Istack [head] = i ; + Jstack [++head] = j2 ; + break ; + } + } + + /* ------------------------------------------------------------------ */ + /* determine how much work was just performed */ + /* ------------------------------------------------------------------ */ + + *work += (p - pstart + 1) ; + + /* ------------------------------------------------------------------ */ + /* node j is done, but the postwork is postponed - see below */ + /* ------------------------------------------------------------------ */ + + if (p == pend) + { + /* If all adjacent nodes of j are already visited, pop j from + * stack and continue. We failed to find a match. */ + head-- ; + } + } + + /* postwork for all nodes j in the stack */ + /* unwind the path and make the corresponding matches */ + if (found) + { + for (p = head ; p >= 0 ; p--) + { + j = Jstack [p] ; + i = Istack [p] ; + + /* -------------------------------------------------------------- */ + /* postwork for node j */ + /* -------------------------------------------------------------- */ + /* if found, match row i with column j */ + Match [i] = j ; + } + } + return (found) ; +} + + +/* ========================================================================== */ +/* === maxtrans ============================================================= */ +/* ========================================================================== */ + +Int BTF(maxtrans) /* returns # of columns in the matching */ +( + /* --- input --- */ + Int nrow, /* A is nrow-by-ncol in compressed column form */ + Int ncol, + Int Ap [ ], /* size ncol+1 */ + Int Ai [ ], /* size nz = Ap [ncol] */ + double maxwork, /* do at most maxwork*nnz(A) work; no limit if <= 0. This + * work limit excludes the O(nnz(A)) cheap-match phase. */ + + /* --- output --- */ + double *work, /* work = -1 if maxwork > 0 and the total work performed + * reached the maximum of maxwork*nnz(A)). + * Otherwise, work = the total work performed. */ + + Int Match [ ], /* size nrow. Match [i] = j if column j matched to row i */ + + /* --- workspace --- */ + Int Work [ ] /* size 5*ncol */ +) +{ + Int *Cheap, *Flag, *Istack, *Jstack, *Pstack ; + Int i, j, k, nmatch, work_limit_reached, result ; + + /* ---------------------------------------------------------------------- */ + /* get workspace and initialize */ + /* ---------------------------------------------------------------------- */ + + Cheap = Work ; Work += ncol ; + Flag = Work ; Work += ncol ; + + /* stack for non-recursive depth-first search in augment function */ + Istack = Work ; Work += ncol ; + Jstack = Work ; Work += ncol ; + Pstack = Work ; + + /* in column j, rows Ai [Ap [j] .. Cheap [j]-1] are known to be matched */ + for (j = 0 ; j < ncol ; j++) + { + Cheap [j] = Ap [j] ; + Flag [j] = EMPTY ; + } + + /* all rows and columns are currently unmatched */ + for (i = 0 ; i < nrow ; i++) + { + Match [i] = EMPTY ; + } + + if (maxwork > 0) + { + maxwork *= Ap [ncol] ; + } + *work = 0 ; + + /* ---------------------------------------------------------------------- */ + /* find a matching row for each column k */ + /* ---------------------------------------------------------------------- */ + + nmatch = 0 ; + work_limit_reached = FALSE ; + for (k = 0 ; k < ncol ; k++) + { + /* find an augmenting path to match some row i to column k */ + result = augment (k, Ap, Ai, Match, Cheap, Flag, Istack, Jstack, Pstack, + work, maxwork) ; + if (result == TRUE) + { + /* we found it. Match [i] = k for some row i has been done. */ + nmatch++ ; + } + else if (result == EMPTY) + { + /* augment gave up because of too much work, and no match found */ + work_limit_reached = TRUE ; + } + } + + /* ---------------------------------------------------------------------- */ + /* return the Match, and the # of matches made */ + /* ---------------------------------------------------------------------- */ + + /* At this point, row i is matched to j = Match [i] if j >= 0. i is an + * unmatched row if Match [i] == EMPTY. */ + + if (work_limit_reached) + { + /* return -1 if the work limit of maxwork*nnz(A) was reached */ + *work = EMPTY ; + } + + return (nmatch) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/Source/btf_order.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/Source/btf_order.c new file mode 100644 index 0000000..b0bdb29 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/Source/btf_order.c @@ -0,0 +1,132 @@ +/* ========================================================================== */ +/* === BTF_ORDER ============================================================ */ +/* ========================================================================== */ + +/* Find a permutation P and Q to permute a square sparse matrix into upper block + * triangular form. A(P,Q) will contain a zero-free diagonal if A has + * structural full-rank. Otherwise, the number of nonzeros on the diagonal of + * A(P,Q) will be maximized, and will equal the structural rank of A. + * + * Q[k] will be "flipped" if a zero-free diagonal was not found. Q[k] will be + * negative, and j = BTF_UNFLIP (Q [k]) gives the corresponding permutation. + * + * R defines the block boundaries of A(P,Q). The kth block consists of rows + * and columns R[k] to R[k+1]-1. + * + * If maxwork > 0 on input, then the work performed in btf_maxtrans is limited + * to maxwork*nnz(A) (excluding the "cheap match" phase, which can take another + * nnz(A) work). On output, the work parameter gives the actual work performed, + * or -1 if the limit was reached. In the latter case, the diagonal of A(P,Q) + * might not be zero-free, and the number of nonzeros on the diagonal of A(P,Q) + * might not be equal to the structural rank. + * + * See btf.h for more details. + * + * By Tim Davis. Copyright (c) 2004-2007, University of Florida. + * with support from Sandia National Laboratories. All Rights Reserved. + */ + +#include "btf.h" +#include "btf_internal.h" + +/* This function only operates on square matrices (either structurally full- + * rank, or structurally rank deficient). */ + +Int BTF(order) /* returns number of blocks found */ +( + /* input, not modified: */ + Int n, /* A is n-by-n in compressed column form */ + Int Ap [ ], /* size n+1 */ + Int Ai [ ], /* size nz = Ap [n] */ + double maxwork, /* do at most maxwork*nnz(A) work in the maximum + * transversal; no limit if <= 0 */ + + /* output, not defined on input */ + double *work, /* work performed in maxtrans, or -1 if limit reached */ + Int P [ ], /* size n, row permutation */ + Int Q [ ], /* size n, column permutation */ + Int R [ ], /* size n+1. block b is in rows/cols R[b] ... R[b+1]-1 */ + Int *nmatch, /* # nonzeros on diagonal of P*A*Q */ + + /* workspace, not defined on input or output */ + Int Work [ ] /* size 5n */ +) +{ + Int *Flag ; + Int nblocks, i, j, nbadcol ; + + /* ---------------------------------------------------------------------- */ + /* compute the maximum matching */ + /* ---------------------------------------------------------------------- */ + + /* if maxwork > 0, then a maximum matching might not be found */ + + *nmatch = BTF(maxtrans) (n, n, Ap, Ai, maxwork, work, Q, Work) ; + + /* ---------------------------------------------------------------------- */ + /* complete permutation if the matrix is structurally singular */ + /* ---------------------------------------------------------------------- */ + + /* Since the matrix is square, ensure BTF_UNFLIP(Q[0..n-1]) is a + * permutation of the columns of A so that A has as many nonzeros on the + * diagonal as possible. + */ + + if (*nmatch < n) + { + /* get a size-n work array */ + Flag = Work + n ; + for (j = 0 ; j < n ; j++) + { + Flag [j] = 0 ; + } + + /* flag all matched columns */ + for (i = 0 ; i < n ; i++) + { + j = Q [i] ; + if (j != EMPTY) + { + /* row i and column j are matched to each other */ + Flag [j] = 1 ; + } + } + + /* make a list of all unmatched columns, in Work [0..nbadcol-1] */ + nbadcol = 0 ; + for (j = n-1 ; j >= 0 ; j--) + { + if (!Flag [j]) + { + /* j is matched to nobody */ + Work [nbadcol++] = j ; + } + } + ASSERT (*nmatch + nbadcol == n) ; + + /* make an assignment for each unmatched row */ + for (i = 0 ; i < n ; i++) + { + if (Q [i] == EMPTY && nbadcol > 0) + { + /* get an unmatched column j */ + j = Work [--nbadcol] ; + /* assign j to row i and flag the entry by "flipping" it */ + Q [i] = BTF_FLIP (j) ; + } + } + } + + /* The permutation of a square matrix can be recovered as follows: Row i is + * matched with column j, where j = BTF_UNFLIP (Q [i]) and where j + * will always be in the valid range 0 to n-1. The entry A(i,j) is zero + * if BTF_ISFLIPPED (Q [i]) is true, and nonzero otherwise. nmatch + * is the number of entries in the Q array that are non-negative. */ + + /* ---------------------------------------------------------------------- */ + /* find the strongly connected components */ + /* ---------------------------------------------------------------------- */ + + nblocks = BTF(strongcomp) (n, Ap, Ai, Q, P, R, Work) ; + return (nblocks) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/Source/btf_strongcomp.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/Source/btf_strongcomp.c new file mode 100644 index 0000000..36ec3e2 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/BTF/Source/btf_strongcomp.c @@ -0,0 +1,593 @@ +/* ========================================================================== */ +/* === BTF_STRONGCOMP ======================================================= */ +/* ========================================================================== */ + +/* Finds the strongly connected components of a graph, or equivalently, permutes + * the matrix into upper block triangular form. See btf.h for more details. + * Input matrix and Q are not checked on input. + * + * By Tim Davis. Copyright (c) 2004-2007, University of Florida. + * with support from Sandia National Laboratories. All Rights Reserved. + */ + +#include "btf.h" +#include "btf_internal.h" + +#define UNVISITED (-2) /* Flag [j] = UNVISITED if node j not visited yet */ +#define UNASSIGNED (-1) /* Flag [j] = UNASSIGNED if node j has been visited, + * but not yet assigned to a strongly-connected + * component (aka block). Flag [j] = k (k in the + * range 0 to nblocks-1) if node j has been visited + * (and completed, with its postwork done) and + * assigned to component k. */ + +/* This file contains two versions of the depth-first-search, a recursive one + * and a non-recursive one. By default, the non-recursive one is used. */ + +#ifndef RECURSIVE + +/* ========================================================================== */ +/* === dfs: non-recursive version (default) ================================= */ +/* ========================================================================== */ + +/* Perform a depth-first-search of a graph, stored in an adjacency-list form. + * The row indices of column j (equivalently, the out-adjacency list of node j) + * are stored in Ai [Ap[j] ... Ap[j+1]-1]. Self-edge (diagonal entries) are + * ignored. Ap[0] must be zero, and thus nz = Ap[n] is the number of entries + * in the matrix (or edges in the graph). The row indices in each column need + * not be in any particular order. If an input column permutation is given, + * node j (in the permuted matrix A*Q) is located in + * Ai [Ap[Q[j]] ... Ap[Q[j]+1]-1]. This Q can be the same as the Match array + * output from the maxtrans routine, for a square matrix that is structurally + * full rank. + * + * The algorithm is from the paper by Robert E. Tarjan, "Depth-first search and + * linear graph algorithms," SIAM Journal on Computing, vol. 1, no. 2, + * pp. 146-160, 1972. The time taken by strongcomp is O(nnz(A)). + * + * See also MC13A/B in the Harwell subroutine library (Iain S. Duff and John + * K. Reid, "Algorithm 529: permutations to block triangular form," ACM Trans. + * on Mathematical Software, vol. 4, no. 2, pp. 189-192, 1978, and "An + * implementation of Tarjan's algorithm for the block triangular form of a + * matrix," same journal, pp. 137-147. This code is implements the same + * algorithm as MC13A/B, except that the data structures are very different. + * Also, unlike MC13A/B, the output permutation preserves the natural ordering + * within each block. + */ + +static void dfs +( + /* inputs, not modified on output: */ + Int j, /* start the DFS at node j */ + Int Ap [ ], /* size n+1, column pointers for the matrix A */ + Int Ai [ ], /* row indices, size nz = Ap [n] */ + Int Q [ ], /* input column permutation */ + + /* inputs, modified on output (each array is of size n): */ + Int Time [ ], /* Time [j] = "time" that node j was first visited */ + Int Flag [ ], /* Flag [j]: see above */ + Int Low [ ], /* Low [j]: see definition below */ + Int *p_nblocks, /* number of blocks (aka strongly-connected-comp.)*/ + Int *p_timestamp, /* current "time" */ + + /* workspace, not defined on input or output: */ + Int Cstack [ ], /* size n, output stack to hold nodes of components */ + Int Jstack [ ], /* size n, stack for the variable j */ + Int Pstack [ ] /* size n, stack for the variable p */ +) +{ + /* ---------------------------------------------------------------------- */ + /* local variables, and initializations */ + /* ---------------------------------------------------------------------- */ + + /* local variables, but "global" to all DFS levels: */ + Int chead ; /* top of Cstack */ + Int jhead ; /* top of Jstack and Pstack */ + + /* variables that are purely local to any one DFS level: */ + Int i ; /* edge (j,i) considered; i can be next node to traverse */ + Int parent ; /* parent of node j in the DFS tree */ + Int pend ; /* one past the end of the adjacency list for node j */ + Int jj ; /* column j of A*Q is column jj of the input matrix A */ + + /* variables that need to be pushed then popped from the stack: */ + Int p ; /* current index into the adj. list for node j */ + /* the variables j and p are stacked in Jstack and Pstack */ + + /* local copies of variables in the calling routine */ + Int nblocks = *p_nblocks ; + Int timestamp = *p_timestamp ; + + /* ---------------------------------------------------------------------- */ + /* start a DFS at node j (same as the recursive call dfs (EMPTY, j)) */ + /* ---------------------------------------------------------------------- */ + + chead = 0 ; /* component stack is empty */ + jhead = 0 ; /* Jstack and Pstack are empty */ + Jstack [0] = j ; /* put the first node j on the Jstack */ + ASSERT (Flag [j] == UNVISITED) ; + + while (jhead >= 0) + { + j = Jstack [jhead] ; /* grab the node j from the top of Jstack */ + + /* determine which column jj of the A is column j of A*Q */ + jj = (Q == (Int *) NULL) ? (j) : (BTF_UNFLIP (Q [j])) ; + pend = Ap [jj+1] ; /* j's row index list ends at Ai [pend-1] */ + + if (Flag [j] == UNVISITED) + { + + /* -------------------------------------------------------------- */ + /* prework at node j */ + /* -------------------------------------------------------------- */ + + /* node j is being visited for the first time */ + Cstack [++chead] = j ; /* push j onto the stack */ + timestamp++ ; /* get a timestamp */ + Time [j] = timestamp ; /* give the timestamp to node j */ + Low [j] = timestamp ; + Flag [j] = UNASSIGNED ; /* flag node j as visited */ + + /* -------------------------------------------------------------- */ + /* set Pstack [jhead] to the first entry in column j to scan */ + /* -------------------------------------------------------------- */ + + Pstack [jhead] = Ap [jj] ; + } + + /* ------------------------------------------------------------------ */ + /* DFS rooted at node j (start it, or continue where left off) */ + /* ------------------------------------------------------------------ */ + + for (p = Pstack [jhead] ; p < pend ; p++) + { + i = Ai [p] ; /* examine the edge from node j to node i */ + if (Flag [i] == UNVISITED) + { + /* Node i has not been visited - start a DFS at node i. + * Keep track of where we left off in the scan of adjacency list + * of node j so we can restart j where we left off. */ + Pstack [jhead] = p + 1 ; + /* Push i onto the stack and immediately break + * so we can recurse on node i. */ + Jstack [++jhead] = i ; + ASSERT (Time [i] == EMPTY) ; + ASSERT (Low [i] == EMPTY) ; + /* break here to do what the recursive call dfs (j,i) does */ + break ; + } + else if (Flag [i] == UNASSIGNED) + { + /* Node i has been visited, but still unassigned to a block + * this is a back or cross edge if Time [i] < Time [j]. + * Note that i might equal j, in which case this code does + * nothing. */ + ASSERT (Time [i] > 0) ; + ASSERT (Low [i] > 0) ; + Low [j] = MIN (Low [j], Time [i]) ; + } + } + + if (p == pend) + { + /* If all adjacent nodes of j are already visited, pop j from + * Jstack and do the post work for node j. This also pops p + * from the Pstack. */ + jhead-- ; + + /* -------------------------------------------------------------- */ + /* postwork at node j */ + /* -------------------------------------------------------------- */ + + /* determine if node j is the head of a component */ + if (Low [j] == Time [j]) + { + /* pop all nodes in this SCC from Cstack */ + while (TRUE) + { + ASSERT (chead >= 0) ; /* stack not empty (j in it) */ + i = Cstack [chead--] ; /* pop a node from the Cstack */ + ASSERT (i >= 0) ; + ASSERT (Flag [i] == UNASSIGNED) ; + Flag [i] = nblocks ; /* assign i to current block */ + if (i == j) break ; /* current block ends at j */ + } + nblocks++ ; /* one more block has been found */ + } + /* update Low [parent], if the parent exists */ + if (jhead >= 0) + { + parent = Jstack [jhead] ; + Low [parent] = MIN (Low [parent], Low [j]) ; + } + } + } + + /* ---------------------------------------------------------------------- */ + /* cleanup: update timestamp and nblocks */ + /* ---------------------------------------------------------------------- */ + + *p_timestamp = timestamp ; + *p_nblocks = nblocks ; +} + +#else + +/* ========================================================================== */ +/* === dfs: recursive version (only for illustration) ======================= */ +/* ========================================================================== */ + +/* The following is a recursive version of dfs, which computes identical results + * as the non-recursive dfs. It is included here because it is easier to read. + * Compare the comments in the code below with the identical comments in the + * non-recursive code above, and that will help you see the correlation between + * the two routines. + * + * This routine can cause stack overflow, and is thus not recommended for heavy + * usage, particularly for large matrices. To help in delaying stack overflow, + * global variables are used, reducing the amount of information each call to + * dfs places on the call/return stack (the integers i, j, p, parent, and the + * return address). Note that this means the recursive code is not thread-safe. + * To try this version, compile the code with -DRECURSIVE or include the + * following line at the top of this file: + +#define RECURSIVE + + */ + +static Int /* for recursive illustration only, not for production use */ + chead, timestamp, nblocks, n, *Ap, *Ai, *Flag, *Cstack, *Time, *Low, + *P, *R, *Q ; + +static void dfs +( + Int parent, /* came from parent node */ + Int j /* at node j in the DFS */ +) +{ + Int p ; /* current index into the adj. list for node j */ + Int i ; /* edge (j,i) considered; i can be next node to traverse */ + Int jj ; /* column j of A*Q is column jj of the input matrix A */ + + /* ---------------------------------------------------------------------- */ + /* prework at node j */ + /* ---------------------------------------------------------------------- */ + + /* node j is being visited for the first time */ + Cstack [++chead] = j ; /* push j onto the stack */ + timestamp++ ; /* get a timestamp */ + Time [j] = timestamp ; /* give the timestamp to node j */ + Low [j] = timestamp ; + Flag [j] = UNASSIGNED ; /* flag node j as visited */ + + /* ---------------------------------------------------------------------- */ + /* DFS rooted at node j */ + /* ---------------------------------------------------------------------- */ + + /* determine which column jj of the A is column j of A*Q */ + jj = (Q == (Int *) NULL) ? (j) : (BTF_UNFLIP (Q [j])) ; + for (p = Ap [jj] ; p < Ap [jj+1] ; p++) + { + i = Ai [p] ; /* examine the edge from node j to node i */ + if (Flag [i] == UNVISITED) + { + /* Node i has not been visited - start a DFS at node i. */ + dfs (j, i) ; + } + else if (Flag [i] == UNASSIGNED) + { + /* Node i has been visited, but still unassigned to a block + * this is a back or cross edge if Time [i] < Time [j]. + * Note that i might equal j, in which case this code does + * nothing. */ + Low [j] = MIN (Low [j], Time [i]) ; + } + } + + /* ---------------------------------------------------------------------- */ + /* postwork at node j */ + /* ---------------------------------------------------------------------- */ + + /* determine if node j is the head of a component */ + if (Low [j] == Time [j]) + { + /* pop all nodes in this strongly connected component from Cstack */ + while (TRUE) + { + i = Cstack [chead--] ; /* pop a node from the Cstack */ + Flag [i] = nblocks ; /* assign node i to current block */ + if (i == j) break ; /* current block ends at node j */ + } + nblocks++ ; /* one more block has been found */ + } + /* update Low [parent] */ + if (parent != EMPTY) + { + /* Note that this could be done with Low[j] = MIN(Low[j],Low[i]) just + * after the dfs (j,i) statement above, and then parent would not have + * to be an input argument. Putting it here places all the postwork + * for node j in one place, thus making the non-recursive DFS easier. */ + Low [parent] = MIN (Low [parent], Low [j]) ; + } +} + +#endif + +/* ========================================================================== */ +/* === btf_strongcomp ======================================================= */ +/* ========================================================================== */ + +#ifndef RECURSIVE + +Int BTF(strongcomp) /* return # of strongly connected components */ +( + /* input, not modified: */ + Int n, /* A is n-by-n in compressed column form */ + Int Ap [ ], /* size n+1 */ + Int Ai [ ], /* size nz = Ap [n] */ + + /* optional input, modified (if present) on output: */ + Int Q [ ], /* size n, input column permutation. The permutation Q can + * include a flag which indicates an unmatched row. + * jold = BTF_UNFLIP (Q [jnew]) is the permutation; + * this function ingnores these flags. On output, it is + * modified according to the permutation P. */ + + /* output, not defined on input: */ + Int P [ ], /* size n. P [k] = j if row and column j are kth row/col + * in permuted matrix. */ + Int R [ ], /* size n+1. kth block is in rows/cols R[k] ... R[k+1]-1 + * of the permuted matrix. */ + + /* workspace, not defined on input or output: */ + Int Work [ ] /* size 4n */ +) + +#else + +Int BTF(strongcomp) /* recursive version - same as above except for Work size */ +( + Int n_in, + Int Ap_in [ ], + Int Ai_in [ ], + Int Q_in [ ], + Int P_in [ ], + Int R_in [ ], + Int Work [ ] /* size 2n */ +) + +#endif + +{ + Int j, k, b ; + +#ifndef RECURSIVE + Int timestamp, nblocks, *Flag, *Cstack, *Time, *Low, *Jstack, *Pstack ; +#else + n = n_in ; + Ap = Ap_in ; + Ai = Ai_in ; + Q = Q_in ; + P = P_in ; + R = R_in ; + chead = EMPTY ; +#endif + + /* ---------------------------------------------------------------------- */ + /* get and initialize workspace */ + /* ---------------------------------------------------------------------- */ + + /* timestamp is incremented each time a new node is visited. + * + * Time [j] is the timestamp given to node j. + * + * Low [j] is the lowest timestamp of any node reachable from j via either + * a path to any descendent of j in the DFS tree, or via a single edge to + * an either an ancestor (a back edge) or another node that's neither an + * ancestor nor a descendant (a cross edge). If Low [j] is equal to + * the timestamp of node j (Time [j]), then node j is the "head" of a + * strongly connected component (SCC). That is, it is the first node + * visited in its strongly connected component, and the DFS subtree rooted + * at node j spans all the nodes of the strongly connected component. + * + * The term "block" and "component" are used interchangebly in this code; + * "block" being a matrix term and "component" being a graph term for the + * same thing. + * + * When a node is visited, it is placed on the Cstack (for "component" + * stack). When node j is found to be an SCC head, all the nodes from the + * top of the stack to node j itself form the nodes in the SCC. This Cstack + * is used for both the recursive and non-recursive versions. + */ + + Time = Work ; Work += n ; + Flag = Work ; Work += n ; + Low = P ; /* use output array P as workspace for Low */ + Cstack = R ; /* use output array R as workspace for Cstack */ + +#ifndef RECURSIVE + /* stack for non-recursive dfs */ + Jstack = Work ; Work += n ; /* stack for j */ + Pstack = Work ; /* stack for p */ +#endif + + for (j = 0 ; j < n ; j++) + { + Flag [j] = UNVISITED ; + Low [j] = EMPTY ; + Time [j] = EMPTY ; +#ifndef NDEBUG + Cstack [j] = EMPTY ; +#ifndef RECURSIVE + Jstack [j] = EMPTY ; + Pstack [j] = EMPTY ; +#endif +#endif + } + + timestamp = 0 ; /* each node given a timestamp when it is visited */ + nblocks = 0 ; /* number of blocks found so far */ + + /* ---------------------------------------------------------------------- */ + /* find the connected components via a depth-first-search */ + /* ---------------------------------------------------------------------- */ + + for (j = 0 ; j < n ; j++) + { + /* node j is unvisited or assigned to a block. Cstack is empty. */ + ASSERT (Flag [j] == UNVISITED || (Flag [j] >= 0 && Flag [j] < nblocks)); + if (Flag [j] == UNVISITED) + { +#ifndef RECURSIVE + /* non-recursive dfs (default) */ + dfs (j, Ap, Ai, Q, Time, Flag, Low, &nblocks, ×tamp, + Cstack, Jstack, Pstack) ; +#else + /* recursive dfs (for illustration only) */ + ASSERT (chead == EMPTY) ; + dfs (EMPTY, j) ; + ASSERT (chead == EMPTY) ; +#endif + } + } + ASSERT (timestamp == n) ; + + /* ---------------------------------------------------------------------- */ + /* construct the block boundary array, R */ + /* ---------------------------------------------------------------------- */ + + for (b = 0 ; b < nblocks ; b++) + { + R [b] = 0 ; + } + for (j = 0 ; j < n ; j++) + { + /* node j has been assigned to block b = Flag [j] */ + ASSERT (Time [j] > 0 && Time [j] <= n) ; + ASSERT (Low [j] > 0 && Low [j] <= n) ; + ASSERT (Flag [j] >= 0 && Flag [j] < nblocks) ; + R [Flag [j]]++ ; + } + /* R [b] is now the number of nodes in block b. Compute cumulative sum + * of R, using Time [0 ... nblocks-1] as workspace. */ + Time [0] = 0 ; + for (b = 1 ; b < nblocks ; b++) + { + Time [b] = Time [b-1] + R [b-1] ; + } + for (b = 0 ; b < nblocks ; b++) + { + R [b] = Time [b] ; + } + R [nblocks] = n ; + + /* ---------------------------------------------------------------------- */ + /* construct the permutation, preserving the natural order */ + /* ---------------------------------------------------------------------- */ + +#ifndef NDEBUG + for (k = 0 ; k < n ; k++) + { + P [k] = EMPTY ; + } +#endif + + for (j = 0 ; j < n ; j++) + { + /* place column j in the permutation */ + P [Time [Flag [j]]++] = j ; + } + +#ifndef NDEBUG + for (k = 0 ; k < n ; k++) + { + ASSERT (P [k] != EMPTY) ; + } +#endif + + /* Now block b consists of the nodes k1 to k2-1 in the permuted matrix, + * where k1 = R [b] and k2 = R [b+1]. Row and column j of the original + * matrix becomes row and column P [k] of the permuted matrix. The set of + * of rows/columns (nodes) in block b is given by P [k1 ... k2-1], and this + * set is sorted in ascending order. Thus, if the matrix consists of just + * one block, P is the identity permutation. */ + + /* ---------------------------------------------------------------------- */ + /* if Q is present on input, set Q = Q*P' */ + /* ---------------------------------------------------------------------- */ + + if (Q != (Int *) NULL) + { + /* We found a symmetric permutation P for the matrix A*Q. The overall + * permutation is thus P*(A*Q)*P'. Set Q=Q*P' so that the final + * permutation is P*A*Q. Use Time as workspace. Note that this + * preserves the negative values of Q if the matrix is structurally + * singular. */ + for (k = 0 ; k < n ; k++) + { + Time [k] = Q [P [k]] ; + } + for (k = 0 ; k < n ; k++) + { + Q [k] = Time [k] ; + } + } + + /* ---------------------------------------------------------------------- */ + /* how to traverse the permuted matrix */ + /* ---------------------------------------------------------------------- */ + + /* If Q is not present, the following code can be used to traverse the + * permuted matrix P*A*P' + * + * // compute the inverse of P + * for (knew = 0 ; knew < n ; knew++) + * { + * // row and column kold in the old matrix is row/column knew + * // in the permuted matrix P*A*P' + * kold = P [knew] ; + * Pinv [kold] = knew ; + * } + * for (b = 0 ; b < nblocks ; b++) + * { + * // traverse block b of the permuted matrix P*A*P' + * k1 = R [b] ; + * k2 = R [b+1] ; + * nk = k2 - k1 ; + * for (jnew = k1 ; jnew < k2 ; jnew++) + * { + * jold = P [jnew] ; + * for (p = Ap [jold] ; p < Ap [jold+1] ; p++) + * { + * iold = Ai [p] ; + * inew = Pinv [iold] ; + * // Entry in the old matrix is A (iold, jold), and its + * // position in the new matrix P*A*P' is (inew, jnew). + * // Let B be the bth diagonal block of the permuted + * // matrix. If inew >= k1, then this entry is in row/ + * // column (inew-k1, jnew-k1) of the nk-by-nk matrix B. + * // Otherwise, the entry is in the upper block triangular + * // part, not in any diagonal block. + * } + * } + * } + * + * If Q is present replace the above statement + * jold = P [jnew] ; + * with + * jold = Q [jnew] ; + * or + * jold = BTF_UNFLIP (Q [jnew]) ; + * + * then entry A (iold,jold) in the old (unpermuted) matrix is at (inew,jnew) + * in the permuted matrix P*A*Q. Everything else remains the same as the + * above (simply replace P*A*P' with P*A*Q in the above comments). + */ + + /* ---------------------------------------------------------------------- */ + /* return # of blocks / # of strongly connected components */ + /* ---------------------------------------------------------------------- */ + + return (nblocks) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Demo/camd_demo.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Demo/camd_demo.c new file mode 100644 index 0000000..0fd909a --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Demo/camd_demo.c @@ -0,0 +1,172 @@ +/* ========================================================================= */ +/* === CAMD demo main program ============================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* CAMD, Copyright (c) Timothy A. Davis, Yanqing Chen, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* A simple C main program that illustrates the use of the ANSI C interface + * to CAMD. + */ + +#include "camd.h" +#include <stdio.h> +#include <stdlib.h> + +int main (void) +{ + /* The symmetric can_24 Harwell/Boeing matrix, including upper and lower + * triangular parts, and the diagonal entries. Note that this matrix is + * 0-based, with row and column indices in the range 0 to n-1. */ + int n = 24, nz, + Ap [ ] = { 0, 9, 15, 21, 27, 33, 39, 48, 57, 61, 70, 76, 82, 88, 94, 100, + 106, 110, 119, 128, 137, 143, 152, 156, 160 }, + Ai [ ] = { + /* column 0: */ 0, 5, 6, 12, 13, 17, 18, 19, 21, + /* column 1: */ 1, 8, 9, 13, 14, 17, + /* column 2: */ 2, 6, 11, 20, 21, 22, + /* column 3: */ 3, 7, 10, 15, 18, 19, + /* column 4: */ 4, 7, 9, 14, 15, 16, + /* column 5: */ 0, 5, 6, 12, 13, 17, + /* column 6: */ 0, 2, 5, 6, 11, 12, 19, 21, 23, + /* column 7: */ 3, 4, 7, 9, 14, 15, 16, 17, 18, + /* column 8: */ 1, 8, 9, 14, + /* column 9: */ 1, 4, 7, 8, 9, 13, 14, 17, 18, + /* column 10: */ 3, 10, 18, 19, 20, 21, + /* column 11: */ 2, 6, 11, 12, 21, 23, + /* column 12: */ 0, 5, 6, 11, 12, 23, + /* column 13: */ 0, 1, 5, 9, 13, 17, + /* column 14: */ 1, 4, 7, 8, 9, 14, + /* column 15: */ 3, 4, 7, 15, 16, 18, + /* column 16: */ 4, 7, 15, 16, + /* column 17: */ 0, 1, 5, 7, 9, 13, 17, 18, 19, + /* column 18: */ 0, 3, 7, 9, 10, 15, 17, 18, 19, + /* column 19: */ 0, 3, 6, 10, 17, 18, 19, 20, 21, + /* column 20: */ 2, 10, 19, 20, 21, 22, + /* column 21: */ 0, 2, 6, 10, 11, 19, 20, 21, 22, + /* column 22: */ 2, 20, 21, 22, + /* column 23: */ 6, 11, 12, 23 } ; + + int P [24], Pinv [24], i, j, k, jnew, p, inew, result ; + double Control [CAMD_CONTROL], Info [CAMD_INFO] ; + char A [24][24] ; + int C [ ] = { 0, 0, 4, 0, 1, 0, 2, 2, 1, 1, 3, 4, 5, 5, 3, 4, + 5, 2, 5, 3, 4, 2, 1, 0 } ; + + printf ("CAMD version %d.%d, date: %s\n", CAMD_MAIN_VERSION, + CAMD_SUB_VERSION, CAMD_DATE) ; + printf ("CAMD demo, with the 24-by-24 Harwell/Boeing matrix, can_24:\n") ; + + /* get the default parameters, and print them */ + camd_defaults (Control) ; + camd_control (Control) ; + + /* print the input matrix */ + nz = Ap [n] ; + printf ("\nInput matrix: %d-by-%d, with %d entries.\n" + " Note that for a symmetric matrix such as this one, only the\n" + " strictly lower or upper triangular parts would need to be\n" + " passed to CAMD, since CAMD computes the ordering of A+A'. The\n" + " diagonal entries are also not needed, since CAMD ignores them.\n" + , n, n, nz) ; + for (j = 0 ; j < n ; j++) + { + printf ("\nColumn: %d, number of entries: %d, with row indices in" + " Ai [%d ... %d]:\n row indices:", + j, Ap [j+1] - Ap [j], Ap [j], Ap [j+1]-1) ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + i = Ai [p] ; + printf (" %d", i) ; + } + printf ("\n") ; + } + + /* print a character plot of the input matrix. This is only reasonable + * because the matrix is small. */ + printf ("\nPlot of input matrix pattern:\n") ; + for (j = 0 ; j < n ; j++) + { + for (i = 0 ; i < n ; i++) A [i][j] = '.' ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + i = Ai [p] ; + A [i][j] = 'X' ; + } + } + printf (" ") ; + for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ; + printf ("\n") ; + for (i = 0 ; i < n ; i++) + { + printf ("%2d: ", i) ; + for (j = 0 ; j < n ; j++) + { + printf (" %c", A [i][j]) ; + } + printf ("\n") ; + } + + /* order the matrix */ + result = camd_order (n, Ap, Ai, P, Control, Info, C) ; + printf ("return value from camd_order: %d (should be %d)\n", + result, CAMD_OK) ; + + /* print the statistics */ + camd_info (Info) ; + + if (result != CAMD_OK) + { + printf ("CAMD failed\n") ; + exit (1) ; + } + + /* print the permutation vector, P, and compute the inverse permutation */ + printf ("Permutation vector:\n") ; + for (k = 0 ; k < n ; k++) + { + /* row/column j is the kth row/column in the permuted matrix */ + j = P [k] ; + Pinv [j] = k ; + printf (" %2d", j) ; + } + printf ("\n\n") ; + + printf ("Inverse permutation vector:\n") ; + for (j = 0 ; j < n ; j++) + { + k = Pinv [j] ; + printf (" %2d", k) ; + } + printf ("\n\n") ; + + /* print a character plot of the permuted matrix. */ + printf ("\nPlot of permuted matrix pattern:\n") ; + for (jnew = 0 ; jnew < n ; jnew++) + { + j = P [jnew] ; + for (inew = 0 ; inew < n ; inew++) A [inew][jnew] = '.' ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + inew = Pinv [Ai [p]] ; + A [inew][jnew] = 'X' ; + } + } + printf (" ") ; + for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ; + printf ("\n") ; + for (i = 0 ; i < n ; i++) + { + printf ("%2d: ", i) ; + for (j = 0 ; j < n ; j++) + { + printf (" %c", A [i][j]) ; + } + printf ("\n") ; + } + + return (0) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Demo/camd_demo2.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Demo/camd_demo2.c new file mode 100644 index 0000000..8dd0b62 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Demo/camd_demo2.c @@ -0,0 +1,216 @@ +/* ========================================================================= */ +/* === CAMD demo main program (jumbled matrix version) ===================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* CAMD, Copyright (c) Timothy A. Davis, Yanqing Chen, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* A simple C main program that illustrates the use of the ANSI C interface + * to CAMD. + * + * Identical to camd_demo.c, except that it operates on an input matrix that has + * unsorted columns and duplicate entries. + */ + +#include "camd.h" +#include <stdio.h> +#include <stdlib.h> + +int main (void) +{ + /* The symmetric can_24 Harwell/Boeing matrix (jumbled, and not symmetric). + * Since CAMD operates on A+A', only A(i,j) or A(j,i) need to be specified, + * or both. The diagonal entries are optional (some are missing). + * There are many duplicate entries, which must be removed. */ + int n = 24, nz, + Ap [ ] = { 0, 9, 14, 20, 28, 33, 37, 44, 53, 58, 63, 63, 66, 69, 72, 75, + 78, 82, 86, 91, 97, 101, 112, 112, 116 }, + Ai [ ] = { + /* column 0: */ 0, 17, 18, 21, 5, 12, 5, 0, 13, + /* column 1: */ 14, 1, 8, 13, 17, + /* column 2: */ 2, 20, 11, 6, 11, 22, + /* column 3: */ 3, 3, 10, 7, 18, 18, 15, 19, + /* column 4: */ 7, 9, 15, 14, 16, + /* column 5: */ 5, 13, 6, 17, + /* column 6: */ 5, 0, 11, 6, 12, 6, 23, + /* column 7: */ 3, 4, 9, 7, 14, 16, 15, 17, 18, + /* column 8: */ 1, 9, 14, 14, 14, + /* column 9: */ 7, 13, 8, 1, 17, + /* column 10: */ + /* column 11: */ 2, 12, 23, + /* column 12: */ 5, 11, 12, + /* column 13: */ 0, 13, 17, + /* column 14: */ 1, 9, 14, + /* column 15: */ 3, 15, 16, + /* column 16: */ 16, 4, 4, 15, + /* column 17: */ 13, 17, 19, 17, + /* column 18: */ 15, 17, 19, 9, 10, + /* column 19: */ 17, 19, 20, 0, 6, 10, + /* column 20: */ 22, 10, 20, 21, + /* column 21: */ 6, 2, 10, 19, 20, 11, 21, 22, 22, 22, 22, + /* column 22: */ + /* column 23: */ 12, 11, 12, 23 } ; + + int P [24], Pinv [24], i, j, k, jnew, p, inew, result ; + double Control [CAMD_CONTROL], Info [CAMD_INFO] ; + char A [24][24] ; + int C [ ] = { 3, 0, 4, 0, 1, 1, 2, 2, 2, 2, 3, 4, 5, 5, 3, 4, 5, 2, + 8, 10, 4, 2, 2, 0 } ; + + printf ("CAMD demo, with a jumbled version of the 24-by-24\n") ; + printf ("Harwell/Boeing matrix, can_24:\n") ; + + /* get the default parameters, and print them */ + camd_defaults (Control) ; + camd_control (Control) ; + + /* print the input matrix */ + nz = Ap [n] ; + printf ("\nJumbled input matrix: %d-by-%d, with %d entries.\n" + " Note that for a symmetric matrix such as this one, only the\n" + " strictly lower or upper triangular parts would need to be\n" + " passed to CAMD, since CAMD computes the ordering of A+A'. The\n" + " diagonal entries are also not needed, since CAMD ignores them.\n" + " This version of the matrix has jumbled columns and duplicate\n" + " row indices.\n", n, n, nz) ; + for (j = 0 ; j < n ; j++) + { + printf ("\nColumn: %d, number of entries: %d, with row indices in" + " Ai [%d ... %d]:\n row indices:", + j, Ap [j+1] - Ap [j], Ap [j], Ap [j+1]-1) ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + i = Ai [p] ; + printf (" %d", i) ; + } + printf ("\n") ; + } + + /* print a character plot of the input matrix. This is only reasonable + * because the matrix is small. */ + printf ("\nPlot of (jumbled) input matrix pattern:\n") ; + for (j = 0 ; j < n ; j++) + { + for (i = 0 ; i < n ; i++) A [i][j] = '.' ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + i = Ai [p] ; + A [i][j] = 'X' ; + } + } + printf (" ") ; + for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ; + printf ("\n") ; + for (i = 0 ; i < n ; i++) + { + printf ("%2d: ", i) ; + for (j = 0 ; j < n ; j++) + { + printf (" %c", A [i][j]) ; + } + printf ("\n") ; + } + + /* print a character plot of the matrix A+A'. */ + printf ("\nPlot of symmetric matrix to be ordered by camd_order:\n") ; + for (j = 0 ; j < n ; j++) + { + for (i = 0 ; i < n ; i++) A [i][j] = '.' ; + } + for (j = 0 ; j < n ; j++) + { + A [j][j] = 'X' ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + i = Ai [p] ; + A [i][j] = 'X' ; + A [j][i] = 'X' ; + } + } + printf (" ") ; + for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ; + printf ("\n") ; + for (i = 0 ; i < n ; i++) + { + printf ("%2d: ", i) ; + for (j = 0 ; j < n ; j++) + { + printf (" %c", A [i][j]) ; + } + printf ("\n") ; + } + + /* order the matrix */ + result = camd_order (n, Ap, Ai, P, Control, Info, C) ; + printf ("return value from camd_order: %d (should be %d)\n", + result, CAMD_OK_BUT_JUMBLED) ; + + /* print the statistics */ + camd_info (Info) ; + + if (result != CAMD_OK_BUT_JUMBLED) + { + printf ("CAMD failed\n") ; + exit (1) ; + } + + /* print the permutation vector, P, and compute the inverse permutation */ + printf ("Permutation vector:\n") ; + for (k = 0 ; k < n ; k++) + { + /* row/column j is the kth row/column in the permuted matrix */ + j = P [k] ; + Pinv [j] = k ; + printf (" %2d", j) ; + } + printf ("\nPermuted constraints:\n") ; + for (k = 0 ; k < n ; k++) + { + /* row/column j is the kth row/column in the permuted matrix */ + printf (" %2d", C [P [k]]) ; + } + printf ("\n\n") ; + + printf ("Inverse permutation vector:\n") ; + for (j = 0 ; j < n ; j++) + { + k = Pinv [j] ; + printf (" %2d", k) ; + } + printf ("\n\n") ; + + /* print a character plot of the permuted matrix. */ + printf ("\nPlot of (symmetrized) permuted matrix pattern:\n") ; + for (j = 0 ; j < n ; j++) + { + for (i = 0 ; i < n ; i++) A [i][j] = '.' ; + } + for (jnew = 0 ; jnew < n ; jnew++) + { + j = P [jnew] ; + A [jnew][jnew] = 'X' ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + inew = Pinv [Ai [p]] ; + A [inew][jnew] = 'X' ; + A [jnew][inew] = 'X' ; + } + } + printf (" ") ; + for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ; + printf ("\n") ; + for (i = 0 ; i < n ; i++) + { + printf ("%2d: ", i) ; + for (j = 0 ; j < n ; j++) + { + printf (" %c", A [i][j]) ; + } + printf ("\n") ; + } + + return (0) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Demo/camd_l_demo.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Demo/camd_l_demo.c new file mode 100644 index 0000000..1c127d0 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Demo/camd_l_demo.c @@ -0,0 +1,173 @@ +/* ========================================================================= */ +/* === CAMD demo main program (long integer version) ======================= */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* CAMD, Copyright (c) Timothy A. Davis, Yanqing Chen, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* A simple C main program that illustrates the use of the ANSI C interface + * to CAMD. + */ + +#include "camd.h" +#include <stdio.h> +#include <stdlib.h> +#define Long SuiteSparse_long + +int main (void) +{ + /* The symmetric can_24 Harwell/Boeing matrix, including upper and lower + * triangular parts, and the diagonal entries. Note that this matrix is + * 0-based, with row and column indices in the range 0 to n-1. */ + Long n = 24, nz, + Ap [ ] = { 0, 9, 15, 21, 27, 33, 39, 48, 57, 61, 70, 76, 82, 88, 94, 100, + 106, 110, 119, 128, 137, 143, 152, 156, 160 }, + Ai [ ] = { + /* column 0: */ 0, 5, 6, 12, 13, 17, 18, 19, 21, + /* column 1: */ 1, 8, 9, 13, 14, 17, + /* column 2: */ 2, 6, 11, 20, 21, 22, + /* column 3: */ 3, 7, 10, 15, 18, 19, + /* column 4: */ 4, 7, 9, 14, 15, 16, + /* column 5: */ 0, 5, 6, 12, 13, 17, + /* column 6: */ 0, 2, 5, 6, 11, 12, 19, 21, 23, + /* column 7: */ 3, 4, 7, 9, 14, 15, 16, 17, 18, + /* column 8: */ 1, 8, 9, 14, + /* column 9: */ 1, 4, 7, 8, 9, 13, 14, 17, 18, + /* column 10: */ 3, 10, 18, 19, 20, 21, + /* column 11: */ 2, 6, 11, 12, 21, 23, + /* column 12: */ 0, 5, 6, 11, 12, 23, + /* column 13: */ 0, 1, 5, 9, 13, 17, + /* column 14: */ 1, 4, 7, 8, 9, 14, + /* column 15: */ 3, 4, 7, 15, 16, 18, + /* column 16: */ 4, 7, 15, 16, + /* column 17: */ 0, 1, 5, 7, 9, 13, 17, 18, 19, + /* column 18: */ 0, 3, 7, 9, 10, 15, 17, 18, 19, + /* column 19: */ 0, 3, 6, 10, 17, 18, 19, 20, 21, + /* column 20: */ 2, 10, 19, 20, 21, 22, + /* column 21: */ 0, 2, 6, 10, 11, 19, 20, 21, 22, + /* column 22: */ 2, 20, 21, 22, + /* column 23: */ 6, 11, 12, 23 } ; + + Long P [24], Pinv [24], i, j, k, jnew, p, inew, result ; + double Control [CAMD_CONTROL], Info [CAMD_INFO] ; + char A [24][24] ; + Long C [ ] = { 0, 0, 4, 0, 1, 0, 2, 2, 1, 1, 3, 4, 5, 5, 3, 4, + 5, 2, 5, 3, 4, 2, 1, 0 }; + + printf ("CAMD version %d.%d, date: %s\n", CAMD_MAIN_VERSION, + CAMD_SUB_VERSION, CAMD_DATE) ; + printf ("CAMD demo, with the 24-by-24 Harwell/Boeing matrix, can_24:\n") ; + + /* get the default parameters, and print them */ + camd_l_defaults (Control) ; + camd_l_control (Control) ; + + /* print the input matrix */ + nz = Ap [n] ; + printf ("\nInput matrix: %ld-by-%ld, with %ld entries.\n" + " Note that for a symmetric matrix such as this one, only the\n" + " strictly lower or upper triangular parts would need to be\n" + " passed to CAMD, since CAMD computes the ordering of A+A'. The\n" + " diagonal entries are also not needed, since CAMD ignores them.\n" + , n, n, nz) ; + for (j = 0 ; j < n ; j++) + { + printf ("\nColumn: %ld, number of entries: %ld, with row indices in" + " Ai [%ld ... %ld]:\n row indices:", + j, Ap [j+1] - Ap [j], Ap [j], Ap [j+1]-1) ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + i = Ai [p] ; + printf (" %ld", i) ; + } + printf ("\n") ; + } + + /* print a character plot of the input matrix. This is only reasonable + * because the matrix is small. */ + printf ("\nPlot of input matrix pattern:\n") ; + for (j = 0 ; j < n ; j++) + { + for (i = 0 ; i < n ; i++) A [i][j] = '.' ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + i = Ai [p] ; + A [i][j] = 'X' ; + } + } + printf (" ") ; + for (j = 0 ; j < n ; j++) printf (" %1ld", j % 10) ; + printf ("\n") ; + for (i = 0 ; i < n ; i++) + { + printf ("%2ld: ", i) ; + for (j = 0 ; j < n ; j++) + { + printf (" %c", A [i][j]) ; + } + printf ("\n") ; + } + + /* order the matrix */ + result = camd_l_order (n, Ap, Ai, P, Control, Info, C) ; + printf ("return value from camd_l_order: %ld (should be %d)\n", + result, CAMD_OK) ; + + /* print the statistics */ + camd_l_info (Info) ; + + if (result != CAMD_OK) + { + printf ("CAMD failed\n") ; + exit (1) ; + } + + /* print the permutation vector, P, and compute the inverse permutation */ + printf ("Permutation vector:\n") ; + for (k = 0 ; k < n ; k++) + { + /* row/column j is the kth row/column in the permuted matrix */ + j = P [k] ; + Pinv [j] = k ; + printf (" %2ld", j) ; + } + printf ("\n\n") ; + + printf ("Inverse permutation vector:\n") ; + for (j = 0 ; j < n ; j++) + { + k = Pinv [j] ; + printf (" %2ld", k) ; + } + printf ("\n\n") ; + + /* print a character plot of the permuted matrix. */ + printf ("\nPlot of permuted matrix pattern:\n") ; + for (jnew = 0 ; jnew < n ; jnew++) + { + j = P [jnew] ; + for (inew = 0 ; inew < n ; inew++) A [inew][jnew] = '.' ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + inew = Pinv [Ai [p]] ; + A [inew][jnew] = 'X' ; + } + } + printf (" ") ; + for (j = 0 ; j < n ; j++) printf (" %1ld", j % 10) ; + printf ("\n") ; + for (i = 0 ; i < n ; i++) + { + printf ("%2ld: ", i) ; + for (j = 0 ; j < n ; j++) + { + printf (" %c", A [i][j]) ; + } + printf ("\n") ; + } + + return (0) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Demo/camd_simple.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Demo/camd_simple.c new file mode 100644 index 0000000..87dbdd5 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Demo/camd_simple.c @@ -0,0 +1,23 @@ +/* ------------------------------------------------------------------------- */ +/* CAMD, Copyright (c) Timothy A. Davis, Yanqing Chen, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +#include <stdio.h> +#include "camd.h" + +int n = 5 ; +int Ap [ ] = { 0, 2, 6, 10, 12, 14} ; +int Ai [ ] = { 0,1, 0,1,2,4, 1,2,3,4, 2,3, 1,4 } ; +int C [ ] = { 2, 0, 0, 0, 1 } ; +int P [5] ; + +int main (void) +{ + int k ; + (void) camd_order (n, Ap, Ai, P, (double *) NULL, (double *) NULL, C) ; + for (k = 0 ; k < n ; k++) printf ("P [%d] = %d\n", k, P [k]) ; + return (0) ; +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Include/camd.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Include/camd.h new file mode 100644 index 0000000..21898e0 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Include/camd.h @@ -0,0 +1,407 @@ +/* ========================================================================= */ +/* === CAMD: approximate minimum degree ordering ========================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* CAMD Version 2.4, Copyright (c) 2013 by Timothy A. Davis, Yanqing Chen, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* CAMD finds a symmetric ordering P of a matrix A so that the Cholesky + * factorization of P*A*P' has fewer nonzeros and takes less work than the + * Cholesky factorization of A. If A is not symmetric, then it performs its + * ordering on the matrix A+A'. Two sets of user-callable routines are + * provided, one for int integers and the other for SuiteSparse_long integers. + * + * The method is based on the approximate minimum degree algorithm, discussed + * in Amestoy, Davis, and Duff, "An approximate degree ordering algorithm", + * SIAM Journal of Matrix Analysis and Applications, vol. 17, no. 4, pp. + * 886-905, 1996. + */ + +#ifndef CAMD_H +#define CAMD_H + +/* make it easy for C++ programs to include CAMD */ +#ifdef __cplusplus +extern "C" { +#endif + +/* get the definition of size_t: */ +#include <stddef.h> + +#include "SuiteSparse_config.h" + +int camd_order /* returns CAMD_OK, CAMD_OK_BUT_JUMBLED, + * CAMD_INVALID, or CAMD_OUT_OF_MEMORY */ +( + int n, /* A is n-by-n. n must be >= 0. */ + const int Ap [ ], /* column pointers for A, of size n+1 */ + const int Ai [ ], /* row indices of A, of size nz = Ap [n] */ + int P [ ], /* output permutation, of size n */ + double Control [ ], /* input Control settings, of size CAMD_CONTROL */ + double Info [ ], /* output Info statistics, of size CAMD_INFO */ + const int C [ ] /* Constraint set of A, of size n; can be NULL */ +) ; + +SuiteSparse_long camd_l_order /* see above for description of arguments */ +( + SuiteSparse_long n, + const SuiteSparse_long Ap [ ], + const SuiteSparse_long Ai [ ], + SuiteSparse_long P [ ], + double Control [ ], + double Info [ ], + const SuiteSparse_long C [ ] +) ; + +/* Input arguments (not modified): + * + * n: the matrix A is n-by-n. + * Ap: an int/SuiteSparse_long array of size n+1, containing column + * pointers of A. + * Ai: an int/SuiteSparse_long array of size nz, containing the row + * indices of A, where nz = Ap [n]. + * Control: a double array of size CAMD_CONTROL, containing control + * parameters. Defaults are used if Control is NULL. + * + * Output arguments (not defined on input): + * + * P: an int/SuiteSparse_long array of size n, containing the output + * permutation. If row i is the kth pivot row, then P [k] = i. In + * MATLAB notation, the reordered matrix is A (P,P). + * Info: a double array of size CAMD_INFO, containing statistical + * information. Ignored if Info is NULL. + * + * On input, the matrix A is stored in column-oriented form. The row indices + * of nonzero entries in column j are stored in Ai [Ap [j] ... Ap [j+1]-1]. + * + * If the row indices appear in ascending order in each column, and there + * are no duplicate entries, then camd_order is slightly more efficient in + * terms of time and memory usage. If this condition does not hold, a copy + * of the matrix is created (where these conditions do hold), and the copy is + * ordered. + * + * Row indices must be in the range 0 to + * n-1. Ap [0] must be zero, and thus nz = Ap [n] is the number of nonzeros + * in A. The array Ap is of size n+1, and the array Ai is of size nz = Ap [n]. + * The matrix does not need to be symmetric, and the diagonal does not need to + * be present (if diagonal entries are present, they are ignored except for + * the output statistic Info [CAMD_NZDIAG]). The arrays Ai and Ap are not + * modified. This form of the Ap and Ai arrays to represent the nonzero + * pattern of the matrix A is the same as that used internally by MATLAB. + * If you wish to use a more flexible input structure, please see the + * umfpack_*_triplet_to_col routines in the UMFPACK package, at + * http://www.suitesparse.com. + * + * Restrictions: n >= 0. Ap [0] = 0. Ap [j] <= Ap [j+1] for all j in the + * range 0 to n-1. nz = Ap [n] >= 0. Ai [0..nz-1] must be in the range 0 + * to n-1. Finally, Ai, Ap, and P must not be NULL. If any of these + * restrictions are not met, CAMD returns CAMD_INVALID. + * + * CAMD returns: + * + * CAMD_OK if the matrix is valid and sufficient memory can be allocated to + * perform the ordering. + * + * CAMD_OUT_OF_MEMORY if not enough memory can be allocated. + * + * CAMD_INVALID if the input arguments n, Ap, Ai are invalid, or if P is + * NULL. + * + * CAMD_OK_BUT_JUMBLED if the matrix had unsorted columns, and/or duplicate + * entries, but was otherwise valid. + * + * The CAMD routine first forms the pattern of the matrix A+A', and then + * computes a fill-reducing ordering, P. If P [k] = i, then row/column i of + * the original is the kth pivotal row. In MATLAB notation, the permuted + * matrix is A (P,P), except that 0-based indexing is used instead of the + * 1-based indexing in MATLAB. + * + * The Control array is used to set various parameters for CAMD. If a NULL + * pointer is passed, default values are used. The Control array is not + * modified. + * + * Control [CAMD_DENSE]: controls the threshold for "dense" rows/columns. + * A dense row/column in A+A' can cause CAMD to spend a lot of time in + * ordering the matrix. If Control [CAMD_DENSE] >= 0, rows/columns + * with more than Control [CAMD_DENSE] * sqrt (n) entries are ignored + * during the ordering, and placed last in the output order. The + * default value of Control [CAMD_DENSE] is 10. If negative, no + * rows/columns are treated as "dense". Rows/columns with 16 or + * fewer off-diagonal entries are never considered "dense". + * + * Control [CAMD_AGGRESSIVE]: controls whether or not to use aggressive + * absorption, in which a prior element is absorbed into the current + * element if is a subset of the current element, even if it is not + * adjacent to the current pivot element (refer to Amestoy, Davis, + * & Duff, 1996, for more details). The default value is nonzero, + * which means to perform aggressive absorption. This nearly always + * leads to a better ordering (because the approximate degrees are + * more accurate) and a lower execution time. There are cases where + * it can lead to a slightly worse ordering, however. To turn it off, + * set Control [CAMD_AGGRESSIVE] to 0. + * + * Control [2..4] are not used in the current version, but may be used in + * future versions. + * + * The Info array provides statistics about the ordering on output. If it is + * not present, the statistics are not returned. This is not an error + * condition. + * + * Info [CAMD_STATUS]: the return value of CAMD, either CAMD_OK, + * CAMD_OK_BUT_JUMBLED, CAMD_OUT_OF_MEMORY, or CAMD_INVALID. + * + * Info [CAMD_N]: n, the size of the input matrix + * + * Info [CAMD_NZ]: the number of nonzeros in A, nz = Ap [n] + * + * Info [CAMD_SYMMETRY]: the symmetry of the matrix A. It is the number + * of "matched" off-diagonal entries divided by the total number of + * off-diagonal entries. An entry A(i,j) is matched if A(j,i) is also + * an entry, for any pair (i,j) for which i != j. In MATLAB notation, + * S = spones (A) ; + * B = tril (S, -1) + triu (S, 1) ; + * symmetry = nnz (B & B') / nnz (B) ; + * + * Info [CAMD_NZDIAG]: the number of entries on the diagonal of A. + * + * Info [CAMD_NZ_A_PLUS_AT]: the number of nonzeros in A+A', excluding the + * diagonal. If A is perfectly symmetric (Info [CAMD_SYMMETRY] = 1) + * with a fully nonzero diagonal, then Info [CAMD_NZ_A_PLUS_AT] = nz-n + * (the smallest possible value). If A is perfectly unsymmetric + * (Info [CAMD_SYMMETRY] = 0, for an upper triangular matrix, for + * example) with no diagonal, then Info [CAMD_NZ_A_PLUS_AT] = 2*nz + * (the largest possible value). + * + * Info [CAMD_NDENSE]: the number of "dense" rows/columns of A+A' that were + * removed from A prior to ordering. These are placed last in the + * output order P. + * + * Info [CAMD_MEMORY]: the amount of memory used by CAMD, in bytes. In the + * current version, this is 1.2 * Info [CAMD_NZ_A_PLUS_AT] + 9*n + * times the size of an integer. This is at most 2.4nz + 9n. This + * excludes the size of the input arguments Ai, Ap, and P, which have + * a total size of nz + 2*n + 1 integers. + * + * Info [CAMD_NCMPA]: the number of garbage collections performed. + * + * Info [CAMD_LNZ]: the number of nonzeros in L (excluding the diagonal). + * This is a slight upper bound because mass elimination is combined + * with the approximate degree update. It is a rough upper bound if + * there are many "dense" rows/columns. The rest of the statistics, + * below, are also slight or rough upper bounds, for the same reasons. + * The post-ordering of the assembly tree might also not exactly + * correspond to a true elimination tree postordering. + * + * Info [CAMD_NDIV]: the number of divide operations for a subsequent LDL' + * or LU factorization of the permuted matrix A (P,P). + * + * Info [CAMD_NMULTSUBS_LDL]: the number of multiply-subtract pairs for a + * subsequent LDL' factorization of A (P,P). + * + * Info [CAMD_NMULTSUBS_LU]: the number of multiply-subtract pairs for a + * subsequent LU factorization of A (P,P), assuming that no numerical + * pivoting is required. + * + * Info [CAMD_DMAX]: the maximum number of nonzeros in any column of L, + * including the diagonal. + * + * Info [14..19] are not used in the current version, but may be used in + * future versions. + */ + +/* ------------------------------------------------------------------------- */ +/* direct interface to CAMD */ +/* ------------------------------------------------------------------------- */ + +/* camd_2 is the primary CAMD ordering routine. It is not meant to be + * user-callable because of its restrictive inputs and because it destroys + * the user's input matrix. It does not check its inputs for errors, either. + * However, if you can work with these restrictions it can be faster than + * camd_order and use less memory (assuming that you can create your own copy + * of the matrix for CAMD to destroy). Refer to CAMD/Source/camd_2.c for a + * description of each parameter. */ + +void camd_2 +( + int n, + int Pe [ ], + int Iw [ ], + int Len [ ], + int iwlen, + int pfree, + int Nv [ ], + int Next [ ], + int Last [ ], + int Head [ ], + int Elen [ ], + int Degree [ ], + int W [ ], + double Control [ ], + double Info [ ], + const int C [ ], + int BucketSet [ ] +) ; + +void camd_l2 +( + SuiteSparse_long n, + SuiteSparse_long Pe [ ], + SuiteSparse_long Iw [ ], + SuiteSparse_long Len [ ], + SuiteSparse_long iwlen, + SuiteSparse_long pfree, + SuiteSparse_long Nv [ ], + SuiteSparse_long Next [ ], + SuiteSparse_long Last [ ], + SuiteSparse_long Head [ ], + SuiteSparse_long Elen [ ], + SuiteSparse_long Degree [ ], + SuiteSparse_long W [ ], + double Control [ ], + double Info [ ], + const SuiteSparse_long C [ ], + SuiteSparse_long BucketSet [ ] + +) ; + +/* ------------------------------------------------------------------------- */ +/* camd_valid */ +/* ------------------------------------------------------------------------- */ + +/* Returns CAMD_OK or CAMD_OK_BUT_JUMBLED if the matrix is valid as input to + * camd_order; the latter is returned if the matrix has unsorted and/or + * duplicate row indices in one or more columns. Returns CAMD_INVALID if the + * matrix cannot be passed to camd_order. For camd_order, the matrix must also + * be square. The first two arguments are the number of rows and the number + * of columns of the matrix. For its use in CAMD, these must both equal n. + */ + +int camd_valid +( + int n_row, /* # of rows */ + int n_col, /* # of columns */ + const int Ap [ ], /* column pointers, of size n_col+1 */ + const int Ai [ ] /* row indices, of size Ap [n_col] */ +) ; + +SuiteSparse_long camd_l_valid +( + SuiteSparse_long n_row, + SuiteSparse_long n_col, + const SuiteSparse_long Ap [ ], + const SuiteSparse_long Ai [ ] +) ; + +/* ------------------------------------------------------------------------- */ +/* camd_cvalid */ +/* ------------------------------------------------------------------------- */ + +/* Returns TRUE if the constraint set is valid as input to camd_order, + * FALSE otherwise. */ + +int camd_cvalid +( + int n, + const int C [ ] +) ; + +SuiteSparse_long camd_l_cvalid +( + SuiteSparse_long n, + const SuiteSparse_long C [ ] +) ; + +/* ------------------------------------------------------------------------- */ +/* CAMD memory manager and printf routines */ +/* ------------------------------------------------------------------------- */ + + /* moved to SuiteSparse_config.c */ + +/* ------------------------------------------------------------------------- */ +/* CAMD Control and Info arrays */ +/* ------------------------------------------------------------------------- */ + +/* camd_defaults: sets the default control settings */ +void camd_defaults (double Control [ ]) ; +void camd_l_defaults (double Control [ ]) ; + +/* camd_control: prints the control settings */ +void camd_control (double Control [ ]) ; +void camd_l_control (double Control [ ]) ; + +/* camd_info: prints the statistics */ +void camd_info (double Info [ ]) ; +void camd_l_info (double Info [ ]) ; + +#define CAMD_CONTROL 5 /* size of Control array */ +#define CAMD_INFO 20 /* size of Info array */ + +/* contents of Control */ +#define CAMD_DENSE 0 /* "dense" if degree > Control [0] * sqrt (n) */ +#define CAMD_AGGRESSIVE 1 /* do aggressive absorption if Control [1] != 0 */ + +/* default Control settings */ +#define CAMD_DEFAULT_DENSE 10.0 /* default "dense" degree 10*sqrt(n) */ +#define CAMD_DEFAULT_AGGRESSIVE 1 /* do aggressive absorption by default */ + +/* contents of Info */ +#define CAMD_STATUS 0 /* return value of camd_order and camd_l_order */ +#define CAMD_N 1 /* A is n-by-n */ +#define CAMD_NZ 2 /* number of nonzeros in A */ +#define CAMD_SYMMETRY 3 /* symmetry of pattern (1 is sym., 0 is unsym.) */ +#define CAMD_NZDIAG 4 /* # of entries on diagonal */ +#define CAMD_NZ_A_PLUS_AT 5 /* nz in A+A' */ +#define CAMD_NDENSE 6 /* number of "dense" rows/columns in A */ +#define CAMD_MEMORY 7 /* amount of memory used by CAMD */ +#define CAMD_NCMPA 8 /* number of garbage collections in CAMD */ +#define CAMD_LNZ 9 /* approx. nz in L, excluding the diagonal */ +#define CAMD_NDIV 10 /* number of fl. point divides for LU and LDL' */ +#define CAMD_NMULTSUBS_LDL 11 /* number of fl. point (*,-) pairs for LDL' */ +#define CAMD_NMULTSUBS_LU 12 /* number of fl. point (*,-) pairs for LU */ +#define CAMD_DMAX 13 /* max nz. in any column of L, incl. diagonal */ + +/* ------------------------------------------------------------------------- */ +/* return values of CAMD */ +/* ------------------------------------------------------------------------- */ + +#define CAMD_OK 0 /* success */ +#define CAMD_OUT_OF_MEMORY -1 /* malloc failed, or problem too large */ +#define CAMD_INVALID -2 /* input arguments are not valid */ +#define CAMD_OK_BUT_JUMBLED 1 /* input matrix is OK for camd_order, but + * columns were not sorted, and/or duplicate entries were present. CAMD had + * to do extra work before ordering the matrix. This is a warning, not an + * error. */ + +/* ========================================================================== */ +/* === CAMD version ========================================================= */ +/* ========================================================================== */ + +/* + * As an example, to test if the version you are using is 1.2 or later: + * + * if (CAMD_VERSION >= CAMD_VERSION_CODE (1,2)) ... + * + * This also works during compile-time: + * + * #if (CAMD_VERSION >= CAMD_VERSION_CODE (1,2)) + * printf ("This is version 1.2 or later\n") ; + * #else + * printf ("This is an early version\n") ; + * #endif + */ + +#define CAMD_DATE "May 4, 2016" +#define CAMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) +#define CAMD_MAIN_VERSION 2 +#define CAMD_SUB_VERSION 4 +#define CAMD_SUBSUB_VERSION 6 +#define CAMD_VERSION CAMD_VERSION_CODE(CAMD_MAIN_VERSION,CAMD_SUB_VERSION) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Include/camd_internal.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Include/camd_internal.h new file mode 100644 index 0000000..92407c8 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Include/camd_internal.h @@ -0,0 +1,317 @@ +/* ========================================================================= */ +/* === camd_internal.h ===================================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* CAMD, Copyright (c) Timothy A. Davis, Yanqing Chen, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* This file is for internal use in CAMD itself, and does not normally need to + * be included in user code (it is included in UMFPACK, however). All others + * should use camd.h instead. + */ + +/* ========================================================================= */ +/* === NDEBUG ============================================================== */ +/* ========================================================================= */ + +/* + * Turning on debugging takes some work (see below). If you do not edit this + * file, then debugging is always turned off, regardless of whether or not + * -DNDEBUG is specified in your compiler options. + * + * If CAMD is being compiled as a mexFunction, then MATLAB_MEX_FILE is defined, + * and mxAssert is used instead of assert. If debugging is not enabled, no + * MATLAB include files or functions are used. Thus, the CAMD library libcamd.a + * can be safely used in either a stand-alone C program or in another + * mexFunction, without any change. + */ + +/* + CAMD will be exceedingly slow when running in debug mode. The next three + lines ensure that debugging is turned off. +*/ +#ifndef NDEBUG +#define NDEBUG +#endif + +/* + To enable debugging, uncomment the following line: +#undef NDEBUG +*/ + + +/* ------------------------------------------------------------------------- */ +/* ANSI include files */ +/* ------------------------------------------------------------------------- */ + +/* from stdlib.h: size_t, malloc, free, realloc, and calloc */ +#include <stdlib.h> + +#if !defined(NPRINT) || !defined(NDEBUG) +/* from stdio.h: printf. Not included if NPRINT is defined at compile time. + * fopen and fscanf are used when debugging. */ +#include <stdio.h> +#endif + +/* from limits.h: INT_MAX and LONG_MAX */ +#include <limits.h> + +/* from math.h: sqrt */ +#include <math.h> + +/* ------------------------------------------------------------------------- */ +/* MATLAB include files (only if being used in or via MATLAB) */ +/* ------------------------------------------------------------------------- */ + +#ifdef MATLAB_MEX_FILE +#include "matrix.h" +#include "mex.h" +#endif + +/* ------------------------------------------------------------------------- */ +/* basic definitions */ +/* ------------------------------------------------------------------------- */ + +#ifdef FLIP +#undef FLIP +#endif + +#ifdef MAX +#undef MAX +#endif + +#ifdef MIN +#undef MIN +#endif + +#ifdef EMPTY +#undef EMPTY +#endif + +#ifdef GLOBAL +#undef GLOBAL +#endif + +#ifdef PRIVATE +#undef PRIVATE +#endif + +/* FLIP is a "negation about -1", and is used to mark an integer i that is + * normally non-negative. FLIP (EMPTY) is EMPTY. FLIP of a number > EMPTY + * is negative, and FLIP of a number < EMTPY is positive. FLIP (FLIP (i)) = i + * for all integers i. UNFLIP (i) is >= EMPTY. */ +#define EMPTY (-1) +#define FLIP(i) (-(i)-2) +#define UNFLIP(i) ((i < EMPTY) ? FLIP (i) : (i)) + +/* for integer MAX/MIN, or for doubles when we don't care how NaN's behave: */ +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +/* logical expression of p implies q: */ +#define IMPLIES(p,q) (!(p) || (q)) + +/* Note that the IBM RS 6000 xlc predefines TRUE and FALSE in <types.h>. */ +/* The Compaq Alpha also predefines TRUE and FALSE. */ +#ifdef TRUE +#undef TRUE +#endif +#ifdef FALSE +#undef FALSE +#endif + +#define TRUE (1) +#define FALSE (0) +#define PRIVATE static +#define GLOBAL +#define EMPTY (-1) + +/* Note that Linux's gcc 2.96 defines NULL as ((void *) 0), but other */ +/* compilers (even gcc 2.95.2 on Solaris) define NULL as 0 or (0). We */ +/* need to use the ANSI standard value of 0. */ +#ifdef NULL +#undef NULL +#endif + +#define NULL 0 + +/* largest value of size_t */ +#ifndef SIZE_T_MAX +#ifdef SIZE_MAX +/* C99 only */ +#define SIZE_T_MAX SIZE_MAX +#else +#define SIZE_T_MAX ((size_t) (-1)) +#endif +#endif + +/* ------------------------------------------------------------------------- */ +/* integer type for CAMD: int or SuiteSparse_long */ +/* ------------------------------------------------------------------------- */ + +#include "camd.h" + +#if defined (DLONG) || defined (ZLONG) + +#define Int SuiteSparse_long +#define ID SuiteSparse_long_id +#define Int_MAX SuiteSparse_long_max + +#define CAMD_order camd_l_order +#define CAMD_defaults camd_l_defaults +#define CAMD_control camd_l_control +#define CAMD_info camd_l_info +#define CAMD_1 camd_l1 +#define CAMD_2 camd_l2 +#define CAMD_valid camd_l_valid +#define CAMD_cvalid camd_l_cvalid +#define CAMD_aat camd_l_aat +#define CAMD_postorder camd_l_postorder +#define CAMD_post_tree camd_l_post_tree +#define CAMD_dump camd_l_dump +#define CAMD_debug camd_l_debug +#define CAMD_debug_init camd_l_debug_init +#define CAMD_preprocess camd_l_preprocess + +#else + +#define Int int +#define ID "%d" +#define Int_MAX INT_MAX + +#define CAMD_order camd_order +#define CAMD_defaults camd_defaults +#define CAMD_control camd_control +#define CAMD_info camd_info +#define CAMD_1 camd_1 +#define CAMD_2 camd_2 +#define CAMD_valid camd_valid +#define CAMD_cvalid camd_cvalid +#define CAMD_aat camd_aat +#define CAMD_postorder camd_postorder +#define CAMD_post_tree camd_post_tree +#define CAMD_dump camd_dump +#define CAMD_debug camd_debug +#define CAMD_debug_init camd_debug_init +#define CAMD_preprocess camd_preprocess + +#endif + +/* ------------------------------------------------------------------------- */ +/* CAMD routine definitions (not user-callable) */ +/* ------------------------------------------------------------------------- */ + +GLOBAL size_t CAMD_aat +( + Int n, + const Int Ap [ ], + const Int Ai [ ], + Int Len [ ], + Int Tp [ ], + double Info [ ] +) ; + +GLOBAL void CAMD_1 +( + Int n, + const Int Ap [ ], + const Int Ai [ ], + Int P [ ], + Int Pinv [ ], + Int Len [ ], + Int slen, + Int S [ ], + double Control [ ], + double Info [ ], + const Int C [ ] +) ; + +GLOBAL Int CAMD_postorder +( + Int j, Int k, Int n, Int head [], Int next [], Int post [], Int stack [] +) ; + +GLOBAL void CAMD_preprocess +( + Int n, + const Int Ap [ ], + const Int Ai [ ], + Int Rp [ ], + Int Ri [ ], + Int W [ ], + Int Flag [ ] +) ; + +/* ------------------------------------------------------------------------- */ +/* debugging definitions */ +/* ------------------------------------------------------------------------- */ + +#ifndef NDEBUG + +/* from assert.h: assert macro */ +#include <assert.h> + +#ifndef EXTERN +#define EXTERN extern +#endif + +EXTERN Int CAMD_debug ; + +GLOBAL void CAMD_debug_init ( char *s ) ; + +GLOBAL void CAMD_dump +( + Int n, + Int Pe [ ], + Int Iw [ ], + Int Len [ ], + Int iwlen, + Int pfree, + Int Nv [ ], + Int Next [ ], + Int Last [ ], + Int Head [ ], + Int Elen [ ], + Int Degree [ ], + Int W [ ], + Int nel, + Int BucketSet [], + const Int C [], + Int Curc +) ; + +#ifdef ASSERT +#undef ASSERT +#endif + +/* Use mxAssert if CAMD is compiled into a mexFunction */ +#ifdef MATLAB_MEX_FILE +#define ASSERT(expression) (mxAssert ((expression), "")) +#else +#define ASSERT(expression) (assert (expression)) +#endif + +#define CAMD_DEBUG0(params) { SUITESPARSE_PRINTF (params) ; } +#define CAMD_DEBUG1(params) \ + { if (CAMD_debug >= 1) SUITESPARSE_PRINTF (params) ; } +#define CAMD_DEBUG2(params) \ + { if (CAMD_debug >= 2) SUITESPARSE_PRINTF (params) ; } +#define CAMD_DEBUG3(params) \ + { if (CAMD_debug >= 3) SUITESPARSE_PRINTF (params) ; } +#define CAMD_DEBUG4(params) \ + { if (CAMD_debug >= 4) SUITESPARSE_PRINTF (params) ; } + +#else + +/* no debugging */ +#define ASSERT(expression) +#define CAMD_DEBUG0(params) +#define CAMD_DEBUG1(params) +#define CAMD_DEBUG2(params) +#define CAMD_DEBUG3(params) +#define CAMD_DEBUG4(params) + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/MATLAB/camd_mex.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/MATLAB/camd_mex.c new file mode 100644 index 0000000..2be6120 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/MATLAB/camd_mex.c @@ -0,0 +1,213 @@ +/* ========================================================================= */ +/* === CAMD mexFunction ==================================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* CAMD, Copyright (c) Timothy A. Davis, Yanqing Chen, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* + * Usage: + * p = camd (A) + * p = camd (A, Control) + * [p, Info] = camd (A) + * [p, Info] = camd (A, Control, C) + * Control = camd ; % return the default Control settings for CAMD + * camd ; % print the default Control settings for CAMD + * + * Given a square matrix A, compute a permutation P suitable for a Cholesky + * factorization of the matrix B (P,P), where B = spones (A) + spones (A'). + * The method used is the approximate minimum degree ordering method. See + * camd.m and camd.h for more information. + * + * The input matrix need not have sorted columns, and can have duplicate + * entries. + */ + +#include "camd.h" +#include "mex.h" +#include "matrix.h" +#define Long SuiteSparse_long + +void mexFunction +( + int nargout, + mxArray *pargout [ ], + int nargin, + const mxArray *pargin [ ] +) +{ + Long i, m, n, *Ap, *Ai, *P, nc, result, spumoni, full, *C, Clen ; + double *Pout, *InfoOut, Control [CAMD_CONTROL], Info [CAMD_INFO], + *ControlIn, *Cin ; + mxArray *A ; + + /* --------------------------------------------------------------------- */ + /* get control parameters */ + /* --------------------------------------------------------------------- */ + + spumoni = 0 ; + if (nargin == 0) + { + /* get the default control parameters, and return */ + pargout [0] = mxCreateDoubleMatrix (CAMD_CONTROL, 1, mxREAL) ; + camd_l_defaults (mxGetPr (pargout [0])) ; + if (nargout == 0) + { + camd_l_control (mxGetPr (pargout [0])) ; + } + return ; + } + + camd_l_defaults (Control) ; + if (nargin > 1) + { + ControlIn = mxGetPr (pargin [1]) ; + nc = mxGetM (pargin [1]) * mxGetN (pargin [1]) ; + Control [CAMD_DENSE] + = (nc > 0) ? ControlIn [CAMD_DENSE] : CAMD_DEFAULT_DENSE ; + Control [CAMD_AGGRESSIVE] + = (nc > 1) ? ControlIn [CAMD_AGGRESSIVE] : CAMD_DEFAULT_AGGRESSIVE ; + spumoni = (nc > 2) ? (ControlIn [2] != 0) : 0 ; + } + + if (spumoni > 0) + { + camd_l_control (Control) ; + } + + /* --------------------------------------------------------------------- */ + /* get inputs */ + /* --------------------------------------------------------------------- */ + + if (nargout > 2 || nargin > 3) + { + mexErrMsgTxt ("Usage: p = camd (A)\n" + "or [p, Info] = camd (A, Control, C)") ; + } + + Clen = 0 ; + C = NULL ; + if (nargin > 2) + { + Cin = mxGetPr (pargin [2]) ; + Clen = mxGetNumberOfElements (pargin [2]) ; + if (Clen != 0) + { + C = (Long *) mxCalloc (Clen, sizeof (Long)) ; + for (i = 0 ; i < Clen ; i++) + { + /* convert c from 1-based to 0-based */ + C [i] = (Long) Cin [i] - 1 ; + } + } + } + + A = (mxArray *) pargin [0] ; + n = mxGetN (A) ; + m = mxGetM (A) ; + if (spumoni > 0) + { + mexPrintf (" input matrix A is %d-by-%d\n", m, n) ; + } + + if (mxGetNumberOfDimensions (A) != 2) + { + mexErrMsgTxt ("camd: A must be 2-dimensional") ; + } + if (m != n) + { + mexErrMsgTxt ("camd: A must be square") ; + } + + /* --------------------------------------------------------------------- */ + /* allocate workspace for output permutation */ + /* --------------------------------------------------------------------- */ + + P = mxMalloc ((n+1) * sizeof (Long)) ; + + /* --------------------------------------------------------------------- */ + /* if A is full, convert to a sparse matrix */ + /* --------------------------------------------------------------------- */ + + full = !mxIsSparse (A) ; + if (full) + { + if (spumoni > 0) + { + mexPrintf ( + " input matrix A is full (sparse copy of A will be created)\n"); + } + mexCallMATLAB (1, &A, 1, (mxArray **) pargin, "sparse") ; + } + Ap = (Long *) mxGetJc (A) ; + Ai = (Long *) mxGetIr (A) ; + if (spumoni > 0) + { + mexPrintf (" input matrix A has %d nonzero entries\n", Ap [n]) ; + } + + /* --------------------------------------------------------------------- */ + /* order the matrix */ + /* --------------------------------------------------------------------- */ + + result = camd_l_order (n, Ap, Ai, P, Control, Info, C) ; + + /* --------------------------------------------------------------------- */ + /* if A is full, free the sparse copy of A */ + /* --------------------------------------------------------------------- */ + + if (full) + { + mxDestroyArray (A) ; + } + + /* --------------------------------------------------------------------- */ + /* print results (including return value) */ + /* --------------------------------------------------------------------- */ + + if (spumoni > 0) + { + camd_l_info (Info) ; + } + + /* --------------------------------------------------------------------- */ + /* check error conditions */ + /* --------------------------------------------------------------------- */ + + if (result == CAMD_OUT_OF_MEMORY) + { + mexErrMsgTxt ("camd: out of memory") ; + } + else if (result == CAMD_INVALID) + { + mexErrMsgTxt ("camd: input matrix A is corrupted") ; + } + + /* --------------------------------------------------------------------- */ + /* copy the outputs to MATLAB */ + /* --------------------------------------------------------------------- */ + + /* output permutation, P */ + pargout [0] = mxCreateDoubleMatrix (1, n, mxREAL) ; + Pout = mxGetPr (pargout [0]) ; + for (i = 0 ; i < n ; i++) + { + Pout [i] = P [i] + 1 ; /* change to 1-based indexing for MATLAB */ + } + mxFree (P) ; + if (nargin > 2) mxFree (C) ; + + /* Info */ + if (nargout > 1) + { + pargout [1] = mxCreateDoubleMatrix (CAMD_INFO, 1, mxREAL) ; + InfoOut = mxGetPr (pargout [1]) ; + for (i = 0 ; i < CAMD_INFO ; i++) + { + InfoOut [i] = Info [i] ; + } + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_1.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_1.c new file mode 100644 index 0000000..753f965 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_1.c @@ -0,0 +1,183 @@ +/* ========================================================================= */ +/* === CAMD_1 ============================================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* CAMD, Copyright (c) Timothy A. Davis, Yanqing Chen, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* CAMD_1: Construct A+A' for a sparse matrix A and perform the CAMD ordering. + * + * The n-by-n sparse matrix A can be unsymmetric. It is stored in MATLAB-style + * compressed-column form, with sorted row indices in each column, and no + * duplicate entries. Diagonal entries may be present, but they are ignored. + * Row indices of column j of A are stored in Ai [Ap [j] ... Ap [j+1]-1]. + * Ap [0] must be zero, and nz = Ap [n] is the number of entries in A. The + * size of the matrix, n, must be greater than or equal to zero. + * + * This routine must be preceded by a call to CAMD_aat, which computes the + * number of entries in each row/column in A+A', excluding the diagonal. + * Len [j], on input, is the number of entries in row/column j of A+A'. This + * routine constructs the matrix A+A' and then calls CAMD_2. No error checking + * is performed (this was done in CAMD_valid). + */ + +#include "camd_internal.h" + +GLOBAL void CAMD_1 +( + Int n, /* n > 0 */ + const Int Ap [ ], /* input of size n+1, not modified */ + const Int Ai [ ], /* input of size nz = Ap [n], not modified */ + Int P [ ], /* size n output permutation */ + Int Pinv [ ], /* size n output inverse permutation */ + Int Len [ ], /* size n input, undefined on output */ + Int slen, /* slen >= sum (Len [0..n-1]) + 7n+2, + * ideally slen = 1.2 * sum (Len) + 8n+2 */ + Int S [ ], /* size slen workspace */ + double Control [ ], /* input array of size CAMD_CONTROL */ + double Info [ ], /* output array of size CAMD_INFO */ + const Int C [ ] /* Constraint set of size n */ +) +{ + Int i, j, k, p, pfree, iwlen, pj, p1, p2, pj2, *Iw, *Pe, *Nv, *Head, + *Elen, *Degree, *s, *W, *Sp, *Tp, *BucketSet ; + + /* --------------------------------------------------------------------- */ + /* construct the matrix for CAMD_2 */ + /* --------------------------------------------------------------------- */ + + ASSERT (n > 0) ; + + iwlen = slen - (7*n+2) ; /* allocate 7*n+2 workspace from S */ + s = S ; + Pe = s ; s += n ; + Nv = s ; s += n ; + Head = s ; s += n+1 ; /* NOTE: was size n in AMD; size n+1 in CAMD */ + Elen = s ; s += n ; + Degree = s ; s += n ; + W = s ; s += n+1 ; /* NOTE: was size n in AMD; size n+1 in CAMD */ + BucketSet = s ; s += n ; + Iw = s ; s += iwlen ; + + ASSERT (CAMD_valid (n, n, Ap, Ai) == CAMD_OK) ; + ASSERT (CAMD_cvalid (n, C)) ; + + /* construct the pointers for A+A' */ + Sp = Nv ; /* use Nv and W as workspace for Sp and Tp [ */ + Tp = W ; + pfree = 0 ; + for (j = 0 ; j < n ; j++) + { + Pe [j] = pfree ; + Sp [j] = pfree ; + pfree += Len [j] ; + } + + /* Note that this restriction on iwlen is slightly more restrictive than + * what is strictly required in CAMD_2. CAMD_2 can operate with no elbow + * room at all, but it will be very slow. For better performance, at + * least size-n elbow room is enforced. */ + ASSERT (iwlen >= pfree + n) ; + +#ifndef NDEBUG + for (p = 0 ; p < iwlen ; p++) Iw [p] = EMPTY ; +#endif + + for (k = 0 ; k < n ; k++) + { + CAMD_DEBUG1 (("Construct row/column k= "ID" of A+A'\n", k)) ; + p1 = Ap [k] ; + p2 = Ap [k+1] ; + + /* construct A+A' */ + for (p = p1 ; p < p2 ; ) + { + /* scan the upper triangular part of A */ + j = Ai [p] ; + ASSERT (j >= 0 && j < n) ; + if (j < k) + { + /* entry A (j,k) in the strictly upper triangular part */ + ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ; + ASSERT (Sp [k] < (k == n-1 ? pfree : Pe [k+1])) ; + Iw [Sp [j]++] = k ; + Iw [Sp [k]++] = j ; + p++ ; + } + else if (j == k) + { + /* skip the diagonal */ + p++ ; + break ; + } + else /* j > k */ + { + /* first entry below the diagonal */ + break ; + } + /* scan lower triangular part of A, in column j until reaching + * row k. Start where last scan left off. */ + ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ; + pj2 = Ap [j+1] ; + for (pj = Tp [j] ; pj < pj2 ; ) + { + i = Ai [pj] ; + ASSERT (i >= 0 && i < n) ; + if (i < k) + { + /* A (i,j) is only in the lower part, not in upper */ + ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ; + ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ; + Iw [Sp [i]++] = j ; + Iw [Sp [j]++] = i ; + pj++ ; + } + else if (i == k) + { + /* entry A (k,j) in lower part and A (j,k) in upper */ + pj++ ; + break ; + } + else /* i > k */ + { + /* consider this entry later, when k advances to i */ + break ; + } + } + Tp [j] = pj ; + } + Tp [k] = p ; + } + + /* clean up, for remaining mismatched entries */ + for (j = 0 ; j < n ; j++) + { + for (pj = Tp [j] ; pj < Ap [j+1] ; pj++) + { + i = Ai [pj] ; + ASSERT (i >= 0 && i < n) ; + /* A (i,j) is only in the lower part, not in upper */ + ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ; + ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ; + Iw [Sp [i]++] = j ; + Iw [Sp [j]++] = i ; + } + } + +#ifndef NDEBUG + for (j = 0 ; j < n-1 ; j++) ASSERT (Sp [j] == Pe [j+1]) ; + ASSERT (Sp [n-1] == pfree) ; +#endif + + /* Tp and Sp no longer needed ] */ + + /* --------------------------------------------------------------------- */ + /* order the matrix */ + /* --------------------------------------------------------------------- */ + + CAMD_2 (n, Pe, Iw, Len, iwlen, pfree, + Nv, Pinv, P, Head, Elen, Degree, W, Control, Info, C, BucketSet) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_2.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_2.c new file mode 100644 index 0000000..ac8d636 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_2.c @@ -0,0 +1,2012 @@ +/* ========================================================================= */ +/* === CAMD_2 ============================================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* CAMD, Copyright (c) Timothy A. Davis, Yanqing Chen, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* CAMD_2: performs the CAMD ordering on a symmetric sparse matrix A, followed + * by a postordering (via depth-first search) of the assembly tree using the + * CAMD_postorder routine. + */ + +/* ========================================================================= */ +/* === Macros and definitions ============================================== */ +/* ========================================================================= */ + +/* True if node i is in the current Constraint Set */ +#define IsInCurrentSet(C,i,curC) ((C == NULL) ? 1 : (C [i] == curC)) + +/* True if i and j are in the same Constraint Set */ +#define InSameConstraintSet(C,i,j) ((C == NULL) ? 1 : (C [i] == C [j])) + +#include "camd_internal.h" + +/* ========================================================================= */ +/* === clear_flag ========================================================== */ +/* ========================================================================= */ + +static Int clear_flag (Int wflg, Int wbig, Int W [ ], Int n) +{ + Int x ; + if (wflg < 2 || wflg >= wbig) + { + for (x = 0 ; x < n ; x++) + { + if (W [x] != 0) W [x] = 1 ; + } + wflg = 2 ; + } + /* at this point, W [0..n-1] < wflg holds */ + return (wflg) ; +} + + +/* ========================================================================= */ +/* === CAMD_2 ============================================================== */ +/* ========================================================================= */ + +GLOBAL void CAMD_2 +( + Int n, /* A is n-by-n, where n > 0 */ + Int Pe [ ], /* Pe [0..n-1]: index in Iw of row i on input */ + Int Iw [ ], /* workspace of size iwlen. Iw [0..pfree-1] + * holds the matrix on input */ + Int Len [ ], /* Len [0..n-1]: length for row/column i on input */ + Int iwlen, /* length of Iw. iwlen >= pfree + n */ + Int pfree, /* Iw [pfree ... iwlen-1] is empty on input */ + + /* 7 size-n or size-n+1 workspaces, not defined on input: */ + Int Nv [ ], /* size n, the size of each supernode on output */ + Int Next [ ], /* size n, the output inverse permutation */ + Int Last [ ], /* size n, the output permutation */ + Int Head [ ], /* size n+1 (Note: it was size n in AMD) */ + Int Elen [ ], /* size n, the size columns of L for each supernode */ + Int Degree [ ], /* size n */ + Int W [ ], /* size n+1 (Note: it was size n in AMD) */ + + /* control parameters and output statistics */ + double Control [ ], /* array of size CAMD_CONTROL */ + double Info [ ], /* array of size CAMD_INFO */ + + /* input, not modified: */ + const Int C [ ], /* size n, C [i] is the constraint set of node i */ + + /* size-n workspace, not defined on input or output: */ + Int BucketSet [ ] /* size n */ +) +{ + +/* + * Given a representation of the nonzero pattern of a symmetric matrix, A, + * (excluding the diagonal) perform an approximate minimum (UMFPACK/MA38-style) + * degree ordering to compute a pivot order such that the introduction of + * nonzeros (fill-in) in the Cholesky factors A = LL' is kept low. At each + * step, the pivot selected is the one with the minimum UMFAPACK/MA38-style + * upper-bound on the external degree. This routine can optionally perform + * aggresive absorption (as done by MC47B in the Harwell Subroutine + * Library). + * + * The approximate degree algorithm implemented here is the symmetric analog of + * the degree update algorithm in MA38 and UMFPACK (the Unsymmetric-pattern + * MultiFrontal PACKage, both by Davis and Duff). The routine is based on the + * MA27 minimum degree ordering algorithm by Iain Duff and John Reid. + * + * This routine is a translation of the original AMDBAR and MC47B routines, + * in Fortran, with the following modifications: + * + * (1) dense rows/columns are removed prior to ordering the matrix, and placed + * last in the output order. The presence of a dense row/column can + * increase the ordering time by up to O(n^2), unless they are removed + * prior to ordering. + * + * (2) the minimum degree ordering is followed by a postordering (depth-first + * search) of the assembly tree. Note that mass elimination (discussed + * below) combined with the approximate degree update can lead to the mass + * elimination of nodes with lower exact degree than the current pivot + * element. No additional fill-in is caused in the representation of the + * Schur complement. The mass-eliminated nodes merge with the current + * pivot element. They are ordered prior to the current pivot element. + * Because they can have lower exact degree than the current element, the + * merger of two or more of these nodes in the current pivot element can + * lead to a single element that is not a "fundamental supernode". The + * diagonal block can have zeros in it. Thus, the assembly tree used here + * is not guaranteed to be the precise supernodal elemination tree (with + * "funadmental" supernodes), and the postordering performed by this + * routine is not guaranteed to be a precise postordering of the + * elimination tree. + * + * (3) input parameters are added, to control aggressive absorption and the + * detection of "dense" rows/columns of A. + * + * (4) additional statistical information is returned, such as the number of + * nonzeros in L, and the flop counts for subsequent LDL' and LU + * factorizations. These are slight upper bounds, because of the mass + * elimination issue discussed above. + * + * (5) additional routines are added to interface this routine to MATLAB + * to provide a simple C-callable user-interface, to check inputs for + * errors, compute the symmetry of the pattern of A and the number of + * nonzeros in each row/column of A+A', to compute the pattern of A+A', + * to perform the assembly tree postordering, and to provide debugging + * ouput. Many of these functions are also provided by the Fortran + * Harwell Subroutine Library routine MC47A. + * + * (6) both "int" and "long" versions are provided. In the descriptions below + * and integer is and "int" or "long", depending on which version is + * being used. + + ********************************************************************** + ***** CAUTION: ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT. ****** + ********************************************************************** + ** If you want error checking, a more versatile input format, and a ** + ** simpler user interface, use camd_order or camd_l_order instead. ** + ** This routine is not meant to be user-callable. ** + ********************************************************************** + + * ---------------------------------------------------------------------------- + * References: + * ---------------------------------------------------------------------------- + * + * [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern multifrontal + * method for sparse LU factorization", SIAM J. Matrix Analysis and + * Applications, vol. 18, no. 1, pp. 140-158. Discusses UMFPACK / MA38, + * which first introduced the approximate minimum degree used by this + * routine. + * + * [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An approximate + * minimum degree ordering algorithm," SIAM J. Matrix Analysis and + * Applications, vol. 17, no. 4, pp. 886-905, 1996. Discusses AMDBAR and + * MC47B, which are the Fortran versions of this routine. + * + * [3] Alan George and Joseph Liu, "The evolution of the minimum degree + * ordering algorithm," SIAM Review, vol. 31, no. 1, pp. 1-19, 1989. + * We list below the features mentioned in that paper that this code + * includes: + * + * mass elimination: + * Yes. MA27 relied on supervariable detection for mass elimination. + * + * indistinguishable nodes: + * Yes (we call these "supervariables"). This was also in the MA27 + * code - although we modified the method of detecting them (the + * previous hash was the true degree, which we no longer keep track + * of). A supervariable is a set of rows with identical nonzero + * pattern. All variables in a supervariable are eliminated together. + * Each supervariable has as its numerical name that of one of its + * variables (its principal variable). + * + * quotient graph representation: + * Yes. We use the term "element" for the cliques formed during + * elimination. This was also in the MA27 code. The algorithm can + * operate in place, but it will work more efficiently if given some + * "elbow room." + * + * element absorption: + * Yes. This was also in the MA27 code. + * + * external degree: + * Yes. The MA27 code was based on the true degree. + * + * incomplete degree update and multiple elimination: + * No. This was not in MA27, either. Our method of degree update + * within MC47B is element-based, not variable-based. It is thus + * not well-suited for use with incomplete degree update or multiple + * elimination. + * + * AMD Authors, and Copyright (C) 2004 by: + * Timothy A. Davis, Patrick Amestoy, Iain S. Duff, John K. Reid. + * Modifications for CAMD authored by Davis and Yanqing "Morris" Chen. + * + * Acknowledgements: This work (and the UMFPACK package) was supported by the + * National Science Foundation (ASC-9111263, DMS-9223088, and CCR-0203270). + * The UMFPACK/MA38 approximate degree update algorithm, the unsymmetric analog + * which forms the basis of CAMD, was developed while Tim Davis was supported by + * CERFACS (Toulouse, France) in a post-doctoral position. This C version, and + * the etree postorder, were written while Tim Davis was on sabbatical at + * Stanford University and Lawrence Berkeley National Laboratory. + * Ordering constraints were added with support from Sandia National Labs (DOE). + + * ---------------------------------------------------------------------------- + * INPUT ARGUMENTS (unaltered): + * ---------------------------------------------------------------------------- + + * n: The matrix order. Restriction: n >= 1. + * + * iwlen: The size of the Iw array. On input, the matrix is stored in + * Iw [0..pfree-1]. However, Iw [0..iwlen-1] should be slightly larger + * than what is required to hold the matrix, at least iwlen >= pfree + n. + * Otherwise, excessive compressions will take place. The recommended + * value of iwlen is 1.2 * pfree + n, which is the value used in the + * user-callable interface to this routine (camd_order.c). The algorithm + * will not run at all if iwlen < pfree. Restriction: iwlen >= pfree + n. + * Note that this is slightly more restrictive than the actual minimum + * (iwlen >= pfree), but CAMD_2 will be very slow with no elbow room. + * Thus, this routine enforces a bare minimum elbow room of size n. + * + * pfree: On input the tail end of the array, Iw [pfree..iwlen-1], is empty, + * and the matrix is stored in Iw [0..pfree-1]. During execution, + * additional data is placed in Iw, and pfree is modified so that + * Iw [pfree..iwlen-1] is always the unused part of Iw. + * + * Control: A double array of size CAMD_CONTROL containing input parameters + * that affect how the ordering is computed. If NULL, then default + * settings are used. + * + * Control [CAMD_DENSE] is used to determine whether or not a given input + * row is "dense". A row is "dense" if the number of entries in the row + * exceeds Control [CAMD_DENSE] times sqrt (n), except that rows with 16 or + * fewer entries are never considered "dense". To turn off the detection + * of dense rows, set Control [CAMD_DENSE] to a negative number, or to a + * number larger than sqrt (n). The default value of Control [CAMD_DENSE] + * is CAMD_DEFAULT_DENSE, which is defined in camd.h as 10. + * + * Control [CAMD_AGGRESSIVE] is used to determine whether or not aggressive + * absorption is to be performed. If nonzero, then aggressive absorption + * is performed (this is the default). + * + * C: defines the ordering constraints. s = C [j] gives the constraint set s + * that contains the row/column j (Restriction: 0 <= s < n). + * In the output row permutation, all rows in set 0 appear first, followed + * by all rows in set 1, and so on. If NULL, all rows are treated as if + * they were in a single constraint set, and you will obtain a similar + * ordering as AMD (slightly different because of the different + * postordering used). + + * ---------------------------------------------------------------------------- + * INPUT/OUPUT ARGUMENTS: + * ---------------------------------------------------------------------------- + * + * Pe: An integer array of size n. On input, Pe [i] is the index in Iw of + * the start of row i. Pe [i] is ignored if row i has no off-diagonal + * entries. Thus Pe [i] must be in the range 0 to pfree-1 for non-empty + * rows. + * + * During execution, it is used for both supervariables and elements: + * + * Principal supervariable i: index into Iw of the description of + * supervariable i. A supervariable represents one or more rows of + * the matrix with identical nonzero pattern. In this case, + * Pe [i] >= 0. + * + * Non-principal supervariable i: if i has been absorbed into another + * supervariable j, then Pe [i] = FLIP (j), where FLIP (j) is defined + * as (-(j)-2). Row j has the same pattern as row i. Note that j + * might later be absorbed into another supervariable j2, in which + * case Pe [i] is still FLIP (j), and Pe [j] = FLIP (j2) which is + * < EMPTY, where EMPTY is defined as (-1) in camd_internal.h. + * + * Unabsorbed element e: the index into Iw of the description of element + * e, if e has not yet been absorbed by a subsequent element. Element + * e is created when the supervariable of the same name is selected as + * the pivot. In this case, Pe [i] >= 0. + * + * Absorbed element e: if element e is absorbed into element e2, then + * Pe [e] = FLIP (e2). This occurs when the pattern of e (which we + * refer to as Le) is found to be a subset of the pattern of e2 (that + * is, Le2). In this case, Pe [i] < EMPTY. If element e is "null" + * (it has no nonzeros outside its pivot block), then Pe [e] = EMPTY, + * and e is the root of an assembly subtree (or the whole tree if + * there is just one such root). + * + * Dense or empty variable i: if i is "dense" or empty (with zero degree), + * then Pe [i] = FLIP (n). + * + * On output, Pe holds the assembly tree/forest, which implicitly + * represents a pivot order with identical fill-in as the actual order + * (via a depth-first search of the tree), as follows. If Nv [i] > 0, + * then i represents a node in the assembly tree, and the parent of i is + * Pe [i], or EMPTY if i is a root. If Nv [i] = 0, then (i, Pe [i]) + * represents an edge in a subtree, the root of which is a node in the + * assembly tree. Note that i refers to a row/column in the original + * matrix, not the permuted matrix. + * + * Info: A double array of size CAMD_INFO. If present, (that is, not NULL), + * then statistics about the ordering are returned in the Info array. + * See camd.h for a description. + + * ---------------------------------------------------------------------------- + * INPUT/MODIFIED (undefined on output): + * ---------------------------------------------------------------------------- + * + * Len: An integer array of size n. On input, Len [i] holds the number of + * entries in row i of the matrix, excluding the diagonal. The contents + * of Len are undefined on output. Len also works as a temporary + * workspace in post ordering with dense nodes detected. + * + * Iw: An integer array of size iwlen. On input, Iw [0..pfree-1] holds the + * description of each row i in the matrix. The matrix must be symmetric, + * and both upper and lower triangular parts must be present. The + * diagonal must not be present. Row i is held as follows: + * + * Len [i]: the length of the row i data structure in the Iw array. + * Iw [Pe [i] ... Pe [i] + Len [i] - 1]: + * the list of column indices for nonzeros in row i (simple + * supervariables), excluding the diagonal. All supervariables + * start with one row/column each (supervariable i is just row i). + * If Len [i] is zero on input, then Pe [i] is ignored on input. + * + * Note that the rows need not be in any particular order, and there + * may be empty space between the rows. + * + * During execution, the supervariable i experiences fill-in. This is + * represented by placing in i a list of the elements that cause fill-in + * in supervariable i: + * + * Len [i]: the length of supervariable i in the Iw array. + * Iw [Pe [i] ... Pe [i] + Elen [i] - 1]: + * the list of elements that contain i. This list is kept short + * by removing absorbed elements. + * Iw [Pe [i] + Elen [i] ... Pe [i] + Len [i] - 1]: + * the list of supervariables in i. This list is kept short by + * removing nonprincipal variables, and any entry j that is also + * contained in at least one of the elements (j in Le) in the list + * for i (e in row i). + * + * When supervariable i is selected as pivot, we create an element e of + * the same name (e=i): + * + * Len [e]: the length of element e in the Iw array. + * Iw [Pe [e] ... Pe [e] + Len [e] - 1]: + * the list of supervariables in element e. + * + * An element represents the fill-in that occurs when supervariable i is + * selected as pivot (which represents the selection of row i and all + * non-principal variables whose principal variable is i). We use the + * term Le to denote the set of all supervariables in element e. Absorbed + * supervariables and elements are pruned from these lists when + * computationally convenient. + * + * CAUTION: THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION. + * The contents of Iw are undefined on output. + + * ---------------------------------------------------------------------------- + * OUTPUT (need not be set on input): + * ---------------------------------------------------------------------------- + * + * + * Nv: An integer array of size n. During execution, ABS (Nv [i]) is equal to + * the number of rows that are represented by the principal supervariable + * i. If i is a nonprincipal or dense variable, then Nv [i] = 0. + * Initially, Nv [i] = 1 for all i. Nv [i] < 0 signifies that i is a + * principal variable in the pattern Lme of the current pivot element me. + * After element me is constructed, Nv [i] is set back to a positive + * value. + * + * On output, Nv [i] holds the number of pivots represented by super + * row/column i of the original matrix, or Nv [i] = 0 for non-principal + * rows/columns. Note that i refers to a row/column in the original + * matrix, not the permuted matrix. + * + * Nv also works as a temporary workspace in initializing the BucketSet + * array. + * + * Elen: An integer array of size n. See the description of Iw above. At the + * start of execution, Elen [i] is set to zero for all rows i. During + * execution, Elen [i] is the number of elements in the list for + * supervariable i. When e becomes an element, Elen [e] = FLIP (esize) is + * set, where esize is the size of the element (the number of pivots, plus + * the number of nonpivotal entries). Thus Elen [e] < EMPTY. + * Elen (i) = EMPTY set when variable i becomes nonprincipal. + * + * For variables, Elen (i) >= EMPTY holds until just before the + * postordering and permutation vectors are computed. For elements, + * Elen [e] < EMPTY holds. + * + * On output, Elen [i] is the degree of the row/column in the Cholesky + * factorization of the permuted matrix, corresponding to the original row + * i, if i is a super row/column. It is equal to EMPTY if i is + * non-principal. Note that i refers to a row/column in the original + * matrix, not the permuted matrix. + * + * Note that the contents of Elen on output differ from the Fortran + * version (Elen holds the inverse permutation in the Fortran version, + * which is instead returned in the Next array in this C version, + * described below). + * + * Last: In a degree list, Last [i] is the supervariable preceding i, or EMPTY + * if i is the head of the list. In a hash bucket, Last [i] is the hash + * key for i. + * + * Last [Head [hash]] is also used as the head of a hash bucket if + * Head [hash] contains a degree list (see the description of Head, + * below). + * + * On output, Last [0..n-1] holds the permutation. That is, if + * i = Last [k], then row i is the kth pivot row (where k ranges from 0 to + * n-1). Row Last [k] of A is the kth row in the permuted matrix, PAP'. + * + * Next: Next [i] is the supervariable following i in a link list, or EMPTY if + * i is the last in the list. Used for two kinds of lists: degree lists + * and hash buckets (a supervariable can be in only one kind of list at a + * time). + * + * On output Next [0..n-1] holds the inverse permutation. That is, if + * k = Next [i], then row i is the kth pivot row. Row i of A appears as + * the (Next[i])-th row in the permuted matrix, PAP'. + * + * Note that the contents of Next on output differ from the Fortran + * version (Next is undefined on output in the Fortran version). + + * ---------------------------------------------------------------------------- + * LOCAL WORKSPACE (not input or output - used only during execution): + * ---------------------------------------------------------------------------- + * + * Degree: An integer array of size n. If i is a supervariable, then + * Degree [i] holds the current approximation of the external degree of + * row i (an upper bound). The external degree is the number of nonzeros + * in row i, minus ABS (Nv [i]), the diagonal part. The bound is equal to + * the exact external degree if Elen [i] is less than or equal to two. + * + * We also use the term "external degree" for elements e to refer to + * |Le \ Lme|. If e is an element, then Degree [e] is |Le|, which is the + * degree of the off-diagonal part of the element e (not including the + * diagonal part). + * + * Head: An integer array of size n. Head is used for degree lists. + * Head [deg] is the first supervariable in a degree list. All + * supervariables i in a degree list Head [deg] have the same approximate + * degree, namely, deg = Degree [i]. If the list Head [deg] is empty then + * Head [deg] = EMPTY. + * + * During supervariable detection Head [hash] also serves as a pointer to + * a hash bucket. If Head [hash] >= 0, there is a degree list of degree + * hash. The hash bucket head pointer is Last [Head [hash]]. If + * Head [hash] = EMPTY, then the degree list and hash bucket are both + * empty. If Head [hash] < EMPTY, then the degree list is empty, and + * FLIP (Head [hash]) is the head of the hash bucket. After supervariable + * detection is complete, all hash buckets are empty, and the + * (Last [Head [hash]] = EMPTY) condition is restored for the non-empty + * degree lists. + * + * Head also workes as a temporary workspace in post ordering with dense + * nodes detected. + * + * W: An integer array of size n. The flag array W determines the status of + * elements and variables, and the external degree of elements. + * + * for elements: + * if W [e] = 0, then the element e is absorbed. + * if W [e] >= wflg, then W [e] - wflg is the size of the set + * |Le \ Lme|, in terms of nonzeros (the sum of ABS (Nv [i]) for + * each principal variable i that is both in the pattern of + * element e and NOT in the pattern of the current pivot element, + * me). + * if wflg > W [e] > 0, then e is not absorbed and has not yet been + * seen in the scan of the element lists in the computation of + * |Le\Lme| in Scan 1 below. + * + * for variables: + * during supervariable detection, if W [j] != wflg then j is + * not in the pattern of variable i. + * + * The W array is initialized by setting W [i] = 1 for all i, and by + * setting wflg = 2. It is reinitialized if wflg becomes too large (to + * ensure that wflg+n does not cause integer overflow). + * + * BucketSet: An integer array of size n. + * During execution it stores the rows that sorted in the ascending order + * based on C []. For instance: if C[]={0,2,1,0,1,0,2,1}, the + * Bucketset will be {0,3,5,2,4,7,1,6}. + * The elements in Bucketset are then modified, to maintain the order of + * roots (Pe[i]=-1) in each Constraint Set. + + * ---------------------------------------------------------------------------- + * LOCAL INTEGERS: + * ---------------------------------------------------------------------------- + */ + + Int deg, degme, dext, lemax, e, elenme, eln, i, ilast, inext, j, + jlast, k, knt1, knt2, knt3, lenj, ln, me, mindeg, nel, nleft, + nvi, nvj, nvpiv, slenme, wbig, we, wflg, wnvi, ok, ndense, ncmpa, nnull, + dense, aggressive ; + + unsigned Int hash ; /* unsigned, so that hash % n is well defined.*/ + +/* + * deg: the degree of a variable or element + * degme: size, |Lme|, of the current element, me (= Degree [me]) + * dext: external degree, |Le \ Lme|, of some element e + * lemax: largest |Le| seen so far (called dmax in Fortran version) + * e: an element + * elenme: the length, Elen [me], of element list of pivotal variable + * eln: the length, Elen [...], of an element list + * hash: the computed value of the hash function + * i: a supervariable + * ilast: the entry in a link list preceding i + * inext: the entry in a link list following i + * j: a supervariable + * jlast: the entry in a link list preceding j + * k: the pivot order of an element or variable + * knt1: loop counter used during element construction + * knt2: loop counter used during element construction + * knt3: loop counter used during compression + * lenj: Len [j] + * ln: length of a supervariable list + * me: current supervariable being eliminated, and the current + * element created by eliminating that supervariable + * mindeg: current minimum degree + * nel: number of pivots selected so far + * nleft: n - nel, the number of nonpivotal rows/columns remaining + * nvi: the number of variables in a supervariable i (= Nv [i]) + * nvj: the number of variables in a supervariable j (= Nv [j]) + * nvpiv: number of pivots in current element + * slenme: number of variables in variable list of pivotal variable + * wbig: = INT_MAX - n for the "int" version, LONG_MAX - n for the + * "long" version. wflg is not allowed to be >= wbig. + * we: W [e] + * wflg: used for flagging the W array. See description of Iw. + * wnvi: wflg - Nv [i] + * x: either a supervariable or an element + * + * ok: true if supervariable j can be absorbed into i + * ndense: number of "dense" rows/columns + * nnull: number of empty rows/columns + * dense: rows/columns with initial degree > dense are considered "dense" + * aggressive: true if aggressive absorption is being performed + * ncmpa: number of garbage collections + + * ---------------------------------------------------------------------------- + * LOCAL DOUBLES, used for statistical output only (except for alpha): + * ---------------------------------------------------------------------------- + */ + + double f, r, ndiv, s, nms_lu, nms_ldl, dmax, alpha, lnz, lnzme ; + +/* + * f: nvpiv + * r: degme + nvpiv + * ndiv: number of divisions for LU or LDL' factorizations + * s: number of multiply-subtract pairs for LU factorization, for the + * current element me + * nms_lu number of multiply-subtract pairs for LU factorization + * nms_ldl number of multiply-subtract pairs for LDL' factorization + * dmax: the largest number of entries in any column of L, including the + * diagonal + * alpha: "dense" degree ratio + * lnz: the number of nonzeros in L (excluding the diagonal) + * lnzme: the number of nonzeros in L (excl. the diagonal) for the + * current element me + + * ---------------------------------------------------------------------------- + * LOCAL "POINTERS" (indices into the Iw array) + * ---------------------------------------------------------------------------- +*/ + + Int p, p1, p2, p3, p4, pdst, pend, pj, pme, pme1, pme2, pn, psrc ; + +/* + * Any parameter (Pe [...] or pfree) or local variable starting with "p" (for + * Pointer) is an index into Iw, and all indices into Iw use variables starting + * with "p." The only exception to this rule is the iwlen input argument. + * + * p: pointer into lots of things + * p1: Pe [i] for some variable i (start of element list) + * p2: Pe [i] + Elen [i] - 1 for some variable i + * p3: index of first supervariable in clean list + * p4: + * pdst: destination pointer, for compression + * pend: end of memory to compress + * pj: pointer into an element or variable + * pme: pointer into the current element (pme1...pme2) + * pme1: the current element, me, is stored in Iw [pme1...pme2] + * pme2: the end of the current element + * pn: pointer into a "clean" variable, also used to compress + * psrc: source pointer, for compression +*/ + + Int curC, pBucket, pBucket2, degreeListCounter, c, cmax = 0, + ndense_or_null ; + Int *Bucket, *Perm ; + +/* + * curC: the current Constraint Set being ordered + * pBucket: pointer into Bucketset[] when building the degreelist for each + * Constraint Set + * pBucket2: pointer into Bucketset[] to tell the post ordering where to stop + * degreeListCounter: number of elements remaining in the + * degreelist of current Constraint Set + * Bucket: used to construct BucketSet + * Perm: permutation + */ + +/* ========================================================================= */ +/* INITIALIZATIONS */ +/* ========================================================================= */ + + /* Note that this restriction on iwlen is slightly more restrictive than + * what is actually required in CAMD_2. CAMD_2 can operate with no elbow + * room at all, but it will be slow. For better performance, at least + * size-n elbow room is enforced. */ + ASSERT (iwlen >= pfree + n) ; + ASSERT (n > 0) ; + + /* initialize output statistics */ + lnz = 0 ; + ndiv = 0 ; + nms_lu = 0 ; + nms_ldl = 0 ; + dmax = 1 ; + me = EMPTY ; + + mindeg = 0 ; + ncmpa = 0 ; + nel = 0 ; + lemax = 0 ; + curC = 0 ; + +/* camd work initBucketSet using CountingSort + * BucketSort the index Array BucketSet According to Contrains Array C, Using + * Nv[] as a temporary workspace + * Input: Index Array from 0 to n.(index of rows) + * Output: Index Array sorted according to C. worked as a bucket set. + * + * All the value in C must be 0 <= C[i] <= n-1 + * For instance: if C[]={0,2,1,0,1,0,2,1}, the output Bucketset should be + * {0,3,5,2,4,7,1,6} + */ + + +/* CountingSort BucketSet[] based on C[], It is O(n) linear time */ + + if (C == NULL) + { + /* store everything in bucket without changing order */ + for (j = 0 ; j < n ; j++) + { + BucketSet [j] = j ; + } + } + else + { + + Bucket = Nv ; + for (i = 0 ; i < n ; i++) + { + Bucket [i] = 0 ; + } + cmax = C [0] ; + for (j = 0 ; j < n ; j++) + { + c = C [j] ; + CAMD_DEBUG1 (("C [%d] = "ID"\n", j, c)) ; + Bucket [c]++ ; + cmax = MAX (cmax, c) ; + ASSERT (c >= 0 && c < n) ; + } + CAMD_DEBUG1 (("Max constraint set: "ID"\n", cmax)) ; + for (i = 1 ; i < n ; i++) + { + Bucket [i] += Bucket [i-1] ; + } + for (j = n-1 ; j >= 0 ; j--) + { + BucketSet [--Bucket [C [j]]] = j ; + } + +#ifndef NDEBUG + CAMD_DEBUG3 (("\nConstraint Set "ID" :", C [BucketSet [0]])); + for (i = 0 ; i < n ; i++) + { + CAMD_DEBUG3 ((ID" ", BucketSet [i])) ; + if (i == n-1) + { + CAMD_DEBUG3 (("\n")) ; + break ; + } + if (C [BucketSet [i+1]] != C [BucketSet [i]]) + { + CAMD_DEBUG3 (("\nConstraint Set "ID" :", C [BucketSet [i+1]])) ; + } + } +#endif + } + + /* get control parameters */ + if (Control != (double *) NULL) + { + alpha = Control [CAMD_DENSE] ; + aggressive = (Control [CAMD_AGGRESSIVE] != 0) ; + } + else + { + alpha = CAMD_DEFAULT_DENSE ; + aggressive = CAMD_DEFAULT_AGGRESSIVE ; + } + /* Note: if alpha is NaN, this is undefined: */ + if (alpha < 0) + { + /* only remove completely dense rows/columns */ + dense = n-2 ; + } + else + { + dense = alpha * sqrt ((double) n) ; + } + dense = MAX (16, dense) ; + dense = MIN (n, dense) ; + CAMD_DEBUG1 (("\n\nCAMD (debug), alpha %g, aggr. "ID"\n", + alpha, aggressive)) ; + + for (i = 0 ; i < n ; i++) + { + Last [i] = EMPTY ; + Head [i] = EMPTY ; + Next [i] = EMPTY ; + /* if separate Hhead array is used for hash buckets: * + Hhead [i] = EMPTY ; + */ + Nv [i] = 1 ; + W [i] = 1 ; + Elen [i] = 0 ; + Degree [i] = Len [i] ; + } + Head [n] = EMPTY ; + + /* initialize wflg */ + wbig = Int_MAX - n ; + wflg = clear_flag (0, wbig, W, n) ; + + /* --------------------------------------------------------------------- */ + /* eliminate dense and empty rows */ + /* --------------------------------------------------------------------- */ + + ndense = 0 ; + nnull = 0 ; + + for (j = 0 ; j < n ; j++) + { + i = BucketSet [j] ; + deg = Degree [i] ; + ASSERT (deg >= 0 && deg < n) ; + if (deg > dense || deg == 0) + { + + /* ------------------------------------------------------------- + * Dense or empty variables are treated as non-principal variables + * represented by node n. That is, i is absorbed into n, just like + * j is absorbed into i in supervariable detection (see "found it!" + * comment, below). + * ------------------------------------------------------------- */ + + if (deg > dense) + { + CAMD_DEBUG1 (("Dense node "ID" degree "ID" bucket "ID"\n", + i, deg, j)) ; + ndense++ ; + } + else + { + CAMD_DEBUG1 (("Empty node "ID" degree "ID" bucket "ID"\n", + i, deg, j)) ; + nnull++ ; + } + Pe [i] = FLIP (n) ; + Nv [i] = 0 ; /* do not postorder this node */ + Elen [i] = EMPTY ; + nel++ ; + } + } + + ndense_or_null = ndense + nnull ; + + pBucket = 0 ; + degreeListCounter = 0 ; + pBucket2 = 0 ; + +/* ========================================================================= */ +/* WHILE (selecting pivots) DO */ +/* ========================================================================= */ + + while (nel < n) + { + + /* ------------------------------------------------------------------ */ + /* if empty, fill the degree list with next non-empty constraint set */ + /* ------------------------------------------------------------------ */ + + while (degreeListCounter == 0) + { + mindeg = n ; + /* determine the new constraint set */ + curC = (C == NULL) ? 0 : C [BucketSet [pBucket]] ; + for ( ; pBucket < n ; pBucket++) + { + /* add i to the degree list, unless it's dead or not in curC */ + i = BucketSet [pBucket] ; + if (!IsInCurrentSet (C, i, curC)) break ; + deg = Degree [i] ; + ASSERT (deg >= 0 && deg < n) ; + if (Pe [i] >= 0) + { + + /* ------------------------------------------------------ + * place i in the degree list corresponding to its degree + * ------------------------------------------------------ */ + + inext = Head [deg] ; + ASSERT (inext >= EMPTY && inext < n) ; + if (inext != EMPTY) Last [inext] = i ; + Next [i] = inext ; + Head [deg] = i ; + degreeListCounter++ ; + Last [i] = EMPTY ; + mindeg = MIN (mindeg, deg) ; + } + } + } + +#ifndef NDEBUG + CAMD_DEBUG1 (("\n======Nel "ID"\n", nel)) ; + if (CAMD_debug >= 2) + { + CAMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next, + Last, Head, Elen, Degree, W, nel, BucketSet, C, curC) ; + } +#endif + +/* ========================================================================= */ +/* GET PIVOT OF MINIMUM DEGREE */ +/* ========================================================================= */ + + /* ----------------------------------------------------------------- */ + /* find next supervariable for elimination */ + /* ----------------------------------------------------------------- */ + + ASSERT (mindeg >= 0 && mindeg < n) ; + for (deg = mindeg ; deg < n ; deg++) + { + me = Head [deg] ; + if (me != EMPTY) break ; + } + mindeg = deg ; + ASSERT (me >= 0 && me < n) ; + CAMD_DEBUG1 (("=================me: "ID"\n", me)) ; + + /* ----------------------------------------------------------------- */ + /* remove chosen variable from link list */ + /* ----------------------------------------------------------------- */ + + inext = Next [me] ; + ASSERT (inext >= EMPTY && inext < n) ; + if (inext != EMPTY) Last [inext] = EMPTY ; + Head [deg] = inext ; + degreeListCounter-- ; + + /* ----------------------------------------------------------------- */ + /* me represents the elimination of pivots nel to nel+Nv[me]-1. */ + /* place me itself as the first in this set. */ + /* ----------------------------------------------------------------- */ + + elenme = Elen [me] ; + nvpiv = Nv [me] ; + ASSERT (nvpiv > 0) ; + nel += nvpiv ; + CAMD_DEBUG1 (("nvpiv is initially "ID"\n", nvpiv)) ; + +/* ========================================================================= */ +/* CONSTRUCT NEW ELEMENT */ +/* ========================================================================= */ + + /* ----------------------------------------------------------------- + * At this point, me is the pivotal supervariable. It will be + * converted into the current element. Scan list of the pivotal + * supervariable, me, setting tree pointers and constructing new list + * of supervariables for the new element, me. p is a pointer to the + * current position in the old list. + * ----------------------------------------------------------------- */ + + /* flag the variable "me" as being in Lme by negating Nv [me] */ + Nv [me] = -nvpiv ; + degme = 0 ; + ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ; + + if (elenme == 0) + { + + /* ------------------------------------------------------------- */ + /* construct the new element in place */ + /* ------------------------------------------------------------- */ + + pme1 = Pe [me] ; + pme2 = pme1 - 1 ; + + for (p = pme1 ; p <= pme1 + Len [me] - 1 ; p++) + { + i = Iw [p] ; + ASSERT (i >= 0 && i < n && Nv [i] >= 0) ; + nvi = Nv [i] ; + if (nvi > 0) + { + + /* ----------------------------------------------------- */ + /* i is a principal variable not yet placed in Lme. */ + /* store i in new list */ + /* ----------------------------------------------------- */ + + /* flag i as being in Lme by negating Nv [i] */ + degme += nvi ; + Nv [i] = -nvi ; + Iw [++pme2] = i ; + + /* ----------------------------------------------------- */ + /* remove variable i from degree list. */ + /* ----------------------------------------------------- */ + + if (IsInCurrentSet (C, i, curC)) + { + ilast = Last [i] ; + inext = Next [i] ; + ASSERT (ilast >= EMPTY && ilast < n) ; + ASSERT (inext >= EMPTY && inext < n) ; + if (inext != EMPTY) Last [inext] = ilast ; + if (ilast != EMPTY) + { + Next [ilast] = inext ; + } + else + { + /* i is at the head of the degree list */ + ASSERT (Degree [i] >= 0 && Degree [i] < n) ; + Head [Degree [i]] = inext ; + } + degreeListCounter-- ; + } + } + } + } + else + { + + /* ------------------------------------------------------------- */ + /* construct the new element in empty space, Iw [pfree ...] */ + /* ------------------------------------------------------------- */ + + p = Pe [me] ; + pme1 = pfree ; + slenme = Len [me] - elenme ; + + for (knt1 = 1 ; knt1 <= elenme + 1 ; knt1++) + { + + if (knt1 > elenme) + { + /* search the supervariables in me. */ + e = me ; + pj = p ; + ln = slenme ; + CAMD_DEBUG2 (("Search sv: "ID" "ID" "ID"\n", me,pj,ln)) ; + } + else + { + /* search the elements in me. */ + e = Iw [p++] ; + ASSERT (e >= 0 && e < n) ; + pj = Pe [e] ; + ln = Len [e] ; + CAMD_DEBUG2 (("Search element e "ID" in me "ID"\n", e,me)) ; + ASSERT (Elen [e] < EMPTY && W [e] > 0 && pj >= 0) ; + } + ASSERT (ln >= 0 && (ln == 0 || (pj >= 0 && pj < iwlen))) ; + + /* --------------------------------------------------------- + * search for different supervariables and add them to the + * new list, compressing when necessary. this loop is + * executed once for each element in the list and once for + * all the supervariables in the list. + * --------------------------------------------------------- */ + + for (knt2 = 1 ; knt2 <= ln ; knt2++) + { + i = Iw [pj++] ; + ASSERT (i >= 0 && i < n && (i == me || Elen [i] >= EMPTY)); + nvi = Nv [i] ; + CAMD_DEBUG2 ((": "ID" "ID" "ID" "ID"\n", + i, Elen [i], Nv [i], wflg)) ; + + if (nvi > 0) + { + + /* ------------------------------------------------- */ + /* compress Iw, if necessary */ + /* ------------------------------------------------- */ + + if (pfree >= iwlen) + { + + CAMD_DEBUG1 (("GARBAGE COLLECTION\n")) ; + + /* prepare for compressing Iw by adjusting pointers + * and lengths so that the lists being searched in + * the inner and outer loops contain only the + * remaining entries. */ + + Pe [me] = p ; + Len [me] -= knt1 ; + /* check if nothing left of supervariable me */ + if (Len [me] == 0) Pe [me] = EMPTY ; + Pe [e] = pj ; + Len [e] = ln - knt2 ; + /* nothing left of element e */ + if (Len [e] == 0) Pe [e] = EMPTY ; + + ncmpa++ ; /* one more garbage collection */ + + /* store first entry of each object in Pe */ + /* FLIP the first entry in each object */ + for (j = 0 ; j < n ; j++) + { + pn = Pe [j] ; + if (pn >= 0) + { + ASSERT (pn >= 0 && pn < iwlen) ; + Pe [j] = Iw [pn] ; + Iw [pn] = FLIP (j) ; + } + } + + /* psrc/pdst point to source/destination */ + psrc = 0 ; + pdst = 0 ; + pend = pme1 - 1 ; + + while (psrc <= pend) + { + /* search for next FLIP'd entry */ + j = FLIP (Iw [psrc++]) ; + if (j >= 0) + { + CAMD_DEBUG2 (("Got object j: "ID"\n", j)) ; + Iw [pdst] = Pe [j] ; + Pe [j] = pdst++ ; + lenj = Len [j] ; + /* copy from source to destination */ + for (knt3 = 0 ; knt3 <= lenj - 2 ; knt3++) + { + Iw [pdst++] = Iw [psrc++] ; + } + } + } + + /* move the new partially-constructed element */ + p1 = pdst ; + for (psrc = pme1 ; psrc <= pfree-1 ; psrc++) + { + Iw [pdst++] = Iw [psrc] ; + } + pme1 = p1 ; + pfree = pdst ; + pj = Pe [e] ; + p = Pe [me] ; + + } + + /* ------------------------------------------------- */ + /* i is a principal variable not yet placed in Lme */ + /* store i in new list */ + /* ------------------------------------------------- */ + + /* flag i as being in Lme by negating Nv [i] */ + degme += nvi ; + Nv [i] = -nvi ; + Iw [pfree++] = i ; + CAMD_DEBUG2 ((" s: "ID" nv "ID"\n", i, Nv [i])); + + /* ------------------------------------------------- */ + /* remove variable i from degree link list */ + /* ------------------------------------------------- */ + + if (IsInCurrentSet (C, i, curC)) + { + ilast = Last [i] ; + inext = Next [i] ; + ASSERT (ilast >= EMPTY && ilast < n) ; + ASSERT (inext >= EMPTY && inext < n) ; + if (inext != EMPTY) Last [inext] = ilast ; + if (ilast != EMPTY) + { + Next [ilast] = inext ; + } + else + { + /* i is at the head of the degree list */ + ASSERT (Degree [i] >= 0 && Degree [i] < n) ; + Head [Degree [i]] = inext ; + } + degreeListCounter-- ; + } + } + } + + if (e != me) + { + if (IsInCurrentSet (C, e, curC)) + { + /* absorb element here if in same bucket */ + /* set tree pointer and flag to indicate element e is + * absorbed into new element me (the parent of e is me) + */ + CAMD_DEBUG1 ((" Element "ID" => "ID"\n", e, me)) ; + Pe [e] = FLIP (me) ; + W [e] = 0 ; + } + else + { + /* make element a root; kill it if not in same bucket */ + CAMD_DEBUG1 (("2 Element "ID" => "ID"\n", e, me)) ; + Pe [e] = EMPTY ; + W [e] = 0 ; + } + } + } + + pme2 = pfree - 1 ; + } + + /* ----------------------------------------------------------------- */ + /* me has now been converted into an element in Iw [pme1..pme2] */ + /* ----------------------------------------------------------------- */ + + /* degme holds the external degree of new element */ + Degree [me] = degme ; + Pe [me] = pme1 ; + Len [me] = pme2 - pme1 + 1 ; + ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ; + + Elen [me] = FLIP (nvpiv + degme) ; + /* FLIP (Elen (me)) is now the degree of pivot (including + * diagonal part). */ + +#ifndef NDEBUG + CAMD_DEBUG2 (("New element structure: length= "ID"\n", pme2-pme1+1)) ; + for (pme = pme1 ; pme <= pme2 ; pme++) CAMD_DEBUG3 ((" "ID"", Iw[pme])); + CAMD_DEBUG3 (("\n")) ; +#endif + + /* ----------------------------------------------------------------- */ + /* make sure that wflg is not too large. */ + /* ----------------------------------------------------------------- */ + + /* With the current value of wflg, wflg+n must not cause integer + * overflow */ + + wflg = clear_flag (wflg, wbig, W, n) ; + +/* ========================================================================= */ +/* COMPUTE (W [e] - wflg) = |Le\Lme| FOR ALL ELEMENTS */ +/* ========================================================================= */ + + /* ----------------------------------------------------------------- + * Scan 1: compute the external degrees of previous elements with + * respect to the current element. That is: + * (W [e] - wflg) = |Le \ Lme| + * for each element e that appears in any supervariable in Lme. The + * notation Le refers to the pattern (list of supervariables) of a + * previous element e, where e is not yet absorbed, stored in + * Iw [Pe [e] + 1 ... Pe [e] + Len [e]]. The notation Lme + * refers to the pattern of the current element (stored in + * Iw [pme1..pme2]). If aggressive absorption is enabled, and + * (W [e] - wflg) becomes zero, then the element e will be absorbed + * in Scan 2. + * ----------------------------------------------------------------- */ + + CAMD_DEBUG2 (("me: ")) ; + for (pme = pme1 ; pme <= pme2 ; pme++) + { + i = Iw [pme] ; + ASSERT (i >= 0 && i < n) ; + eln = Elen [i] ; + CAMD_DEBUG3 ((""ID" Elen "ID": \n", i, eln)) ; + if (eln > 0) + { + /* note that Nv [i] has been negated to denote i in Lme: */ + nvi = -Nv [i] ; + ASSERT (nvi > 0 && Pe [i] >= 0 && Pe [i] < iwlen) ; + wnvi = wflg - nvi ; + for (p = Pe [i] ; p <= Pe [i] + eln - 1 ; p++) + { + e = Iw [p] ; + ASSERT (e >= 0 && e < n) ; + we = W [e] ; + CAMD_DEBUG4 ((" e "ID" we "ID" ", e, we)) ; + if (we >= wflg) + { + /* unabsorbed element e has been seen in this loop */ + CAMD_DEBUG4 ((" unabsorbed, first time seen")) ; + we -= nvi ; + } + else if (we != 0) + { + /* e is an unabsorbed element */ + /* this is the first we have seen e in all of Scan 1 */ + CAMD_DEBUG4 ((" unabsorbed")) ; + we = Degree [e] + wnvi ; + } + CAMD_DEBUG4 (("\n")) ; + W [e] = we ; + } + } + } + CAMD_DEBUG2 (("\n")) ; + +/* ========================================================================= */ +/* DEGREE UPDATE AND ELEMENT ABSORPTION */ +/* ========================================================================= */ + + /* ----------------------------------------------------------------- + * Scan 2: for each i in Lme, sum up the degree of Lme (which is + * degme), plus the sum of the external degrees of each Le for the + * elements e appearing within i, plus the supervariables in i. + * Place i in hash list. + * ----------------------------------------------------------------- */ + + for (pme = pme1 ; pme <= pme2 ; pme++) + { + i = Iw [pme] ; + ASSERT (i >= 0 && i < n && Nv [i] < 0 && Elen [i] >= 0) ; + CAMD_DEBUG2 (("Updating: i "ID" "ID" "ID"\n", i, Elen[i], Len [i])); + p1 = Pe [i] ; + p2 = p1 + Elen [i] - 1 ; + pn = p1 ; + hash = 0 ; + deg = 0 ; + ASSERT (p1 >= 0 && p1 < iwlen && p2 >= -1 && p2 < iwlen) ; + + /* ------------------------------------------------------------- */ + /* scan the element list associated with supervariable i */ + /* ------------------------------------------------------------- */ + + /* UMFPACK/MA38-style approximate degree: */ + if (aggressive) + { + for (p = p1 ; p <= p2 ; p++) + { + e = Iw [p] ; + ASSERT (e >= 0 && e < n) ; + we = W [e] ; + if (we != 0) + { + /* e is an unabsorbed element */ + /* dext = | Le \ Lme | */ + dext = we - wflg ; + if (dext > 0) + { + deg += dext ; + Iw [pn++] = e ; + hash += e ; + CAMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ; + } + else + { + if (IsInCurrentSet (C, e, curC)) + { + /* external degree of e is zero and if + * C[e] = curC; absorb e into me */ + CAMD_DEBUG1 ((" Element "ID" =>"ID" (aggr)\n", + e, me)) ; + ASSERT (dext == 0) ; + Pe [e] = FLIP (me) ; + W [e] = 0 ; + } + else + { + /* make element a root; kill it if not in same + * bucket */ + CAMD_DEBUG1 (("2 Element "ID" =>"ID" (aggr)\n", + e, me)) ; + ASSERT (dext == 0) ; + Pe [e] = EMPTY ; + W [e] = 0 ; + } + } + } + } + } + else + { + for (p = p1 ; p <= p2 ; p++) + { + e = Iw [p] ; + ASSERT (e >= 0 && e < n) ; + we = W [e] ; + if (we != 0) + { + /* e is an unabsorbed element */ + dext = we - wflg ; + ASSERT (dext >= 0) ; + deg += dext ; + Iw [pn++] = e ; + hash += e ; + CAMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ; + } + } + } + + /* count the number of elements in i (including me): */ + Elen [i] = pn - p1 + 1 ; + + /* ------------------------------------------------------------- */ + /* scan the supervariables in the list associated with i */ + /* ------------------------------------------------------------- */ + + /* The bulk of the CAMD run time is typically spent in this loop, + * particularly if the matrix has many dense rows that are not + * removed prior to ordering. */ + p3 = pn ; + p4 = p1 + Len [i] ; + for (p = p2 + 1 ; p < p4 ; p++) + { + j = Iw [p] ; + ASSERT (j >= 0 && j < n) ; + nvj = Nv [j] ; + if (nvj > 0) + { + /* j is unabsorbed, and not in Lme. */ + /* add to degree and add to new list */ + deg += nvj ; + Iw [pn++] = j ; + hash += j ; + CAMD_DEBUG4 ((" s: "ID" hash "ID" Nv[j]= "ID"\n", + j, hash, nvj)) ; + } + } + + /* ------------------------------------------------------------- */ + /* update the degree and check for mass elimination */ + /* ------------------------------------------------------------- */ + + /* with aggressive absorption, deg==0 is identical to the + * Elen [i] == 1 && p3 == pn test, below. */ + ASSERT (IMPLIES (aggressive, (deg==0) == (Elen[i]==1 && p3==pn))) ; + + if (Elen [i] == 1 && p3 == pn && IsInCurrentSet (C, i, curC)) + { + + /* --------------------------------------------------------- */ + /* mass elimination */ + /* --------------------------------------------------------- */ + + /* There is nothing left of this node except for an edge to + * the current pivot element. Elen [i] is 1, and there are + * no variables adjacent to node i. Absorb i into the + * current pivot element, me. Note that if there are two or + * more mass eliminations, fillin due to mass elimination is + * possible within the nvpiv-by-nvpiv pivot block. It is this + * step that causes CAMD's analysis to be an upper bound. + * + * The reason is that the selected pivot has a lower + * approximate degree than the true degree of the two mass + * eliminated nodes. There is no edge between the two mass + * eliminated nodes. They are merged with the current pivot + * anyway. + * + * No fillin occurs in the Schur complement, in any case, + * and this effect does not decrease the quality of the + * ordering itself, just the quality of the nonzero and + * flop count analysis. It also means that the post-ordering + * is not an exact elimination tree post-ordering. */ + + CAMD_DEBUG1 ((" MASS i "ID" => parent e "ID"\n", i, me)) ; + Pe [i] = FLIP (me) ; + nvi = -Nv [i] ; + degme -= nvi ; + nvpiv += nvi ; + nel += nvi ; + Nv [i] = 0 ; + Elen [i] = EMPTY ; + + } + else + { + + /* --------------------------------------------------------- */ + /* update the upper-bound degree of i */ + /* --------------------------------------------------------- */ + + /* the following degree does not yet include the size + * of the current element, which is added later: */ + + Degree [i] = MIN (Degree [i], deg) ; + + /* --------------------------------------------------------- */ + /* add me to the list for i */ + /* --------------------------------------------------------- */ + + /* move first supervariable to end of list */ + Iw [pn] = Iw [p3] ; + /* move first element to end of element part of list */ + Iw [p3] = Iw [p1] ; + /* add new element, me, to front of list. */ + Iw [p1] = me ; + /* store the new length of the list in Len [i] */ + Len [i] = pn - p1 + 1 ; + + /* --------------------------------------------------------- */ + /* place in hash bucket. Save hash key of i in Last [i]. */ + /* --------------------------------------------------------- */ + + /* NOTE: this can fail if hash is negative, because the ANSI C + * standard does not define a % b when a and/or b are negative. + * That's why hash is defined as an unsigned Int, to avoid this + * problem. */ + hash = hash % n ; + ASSERT (((Int) hash) >= 0 && ((Int) hash) < n) ; + + /* if the Hhead array is not used: */ + j = Head [hash] ; + if (j <= EMPTY) + { + /* degree list is empty, hash head is FLIP (j) */ + Next [i] = FLIP (j) ; + Head [hash] = FLIP (i) ; + } + else + { + /* degree list is not empty, use Last [Head [hash]] as + * hash head. */ + Next [i] = Last [j] ; + Last [j] = i ; + } + + /* if a separate Hhead array is used: * + Next [i] = Hhead [hash] ; + Hhead [hash] = i ; + */ + + CAMD_DEBUG4 ((" s: "ID" hash "ID" \n", i, hash)) ; + Last [i] = hash ; + } + } + + Degree [me] = degme ; + + /* ----------------------------------------------------------------- */ + /* Clear the counter array, W [...], by incrementing wflg. */ + /* ----------------------------------------------------------------- */ + + /* make sure that wflg+n does not cause integer overflow */ + lemax = MAX (lemax, degme) ; + wflg += lemax ; + wflg = clear_flag (wflg, wbig, W, n) ; + /* at this point, W [0..n-1] < wflg holds */ + +/* ========================================================================= */ +/* SUPERVARIABLE DETECTION */ +/* ========================================================================= */ + + CAMD_DEBUG1 (("Detecting supervariables:\n")) ; + for (pme = pme1 ; pme <= pme2 ; pme++) + { + i = Iw [pme] ; + ASSERT (i >= 0 && i < n) ; + CAMD_DEBUG2 (("Consider i "ID" nv "ID"\n", i, Nv [i])) ; + if (Nv [i] < 0) + { + /* i is a principal variable in Lme */ + + /* --------------------------------------------------------- + * examine all hash buckets with 2 or more variables. We do + * this by examing all unique hash keys for supervariables in + * the pattern Lme of the current element, me + * --------------------------------------------------------- */ + + CAMD_DEBUG2 (("Last: "ID"\n", Last [i])) ; + + /* let i = head of hash bucket, and empty the hash bucket */ + ASSERT (Last [i] >= 0 && Last [i] < n) ; + hash = Last [i] ; + + /* if Hhead array is not used: */ + j = Head [hash] ; + if (j == EMPTY) + { + /* hash bucket and degree list are both empty */ + i = EMPTY ; + } + else if (j < EMPTY) + { + /* degree list is empty */ + i = FLIP (j) ; + Head [hash] = EMPTY ; + } + else + { + /* degree list is not empty, restore Last [j] of head j */ + i = Last [j] ; + Last [j] = EMPTY ; + } + + /* if separate Hhead array is used: * + i = Hhead [hash] ; + Hhead [hash] = EMPTY ; + */ + + ASSERT (i >= EMPTY && i < n) ; + CAMD_DEBUG2 (("----i "ID" hash "ID"\n", i, hash)) ; + + while (i != EMPTY && Next [i] != EMPTY) + { + + /* ----------------------------------------------------- + * this bucket has one or more variables following i. + * scan all of them to see if i can absorb any entries + * that follow i in hash bucket. Scatter i into w. + * ----------------------------------------------------- */ + + ln = Len [i] ; + eln = Elen [i] ; + ASSERT (ln >= 0 && eln >= 0) ; + ASSERT (Pe [i] >= 0 && Pe [i] < iwlen) ; + /* do not flag the first element in the list (me) */ + for (p = Pe [i] + 1 ; p <= Pe [i] + ln - 1 ; p++) + { + ASSERT (Iw [p] >= 0 && Iw [p] < n) ; + W [Iw [p]] = wflg ; + } + + /* ----------------------------------------------------- */ + /* scan every other entry j following i in bucket */ + /* ----------------------------------------------------- */ + + jlast = i ; + j = Next [i] ; + ASSERT (j >= EMPTY && j < n) ; + + while (j != EMPTY) + { + /* ------------------------------------------------- */ + /* check if j and i have identical nonzero pattern */ + /* ------------------------------------------------- */ + + CAMD_DEBUG3 (("compare i "ID" and j "ID"\n", i,j)) ; + + /* check if i and j have the same Len and Elen */ + /* and are in the same bucket */ + ASSERT (Len [j] >= 0 && Elen [j] >= 0) ; + ASSERT (Pe [j] >= 0 && Pe [j] < iwlen) ; + ok = (Len [j] == ln) && (Elen [j] == eln) ; + ok = ok && InSameConstraintSet (C,i,j) ; + + /* skip the first element in the list (me) */ + for (p = Pe [j] + 1 ; ok && p <= Pe [j] + ln - 1 ; p++) + { + ASSERT (Iw [p] >= 0 && Iw [p] < n) ; + if (W [Iw [p]] != wflg) ok = 0 ; + } + if (ok) + { + /* --------------------------------------------- */ + /* found it! j can be absorbed into i */ + /* --------------------------------------------- */ + + CAMD_DEBUG1 (("found it! j "ID" => i "ID"\n", j,i)); + Pe [j] = FLIP (i) ; + /* both Nv [i] and Nv [j] are negated since they */ + /* are in Lme, and the absolute values of each */ + /* are the number of variables in i and j: */ + Nv [i] += Nv [j] ; + Nv [j] = 0 ; + Elen [j] = EMPTY ; + /* delete j from hash bucket */ + ASSERT (j != Next [j]) ; + j = Next [j] ; + Next [jlast] = j ; + + } + else + { + /* j cannot be absorbed into i */ + jlast = j ; + ASSERT (j != Next [j]) ; + j = Next [j] ; + } + ASSERT (j >= EMPTY && j < n) ; + } + + /* ----------------------------------------------------- + * no more variables can be absorbed into i + * go to next i in bucket and clear flag array + * ----------------------------------------------------- */ + + wflg++ ; + i = Next [i] ; + ASSERT (i >= EMPTY && i < n) ; + + } + } + } + CAMD_DEBUG2 (("detect done\n")) ; + +/* ========================================================================= */ +/* RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVARIABLES FROM ELEMENT */ +/* ========================================================================= */ + + p = pme1 ; + nleft = n - nel ; + for (pme = pme1 ; pme <= pme2 ; pme++) + { + i = Iw [pme] ; + ASSERT (i >= 0 && i < n) ; + nvi = -Nv [i] ; + CAMD_DEBUG3 (("Restore i "ID" "ID"\n", i, nvi)) ; + if (nvi > 0) + { + /* i is a principal variable in Lme */ + /* restore Nv [i] to signify that i is principal */ + Nv [i] = nvi ; + + /* --------------------------------------------------------- */ + /* compute the external degree (add size of current element) */ + /* --------------------------------------------------------- */ + + deg = Degree [i] + degme - nvi ; + deg = MIN (deg, nleft - nvi) ; + ASSERT (deg >= 0 && deg < n) ; + + /* --------------------------------------------------------- */ + /* place the supervariable at the head of the degree list */ + /* --------------------------------------------------------- */ + + if (IsInCurrentSet (C, i, curC)) + { + inext = Head [deg] ; + ASSERT (inext >= EMPTY && inext < n) ; + if (inext != EMPTY) Last [inext] = i ; + Next [i] = inext ; + Last [i] = EMPTY ; + Head [deg] = i ; + degreeListCounter++ ; + } + + /* --------------------------------------------------------- */ + /* save the new degree, and find the minimum degree */ + /* --------------------------------------------------------- */ + + mindeg = MIN (mindeg, deg) ; + Degree [i] = deg ; + + /* --------------------------------------------------------- */ + /* place the supervariable in the element pattern */ + /* --------------------------------------------------------- */ + + Iw [p++] = i ; + } + } + CAMD_DEBUG2 (("restore done\n")) ; + +/* ========================================================================= */ +/* FINALIZE THE NEW ELEMENT */ +/* ========================================================================= */ + + CAMD_DEBUG2 (("ME = "ID" DONE\n", me)) ; + Nv [me] = nvpiv ; + /* save the length of the list for the new element me */ + Len [me] = p - pme1 ; + if (Len [me] == 0) + { + /* there is nothing left of the current pivot element */ + /* it is a root of the assembly tree */ + Pe [me] = EMPTY ; + W [me] = 0 ; + } + if (elenme != 0) + { + /* element was not constructed in place: deallocate part of */ + /* it since newly nonprincipal variables may have been removed */ + pfree = p ; + } + + /* Store the element back into BucketSet. This is the way to maintain + * the order of roots (Pe[i]=-1) in each Constraint Set. */ + BucketSet [pBucket2++] = me ; + + /* The new element has nvpiv pivots and the size of the contribution + * block for a multifrontal method is degme-by-degme, not including + * the "dense" rows/columns. If the "dense" rows/columns are included, + * the frontal matrix is no larger than + * (degme+ndense)-by-(degme+ndense). + */ + + if (Info != (double *) NULL) + { + f = nvpiv ; + r = degme + ndense ; + dmax = MAX (dmax, f + r) ; + + /* number of nonzeros in L (excluding the diagonal) */ + lnzme = f*r + (f-1)*f/2 ; + lnz += lnzme ; + + /* number of divide operations for LDL' and for LU */ + ndiv += lnzme ; + + /* number of multiply-subtract pairs for LU */ + s = f*r*r + r*(f-1)*f + (f-1)*f*(2*f-1)/6 ; + nms_lu += s ; + + /* number of multiply-subtract pairs for LDL' */ + nms_ldl += (s + lnzme)/2 ; + } + +#ifndef NDEBUG + CAMD_DEBUG2 (("finalize done nel "ID" n "ID"\n ::::\n", nel, n)) ; + for (pme = Pe [me] ; pme <= Pe [me] + Len [me] - 1 ; pme++) + { + CAMD_DEBUG3 ((" "ID"", Iw [pme])) ; + } + CAMD_DEBUG3 (("\n")) ; +#endif + + } + +/* ========================================================================= */ +/* DONE SELECTING PIVOTS */ +/* ========================================================================= */ + + if (Info != (double *) NULL) + { + + /* count the work to factorize the ndense-by-ndense submatrix */ + f = ndense ; + dmax = MAX (dmax, (double) ndense) ; + + /* number of nonzeros in L (excluding the diagonal) */ + lnzme = (f-1)*f/2 ; + lnz += lnzme ; + + /* number of divide operations for LDL' and for LU */ + ndiv += lnzme ; + + /* number of multiply-subtract pairs for LU */ + s = (f-1)*f*(2*f-1)/6 ; + nms_lu += s ; + + /* number of multiply-subtract pairs for LDL' */ + nms_ldl += (s + lnzme)/2 ; + + /* number of nz's in L (excl. diagonal) */ + Info [CAMD_LNZ] = lnz ; + + /* number of divide ops for LU and LDL' */ + Info [CAMD_NDIV] = ndiv ; + + /* number of multiply-subtract pairs for LDL' */ + Info [CAMD_NMULTSUBS_LDL] = nms_ldl ; + + /* number of multiply-subtract pairs for LU */ + Info [CAMD_NMULTSUBS_LU] = nms_lu ; + + /* number of "dense" rows/columns */ + Info [CAMD_NDENSE] = ndense ; + + /* largest front is dmax-by-dmax */ + Info [CAMD_DMAX] = dmax ; + + /* number of garbage collections in CAMD */ + Info [CAMD_NCMPA] = ncmpa ; + + /* successful ordering */ + Info [CAMD_STATUS] = CAMD_OK ; + } + +/* ========================================================================= */ +/* POST-ORDERING */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- + * Variables at this point: + * + * Pe: holds the elimination tree. The parent of j is FLIP (Pe [j]), + * or EMPTY if j is a root. The tree holds both elements and + * non-principal (unordered) variables absorbed into them. + * Dense and empty variables are non-principal and unordered. They are + * all represented by the fictitious node n (that is, Pe [i] = FLIP (n) + * and Elen [i] = EMPTY if i is a dense or empty node). + * + * Elen: holds the size of each element, including the diagonal part. + * FLIP (Elen [e]) > 0 if e is an element. For unordered + * variables i, Elen [i] is EMPTY. + * + * Nv: Nv [e] > 0 is the number of pivots represented by the element e. + * For unordered variables i, Nv [i] is zero. + * + * BucketSet: BucketSet [0.....pBucket2] holds all + * the elements that removed during the elimination, in eliminated order. + * + * + * Contents no longer needed: + * W, Iw, Len, Degree, Head, Next, Last. + * + * The matrix itself has been destroyed. + * + * n: the size of the matrix. + * ndense: the number of "dense" nodes. + * nnull: the number of empty nodes (zero degree) + * No other scalars needed (pfree, iwlen, etc.) + * ------------------------------------------------------------------------- */ + + + /* restore Pe */ + for (i = 0 ; i < n ; i++) + { + Pe [i] = FLIP (Pe [i]) ; + } + + /* restore Elen, for output information only */ + for (i = 0 ; i < n ; i++) + { + Elen [i] = FLIP (Elen [i]) ; + } + + /* Now, Pe [j] is the parent of j, or EMPTY if j is a root. + * Pe [j] = n if j is a dense/empty node */ + + /* place all variables in the list of children of their parents */ + for (j = n-1 ; j >= 0 ; j--) + { + if (Nv [j] > 0) continue ; /* skip if j is an element */ + ASSERT (Pe [j] >= 0 && Pe [j] <= n) ; + Next [j] = Head [Pe [j]] ; /* place j in list of its parent */ + Head [Pe [j]] = j ; + } + + /* place all elements in the list of children of their parents */ + for (e = n-1 ; e >= 0 ; e--) + { + if (Nv [e] <= 0) continue ; /* skip if e is a variable */ + if (Pe [e] == EMPTY) continue ; /* skip if e is a root */ + Next [e] = Head [Pe [e]] ; /* place e in list of its parent */ + Head [Pe [e]] = e ; + } + + /* determine where to put the postordering permutation */ + if (C != NULL && ndense_or_null > 0) + { + /* Perm needs to be computed in a temporary workspace, and then + * transformed and copied into the output permutation, in Last */ + Perm = Degree ; + } + else + { + /* the postorder computes the permutation directly, in Last */ + Perm = Last ; + } + + /* postorder the elements and their descendants (both elements and + * variables), but not (yet) the dense/empty nodes */ + for (k = 0 , i = 0 ; i < pBucket2 ; i++) + { + j = BucketSet [i] ; + ASSERT (j >= 0 && j < n) ; + if (Pe [j] == EMPTY) + { + k = CAMD_postorder (j, k, n, Head, Next, Perm, W) ; + } + } + + /* Perm [0..k-1] now contains a list of the nonempty/nondense nodes, + * ordered via minimum degree and following the constraints. */ + + CAMD_DEBUG1 (("before dense/empty, k = "ID"\n", k)) ; + fflush (stdout) ; + ASSERT (k + ndense_or_null == n) ; + + if (ndense_or_null > 0) + { + if (C == NULL) + { + /* postorder the dense/empty nodes (the parent of all these is n) */ + CAMD_postorder (n, k, n, Head, Next, Perm, W) ; + } + else + { + /* dense (or empty) nodes exist, AND C also exists. The dense/empty + * nodes are a link list whose head is Head[n], and Next[i] gives the + * next node after i in the list. They need to be sorted by their + * constraints, and then merged with Perm [0..k-1].*/ + + /* count how many dense/empty nodes are in each constraint set */ + + Bucket = W ; /* use W as workspace (it has size n+1) */ + + /* count the number of dense/empty nodes in each constraint set */ + for (c = 0 ; c <= cmax ; c++) + { + Bucket [c] = 0 ; + } + i = 0 ; + for (j = Head [n] ; j != EMPTY ; j = Next [j]) + { + CAMD_DEBUG1 (("Dense/empty node: "ID" : "ID" "ID"\n", j, + Pe [j], Elen [j])) ; + fflush (stdout) ; + ASSERT (Pe [j] == n && Elen [j] == EMPTY) ; + i++ ; + Bucket [C [j]]++ ; + } + ASSERT (i == ndense_or_null) ; + + /* find the cumulative sum of Bucket */ + knt1 = 0 ; + for (c = 0 ; c <= cmax ; c++) + { + i = Bucket [c] ; + Bucket [c] = knt1 ; + knt1 += i ; + } + CAMD_DEBUG1 (("knt1 "ID" dense/empty "ID"\n", knt1, ndense_or_null)); + ASSERT (knt1 == ndense_or_null) ; + + /* place dense/empty nodes in BucketSet, in constraint order, + * ties in natural order */ + for (j = Head [n] ; j != EMPTY ; j = Next [j]) + { + BucketSet [Bucket [C [j]]++] = j ; + } + +#ifndef NDEBUG + /* each set is in monotonically increasing order of constraints */ + for (i = 1 ; i < k ; i++) + { + ASSERT (C [Perm [i]] >= C [Perm [i-1]]) ; + } + for (i = 1 ; i < ndense_or_null ; i++) + { + /* in order of constraints, with ties in natural order */ + ASSERT ( + (C [BucketSet [i]] > C [BucketSet [i-1]]) || + (C [BucketSet [i]] == C [BucketSet [i-1]] + && (BucketSet [i] > BucketSet [i-1]))) ; + } +#endif + + /* merge Perm [0..k-1] and BucketSet [0..ndense+nnull] */ + p1 = 0 ; + p2 = 0 ; + p3 = 0 ; + while (p1 < k && p2 < ndense_or_null) + { + /* place the dense/empty nodes at the end of each constraint + * set, after the non-dense/non-empty nodes in the same set */ + if (C [Perm [p1]] <= C [BucketSet [p2]]) + { + /* non-dense/non-empty node */ + Last [p3++] = Perm [p1++] ; + } + else + { + /* dense/empty node */ + Last [p3++] = BucketSet [p2++] ; + } + } + /* wrap up; either Perm[0..k-1] or BucketSet[ ] is used up */ + while (p1 < k) + { + Last [p3++] = Perm [p1++] ; + } + while (p2 < ndense_or_null) + { + Last [p3++] = BucketSet [p2++] ; + } + } + } + +#ifndef NDEBUG + CAMD_DEBUG1 (("\nFinal constrained ordering:\n")) ; + i = 0 ; + CAMD_DEBUG1 (("Last ["ID"] = "ID", C["ID"] = "ID"\n", i, Last [i], + Last [i], C [Last [i]])) ; + for (i = 1 ; i < n ; i++) + { + CAMD_DEBUG1 (("Last ["ID"] = "ID", C["ID"] = "ID"\n", i, Last [i], + Last [i], C [Last [i]])) ; + + /* This is the critical assertion. It states that the permutation + * satisfies the constraints. */ + ASSERT (C [Last [i]] >= C [Last [i-1]]) ; + } +#endif +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_aat.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_aat.c new file mode 100644 index 0000000..b385fc7 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_aat.c @@ -0,0 +1,183 @@ +/* ========================================================================= */ +/* === CAMD_aat ============================================================ */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* CAMD, Copyright (c) Timothy A. Davis, Yanqing Chen, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* CAMD_aat: compute the symmetry of the pattern of A, and count the number of + * nonzeros each column of A+A' (excluding the diagonal). Assumes the input + * matrix has no errors, with sorted columns and no duplicates + * (CAMD_valid (n, n, Ap, Ai) must be CAMD_OK, but this condition is not + * checked). + */ + +#include "camd_internal.h" + +GLOBAL size_t CAMD_aat /* returns nz in A+A' */ +( + Int n, + const Int Ap [ ], + const Int Ai [ ], + Int Len [ ], /* Len [j]: length of column j of A+A', excl diagonal*/ + Int Tp [ ], /* workspace of size n */ + double Info [ ] +) +{ + Int p1, p2, p, i, j, pj, pj2, k, nzdiag, nzboth, nz ; + double sym ; + size_t nzaat ; + +#ifndef NDEBUG + CAMD_debug_init ("CAMD AAT") ; + for (k = 0 ; k < n ; k++) Tp [k] = EMPTY ; + ASSERT (CAMD_valid (n, n, Ap, Ai) == CAMD_OK) ; +#endif + + if (Info != (double *) NULL) + { + /* clear the Info array, if it exists */ + for (i = 0 ; i < CAMD_INFO ; i++) + { + Info [i] = EMPTY ; + } + Info [CAMD_STATUS] = CAMD_OK ; + } + + for (k = 0 ; k < n ; k++) + { + Len [k] = 0 ; + } + + nzdiag = 0 ; + nzboth = 0 ; + nz = Ap [n] ; + + for (k = 0 ; k < n ; k++) + { + p1 = Ap [k] ; + p2 = Ap [k+1] ; + CAMD_DEBUG2 (("\nAAT Column: "ID" p1: "ID" p2: "ID"\n", k, p1, p2)) ; + + /* construct A+A' */ + for (p = p1 ; p < p2 ; ) + { + /* scan the upper triangular part of A */ + j = Ai [p] ; + if (j < k) + { + /* entry A (j,k) is in the strictly upper triangular part, + * add both A (j,k) and A (k,j) to the matrix A+A' */ + Len [j]++ ; + Len [k]++ ; + CAMD_DEBUG3 ((" upper ("ID","ID") ("ID","ID")\n", j,k, k,j)); + p++ ; + } + else if (j == k) + { + /* skip the diagonal */ + p++ ; + nzdiag++ ; + break ; + } + else /* j > k */ + { + /* first entry below the diagonal */ + break ; + } + /* scan lower triangular part of A, in column j until reaching + * row k. Start where last scan left off. */ + ASSERT (Tp [j] != EMPTY) ; + ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ; + pj2 = Ap [j+1] ; + for (pj = Tp [j] ; pj < pj2 ; ) + { + i = Ai [pj] ; + if (i < k) + { + /* A (i,j) is only in the lower part, not in upper. + * add both A (i,j) and A (j,i) to the matrix A+A' */ + Len [i]++ ; + Len [j]++ ; + CAMD_DEBUG3 ((" lower ("ID","ID") ("ID","ID")\n", + i,j, j,i)) ; + pj++ ; + } + else if (i == k) + { + /* entry A (k,j) in lower part and A (j,k) in upper */ + pj++ ; + nzboth++ ; + break ; + } + else /* i > k */ + { + /* consider this entry later, when k advances to i */ + break ; + } + } + Tp [j] = pj ; + } + /* Tp [k] points to the entry just below the diagonal in column k */ + Tp [k] = p ; + } + + /* clean up, for remaining mismatched entries */ + for (j = 0 ; j < n ; j++) + { + for (pj = Tp [j] ; pj < Ap [j+1] ; pj++) + { + i = Ai [pj] ; + /* A (i,j) is only in the lower part, not in upper. + * add both A (i,j) and A (j,i) to the matrix A+A' */ + Len [i]++ ; + Len [j]++ ; + CAMD_DEBUG3 ((" lower cleanup ("ID","ID") ("ID","ID")\n", + i,j, j,i)) ; + } + } + + /* --------------------------------------------------------------------- */ + /* compute the symmetry of the nonzero pattern of A */ + /* --------------------------------------------------------------------- */ + + /* Given a matrix A, the symmetry of A is: + * B = tril (spones (A), -1) + triu (spones (A), 1) ; + * sym = nnz (B & B') / nnz (B) ; + * or 1 if nnz (B) is zero. + */ + + if (nz == nzdiag) + { + sym = 1 ; + } + else + { + sym = (2 * (double) nzboth) / ((double) (nz - nzdiag)) ; + } + + nzaat = 0 ; + for (k = 0 ; k < n ; k++) + { + nzaat += Len [k] ; + } + CAMD_DEBUG1 (("CAMD nz in A+A', excluding diagonal (nzaat) = %g\n", + (double) nzaat)) ; + CAMD_DEBUG1 ((" nzboth: "ID" nz: "ID" nzdiag: "ID" symmetry: %g\n", + nzboth, nz, nzdiag, sym)) ; + + if (Info != (double *) NULL) + { + Info [CAMD_STATUS] = CAMD_OK ; + Info [CAMD_N] = n ; + Info [CAMD_NZ] = nz ; + Info [CAMD_SYMMETRY] = sym ; /* symmetry of pattern of A */ + Info [CAMD_NZDIAG] = nzdiag ; /* nonzeros on diagonal of A */ + Info [CAMD_NZ_A_PLUS_AT] = nzaat ; /* nonzeros in A+A' */ + } + + return (nzaat) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_control.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_control.c new file mode 100644 index 0000000..c1c5754 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_control.c @@ -0,0 +1,64 @@ +/* ========================================================================= */ +/* === CAMD_control ======================================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* CAMD, Copyright (c) Timothy A. Davis, Yanqing Chen, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* User-callable. Prints the control parameters for CAMD. See camd.h + * for details. If the Control array is not present, the defaults are + * printed instead. + */ + +#include "camd_internal.h" + +GLOBAL void CAMD_control +( + double Control [ ] +) +{ + double alpha ; + Int aggressive ; + + if (Control != (double *) NULL) + { + alpha = Control [CAMD_DENSE] ; + aggressive = Control [CAMD_AGGRESSIVE] != 0 ; + } + else + { + alpha = CAMD_DEFAULT_DENSE ; + aggressive = CAMD_DEFAULT_AGGRESSIVE ; + } + + SUITESPARSE_PRINTF (( + "\ncamd version %d.%d, %s: approximate minimum degree ordering:\n" + " dense row parameter: %g\n", CAMD_MAIN_VERSION, CAMD_SUB_VERSION, + CAMD_DATE, alpha)) ; + + if (alpha < 0) + { + SUITESPARSE_PRINTF ((" no rows treated as dense\n")) ; + } + else + { + SUITESPARSE_PRINTF (( + " (rows with more than max (%g * sqrt (n), 16) entries are\n" + " considered \"dense\", and placed last in output permutation)\n", + alpha)) ; + } + + if (aggressive) + { + SUITESPARSE_PRINTF ((" aggressive absorption: yes\n")) ; + } + else + { + SUITESPARSE_PRINTF ((" aggressive absorption: no\n")) ; + } + + SUITESPARSE_PRINTF ((" size of CAMD integer: %d\n\n", sizeof (Int))) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_defaults.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_defaults.c new file mode 100644 index 0000000..5ac59bf --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_defaults.c @@ -0,0 +1,36 @@ +/* ========================================================================= */ +/* === CAMD_defaults ======================================================= */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* CAMD, Copyright (c) Timothy A. Davis, Yanqing Chen, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* User-callable. Sets default control parameters for CAMD. See camd.h + * for details. + */ + +#include "camd_internal.h" + +/* ========================================================================= */ +/* === CAMD defaults ======================================================= */ +/* ========================================================================= */ + +GLOBAL void CAMD_defaults +( + double Control [ ] +) +{ + Int i ; + if (Control != (double *) NULL) + { + for (i = 0 ; i < CAMD_CONTROL ; i++) + { + Control [i] = 0 ; + } + Control [CAMD_DENSE] = CAMD_DEFAULT_DENSE ; + Control [CAMD_AGGRESSIVE] = CAMD_DEFAULT_AGGRESSIVE ; + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_dump.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_dump.c new file mode 100644 index 0000000..6b0b495 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_dump.c @@ -0,0 +1,189 @@ +/* ========================================================================= */ +/* === CAMD_dump =========================================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* CAMD, Copyright (c) Timothy A. Davis, Yanqing Chen, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* Debugging routines for CAMD. Not used if NDEBUG is not defined at compile- + * time (the default). See comments in camd_internal.h on how to enable + * debugging. Not user-callable. + */ + +#include "camd_internal.h" + +#ifndef NDEBUG + +/* This global variable is present only when debugging */ +GLOBAL Int CAMD_debug = -999 ; /* default is no debug printing */ + +/* ========================================================================= */ +/* === CAMD_debug_init ===================================================== */ +/* ========================================================================= */ + +/* Sets the debug print level, by reading the file debug.camd (if it exists) */ + +GLOBAL void CAMD_debug_init ( char *s ) +{ + FILE *f ; + f = fopen ("debug.camd", "r") ; + if (f == (FILE *) NULL) + { + CAMD_debug = -999 ; + } + else + { + fscanf (f, ID, &CAMD_debug) ; + fclose (f) ; + } + if (CAMD_debug >= 0) + { + printf ("%s: CAMD_debug_init, D= "ID"\n", s, CAMD_debug) ; + } +} + +/* ========================================================================= */ +/* === CAMD_dump =========================================================== */ +/* ========================================================================= */ + +/* Dump CAMD's data structure, except for the hash buckets. This routine + * cannot be called when the hash buckets are non-empty. + */ + +GLOBAL void CAMD_dump ( + Int n, /* A is n-by-n */ + Int Pe [ ], /* pe [0..n-1]: index in iw of start of row i */ + Int Iw [ ], /* workspace of size iwlen, iwlen [0..pfree-1] + * holds the matrix on input */ + Int Len [ ], /* len [0..n-1]: length for row i */ + Int iwlen, /* length of iw */ + Int pfree, /* iw [pfree ... iwlen-1] is empty on input */ + Int Nv [ ], /* nv [0..n-1] */ + Int Next [ ], /* next [0..n-1] */ + Int Last [ ], /* last [0..n-1] */ + Int Head [ ], /* head [0..n-1] */ + Int Elen [ ], /* size n */ + Int Degree [ ], /* size n */ + Int W [ ], /* size n */ + Int nel, + Int BucketSet [ ], + const Int C [ ], + Int CurC +) +{ + Int i, pe, elen, nv, len, e, p, k, j, deg, w, cnt, ilast ; + + if (CAMD_debug < 0) return ; + ASSERT (pfree <= iwlen) ; + CAMD_DEBUG3 (("\nCAMD dump, pfree: "ID"\n", pfree)) ; + for (i = 0 ; i < n ; i++) + { + pe = Pe [i] ; + elen = Elen [i] ; + nv = Nv [i] ; + len = Len [i] ; + w = W [i] ; + + if (elen >= EMPTY) + { + if (nv == 0) + { + CAMD_DEBUG4 (("\nI "ID": nonprincipal: ", i)) ; + ASSERT (elen == EMPTY) ; + if (pe == FLIP(n)) + { + CAMD_DEBUG4 ((" dense node\n")) ; + ASSERT (w == 1) ; + } + else + { + ASSERT (pe < EMPTY) ; + CAMD_DEBUG4 ((" i "ID" -> parent "ID"\n", i, FLIP (Pe[i]))); + } + } + else + { + CAMD_DEBUG4 (("\nI "ID": active principal supervariable:\n",i)); + CAMD_DEBUG4 ((" nv(i): "ID" Flag: %d\n", nv, (nv < 0))) ; + ASSERT (elen >= 0) ; + ASSERT (nv > 0 && pe >= 0) ; + p = pe ; + CAMD_DEBUG4 ((" e/s: ")) ; + if (elen == 0) CAMD_DEBUG4 ((" : ")) ; + ASSERT (pe + len <= pfree) ; + for (k = 0 ; k < len ; k++) + { + j = Iw [p] ; + CAMD_DEBUG4 ((" "ID"", j)) ; + ASSERT (j >= 0 && j < n) ; + if (k == elen-1) CAMD_DEBUG4 ((" : ")) ; + p++ ; + } + CAMD_DEBUG4 (("\n")) ; + } + } + else + { + e = i ; + if (w == 0) + { + CAMD_DEBUG4 (("\nE "ID": absorbed element: w "ID"\n", e, w)) ; + ASSERT (nv > 0 && pe < 0) ; + CAMD_DEBUG4 ((" e "ID" -> parent "ID"\n", e, FLIP (Pe [e]))) ; + } + else + { + CAMD_DEBUG4 (("\nE "ID": unabsorbed element: w "ID"\n", e, w)) ; + ASSERT (nv > 0 && pe >= 0) ; + p = pe ; + CAMD_DEBUG4 ((" : ")) ; + ASSERT (pe + len <= pfree) ; + for (k = 0 ; k < len ; k++) + { + j = Iw [p] ; + CAMD_DEBUG4 ((" "ID"", j)) ; + ASSERT (j >= 0 && j < n) ; + p++ ; + } + CAMD_DEBUG4 (("\n")) ; + } + } + CAMD_DEBUG4 (("C[i] is :"ID"\n", (C == NULL) ? 0 : C [i])); + } + + /* this routine cannot be called when the hash buckets are non-empty */ + CAMD_DEBUG4 (("\nDegree lists:\n")) ; + if (nel >= 0) + { + cnt = 0 ; + for (deg = 0 ; deg < n ; deg++) + { + if (Head [deg] == EMPTY) continue ; + ilast = EMPTY ; + CAMD_DEBUG4 ((ID": \n", deg)) ; + for (i = Head [deg] ; i != EMPTY ; i = Next [i]) + { + CAMD_DEBUG4 ((" "ID" : next "ID" last "ID" deg "ID"\n", + i, Next [i], Last [i], Degree [i])) ; + ASSERT (i >= 0 && i < n && ilast == Last [i] && + deg == Degree [i]) ; + cnt += Nv [i] ; + ilast = i ; + } + CAMD_DEBUG4 (("\n")) ; + } + } + + CAMD_DEBUG4(("\nCurrent C[i] is "ID". current Buckets are:\n", CurC)) ; + for (i = 0 ; i < n ; i++) + { + if ((C == NULL) ? 1 : (C [BucketSet [i]] <= CurC)) + CAMD_DEBUG4((ID",",BucketSet [i])); + } + CAMD_DEBUG4 (("\n")) ; +} + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_global.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_global.c new file mode 100644 index 0000000..eef93ee --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_global.c @@ -0,0 +1,14 @@ +/* ========================================================================= */ +/* === camd_global ========================================================= */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* CAMD, Copyright (c) Timothy A. Davis, Yanqing Chen, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* In prior versions of CAMD, this file declared the camd_malloc, camd_free, + camd_realloc, camd_calloc, and camd_printf functions. They are now replaced + by functions defined in SuiteSparse_config/SuiteSparse_config.c. + */ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_info.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_info.c new file mode 100644 index 0000000..96547e6 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_info.c @@ -0,0 +1,119 @@ +/* ========================================================================= */ +/* === CAMD_info =========================================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* CAMD, Copyright (c) Timothy A. Davis, Yanqing Chen, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* User-callable. Prints the output statistics for CAMD. See camd.h + * for details. If the Info array is not present, nothing is printed. + */ + +#include "camd_internal.h" + +#define PRI(format,x) { if (x >= 0) { SUITESPARSE_PRINTF ((format, x)) ; }} + +GLOBAL void CAMD_info +( + double Info [ ] +) +{ + double n, ndiv, nmultsubs_ldl, nmultsubs_lu, lnz, lnzd ; + + SUITESPARSE_PRINTF (("\nCAMD version %d.%d.%d, %s, results:\n", + CAMD_MAIN_VERSION, CAMD_SUB_VERSION, CAMD_SUBSUB_VERSION, CAMD_DATE)) ; + + if (!Info) + { + return ; + } + + n = Info [CAMD_N] ; + ndiv = Info [CAMD_NDIV] ; + nmultsubs_ldl = Info [CAMD_NMULTSUBS_LDL] ; + nmultsubs_lu = Info [CAMD_NMULTSUBS_LU] ; + lnz = Info [CAMD_LNZ] ; + lnzd = (n >= 0 && lnz >= 0) ? (n + lnz) : (-1) ; + + /* CAMD return status */ + SUITESPARSE_PRINTF ((" status: ")) ; + if (Info [CAMD_STATUS] == CAMD_OK) + { + SUITESPARSE_PRINTF (("OK\n")) ; + } + else if (Info [CAMD_STATUS] == CAMD_OUT_OF_MEMORY) + { + SUITESPARSE_PRINTF (("out of memory\n")) ; + } + else if (Info [CAMD_STATUS] == CAMD_INVALID) + { + SUITESPARSE_PRINTF (("invalid matrix\n")) ; + } + else if (Info [CAMD_STATUS] == CAMD_OK_BUT_JUMBLED) + { + SUITESPARSE_PRINTF (("OK, but jumbled\n")) ; + } + else + { + SUITESPARSE_PRINTF (("unknown\n")) ; + } + + /* statistics about the input matrix */ + PRI (" n, dimension of A: %.20g\n", n); + PRI (" nz, number of nonzeros in A: %.20g\n", + Info [CAMD_NZ]) ; + PRI (" symmetry of A: %.4f\n", + Info [CAMD_SYMMETRY]) ; + PRI (" number of nonzeros on diagonal: %.20g\n", + Info [CAMD_NZDIAG]) ; + PRI (" nonzeros in pattern of A+A' (excl. diagonal): %.20g\n", + Info [CAMD_NZ_A_PLUS_AT]) ; + PRI (" # dense rows/columns of A+A': %.20g\n", + Info [CAMD_NDENSE]) ; + + /* statistics about CAMD's behavior */ + PRI (" memory used, in bytes: %.20g\n", + Info [CAMD_MEMORY]) ; + PRI (" # of memory compactions: %.20g\n", + Info [CAMD_NCMPA]) ; + + /* statistics about the ordering quality */ + SUITESPARSE_PRINTF (("\n" + " The following approximate statistics are for a subsequent\n" + " factorization of A(P,P) + A(P,P)'. They are slight upper\n" + " bounds if there are no dense rows/columns in A+A', and become\n" + " looser if dense rows/columns exist.\n\n")) ; + + PRI (" nonzeros in L (excluding diagonal): %.20g\n", + lnz) ; + PRI (" nonzeros in L (including diagonal): %.20g\n", + lnzd) ; + PRI (" # divide operations for LDL' or LU: %.20g\n", + ndiv) ; + PRI (" # multiply-subtract operations for LDL': %.20g\n", + nmultsubs_ldl) ; + PRI (" # multiply-subtract operations for LU: %.20g\n", + nmultsubs_lu) ; + PRI (" max nz. in any column of L (incl. diagonal): %.20g\n", + Info [CAMD_DMAX]) ; + + /* total flop counts for various factorizations */ + + if (n >= 0 && ndiv >= 0 && nmultsubs_ldl >= 0 && nmultsubs_lu >= 0) + { + SUITESPARSE_PRINTF (("\n" + " chol flop count for real A, sqrt counted as 1 flop: %.20g\n" + " LDL' flop count for real A: %.20g\n" + " LDL' flop count for complex A: %.20g\n" + " LU flop count for real A (with no pivoting): %.20g\n" + " LU flop count for complex A (with no pivoting): %.20g\n\n", + n + ndiv + 2*nmultsubs_ldl, + ndiv + 2*nmultsubs_ldl, + 9*ndiv + 8*nmultsubs_ldl, + ndiv + 2*nmultsubs_lu, + 9*ndiv + 8*nmultsubs_lu)) ; + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_order.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_order.c new file mode 100644 index 0000000..67eb1fd --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_order.c @@ -0,0 +1,200 @@ +/* ========================================================================= */ +/* === CAMD_order ========================================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* CAMD, Copyright (c) Timothy A. Davis, Yanqing Chen, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* User-callable CAMD minimum degree ordering routine. See camd.h for + * documentation. + */ + +#include "camd_internal.h" + +/* ========================================================================= */ +/* === CAMD_order ========================================================== */ +/* ========================================================================= */ + +GLOBAL Int CAMD_order +( + Int n, + const Int Ap [ ], + const Int Ai [ ], + Int P [ ], + double Control [ ], + double Info [ ], + const Int C [ ] +) +{ + Int *Len, *S, nz, i, *Pinv, info, status, *Rp, *Ri, *Cp, *Ci, ok ; + size_t nzaat, slen ; + double mem = 0 ; + +#ifndef NDEBUG + CAMD_debug_init ("camd") ; +#endif + + /* clear the Info array, if it exists */ + info = Info != (double *) NULL ; + if (info) + { + for (i = 0 ; i < CAMD_INFO ; i++) + { + Info [i] = EMPTY ; + } + Info [CAMD_N] = n ; + Info [CAMD_STATUS] = CAMD_OK ; + } + + /* make sure inputs exist and n is >= 0 */ + if (Ai == (Int *) NULL || Ap == (Int *) NULL || P == (Int *) NULL || n < 0) + { + if (info) Info [CAMD_STATUS] = CAMD_INVALID ; + return (CAMD_INVALID) ; /* arguments are invalid */ + } + + if (n == 0) + { + return (CAMD_OK) ; /* n is 0 so there's nothing to do */ + } + + nz = Ap [n] ; + if (info) + { + Info [CAMD_NZ] = nz ; + } + if (nz < 0) + { + if (info) Info [CAMD_STATUS] = CAMD_INVALID ; + return (CAMD_INVALID) ; + } + + /* check if n or nz will cause size_t overflow */ + if ((size_t) n >= SIZE_T_MAX / sizeof (Int) + || (size_t) nz >= SIZE_T_MAX / sizeof (Int)) + { + if (info) Info [CAMD_STATUS] = CAMD_OUT_OF_MEMORY ; + return (CAMD_OUT_OF_MEMORY) ; /* problem too large */ + } + + /* check the input matrix: CAMD_OK, CAMD_INVALID, or CAMD_OK_BUT_JUMBLED */ + status = CAMD_valid (n, n, Ap, Ai) ; + + if (status == CAMD_INVALID) + { + if (info) Info [CAMD_STATUS] = CAMD_INVALID ; + return (CAMD_INVALID) ; /* matrix is invalid */ + } + + /* allocate two size-n integer workspaces */ + Len = SuiteSparse_malloc (n, sizeof (Int)) ; + Pinv = SuiteSparse_malloc (n, sizeof (Int)) ; + mem += n ; + mem += n ; + if (!Len || !Pinv) + { + /* :: out of memory :: */ + SuiteSparse_free (Len) ; + SuiteSparse_free (Pinv) ; + if (info) Info [CAMD_STATUS] = CAMD_OUT_OF_MEMORY ; + return (CAMD_OUT_OF_MEMORY) ; + } + + if (status == CAMD_OK_BUT_JUMBLED) + { + /* sort the input matrix and remove duplicate entries */ + CAMD_DEBUG1 (("Matrix is jumbled\n")) ; + Rp = SuiteSparse_malloc (n+1, sizeof (Int)) ; + Ri = SuiteSparse_malloc (nz, sizeof (Int)) ; + mem += (n+1) ; + mem += MAX (nz,1) ; + if (!Rp || !Ri) + { + /* :: out of memory :: */ + SuiteSparse_free (Rp) ; + SuiteSparse_free (Ri) ; + SuiteSparse_free (Len) ; + SuiteSparse_free (Pinv) ; + if (info) Info [CAMD_STATUS] = CAMD_OUT_OF_MEMORY ; + return (CAMD_OUT_OF_MEMORY) ; + } + /* use Len and Pinv as workspace to create R = A' */ + CAMD_preprocess (n, Ap, Ai, Rp, Ri, Len, Pinv) ; + Cp = Rp ; + Ci = Ri ; + } + else + { + /* order the input matrix as-is. No need to compute R = A' first */ + Rp = NULL ; + Ri = NULL ; + Cp = (Int *) Ap ; + Ci = (Int *) Ai ; + } + + /* --------------------------------------------------------------------- */ + /* determine the symmetry and count off-diagonal nonzeros in A+A' */ + /* --------------------------------------------------------------------- */ + + nzaat = CAMD_aat (n, Cp, Ci, Len, P, Info) ; + CAMD_DEBUG1 (("nzaat: %g\n", (double) nzaat)) ; + ASSERT ((MAX (nz-n, 0) <= nzaat) && (nzaat <= 2 * (size_t) nz)) ; + + /* --------------------------------------------------------------------- */ + /* allocate workspace for matrix, elbow room, and 7 size-n vectors */ + /* --------------------------------------------------------------------- */ + + S = NULL ; + slen = nzaat ; /* space for matrix */ + ok = ((slen + nzaat/5) >= slen) ; /* check for size_t overflow */ + slen += nzaat/5 ; /* add elbow room */ + for (i = 0 ; ok && i < 8 ; i++) + { + ok = ((slen + n+1) > slen) ; /* check for size_t overflow */ + slen += (n+1) ; /* size-n elbow room, 7 size-(n+1) workspace */ + } + mem += slen ; + ok = ok && (slen < SIZE_T_MAX / sizeof (Int)) ; /* check for overflow */ + ok = ok && (slen < Int_MAX) ; /* S[i] for Int i must be OK */ + if (ok) + { + S = SuiteSparse_malloc (slen, sizeof (Int)) ; + } + CAMD_DEBUG1 (("slen %g\n", (double) slen)) ; + if (!S) + { + /* :: out of memory :: (or problem too large) */ + SuiteSparse_free (Rp) ; + SuiteSparse_free (Ri) ; + SuiteSparse_free (Len) ; + SuiteSparse_free (Pinv) ; + if (info) Info [CAMD_STATUS] = CAMD_OUT_OF_MEMORY ; + return (CAMD_OUT_OF_MEMORY) ; + } + if (info) + { + /* memory usage, in bytes. */ + Info [CAMD_MEMORY] = mem * sizeof (Int) ; + } + + /* --------------------------------------------------------------------- */ + /* order the matrix */ + /* --------------------------------------------------------------------- */ + + CAMD_1 (n, Cp, Ci, P, Pinv, Len, slen, S, Control, Info, C) ; + + /* --------------------------------------------------------------------- */ + /* free the workspace */ + /* --------------------------------------------------------------------- */ + + SuiteSparse_free (Rp) ; + SuiteSparse_free (Ri) ; + SuiteSparse_free (Len) ; + SuiteSparse_free (Pinv) ; + SuiteSparse_free (S) ; + if (info) Info [CAMD_STATUS] = status ; + return (status) ; /* successful ordering */ +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_postorder.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_postorder.c new file mode 100644 index 0000000..4af03e1 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_postorder.c @@ -0,0 +1,50 @@ +/* ========================================================================= */ +/* === CAMD_postorder ====================================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* CAMD, Copyright (c) Timothy A. Davis, Yanqing Chen, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* Perform a postordering (via depth-first search) of an assembly tree. */ + +#include "camd_internal.h" + +GLOBAL Int CAMD_postorder +( + Int j, /* start at node j, a root of the assembly tree */ + Int k, /* on input, next node is the kth node */ + Int n, /* normal nodes 0 to n-1, place-holder node n */ + Int head [], /* head of link list of children of each node */ + Int next [], /* next[i] is the next child after i in link list */ + Int post [], /* postordering, post [k] = p if p is the kth node */ + Int stack [] /* recursion stack */ +) +{ + int i, p, top = 0 ; + stack [0] = j ; /* place j on the stack, maybe place-holder node n */ + while (top >= 0) /* while (stack is not empty) */ + { + p = stack [top] ; /* p = top of stack */ + i = head [p] ; /* i = youngest child of p */ + if (i == -1) + { + top-- ; /* p has no unordered children left */ + if (p != n) + { + /* node p is the kth postordered node. Do not postorder the + * place-holder node n, which is the root of a subtree + * containing all dense and empty nodes. */ + post [k++] = p ; + } + } + else + { + head [p] = next [i] ; /* remove i from children of p */ + stack [++top] = i ; /* start dfs on child node i */ + } + } + return (k) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_preprocess.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_preprocess.c new file mode 100644 index 0000000..aa399c3 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_preprocess.c @@ -0,0 +1,118 @@ +/* ========================================================================= */ +/* === CAMD_preprocess ===================================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* CAMD, Copyright (c) Timothy A. Davis, Yanqing Chen, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* Sorts, removes duplicate entries, and transposes from the nonzero pattern of + * a column-form matrix A, to obtain the matrix R. The input matrix can have + * duplicate entries and/or unsorted columns (CAMD_valid (n,Ap,Ai) must not be + * CAMD_INVALID). + * + * This input condition is NOT checked. This routine is not user-callable. + */ + +#include "camd_internal.h" + +/* ========================================================================= */ +/* === CAMD_preprocess ===================================================== */ +/* ========================================================================= */ + +/* CAMD_preprocess does not check its input for errors or allocate workspace. + * On input, the condition (CAMD_valid (n,n,Ap,Ai) != CAMD_INVALID) must hold. + */ + +GLOBAL void CAMD_preprocess +( + Int n, /* input matrix: A is n-by-n */ + const Int Ap [ ], /* size n+1 */ + const Int Ai [ ], /* size nz = Ap [n] */ + + /* output matrix R: */ + Int Rp [ ], /* size n+1 */ + Int Ri [ ], /* size nz (or less, if duplicates present) */ + + Int W [ ], /* workspace of size n */ + Int Flag [ ] /* workspace of size n */ +) +{ + + /* --------------------------------------------------------------------- */ + /* local variables */ + /* --------------------------------------------------------------------- */ + + Int i, j, p, p2 ; + + ASSERT (CAMD_valid (n, n, Ap, Ai) != CAMD_INVALID) ; + + /* --------------------------------------------------------------------- */ + /* count the entries in each row of A (excluding duplicates) */ + /* --------------------------------------------------------------------- */ + + for (i = 0 ; i < n ; i++) + { + W [i] = 0 ; /* # of nonzeros in row i (excl duplicates) */ + Flag [i] = EMPTY ; /* Flag [i] = j if i appears in column j */ + } + for (j = 0 ; j < n ; j++) + { + p2 = Ap [j+1] ; + for (p = Ap [j] ; p < p2 ; p++) + { + i = Ai [p] ; + if (Flag [i] != j) + { + /* row index i has not yet appeared in column j */ + W [i]++ ; /* one more entry in row i */ + Flag [i] = j ; /* flag row index i as appearing in col j*/ + } + } + } + + /* --------------------------------------------------------------------- */ + /* compute the row pointers for R */ + /* --------------------------------------------------------------------- */ + + Rp [0] = 0 ; + for (i = 0 ; i < n ; i++) + { + Rp [i+1] = Rp [i] + W [i] ; + } + for (i = 0 ; i < n ; i++) + { + W [i] = Rp [i] ; + Flag [i] = EMPTY ; + } + + /* --------------------------------------------------------------------- */ + /* construct the row form matrix R */ + /* --------------------------------------------------------------------- */ + + /* R = row form of pattern of A */ + for (j = 0 ; j < n ; j++) + { + p2 = Ap [j+1] ; + for (p = Ap [j] ; p < p2 ; p++) + { + i = Ai [p] ; + if (Flag [i] != j) + { + /* row index i has not yet appeared in column j */ + Ri [W [i]++] = j ; /* put col j in row i */ + Flag [i] = j ; /* flag row index i as appearing in col j*/ + } + } + } + +#ifndef NDEBUG + ASSERT (CAMD_valid (n, n, Rp, Ri) == CAMD_OK) ; + for (j = 0 ; j < n ; j++) + { + ASSERT (W [j] == Rp [j+1]) ; + } +#endif +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_valid.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_valid.c new file mode 100644 index 0000000..a1da203 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/CAMD/Source/camd_valid.c @@ -0,0 +1,112 @@ +/* ========================================================================= */ +/* === CAMD_valid ========================================================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* CAMD, Copyright (c) Timothy A. Davis, Yanqing Chen, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* Check if a column-form matrix is valid or not. The matrix A is + * n_row-by-n_col. The row indices of entries in column j are in + * Ai [Ap [j] ... Ap [j+1]-1]. Required conditions are: + * + * n_row >= 0 + * n_col >= 0 + * nz = Ap [n_col] >= 0 number of entries in the matrix + * Ap [0] == 0 + * Ap [j] <= Ap [j+1] for all j in the range 0 to n_col. + * Ai [0 ... nz-1] must be in the range 0 to n_row-1. + * + * If any of the above conditions hold, CAMD_INVALID is returned. If the + * following condition holds, CAMD_OK_BUT_JUMBLED is returned (a warning, + * not an error): + * + * row indices in Ai [Ap [j] ... Ap [j+1]-1] are not sorted in ascending + * order, and/or duplicate entries exist. + * + * Otherwise, CAMD_OK is returned. + */ + +#include "camd_internal.h" + +GLOBAL Int CAMD_valid +( + /* inputs, not modified on output: */ + Int n_row, /* A is n_row-by-n_col */ + Int n_col, + const Int Ap [ ], /* column pointers of A, of size n_col+1 */ + const Int Ai [ ] /* row indices of A, of size nz = Ap [n_col] */ +) +{ + Int nz, j, p1, p2, ilast, i, p, result = CAMD_OK ; + if (n_row < 0 || n_col < 0 || Ap == NULL || Ai == NULL) + { + return (CAMD_INVALID) ; + } + nz = Ap [n_col] ; + if (Ap [0] != 0 || nz < 0) + { + /* column pointers must start at Ap [0] = 0, and Ap [n] must be >= 0 */ + CAMD_DEBUG0 (("column 0 pointer bad or nz < 0\n")) ; + return (CAMD_INVALID) ; + } + for (j = 0 ; j < n_col ; j++) + { + p1 = Ap [j] ; + p2 = Ap [j+1] ; + CAMD_DEBUG2 (("\nColumn: "ID" p1: "ID" p2: "ID"\n", j, p1, p2)) ; + if (p1 > p2) + { + /* column pointers must be ascending */ + CAMD_DEBUG0 (("column "ID" pointer bad\n", j)) ; + return (CAMD_INVALID) ; + } + ilast = EMPTY ; + for (p = p1 ; p < p2 ; p++) + { + i = Ai [p] ; + CAMD_DEBUG3 (("row: "ID"\n", i)) ; + if (i < 0 || i >= n_row) + { + /* row index out of range */ + CAMD_DEBUG0 (("index out of range, col "ID" row "ID"\n", j, i)); + return (CAMD_INVALID) ; + } + if (i <= ilast) + { + /* row index unsorted, or duplicate entry present */ + CAMD_DEBUG1 (("index unsorted/dupl col "ID" row "ID"\n", j, i)); + result = CAMD_OK_BUT_JUMBLED ; + } + ilast = i ; + } + } + return (result) ; +} + + +GLOBAL Int CAMD_cvalid /* return TRUE if the Constraint set is valid, + * FALSE otherwise */ +( + /* inputs, not modified on output: */ + Int n, /* the length of constraint set */ + const Int C [ ] /* constraint set */ +) +{ + Int i ; + if (C != NULL) + { + for (i = 0 ; i < n ; i++) + { + if (C [i] < 0 || C [i] > n - 1) + { + CAMD_DEBUG0 (("C["ID"] = "ID" invalid\n", i, C [i])) ; + return (FALSE) ; + } + } + } + return (TRUE) ; +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/Demo/colamd_example.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/Demo/colamd_example.c new file mode 100644 index 0000000..02fa369 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/Demo/colamd_example.c @@ -0,0 +1,178 @@ +/* ========================================================================== */ +/* === colamd and symamd example ============================================ */ +/* ========================================================================== */ + +/* COLAMD / SYMAMD example + + colamd example of use, to order the columns of a 5-by-4 matrix with + 11 nonzero entries in the following nonzero pattern, with default knobs. + + x 0 x 0 + x 0 x x + 0 x x 0 + 0 0 x x + x x 0 0 + + symamd example of use, to order the rows and columns of a 5-by-5 + matrix with 13 nonzero entries in the following nonzero pattern, + with default knobs. + + x x 0 0 0 + x x x x 0 + 0 x x 0 0 + 0 x 0 x x + 0 0 0 x x + + (where x denotes a nonzero value). +*/ + +/* ========================================================================== */ + +#include <stdio.h> +#include "colamd.h" + +#define A_NNZ 11 +#define A_NROW 5 +#define A_NCOL 4 +#define ALEN 150 + +#define B_NNZ 4 +#define B_N 5 + +int main (void) +{ + + /* ====================================================================== */ + /* input matrix A definition */ + /* ====================================================================== */ + + int A [ALEN] = { + + 0, 1, 4, /* row indices of nonzeros in column 0 */ + 2, 4, /* row indices of nonzeros in column 1 */ + 0, 1, 2, 3, /* row indices of nonzeros in column 2 */ + 1, 3} ; /* row indices of nonzeros in column 3 */ + + int p [ ] = { + + 0, /* column 0 is in A [0..2] */ + 3, /* column 1 is in A [3..4] */ + 5, /* column 2 is in A [5..8] */ + 9, /* column 3 is in A [9..10] */ + A_NNZ} ; /* number of nonzeros in A */ + + /* ====================================================================== */ + /* input matrix B definition */ + /* ====================================================================== */ + + int B [ ] = { /* Note: only strictly lower triangular part */ + /* is included, since symamd ignores the */ + /* diagonal and upper triangular part of B. */ + + 1, /* row indices of nonzeros in column 0 */ + 2, 3, /* row indices of nonzeros in column 1 */ + /* row indices of nonzeros in column 2 (none) */ + 4 /* row indices of nonzeros in column 3 */ + } ; /* row indices of nonzeros in column 4 (none) */ + + int q [ ] = { + + 0, /* column 0 is in B [0] */ + 1, /* column 1 is in B [1..2] */ + 3, /* column 2 is empty */ + 3, /* column 3 is in B [3] */ + 4, /* column 4 is empty */ + B_NNZ} ; /* number of nonzeros in strictly lower B */ + + /* ====================================================================== */ + /* other variable definitions */ + /* ====================================================================== */ + + int perm [B_N+1] ; /* note the size is N+1 */ + int stats [COLAMD_STATS] ; /* for colamd and symamd output statistics */ + + int row, col, pp, length, ok ; + + /* ====================================================================== */ + /* dump the input matrix A */ + /* ====================================================================== */ + + printf ("colamd %d-by-%d input matrix:\n", A_NROW, A_NCOL) ; + for (col = 0 ; col < A_NCOL ; col++) + { + length = p [col+1] - p [col] ; + printf ("Column %d, with %d entries:\n", col, length) ; + for (pp = p [col] ; pp < p [col+1] ; pp++) + { + row = A [pp] ; + printf (" row %d\n", row) ; + } + } + + /* ====================================================================== */ + /* order the matrix. Note that this destroys A and overwrites p */ + /* ====================================================================== */ + + ok = colamd (A_NROW, A_NCOL, ALEN, A, p, (double *) NULL, stats) ; + colamd_report (stats) ; + + if (!ok) + { + printf ("colamd error!\n") ; + exit (1) ; + } + + /* ====================================================================== */ + /* print the column ordering */ + /* ====================================================================== */ + + printf ("colamd column ordering:\n") ; + printf ("1st column: %d\n", p [0]) ; + printf ("2nd column: %d\n", p [1]) ; + printf ("3rd column: %d\n", p [2]) ; + printf ("4th column: %d\n", p [3]) ; + + /* ====================================================================== */ + /* dump the strictly lower triangular part of symmetric input matrix B */ + /* ====================================================================== */ + + printf ("\n\nsymamd %d-by-%d input matrix:\n", B_N, B_N) ; + printf ("Entries in strictly lower triangular part:\n") ; + for (col = 0 ; col < B_N ; col++) + { + length = q [col+1] - q [col] ; + printf ("Column %d, with %d entries:\n", col, length) ; + for (pp = q [col] ; pp < q [col+1] ; pp++) + { + row = B [pp] ; + printf (" row %d\n", row) ; + } + } + + /* ====================================================================== */ + /* order the matrix B. Note that this does not modify B or q. */ + /* ====================================================================== */ + + ok = symamd (B_N, B, q, perm, (double *) NULL, stats, &calloc, &free) ; + symamd_report (stats) ; + + if (!ok) + { + printf ("symamd error!\n") ; + exit (1) ; + } + + /* ====================================================================== */ + /* print the symmetric ordering */ + /* ====================================================================== */ + + printf ("symamd column ordering:\n") ; + printf ("1st row/column: %d\n", perm [0]) ; + printf ("2nd row/column: %d\n", perm [1]) ; + printf ("3rd row/column: %d\n", perm [2]) ; + printf ("4th row/column: %d\n", perm [3]) ; + printf ("5th row/column: %d\n", perm [4]) ; + + exit (0) ; +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/Demo/colamd_l_example.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/Demo/colamd_l_example.c new file mode 100644 index 0000000..657a9a7 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/Demo/colamd_l_example.c @@ -0,0 +1,179 @@ +/* ========================================================================== */ +/* === colamd and symamd example ============================================ */ +/* ========================================================================== */ + +/* COLAMD / SYMAMD example + + colamd example of use, to order the columns of a 5-by-4 matrix with + 11 nonzero entries in the following nonzero pattern, with default knobs. + + x 0 x 0 + x 0 x x + 0 x x 0 + 0 0 x x + x x 0 0 + + symamd example of use, to order the rows and columns of a 5-by-5 + matrix with 13 nonzero entries in the following nonzero pattern, + with default knobs. + + x x 0 0 0 + x x x x 0 + 0 x x 0 0 + 0 x 0 x x + 0 0 0 x x + + (where x denotes a nonzero value). +*/ + +/* ========================================================================== */ + +#include <stdio.h> +#include "colamd.h" +#define Long SuiteSparse_long + +#define A_NNZ 11 +#define A_NROW 5 +#define A_NCOL 4 +#define ALEN 150 + +#define B_NNZ 4 +#define B_N 5 + +int main (void) +{ + + /* ====================================================================== */ + /* input matrix A definition */ + /* ====================================================================== */ + + Long A [ALEN] = { + + 0, 1, 4, /* row indices of nonzeros in column 0 */ + 2, 4, /* row indices of nonzeros in column 1 */ + 0, 1, 2, 3, /* row indices of nonzeros in column 2 */ + 1, 3} ; /* row indices of nonzeros in column 3 */ + + Long p [ ] = { + + 0, /* column 0 is in A [0..2] */ + 3, /* column 1 is in A [3..4] */ + 5, /* column 2 is in A [5..8] */ + 9, /* column 3 is in A [9..10] */ + A_NNZ} ; /* number of nonzeros in A */ + + /* ====================================================================== */ + /* input matrix B definition */ + /* ====================================================================== */ + + Long B [ ] = { /* Note: only strictly lower triangular part */ + /* is included, since symamd ignores the */ + /* diagonal and upper triangular part of B. */ + + 1, /* row indices of nonzeros in column 0 */ + 2, 3, /* row indices of nonzeros in column 1 */ + /* row indices of nonzeros in column 2 (none) */ + 4 /* row indices of nonzeros in column 3 */ + } ; /* row indices of nonzeros in column 4 (none) */ + + Long q [ ] = { + + 0, /* column 0 is in B [0] */ + 1, /* column 1 is in B [1..2] */ + 3, /* column 2 is empty */ + 3, /* column 3 is in B [3] */ + 4, /* column 4 is empty */ + B_NNZ} ; /* number of nonzeros in strictly lower B */ + + /* ====================================================================== */ + /* other variable definitions */ + /* ====================================================================== */ + + Long perm [B_N+1] ; /* note the size is N+1 */ + Long stats [COLAMD_STATS] ; /* for colamd and symamd output statistics */ + + Long row, col, pp, length, ok ; + + /* ====================================================================== */ + /* dump the input matrix A */ + /* ====================================================================== */ + + printf ("colamd %d-by-%d input matrix:\n", A_NROW, A_NCOL) ; + for (col = 0 ; col < A_NCOL ; col++) + { + length = p [col+1] - p [col] ; + printf ("Column %ld, with %ld entries:\n", col, length) ; + for (pp = p [col] ; pp < p [col+1] ; pp++) + { + row = A [pp] ; + printf (" row %ld\n", row) ; + } + } + + /* ====================================================================== */ + /* order the matrix. Note that this destroys A and overwrites p */ + /* ====================================================================== */ + + ok = colamd_l (A_NROW, A_NCOL, ALEN, A, p, (double *) NULL, stats) ; + colamd_l_report (stats) ; + + if (!ok) + { + printf ("colamd error!\n") ; + exit (1) ; + } + + /* ====================================================================== */ + /* print the column ordering */ + /* ====================================================================== */ + + printf ("colamd_l column ordering:\n") ; + printf ("1st column: %ld\n", p [0]) ; + printf ("2nd column: %ld\n", p [1]) ; + printf ("3rd column: %ld\n", p [2]) ; + printf ("4th column: %ld\n", p [3]) ; + + /* ====================================================================== */ + /* dump the strictly lower triangular part of symmetric input matrix B */ + /* ====================================================================== */ + + printf ("\n\nsymamd_l %d-by-%d input matrix:\n", B_N, B_N) ; + printf ("Entries in strictly lower triangular part:\n") ; + for (col = 0 ; col < B_N ; col++) + { + length = q [col+1] - q [col] ; + printf ("Column %ld, with %ld entries:\n", col, length) ; + for (pp = q [col] ; pp < q [col+1] ; pp++) + { + row = B [pp] ; + printf (" row %ld\n", row) ; + } + } + + /* ====================================================================== */ + /* order the matrix B. Note that this does not modify B or q. */ + /* ====================================================================== */ + + ok = symamd_l (B_N, B, q, perm, (double *) NULL, stats, &calloc, &free) ; + symamd_l_report (stats) ; + + if (!ok) + { + printf ("symamd error!\n") ; + exit (1) ; + } + + /* ====================================================================== */ + /* print the symmetric ordering */ + /* ====================================================================== */ + + printf ("symamd_l column ordering:\n") ; + printf ("1st row/column: %ld\n", perm [0]) ; + printf ("2nd row/column: %ld\n", perm [1]) ; + printf ("3rd row/column: %ld\n", perm [2]) ; + printf ("4th row/column: %ld\n", perm [3]) ; + printf ("5th row/column: %ld\n", perm [4]) ; + + exit (0) ; +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/Include/colamd.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/Include/colamd.h new file mode 100644 index 0000000..fbe9593 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/Include/colamd.h @@ -0,0 +1,237 @@ +/* ========================================================================== */ +/* === colamd/symamd prototypes and definitions ============================= */ +/* ========================================================================== */ + +/* COLAMD / SYMAMD include file + + You must include this file (colamd.h) in any routine that uses colamd, + symamd, or the related macros and definitions. + + Authors: + + The authors of the code itself are Stefan I. Larimore and Timothy A. + Davis (DrTimothyAldenDavis@gmail.com). The algorithm was + developed in collaboration with John Gilbert, Xerox PARC, and Esmond + Ng, Oak Ridge National Laboratory. + + Acknowledgements: + + This work was supported by the National Science Foundation, under + grants DMS-9504974 and DMS-9803599. + + Notice: + + Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved. + See COLAMD/Doc/License.txt for the license. + + Availability: + + The colamd/symamd library is available at http://www.suitesparse.com + This file is required by the colamd.c, colamdmex.c, and symamdmex.c + files, and by any C code that calls the routines whose prototypes are + listed below, or that uses the colamd/symamd definitions listed below. + +*/ + +#ifndef COLAMD_H +#define COLAMD_H + +/* make it easy for C++ programs to include COLAMD */ +#ifdef __cplusplus +extern "C" { +#endif + +/* ========================================================================== */ +/* === Include files ======================================================== */ +/* ========================================================================== */ + +#include <stdlib.h> + +/* ========================================================================== */ +/* === COLAMD version ======================================================= */ +/* ========================================================================== */ + +/* COLAMD Version 2.4 and later will include the following definitions. + * As an example, to test if the version you are using is 2.4 or later: + * + * #ifdef COLAMD_VERSION + * if (COLAMD_VERSION >= COLAMD_VERSION_CODE (2,4)) ... + * #endif + * + * This also works during compile-time: + * + * #if defined(COLAMD_VERSION) && (COLAMD_VERSION >= COLAMD_VERSION_CODE (2,4)) + * printf ("This is version 2.4 or later\n") ; + * #else + * printf ("This is an early version\n") ; + * #endif + * + * Versions 2.3 and earlier of COLAMD do not include a #define'd version number. + */ + +#define COLAMD_DATE "May 4, 2016" +#define COLAMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) +#define COLAMD_MAIN_VERSION 2 +#define COLAMD_SUB_VERSION 9 +#define COLAMD_SUBSUB_VERSION 6 +#define COLAMD_VERSION \ + COLAMD_VERSION_CODE(COLAMD_MAIN_VERSION,COLAMD_SUB_VERSION) + +/* ========================================================================== */ +/* === Knob and statistics definitions ====================================== */ +/* ========================================================================== */ + +/* size of the knobs [ ] array. Only knobs [0..1] are currently used. */ +#define COLAMD_KNOBS 20 + +/* number of output statistics. Only stats [0..6] are currently used. */ +#define COLAMD_STATS 20 + +/* knobs [0] and stats [0]: dense row knob and output statistic. */ +#define COLAMD_DENSE_ROW 0 + +/* knobs [1] and stats [1]: dense column knob and output statistic. */ +#define COLAMD_DENSE_COL 1 + +/* knobs [2]: aggressive absorption */ +#define COLAMD_AGGRESSIVE 2 + +/* stats [2]: memory defragmentation count output statistic */ +#define COLAMD_DEFRAG_COUNT 2 + +/* stats [3]: colamd status: zero OK, > 0 warning or notice, < 0 error */ +#define COLAMD_STATUS 3 + +/* stats [4..6]: error info, or info on jumbled columns */ +#define COLAMD_INFO1 4 +#define COLAMD_INFO2 5 +#define COLAMD_INFO3 6 + +/* error codes returned in stats [3]: */ +#define COLAMD_OK (0) +#define COLAMD_OK_BUT_JUMBLED (1) +#define COLAMD_ERROR_A_not_present (-1) +#define COLAMD_ERROR_p_not_present (-2) +#define COLAMD_ERROR_nrow_negative (-3) +#define COLAMD_ERROR_ncol_negative (-4) +#define COLAMD_ERROR_nnz_negative (-5) +#define COLAMD_ERROR_p0_nonzero (-6) +#define COLAMD_ERROR_A_too_small (-7) +#define COLAMD_ERROR_col_length_negative (-8) +#define COLAMD_ERROR_row_index_out_of_bounds (-9) +#define COLAMD_ERROR_out_of_memory (-10) +#define COLAMD_ERROR_internal_error (-999) + + +/* ========================================================================== */ +/* === Prototypes of user-callable routines ================================= */ +/* ========================================================================== */ + +#include "SuiteSparse_config.h" + +size_t colamd_recommended /* returns recommended value of Alen, */ + /* or 0 if input arguments are erroneous */ +( + int nnz, /* nonzeros in A */ + int n_row, /* number of rows in A */ + int n_col /* number of columns in A */ +) ; + +size_t colamd_l_recommended /* returns recommended value of Alen, */ + /* or 0 if input arguments are erroneous */ +( + SuiteSparse_long nnz, /* nonzeros in A */ + SuiteSparse_long n_row, /* number of rows in A */ + SuiteSparse_long n_col /* number of columns in A */ +) ; + +void colamd_set_defaults /* sets default parameters */ +( /* knobs argument is modified on output */ + double knobs [COLAMD_KNOBS] /* parameter settings for colamd */ +) ; + +void colamd_l_set_defaults /* sets default parameters */ +( /* knobs argument is modified on output */ + double knobs [COLAMD_KNOBS] /* parameter settings for colamd */ +) ; + +int colamd /* returns (1) if successful, (0) otherwise*/ +( /* A and p arguments are modified on output */ + int n_row, /* number of rows in A */ + int n_col, /* number of columns in A */ + int Alen, /* size of the array A */ + int A [], /* row indices of A, of size Alen */ + int p [], /* column pointers of A, of size n_col+1 */ + double knobs [COLAMD_KNOBS],/* parameter settings for colamd */ + int stats [COLAMD_STATS] /* colamd output statistics and error codes */ +) ; + +SuiteSparse_long colamd_l /* returns (1) if successful, (0) otherwise*/ +( /* A and p arguments are modified on output */ + SuiteSparse_long n_row, /* number of rows in A */ + SuiteSparse_long n_col, /* number of columns in A */ + SuiteSparse_long Alen, /* size of the array A */ + SuiteSparse_long A [], /* row indices of A, of size Alen */ + SuiteSparse_long p [], /* column pointers of A, of size n_col+1 */ + double knobs [COLAMD_KNOBS],/* parameter settings for colamd */ + SuiteSparse_long stats [COLAMD_STATS] /* colamd output statistics + * and error codes */ +) ; + +int symamd /* return (1) if OK, (0) otherwise */ +( + int n, /* number of rows and columns of A */ + int A [], /* row indices of A */ + int p [], /* column pointers of A */ + int perm [], /* output permutation, size n_col+1 */ + double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */ + int stats [COLAMD_STATS], /* output statistics and error codes */ + void * (*allocate) (size_t, size_t), + /* pointer to calloc (ANSI C) or */ + /* mxCalloc (for MATLAB mexFunction) */ + void (*release) (void *) + /* pointer to free (ANSI C) or */ + /* mxFree (for MATLAB mexFunction) */ +) ; + +SuiteSparse_long symamd_l /* return (1) if OK, (0) otherwise */ +( + SuiteSparse_long n, /* number of rows and columns of A */ + SuiteSparse_long A [], /* row indices of A */ + SuiteSparse_long p [], /* column pointers of A */ + SuiteSparse_long perm [], /* output permutation, size n_col+1 */ + double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */ + SuiteSparse_long stats [COLAMD_STATS], /* output stats and error codes */ + void * (*allocate) (size_t, size_t), + /* pointer to calloc (ANSI C) or */ + /* mxCalloc (for MATLAB mexFunction) */ + void (*release) (void *) + /* pointer to free (ANSI C) or */ + /* mxFree (for MATLAB mexFunction) */ +) ; + +void colamd_report +( + int stats [COLAMD_STATS] +) ; + +void colamd_l_report +( + SuiteSparse_long stats [COLAMD_STATS] +) ; + +void symamd_report +( + int stats [COLAMD_STATS] +) ; + +void symamd_l_report +( + SuiteSparse_long stats [COLAMD_STATS] +) ; + +#ifdef __cplusplus +} +#endif + +#endif /* COLAMD_H */ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/MATLAB/colamdmex.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/MATLAB/colamdmex.c new file mode 100644 index 0000000..f6be92f --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/MATLAB/colamdmex.c @@ -0,0 +1,210 @@ +/* ========================================================================== */ +/* === colamd mexFunction =================================================== */ +/* ========================================================================== */ + +/* Usage: + + P = colamd2 (A) ; + [ P, stats ] = colamd2 (A, knobs) ; + + see colamd.m for a description. + + Authors: + + The authors of the code itself are Stefan I. Larimore and Timothy A. + Davis (DrTimothyAldenDavis@gmail.com). The algorithm was + developed in collaboration with John Gilbert, Xerox PARC, and Esmond + Ng, Oak Ridge National Laboratory. + + Acknowledgements: + + This work was supported by the National Science Foundation, under + grants DMS-9504974 and DMS-9803599. + + Notice: + + Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved. + + Availability: + + The colamd/symamd library is available at http://www.suitesparse.com + +*/ + +/* ========================================================================== */ +/* === Include files ======================================================== */ +/* ========================================================================== */ + +#include "colamd.h" +#include "mex.h" +#include "matrix.h" +#include <stdlib.h> +#include <string.h> +#define Long SuiteSparse_long + +/* ========================================================================== */ +/* === colamd mexFunction =================================================== */ +/* ========================================================================== */ + +void mexFunction +( + /* === Parameters ======================================================= */ + + int nlhs, /* number of left-hand sides */ + mxArray *plhs [], /* left-hand side matrices */ + int nrhs, /* number of right--hand sides */ + const mxArray *prhs [] /* right-hand side matrices */ +) +{ + /* === Local variables ================================================== */ + + Long *A ; /* colamd's copy of the matrix, and workspace */ + Long *p ; /* colamd's copy of the column pointers */ + Long Alen ; /* size of A */ + Long n_col ; /* number of columns of A */ + Long n_row ; /* number of rows of A */ + Long nnz ; /* number of entries in A */ + Long full ; /* TRUE if input matrix full, FALSE if sparse */ + double knobs [COLAMD_KNOBS] ; /* colamd user-controllable parameters */ + double *out_perm ; /* output permutation vector */ + double *out_stats ; /* output stats vector */ + double *in_knobs ; /* input knobs vector */ + Long i ; /* loop counter */ + mxArray *Ainput ; /* input matrix handle */ + Long spumoni ; /* verbosity variable */ + Long stats [COLAMD_STATS] ; /* stats for colamd */ + + /* === Check inputs ===================================================== */ + + if (nrhs < 1 || nrhs > 2 || nlhs < 0 || nlhs > 2) + { + mexErrMsgTxt ( + "colamd: incorrect number of input and/or output arguments") ; + } + + /* === Get knobs ======================================================== */ + + colamd_l_set_defaults (knobs) ; + spumoni = 0 ; + + /* check for user-passed knobs */ + if (nrhs == 2) + { + in_knobs = mxGetPr (prhs [1]) ; + i = mxGetNumberOfElements (prhs [1]) ; + if (i > 0) knobs [COLAMD_DENSE_ROW] = in_knobs [0] ; + if (i > 1) knobs [COLAMD_DENSE_COL] = in_knobs [1] ; + if (i > 2) spumoni = (Long) (in_knobs [2] != 0) ; + } + + /* print knob settings if spumoni is set */ + if (spumoni) + { + mexPrintf ("\ncolamd version %d.%d, %s:\n", + COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE) ; + if (knobs [COLAMD_DENSE_ROW] >= 0) + { + mexPrintf ("knobs(1): %g, rows with > max(16,%g*sqrt(size(A,2)))" + " entries removed\n", in_knobs [0], knobs [COLAMD_DENSE_ROW]) ; + } + else + { + mexPrintf ("knobs(1): %g, only completely dense rows removed\n", + in_knobs [0]) ; + } + if (knobs [COLAMD_DENSE_COL] >= 0) + { + mexPrintf ("knobs(2): %g, cols with > max(16,%g*sqrt(min(size(A)))" + " entries removed\n", in_knobs [1], knobs [COLAMD_DENSE_COL]) ; + } + else + { + mexPrintf ("knobs(2): %g, only completely dense columns removed\n", + in_knobs [1]) ; + } + mexPrintf ("knobs(3): %g, statistics and knobs printed\n", + in_knobs [2]) ; + } + + /* === If A is full, convert to a sparse matrix ========================= */ + + Ainput = (mxArray *) prhs [0] ; + if (mxGetNumberOfDimensions (Ainput) != 2) + { + mexErrMsgTxt ("colamd: input matrix must be 2-dimensional") ; + } + full = !mxIsSparse (Ainput) ; + if (full) + { + mexCallMATLAB (1, &Ainput, 1, (mxArray **) prhs, "sparse") ; + } + + /* === Allocate workspace for colamd ==================================== */ + + /* get size of matrix */ + n_row = mxGetM (Ainput) ; + n_col = mxGetN (Ainput) ; + + /* get column pointer vector so we can find nnz */ + p = (Long *) mxCalloc (n_col+1, sizeof (Long)) ; + (void) memcpy (p, mxGetJc (Ainput), (n_col+1)*sizeof (Long)) ; + nnz = p [n_col] ; + Alen = (Long) colamd_l_recommended (nnz, n_row, n_col) ; + if (Alen == 0) + { + mexErrMsgTxt ("colamd: problem too large") ; + } + + /* === Copy input matrix into workspace ================================= */ + + A = (Long *) mxCalloc (Alen, sizeof (Long)) ; + (void) memcpy (A, mxGetIr (Ainput), nnz*sizeof (Long)) ; + + if (full) + { + mxDestroyArray (Ainput) ; + } + + /* === Order the columns (destroys A) =================================== */ + + if (!colamd_l (n_row, n_col, Alen, A, p, knobs, stats)) + { + colamd_l_report (stats) ; + mexErrMsgTxt ("colamd error!") ; + } + mxFree (A) ; + + /* === Return the permutation vector ==================================== */ + + plhs [0] = mxCreateDoubleMatrix (1, n_col, mxREAL) ; + out_perm = mxGetPr (plhs [0]) ; + for (i = 0 ; i < n_col ; i++) + { + /* colamd is 0-based, but MATLAB expects this to be 1-based */ + out_perm [i] = p [i] + 1 ; + } + mxFree (p) ; + + /* === Return the stats vector ========================================== */ + + /* print stats if spumoni is set */ + if (spumoni) + { + colamd_l_report (stats) ; + } + + if (nlhs == 2) + { + plhs [1] = mxCreateDoubleMatrix (1, COLAMD_STATS, mxREAL) ; + out_stats = mxGetPr (plhs [1]) ; + for (i = 0 ; i < COLAMD_STATS ; i++) + { + out_stats [i] = stats [i] ; + } + + /* fix stats (5) and (6), for 1-based information on jumbled matrix. */ + /* note that this correction doesn't occur if symamd returns FALSE */ + out_stats [COLAMD_INFO1] ++ ; + out_stats [COLAMD_INFO2] ++ ; + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/MATLAB/colamdtestmex.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/MATLAB/colamdtestmex.c new file mode 100644 index 0000000..64ef2cb --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/MATLAB/colamdtestmex.c @@ -0,0 +1,567 @@ +/* ========================================================================== */ +/* === colamdtest mexFunction =============================================== */ +/* ========================================================================== */ + +/* COLAMD test function + + This MATLAB mexFunction is for testing only. It is not meant for + production use. See colamdmex.c instead. + + Usage: + + [ P, stats ] = colamdtest (A, knobs) ; + + See colamd.m for a description. knobs is required. + + knobs (1) dense row control + knobs (2) dense column control + knobs (3) spumoni + knobs (4) for testing only. Controls the workspace used by + colamd. + + knobs (5) for testing only. Controls how the input matrix is + jumbled prior to calling colamd, to test its error + handling capability. + + Authors: + + The authors of the code itself are Stefan I. Larimore and Timothy A. + Davis (DrTimothyAldenDavis@gmail.com). The algorithm was + developed in collaboration with John Gilbert, Xerox PARC, and Esmond + Ng, Oak Ridge National Laboratory. + + Acknowledgements: + + This work was supported by the National Science Foundation, under + grants DMS-9504974 and DMS-9803599. + + Notice: + + Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved. + See COLAMD/Doc/License.txt for the License. + + Availability: + + The colamd/symamd library is available at http://www.suitesparse.com + +*/ + +/* ========================================================================== */ +/* === Include files ======================================================== */ +/* ========================================================================== */ + +#include "colamd.h" +#include "mex.h" +#include "matrix.h" +#include <stdlib.h> +#include <string.h> +#define Long SuiteSparse_long + +static void dump_matrix +( + Long A [ ], + Long p [ ], + Long n_row, + Long n_col, + Long Alen, + Long limit +) ; + +/* ========================================================================== */ +/* === colamd mexFunction =================================================== */ +/* ========================================================================== */ + +void mexFunction +( + /* === Parameters ======================================================= */ + + int nlhs, /* number of left-hand sides */ + mxArray *plhs [], /* left-hand side matrices */ + int nrhs, /* number of right--hand sides */ + const mxArray *prhs [] /* right-hand side matrices */ +) +{ + /* === Local variables ================================================== */ + + Long *A ; /* colamd's copy of the matrix, and workspace */ + Long *p ; /* colamd's copy of the column pointers */ + Long Alen ; /* size of A */ + Long n_col ; /* number of columns of A */ + Long n_row ; /* number of rows of A */ + Long nnz ; /* number of entries in A */ + Long full ; /* TRUE if input matrix full, FALSE if sparse */ + double knobs [COLAMD_KNOBS] ; /* colamd user-controllable parameters */ + double *out_perm ; /* output permutation vector */ + double *out_stats ; /* output stats vector */ + double *in_knobs ; /* input knobs vector */ + Long i ; /* loop counter */ + mxArray *Ainput ; /* input matrix handle */ + Long spumoni ; /* verbosity variable */ + Long stats2 [COLAMD_STATS] ;/* stats for colamd */ + + Long *cp, *cp_end, result, col, length ; + Long *stats ; + stats = stats2 ; + + /* === Check inputs ===================================================== */ + + if (nrhs < 1 || nrhs > 2 || nlhs < 0 || nlhs > 2) + { + mexErrMsgTxt ( + "colamd: incorrect number of input and/or output arguments") ; + } + + if (nrhs != 2) + { + mexErrMsgTxt ("colamdtest: knobs are required") ; + } + /* for testing we require all 5 knobs */ + if (mxGetNumberOfElements (prhs [1]) != 5) + { + mexErrMsgTxt ("colamd: must have all 5 knobs for testing") ; + } + + /* === Get knobs ======================================================== */ + + colamd_l_set_defaults (knobs) ; + spumoni = 0 ; + + /* check for user-passed knobs */ + if (nrhs == 2) + { + in_knobs = mxGetPr (prhs [1]) ; + i = mxGetNumberOfElements (prhs [1]) ; + if (i > 0) knobs [COLAMD_DENSE_ROW] = in_knobs [0] ; + if (i > 1) knobs [COLAMD_DENSE_COL] = in_knobs [1] ; + if (i > 2) spumoni = (Long) in_knobs [2] ; + } + + /* print knob settings if spumoni is set */ + if (spumoni) + { + mexPrintf ("\ncolamd version %d.%d, %s:\n", + COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE) ; + if (knobs [COLAMD_DENSE_ROW] >= 0) + { + mexPrintf ("knobs(1): %g, rows with > max(16,%g*sqrt(size(A,2)))" + " entries removed\n", in_knobs [0], knobs [COLAMD_DENSE_ROW]) ; + } + else + { + mexPrintf ("knobs(1): %g, only completely dense rows removed\n", + in_knobs [0]) ; + } + if (knobs [COLAMD_DENSE_COL] >= 0) + { + mexPrintf ("knobs(2): %g, cols with > max(16,%g*sqrt(min(size(A)))" + " entries removed\n", in_knobs [1], knobs [COLAMD_DENSE_COL]) ; + } + else + { + mexPrintf ("knobs(2): %g, only completely dense columns removed\n", + in_knobs [1]) ; + } + mexPrintf ("knobs(3): %g, statistics and knobs printed\n", + in_knobs [2]) ; + } + + /* === If A is full, convert to a sparse matrix ========================= */ + + Ainput = (mxArray *) prhs [0] ; + if (mxGetNumberOfDimensions (Ainput) != 2) + { + mexErrMsgTxt ("colamd: input matrix must be 2-dimensional") ; + } + full = !mxIsSparse (Ainput) ; + if (full) + { + mexCallMATLAB (1, &Ainput, 1, (mxArray **) prhs, "sparse") ; + } + + /* === Allocate workspace for colamd ==================================== */ + + /* get size of matrix */ + n_row = mxGetM (Ainput) ; + n_col = mxGetN (Ainput) ; + + /* get column pointer vector so we can find nnz */ + p = (Long *) mxCalloc (n_col+1, sizeof (Long)) ; + (void) memcpy (p, mxGetJc (Ainput), (n_col+1)*sizeof (Long)) ; + nnz = p [n_col] ; + Alen = (Long) colamd_l_recommended (nnz, n_row, n_col) ; + if (Alen == 0) + { + mexErrMsgTxt ("colamd: problem too large") ; + } + + +/* === Modify size of Alen if testing ======================================= */ + +/* + knobs [3] amount of workspace given to colamd. + < 0 : TIGHT memory + > 0 : MIN + knob [3] - 1 + == 0 : RECOMMENDED memory +*/ + +/* Here only for testing */ +/* size of the Col and Row structures */ +#define COLAMD_C(n_col) (((n_col) + 1) * 24 / sizeof (Long)) +#define COLAMD_R(n_row) (((n_row) + 1) * 16 / sizeof (Long)) +#ifdef MIN +#undef MIN +#endif +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define COLAMD_MIN_MEMORY(nnz,n_row,n_col) \ + (2 * (nnz) + COLAMD_C (n_col) + COLAMD_R (n_row)) + + /* get knob [3], if negative */ + if (in_knobs [3] < 0) + { + Alen = COLAMD_MIN_MEMORY (nnz, n_row, n_col) + n_col ; + } + else if (in_knobs [3] > 0) + { + Alen = COLAMD_MIN_MEMORY (nnz, n_row, n_col) + in_knobs [3] - 1 ; + } + + /* otherwise, we use the recommended amount set above */ + + /* === Copy input matrix into workspace ================================= */ + + A = (Long *) mxCalloc (Alen, sizeof (Long)) ; + (void) memcpy (A, mxGetIr (Ainput), nnz*sizeof (Long)) ; + + if (full) + { + mxDestroyArray (Ainput) ; + } + + +/* === Jumble matrix ======================================================== */ + +/* + knobs [4] FOR TESTING ONLY: Specifies how to jumble matrix + 0 : No jumbling + 1 : Make n_row less than zero + 2 : Make first pointer non-zero + 3 : Make column pointers not non-decreasing + 4 : Make a column pointer greater or equal to Alen + 5 : Make row indices not strictly increasing + 6 : Make a row index greater or equal to n_row + 7 : Set A = NULL + 8 : Set p = NULL + 9 : Repeat row index + 10: make row indices not sorted + 11: jumble columns massively (note this changes + the pattern of the matrix A.) + 12: Set stats = NULL + 13: Make n_col less than zero +*/ + + /* jumble appropriately */ + switch ((Long) in_knobs [4]) + { + + case 0 : + if (spumoni > 0) + { + mexPrintf ("colamdtest: no errors expected\n") ; + } + result = 1 ; /* no errors */ + break ; + + case 1 : + if (spumoni > 0) + { + mexPrintf ("colamdtest: nrow out of range\n") ; + } + result = 0 ; /* nrow out of range */ + n_row = -1 ; + break ; + + case 2 : + if (spumoni > 0) + { + mexPrintf ("colamdtest: p [0] nonzero\n") ; + } + result = 0 ; /* p [0] must be zero */ + p [0] = 1 ; + break ; + + case 3 : + if (spumoni > 0) + { + mexPrintf ("colamdtest: negative length last column\n") ; + } + result = (n_col == 0) ; /* p must be monotonically inc. */ + p [n_col] = p [0] ; + break ; + + case 4 : + if (spumoni > 0) + { + mexPrintf ("colamdtest: Alen too small\n") ; + } + result = 0 ; /* out of memory */ + p [n_col] = Alen ; + break ; + + case 5 : + if (spumoni > 0) + { + mexPrintf ("colamdtest: row index out of range (-1)\n") ; + } + if (nnz > 0) /* row index out of range */ + { + result = 0 ; + A [nnz-1] = -1 ; + } + else + { + if (spumoni > 0) + { + mexPrintf ("Note: no row indices to put out of range\n") ; + } + result = 1 ; + } + break ; + + case 6 : + if (spumoni > 0) + { + mexPrintf ("colamdtest: row index out of range (n_row)\n") ; + } + if (nnz > 0) /* row index out of range */ + { + if (spumoni > 0) + { + mexPrintf ("Changing A[nnz-1] from %d to %d\n", + A [nnz-1], n_row) ; + } + result = 0 ; + A [nnz-1] = n_row ; + } + else + { + if (spumoni > 0) + { + mexPrintf ("Note: no row indices to put out of range\n") ; + } + result = 1 ; + } + break ; + + case 7 : + if (spumoni > 0) + { + mexPrintf ("colamdtest: A not present\n") ; + } + result = 0 ; /* A not present */ + A = (Long *) NULL ; + break ; + + case 8 : + if (spumoni > 0) + { + mexPrintf ("colamdtest: p not present\n") ; + } + result = 0 ; /* p not present */ + p = (Long *) NULL ; + break ; + + case 9 : + if (spumoni > 0) + { + mexPrintf ("colamdtest: duplicate row index\n") ; + } + result = 1 ; /* duplicate row index */ + + for (col = 0 ; col < n_col ; col++) + { + length = p [col+1] - p [col] ; + if (length > 1) + { + A [p [col]] = A [p [col] + 1] ; + if (spumoni > 0) + { + mexPrintf ("Made duplicate row %d in col %d\n", + A [p [col] + 1], col) ; + } + break ; + } + } + + if (spumoni > 1) + { + dump_matrix (A, p, n_row, n_col, Alen, col+2) ; + } + break ; + + case 10 : + if (spumoni > 0) + { + mexPrintf ("colamdtest: unsorted column\n") ; + } + result = 1 ; /* jumbled columns */ + + for (col = 0 ; col < n_col ; col++) + { + length = p [col+1] - p [col] ; + if (length > 1) + { + i = A[p [col]] ; + A [p [col]] = A[p [col] + 1] ; + A [p [col] + 1] = i ; + if (spumoni > 0) + { + mexPrintf ("Unsorted column %d \n", col) ; + } + break ; + } + } + + if (spumoni > 1) + { + dump_matrix (A, p, n_row, n_col, Alen, col+2) ; + } + break ; + + case 11 : + if (spumoni > 0) + { + mexPrintf ("colamdtest: massive jumbling\n") ; + } + result = 1 ; /* massive jumbling, but no errors */ + srand (1) ; + for (i = 0 ; i < n_col ; i++) + { + cp = &A [p [i]] ; + cp_end = &A [p [i+1]] ; + while (cp < cp_end) + { + *cp++ = rand() % n_row ; + } + } + if (spumoni > 1) + { + dump_matrix (A, p, n_row, n_col, Alen, n_col) ; + } + break ; + + case 12 : + if (spumoni > 0) + { + mexPrintf ("colamdtest: stats not present\n") ; + } + result = 0 ; /* stats not present */ + stats = (Long *) NULL ; + break ; + + case 13 : + if (spumoni > 0) + { + mexPrintf ("colamdtest: ncol out of range\n") ; + } + result = 0 ; /* ncol out of range */ + n_col = -1 ; + break ; + + } + + + /* === Order the columns (destroys A) =================================== */ + + if (!colamd_l (n_row, n_col, Alen, A, p, knobs, stats)) + { + + /* return p = -1 if colamd failed */ + plhs [0] = mxCreateDoubleMatrix (1, 1, mxREAL) ; + out_perm = mxGetPr (plhs [0]) ; + out_perm [0] = -1 ; + mxFree (p) ; + mxFree (A) ; + + if (spumoni > 0 || result) + { + colamd_l_report (stats) ; + } + + if (result) + { + mexErrMsgTxt ("colamd should have returned TRUE\n") ; + } + + return ; + /* mexErrMsgTxt ("colamd error!") ; */ + } + + if (!result) + { + colamd_l_report (stats) ; + mexErrMsgTxt ("colamd should have returned FALSE\n") ; + } + mxFree (A) ; + + /* === Return the permutation vector ==================================== */ + + plhs [0] = mxCreateDoubleMatrix (1, n_col, mxREAL) ; + out_perm = mxGetPr (plhs [0]) ; + for (i = 0 ; i < n_col ; i++) + { + /* colamd is 0-based, but MATLAB expects this to be 1-based */ + out_perm [i] = p [i] + 1 ; + } + mxFree (p) ; + + /* === Return the stats vector ========================================== */ + + /* print stats if spumoni > 0 */ + if (spumoni > 0) + { + colamd_l_report (stats) ; + } + + if (nlhs == 2) + { + plhs [1] = mxCreateDoubleMatrix (1, COLAMD_STATS, mxREAL) ; + out_stats = mxGetPr (plhs [1]) ; + for (i = 0 ; i < COLAMD_STATS ; i++) + { + out_stats [i] = stats [i] ; + } + + /* fix stats (5) and (6), for 1-based information on jumbled matrix. */ + /* note that this correction doesn't occur if symamd returns FALSE */ + out_stats [COLAMD_INFO1] ++ ; + out_stats [COLAMD_INFO2] ++ ; + } +} + + +static void dump_matrix +( + Long A [ ], + Long p [ ], + Long n_row, + Long n_col, + Long Alen, + Long limit +) +{ + Long col, k, row ; + + mexPrintf ("dump matrix: nrow %d ncol %d Alen %d\n", n_row, n_col, Alen) ; + + for (col = 0 ; col < MIN (n_col, limit) ; col++) + { + mexPrintf ("column %d, p[col] %d, p [col+1] %d, length %d\n", + col, p [col], p [col+1], p [col+1] - p [col]) ; + for (k = p [col] ; k < p [col+1] ; k++) + { + row = A [k] ; + mexPrintf (" %d", row) ; + } + mexPrintf ("\n") ; + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/MATLAB/symamdmex.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/MATLAB/symamdmex.c new file mode 100644 index 0000000..af79e26 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/MATLAB/symamdmex.c @@ -0,0 +1,192 @@ +/* ========================================================================== */ +/* === symamd mexFunction =================================================== */ +/* ========================================================================== */ + +/* SYMAMD mexFunction + + Usage: + + P = symamd2 (A) ; + [ P, stats ] = symamd2 (A, knobs) ; + + See symamd.m for a description. + + Authors: + + The authors of the code itself are Stefan I. Larimore and Timothy A. + Davis (DrTimothyAldenDavis@gmail.com). The algorithm was + developed in collaboration with John Gilbert, Xerox PARC, and Esmond + Ng, Oak Ridge National Laboratory. + + Acknowledgements: + + This work was supported by the National Science Foundation, under + grants DMS-9504974 and DMS-9803599. + + Notice: + + Copyright (c) 1998-2007, Timothy A. Davis. All Rights Reserved. + See COLAMD/Doc/License.txt for the License. + + Availability: + + The colamd/symamd library is available at http://www.suitesparse.com + +*/ + +/* ========================================================================== */ +/* === Include files ======================================================== */ +/* ========================================================================== */ + +#include "colamd.h" +#include "mex.h" +#include "matrix.h" +#include <stdlib.h> +#define Long SuiteSparse_long + +/* ========================================================================== */ +/* === symamd mexFunction =================================================== */ +/* ========================================================================== */ + +void mexFunction +( + /* === Parameters ======================================================= */ + + int nlhs, /* number of left-hand sides */ + mxArray *plhs [], /* left-hand side matrices */ + int nrhs, /* number of right--hand sides */ + const mxArray *prhs [] /* right-hand side matrices */ +) +{ + /* === Local variables ================================================== */ + + Long *perm ; /* column ordering of M and ordering of A */ + Long *A ; /* row indices of input matrix A */ + Long *p ; /* column pointers of input matrix A */ + Long n_col ; /* number of columns of A */ + Long n_row ; /* number of rows of A */ + Long full ; /* TRUE if input matrix full, FALSE if sparse */ + double knobs [COLAMD_KNOBS] ; /* colamd user-controllable parameters */ + double *out_perm ; /* output permutation vector */ + double *out_stats ; /* output stats vector */ + double *in_knobs ; /* input knobs vector */ + Long i ; /* loop counter */ + mxArray *Ainput ; /* input matrix handle */ + Long spumoni ; /* verbosity variable */ + Long stats [COLAMD_STATS] ; /* stats for symamd */ + + /* === Check inputs ===================================================== */ + + if (nrhs < 1 || nrhs > 2 || nlhs < 0 || nlhs > 2) + { + mexErrMsgTxt ( + "symamd: incorrect number of input and/or output arguments.") ; + } + + /* === Get knobs ======================================================== */ + + colamd_l_set_defaults (knobs) ; + spumoni = 0 ; + + /* check for user-passed knobs */ + if (nrhs == 2) + { + in_knobs = mxGetPr (prhs [1]) ; + i = mxGetNumberOfElements (prhs [1]) ; + if (i > 0) knobs [COLAMD_DENSE_ROW] = in_knobs [0] ; + if (i > 1) spumoni = (Long) (in_knobs [1] != 0) ; + } + + /* print knob settings if spumoni is set */ + if (spumoni) + { + mexPrintf ("\nsymamd version %d.%d, %s:\n", + COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE) ; + if (knobs [COLAMD_DENSE_ROW] >= 0) + { + mexPrintf ("knobs(1): %g, rows/cols with > " + "max(16,%g*sqrt(size(A,2))) entries removed\n", + in_knobs [0], knobs [COLAMD_DENSE_ROW]) ; + } + else + { + mexPrintf ("knobs(1): %g, no dense rows removed\n", in_knobs [0]) ; + } + mexPrintf ("knobs(2): %g, statistics and knobs printed\n", + in_knobs [1]) ; + } + + /* === If A is full, convert to a sparse matrix ========================= */ + + Ainput = (mxArray *) prhs [0] ; + if (mxGetNumberOfDimensions (Ainput) != 2) + { + mexErrMsgTxt ("symamd: input matrix must be 2-dimensional.") ; + } + full = !mxIsSparse (Ainput) ; + if (full) + { + mexCallMATLAB (1, &Ainput, 1, (mxArray **) prhs, "sparse") ; + } + + /* === Allocate workspace for symamd ==================================== */ + + /* get size of matrix */ + n_row = mxGetM (Ainput) ; + n_col = mxGetN (Ainput) ; + if (n_col != n_row) + { + mexErrMsgTxt ("symamd: matrix must be square.") ; + } + + A = (Long *) mxGetIr (Ainput) ; + p = (Long *) mxGetJc (Ainput) ; + perm = (Long *) mxCalloc (n_col+1, sizeof (Long)) ; + + /* === Order the rows and columns of A (does not destroy A) ============= */ + + if (!symamd_l (n_col, A, p, perm, knobs, stats, &mxCalloc, &mxFree)) + { + symamd_l_report (stats) ; + mexErrMsgTxt ("symamd error!") ; + } + + if (full) + { + mxDestroyArray (Ainput) ; + } + + /* === Return the permutation vector ==================================== */ + + plhs [0] = mxCreateDoubleMatrix (1, n_col, mxREAL) ; + out_perm = mxGetPr (plhs [0]) ; + for (i = 0 ; i < n_col ; i++) + { + /* symamd is 0-based, but MATLAB expects this to be 1-based */ + out_perm [i] = perm [i] + 1 ; + } + mxFree (perm) ; + + /* === Return the stats vector ========================================== */ + + /* print stats if spumoni is set */ + if (spumoni) + { + symamd_l_report (stats) ; + } + + if (nlhs == 2) + { + plhs [1] = mxCreateDoubleMatrix (1, COLAMD_STATS, mxREAL) ; + out_stats = mxGetPr (plhs [1]) ; + for (i = 0 ; i < COLAMD_STATS ; i++) + { + out_stats [i] = stats [i] ; + } + + /* fix stats (5) and (6), for 1-based information on jumbled matrix. */ + /* note that this correction doesn't occur if symamd returns FALSE */ + out_stats [COLAMD_INFO1] ++ ; + out_stats [COLAMD_INFO2] ++ ; + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/MATLAB/symamdtestmex.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/MATLAB/symamdtestmex.c new file mode 100644 index 0000000..57cf05c --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/MATLAB/symamdtestmex.c @@ -0,0 +1,533 @@ +/* ========================================================================== */ +/* === symamdtest mexFunction =============================================== */ +/* ========================================================================== */ + +/* SYMAMD test function + + This MATLAB mexFunction is for testing only. It is not meant for + production use. See symamdmex.c instead. + + Usage: + + [ P, stats ] = symamdtest (A, knobs) ; + + See symamd.m for a description. knobs is required. + + knobs (1) dense row control + knobs (2) spumoni + knobs (3) for testing only. Controls how the input matrix is + jumbled prior to calling symamd, to test its error + handling capability. + + Authors: + + The authors of the code itself are Stefan I. Larimore and Timothy A. + Davis (DrTimothyAldenDavis@gmail.com). The algorithm was + developed in collaboration with John Gilbert, Xerox PARC, and Esmond + Ng, Oak Ridge National Laboratory. + + Acknowledgements: + + This work was supported by the National Science Foundation, under + grants DMS-9504974 and DMS-9803599. + + Notice: + + Copyright (c) 1998-2007, Timothy A. Davis. All Rights Reserved. + See COLAMD/Doc/License.txt for the License. + + Availability: + + The colamd/symamd library is available at http://www.suitesparse.com + +*/ + +/* ========================================================================== */ +/* === Include files ======================================================== */ +/* ========================================================================== */ + +#include "colamd.h" +#include "mex.h" +#include "matrix.h" +#include <stdlib.h> +#include <string.h> +#define Long SuiteSparse_long + +static void dump_matrix +( + Long A [ ], + Long p [ ], + Long n_row, + Long n_col, + Long Alen, + Long limit +) ; + +/* ========================================================================== */ +/* === symamd mexFunction =================================================== */ +/* ========================================================================== */ + +void mexFunction +( + /* === Parameters ======================================================= */ + + int nlhs, /* number of left-hand sides */ + mxArray *plhs [], /* left-hand side matrices */ + int nrhs, /* number of right--hand sides */ + const mxArray *prhs [] /* right-hand side matrices */ +) +{ + /* === Local variables ================================================== */ + + Long *perm ; /* column ordering of M and ordering of A */ + Long *A ; /* row indices of input matrix A */ + Long *p ; /* column pointers of input matrix A */ + Long n_col ; /* number of columns of A */ + Long n_row ; /* number of rows of A */ + Long full ; /* TRUE if input matrix full, FALSE if sparse */ + double knobs [COLAMD_KNOBS] ; /* colamd user-controllable parameters */ + double *out_perm ; /* output permutation vector */ + double *out_stats ; /* output stats vector */ + double *in_knobs ; /* input knobs vector */ + Long i ; /* loop counter */ + mxArray *Ainput ; /* input matrix handle */ + Long spumoni ; /* verbosity variable */ + Long stats2 [COLAMD_STATS] ;/* stats for symamd */ + + Long *cp, *cp_end, result, nnz, col, length ; + Long *stats ; + stats = stats2 ; + + /* === Check inputs ===================================================== */ + + if (nrhs < 1 || nrhs > 2 || nlhs < 0 || nlhs > 2) + { + mexErrMsgTxt ( + "symamd: incorrect number of input and/or output arguments.") ; + } + + if (nrhs != 2) + { + mexErrMsgTxt ("symamdtest: knobs are required") ; + } + /* for testing we require all 3 knobs */ + if (mxGetNumberOfElements (prhs [1]) != 3) + { + mexErrMsgTxt ("symamdtest: must have all 3 knobs for testing") ; + } + + /* === Get knobs ======================================================== */ + + colamd_l_set_defaults (knobs) ; + spumoni = 0 ; + + /* check for user-passed knobs */ + if (nrhs == 2) + { + in_knobs = mxGetPr (prhs [1]) ; + i = mxGetNumberOfElements (prhs [1]) ; + if (i > 0) knobs [COLAMD_DENSE_ROW] = in_knobs [0] ; + if (i > 1) spumoni = (Long) in_knobs [1] ; + } + + /* print knob settings if spumoni is set */ + if (spumoni) + { + mexPrintf ("\nsymamd version %d.%d, %s:\n", + COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE) ; + if (knobs [COLAMD_DENSE_ROW] >= 0) + { + mexPrintf ("knobs(1): %g, rows/cols with > " + "max(16,%g*sqrt(size(A,2))) entries removed\n", + in_knobs [0], knobs [COLAMD_DENSE_ROW]) ; + } + else + { + mexPrintf ("knobs(1): %g, no dense rows removed\n", in_knobs [0]) ; + } + mexPrintf ("knobs(2): %g, statistics and knobs printed\n", + in_knobs [1]) ; + mexPrintf ("Testing %d\n", in_knobs [2]) ; + } + + /* === If A is full, convert to a sparse matrix ========================= */ + + Ainput = (mxArray *) prhs [0] ; + if (mxGetNumberOfDimensions (Ainput) != 2) + { + mexErrMsgTxt ("symamd: input matrix must be 2-dimensional.") ; + } + full = !mxIsSparse (Ainput) ; + if (full) + { + mexCallMATLAB (1, &Ainput, 1, (mxArray **) prhs, "sparse") ; + } + + /* === Allocate workspace for symamd ==================================== */ + + /* get size of matrix */ + n_row = mxGetM (Ainput) ; + n_col = mxGetN (Ainput) ; + if (n_col != n_row) + { + mexErrMsgTxt ("symamd: matrix must be square.") ; + } + + /* p = mxGetJc (Ainput) ; */ + p = (Long *) mxCalloc (n_col+1, sizeof (Long)) ; + (void) memcpy (p, mxGetJc (Ainput), (n_col+1)*sizeof (Long)) ; + + nnz = p [n_col] ; + if (spumoni > 0) + { + mexPrintf ("symamdtest: nnz %d\n", nnz) ; + } + + /* A = mxGetIr (Ainput) ; */ + A = (Long *) mxCalloc (nnz+1, sizeof (Long)) ; + (void) memcpy (A, mxGetIr (Ainput), nnz*sizeof (Long)) ; + + perm = (Long *) mxCalloc (n_col+1, sizeof (Long)) ; + +/* === Jumble matrix ======================================================== */ + + +/* + knobs [2] FOR TESTING ONLY: Specifies how to jumble matrix + 0 : No jumbling + 1 : (no errors) + 2 : Make first pointer non-zero + 3 : Make column pointers not non-decreasing + 4 : (no errors) + 5 : Make row indices not strictly increasing + 6 : Make a row index greater or equal to n_row + 7 : Set A = NULL + 8 : Set p = NULL + 9 : Repeat row index + 10: make row indices not sorted + 11: jumble columns massively (note this changes + the pattern of the matrix A.) + 12: Set stats = NULL + 13: Make n_col less than zero +*/ + + /* jumble appropriately */ + switch ((Long) in_knobs [2]) + { + + case 0 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: no errors expected\n") ; + } + result = 1 ; /* no errors */ + break ; + + case 1 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: no errors expected (1)\n") ; + } + result = 1 ; + break ; + + case 2 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: p [0] nonzero\n") ; + } + result = 0 ; /* p [0] must be zero */ + p [0] = 1 ; + break ; + + case 3 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: negative length last column\n") ; + } + result = (n_col == 0) ; /* p must be monotonically inc. */ + p [n_col] = p [0] ; + break ; + + case 4 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: no errors expected (4)\n") ; + } + result = 1 ; + break ; + + case 5 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: row index out of range (-1)\n") ; + } + if (nnz > 0) /* row index out of range */ + { + result = 0 ; + A [nnz-1] = -1 ; + } + else + { + if (spumoni > 0) + { + mexPrintf ("Note: no row indices to put out of range\n") ; + } + result = 1 ; + } + break ; + + case 6 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: row index out of range (ncol)\n") ; + } + if (nnz > 0) /* row index out of range */ + { + result = 0 ; + A [nnz-1] = n_col ; + } + else + { + if (spumoni > 0) + { + mexPrintf ("Note: no row indices to put out of range\n") ; + } + result = 1 ; + } + break ; + + case 7 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: A not present\n") ; + } + result = 0 ; /* A not present */ + A = (Long *) NULL ; + break ; + + case 8 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: p not present\n") ; + } + result = 0 ; /* p not present */ + p = (Long *) NULL ; + break ; + + case 9 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: duplicate row index\n") ; + } + result = 1 ; /* duplicate row index */ + + for (col = 0 ; col < n_col ; col++) + { + length = p [col+1] - p [col] ; + if (length > 1) + { + A [p [col+1]-2] = A [p [col+1] - 1] ; + if (spumoni > 0) + { + mexPrintf ("Made duplicate row %d in col %d\n", + A [p [col+1] - 1], col) ; + } + break ; + } + } + + if (spumoni > 1) + { + dump_matrix (A, p, n_row, n_col, nnz, col+2) ; + } + break ; + + case 10 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: unsorted column\n") ; + } + result = 1 ; /* jumbled columns */ + + for (col = 0 ; col < n_col ; col++) + { + length = p [col+1] - p [col] ; + if (length > 1) + { + i = A[p [col]] ; + A [p [col]] = A[p [col] + 1] ; + A [p [col] + 1] = i ; + if (spumoni > 0) + { + mexPrintf ("Unsorted column %d \n", col) ; + } + break ; + } + } + + if (spumoni > 1) + { + dump_matrix (A, p, n_row, n_col, nnz, col+2) ; + } + break ; + + case 11 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: massive jumbling\n") ; + } + result = 1 ; /* massive jumbling, but no errors */ + srand (1) ; + for (i = 0 ; i < n_col ; i++) + { + cp = &A [p [i]] ; + cp_end = &A [p [i+1]] ; + while (cp < cp_end) + { + *cp++ = rand() % n_row ; + } + } + if (spumoni > 1) + { + dump_matrix (A, p, n_row, n_col, nnz, n_col) ; + } + break ; + + case 12 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: stats not present\n") ; + } + result = 0 ; /* stats not present */ + stats = (Long *) NULL ; + break ; + + case 13 : + if (spumoni > 0) + { + mexPrintf ("symamdtest: ncol out of range\n") ; + } + result = 0 ; /* ncol out of range */ + n_col = -1 ; + break ; + + } + + /* === Order the rows and columns of A (does not destroy A) ============= */ + + if (!symamd_l (n_col, A, p, perm, knobs, stats, &mxCalloc, &mxFree)) + { + + /* return p = -1 if colamd failed */ + plhs [0] = mxCreateDoubleMatrix (1, 1, mxREAL) ; + out_perm = mxGetPr (plhs [0]) ; + out_perm [0] = -1 ; + mxFree (p) ; + mxFree (A) ; + + if (spumoni > 0 || result) + { + symamd_l_report (stats) ; + } + + if (result) + { + mexErrMsgTxt ("symamd should have returned TRUE\n") ; + } + + return ; + /* mexErrMsgTxt ("symamd error!") ; */ + } + + if (!result) + { + symamd_l_report (stats) ; + mexErrMsgTxt ("symamd should have returned FALSE\n") ; + } + + if (full) + { + mxDestroyArray (Ainput) ; + } + + /* === Return the permutation vector ==================================== */ + + plhs [0] = mxCreateDoubleMatrix (1, n_col, mxREAL) ; + out_perm = mxGetPr (plhs [0]) ; + for (i = 0 ; i < n_col ; i++) + { + /* symamd is 0-based, but MATLAB expects this to be 1-based */ + out_perm [i] = perm [i] + 1 ; + } + mxFree (perm) ; + + /* === Return the stats vector ========================================== */ + + /* print stats if spumoni > 0 */ + if (spumoni > 0) + { + symamd_l_report (stats) ; + } + + if (nlhs == 2) + { + plhs [1] = mxCreateDoubleMatrix (1, COLAMD_STATS, mxREAL) ; + out_stats = mxGetPr (plhs [1]) ; + for (i = 0 ; i < COLAMD_STATS ; i++) + { + out_stats [i] = stats [i] ; + } + + /* fix stats (5) and (6), for 1-based information on jumbled matrix. */ + /* note that this correction doesn't occur if symamd returns FALSE */ + out_stats [COLAMD_INFO1] ++ ; + out_stats [COLAMD_INFO2] ++ ; + } +} + + +#ifdef MIN +#undef MIN +#endif +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + + +static void dump_matrix +( + Long A [ ], + Long p [ ], + Long n_row, + Long n_col, + Long Alen, + Long limit +) +{ + Long col, k, row ; + + mexPrintf ("dump matrix: nrow %d ncol %d Alen %d\n", n_row, n_col, Alen) ; + + if (!A) + { + mexPrintf ("A not present\n") ; + return ; + } + + if (!p) + { + mexPrintf ("p not present\n") ; + return ; + } + + for (col = 0 ; col < MIN (n_col, limit) ; col++) + { + mexPrintf ("column %d, p[col] %d, p [col+1] %d, length %d\n", + col, p [col], p [col+1], p [col+1] - p [col]) ; + for (k = p [col] ; k < p [col+1] ; k++) + { + row = A [k] ; + mexPrintf (" %d", row) ; + } + mexPrintf ("\n") ; + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/Source/colamd.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/Source/colamd.c new file mode 100644 index 0000000..8d56c38 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/COLAMD/Source/colamd.c @@ -0,0 +1,3590 @@ +/* ========================================================================== */ +/* === colamd/symamd - a sparse matrix column ordering algorithm ============ */ +/* ========================================================================== */ + +/* COLAMD / SYMAMD + + colamd: an approximate minimum degree column ordering algorithm, + for LU factorization of symmetric or unsymmetric matrices, + QR factorization, least squares, interior point methods for + linear programming problems, and other related problems. + + symamd: an approximate minimum degree ordering algorithm for Cholesky + factorization of symmetric matrices. + + Purpose: + + Colamd computes a permutation Q such that the Cholesky factorization of + (AQ)'(AQ) has less fill-in and requires fewer floating point operations + than A'A. This also provides a good ordering for sparse partial + pivoting methods, P(AQ) = LU, where Q is computed prior to numerical + factorization, and P is computed during numerical factorization via + conventional partial pivoting with row interchanges. Colamd is the + column ordering method used in SuperLU, part of the ScaLAPACK library. + It is also available as built-in function in MATLAB Version 6, + available from MathWorks, Inc. (http://www.mathworks.com). This + routine can be used in place of colmmd in MATLAB. + + Symamd computes a permutation P of a symmetric matrix A such that the + Cholesky factorization of PAP' has less fill-in and requires fewer + floating point operations than A. Symamd constructs a matrix M such + that M'M has the same nonzero pattern of A, and then orders the columns + of M using colmmd. The column ordering of M is then returned as the + row and column ordering P of A. + + Authors: + + The authors of the code itself are Stefan I. Larimore and Timothy A. + Davis (DrTimothyAldenDavis@gmail.com). The algorithm was + developed in collaboration with John Gilbert, Xerox PARC, and Esmond + Ng, Oak Ridge National Laboratory. + + Acknowledgements: + + This work was supported by the National Science Foundation, under + grants DMS-9504974 and DMS-9803599. + + Copyright and License: + + Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved. + COLAMD is also available under alternate licenses, contact T. Davis + for details. + + See COLAMD/Doc/License.txt for the license. + + Availability: + + The colamd/symamd library is available at http://www.suitesparse.com + Appears as ACM Algorithm 836. + + See the ChangeLog file for changes since Version 1.0. + + References: + + T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate column + minimum degree ordering algorithm, ACM Transactions on Mathematical + Software, vol. 30, no. 3., pp. 353-376, 2004. + + T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD, + an approximate column minimum degree ordering algorithm, ACM + Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380, + 2004. + +*/ + +/* ========================================================================== */ +/* === Description of user-callable routines ================================ */ +/* ========================================================================== */ + +/* COLAMD includes both int and SuiteSparse_long versions of all its routines. + The description below is for the int version. For SuiteSparse_long, all + int arguments become SuiteSparse_long. SuiteSparse_long is normally + defined as long, except for WIN64. + + ---------------------------------------------------------------------------- + colamd_recommended: + ---------------------------------------------------------------------------- + + C syntax: + + #include "colamd.h" + size_t colamd_recommended (int nnz, int n_row, int n_col) ; + size_t colamd_l_recommended (SuiteSparse_long nnz, + SuiteSparse_long n_row, SuiteSparse_long n_col) ; + + Purpose: + + Returns recommended value of Alen for use by colamd. Returns 0 + if any input argument is negative. The use of this routine + is optional. Not needed for symamd, which dynamically allocates + its own memory. + + Note that in v2.4 and earlier, these routines returned int or long. + They now return a value of type size_t. + + Arguments (all input arguments): + + int nnz ; Number of nonzeros in the matrix A. This must + be the same value as p [n_col] in the call to + colamd - otherwise you will get a wrong value + of the recommended memory to use. + + int n_row ; Number of rows in the matrix A. + + int n_col ; Number of columns in the matrix A. + + ---------------------------------------------------------------------------- + colamd_set_defaults: + ---------------------------------------------------------------------------- + + C syntax: + + #include "colamd.h" + colamd_set_defaults (double knobs [COLAMD_KNOBS]) ; + colamd_l_set_defaults (double knobs [COLAMD_KNOBS]) ; + + Purpose: + + Sets the default parameters. The use of this routine is optional. + + Arguments: + + double knobs [COLAMD_KNOBS] ; Output only. + + NOTE: the meaning of the dense row/col knobs has changed in v2.4 + + knobs [0] and knobs [1] control dense row and col detection: + + Colamd: rows with more than + max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n_col)) + entries are removed prior to ordering. Columns with more than + max (16, knobs [COLAMD_DENSE_COL] * sqrt (MIN (n_row,n_col))) + entries are removed prior to + ordering, and placed last in the output column ordering. + + Symamd: uses only knobs [COLAMD_DENSE_ROW], which is knobs [0]. + Rows and columns with more than + max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n)) + entries are removed prior to ordering, and placed last in the + output ordering. + + COLAMD_DENSE_ROW and COLAMD_DENSE_COL are defined as 0 and 1, + respectively, in colamd.h. Default values of these two knobs + are both 10. Currently, only knobs [0] and knobs [1] are + used, but future versions may use more knobs. If so, they will + be properly set to their defaults by the future version of + colamd_set_defaults, so that the code that calls colamd will + not need to change, assuming that you either use + colamd_set_defaults, or pass a (double *) NULL pointer as the + knobs array to colamd or symamd. + + knobs [2]: aggressive absorption + + knobs [COLAMD_AGGRESSIVE] controls whether or not to do + aggressive absorption during the ordering. Default is TRUE. + + + ---------------------------------------------------------------------------- + colamd: + ---------------------------------------------------------------------------- + + C syntax: + + #include "colamd.h" + int colamd (int n_row, int n_col, int Alen, int *A, int *p, + double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS]) ; + SuiteSparse_long colamd_l (SuiteSparse_long n_row, + SuiteSparse_long n_col, SuiteSparse_long Alen, + SuiteSparse_long *A, SuiteSparse_long *p, double knobs + [COLAMD_KNOBS], SuiteSparse_long stats [COLAMD_STATS]) ; + + Purpose: + + Computes a column ordering (Q) of A such that P(AQ)=LU or + (AQ)'AQ=LL' have less fill-in and require fewer floating point + operations than factorizing the unpermuted matrix A or A'A, + respectively. + + Returns: + + TRUE (1) if successful, FALSE (0) otherwise. + + Arguments: + + int n_row ; Input argument. + + Number of rows in the matrix A. + Restriction: n_row >= 0. + Colamd returns FALSE if n_row is negative. + + int n_col ; Input argument. + + Number of columns in the matrix A. + Restriction: n_col >= 0. + Colamd returns FALSE if n_col is negative. + + int Alen ; Input argument. + + Restriction (see note): + Alen >= 2*nnz + 6*(n_col+1) + 4*(n_row+1) + n_col + Colamd returns FALSE if these conditions are not met. + + Note: this restriction makes an modest assumption regarding + the size of the two typedef's structures in colamd.h. + We do, however, guarantee that + + Alen >= colamd_recommended (nnz, n_row, n_col) + + will be sufficient. Note: the macro version does not check + for integer overflow, and thus is not recommended. Use + the colamd_recommended routine instead. + + int A [Alen] ; Input argument, undefined on output. + + A is an integer array of size Alen. Alen must be at least as + large as the bare minimum value given above, but this is very + low, and can result in excessive run time. For best + performance, we recommend that Alen be greater than or equal to + colamd_recommended (nnz, n_row, n_col), which adds + nnz/5 to the bare minimum value given above. + + On input, the row indices of the entries in column c of the + matrix are held in A [(p [c]) ... (p [c+1]-1)]. The row indices + in a given column c need not be in ascending order, and + duplicate row indices may be be present. However, colamd will + work a little faster if both of these conditions are met + (Colamd puts the matrix into this format, if it finds that the + the conditions are not met). + + The matrix is 0-based. That is, rows are in the range 0 to + n_row-1, and columns are in the range 0 to n_col-1. Colamd + returns FALSE if any row index is out of range. + + The contents of A are modified during ordering, and are + undefined on output. + + int p [n_col+1] ; Both input and output argument. + + p is an integer array of size n_col+1. On input, it holds the + "pointers" for the column form of the matrix A. Column c of + the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first + entry, p [0], must be zero, and p [c] <= p [c+1] must hold + for all c in the range 0 to n_col-1. The value p [n_col] is + thus the total number of entries in the pattern of the matrix A. + Colamd returns FALSE if these conditions are not met. + + On output, if colamd returns TRUE, the array p holds the column + permutation (Q, for P(AQ)=LU or (AQ)'(AQ)=LL'), where p [0] is + the first column index in the new ordering, and p [n_col-1] is + the last. That is, p [k] = j means that column j of A is the + kth pivot column, in AQ, where k is in the range 0 to n_col-1 + (p [0] = j means that column j of A is the first column in AQ). + + If colamd returns FALSE, then no permutation is returned, and + p is undefined on output. + + double knobs [COLAMD_KNOBS] ; Input argument. + + See colamd_set_defaults for a description. + + int stats [COLAMD_STATS] ; Output argument. + + Statistics on the ordering, and error status. + See colamd.h for related definitions. + Colamd returns FALSE if stats is not present. + + stats [0]: number of dense or empty rows ignored. + + stats [1]: number of dense or empty columns ignored (and + ordered last in the output permutation p) + Note that a row can become "empty" if it + contains only "dense" and/or "empty" columns, + and similarly a column can become "empty" if it + only contains "dense" and/or "empty" rows. + + stats [2]: number of garbage collections performed. + This can be excessively high if Alen is close + to the minimum required value. + + stats [3]: status code. < 0 is an error code. + > 1 is a warning or notice. + + 0 OK. Each column of the input matrix contained + row indices in increasing order, with no + duplicates. + + 1 OK, but columns of input matrix were jumbled + (unsorted columns or duplicate entries). Colamd + had to do some extra work to sort the matrix + first and remove duplicate entries, but it + still was able to return a valid permutation + (return value of colamd was TRUE). + + stats [4]: highest numbered column that + is unsorted or has duplicate + entries. + stats [5]: last seen duplicate or + unsorted row index. + stats [6]: number of duplicate or + unsorted row indices. + + -1 A is a null pointer + + -2 p is a null pointer + + -3 n_row is negative + + stats [4]: n_row + + -4 n_col is negative + + stats [4]: n_col + + -5 number of nonzeros in matrix is negative + + stats [4]: number of nonzeros, p [n_col] + + -6 p [0] is nonzero + + stats [4]: p [0] + + -7 A is too small + + stats [4]: required size + stats [5]: actual size (Alen) + + -8 a column has a negative number of entries + + stats [4]: column with < 0 entries + stats [5]: number of entries in col + + -9 a row index is out of bounds + + stats [4]: column with bad row index + stats [5]: bad row index + stats [6]: n_row, # of rows of matrx + + -10 (unused; see symamd.c) + + -999 (unused; see symamd.c) + + Future versions may return more statistics in the stats array. + + Example: + + See colamd_example.c for a complete example. + + To order the columns of a 5-by-4 matrix with 11 nonzero entries in + the following nonzero pattern + + x 0 x 0 + x 0 x x + 0 x x 0 + 0 0 x x + x x 0 0 + + with default knobs and no output statistics, do the following: + + #include "colamd.h" + #define ALEN 100 + int A [ALEN] = {0, 1, 4, 2, 4, 0, 1, 2, 3, 1, 3} ; + int p [ ] = {0, 3, 5, 9, 11} ; + int stats [COLAMD_STATS] ; + colamd (5, 4, ALEN, A, p, (double *) NULL, stats) ; + + The permutation is returned in the array p, and A is destroyed. + + ---------------------------------------------------------------------------- + symamd: + ---------------------------------------------------------------------------- + + C syntax: + + #include "colamd.h" + int symamd (int n, int *A, int *p, int *perm, + double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS], + void (*allocate) (size_t, size_t), void (*release) (void *)) ; + SuiteSparse_long symamd_l (SuiteSparse_long n, SuiteSparse_long *A, + SuiteSparse_long *p, SuiteSparse_long *perm, double knobs + [COLAMD_KNOBS], SuiteSparse_long stats [COLAMD_STATS], void + (*allocate) (size_t, size_t), void (*release) (void *)) ; + + Purpose: + + The symamd routine computes an ordering P of a symmetric sparse + matrix A such that the Cholesky factorization PAP' = LL' remains + sparse. It is based on a column ordering of a matrix M constructed + so that the nonzero pattern of M'M is the same as A. The matrix A + is assumed to be symmetric; only the strictly lower triangular part + is accessed. You must pass your selected memory allocator (usually + calloc/free or mxCalloc/mxFree) to symamd, for it to allocate + memory for the temporary matrix M. + + Returns: + + TRUE (1) if successful, FALSE (0) otherwise. + + Arguments: + + int n ; Input argument. + + Number of rows and columns in the symmetrix matrix A. + Restriction: n >= 0. + Symamd returns FALSE if n is negative. + + int A [nnz] ; Input argument. + + A is an integer array of size nnz, where nnz = p [n]. + + The row indices of the entries in column c of the matrix are + held in A [(p [c]) ... (p [c+1]-1)]. The row indices in a + given column c need not be in ascending order, and duplicate + row indices may be present. However, symamd will run faster + if the columns are in sorted order with no duplicate entries. + + The matrix is 0-based. That is, rows are in the range 0 to + n-1, and columns are in the range 0 to n-1. Symamd + returns FALSE if any row index is out of range. + + The contents of A are not modified. + + int p [n+1] ; Input argument. + + p is an integer array of size n+1. On input, it holds the + "pointers" for the column form of the matrix A. Column c of + the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first + entry, p [0], must be zero, and p [c] <= p [c+1] must hold + for all c in the range 0 to n-1. The value p [n] is + thus the total number of entries in the pattern of the matrix A. + Symamd returns FALSE if these conditions are not met. + + The contents of p are not modified. + + int perm [n+1] ; Output argument. + + On output, if symamd returns TRUE, the array perm holds the + permutation P, where perm [0] is the first index in the new + ordering, and perm [n-1] is the last. That is, perm [k] = j + means that row and column j of A is the kth column in PAP', + where k is in the range 0 to n-1 (perm [0] = j means + that row and column j of A are the first row and column in + PAP'). The array is used as a workspace during the ordering, + which is why it must be of length n+1, not just n. + + double knobs [COLAMD_KNOBS] ; Input argument. + + See colamd_set_defaults for a description. + + int stats [COLAMD_STATS] ; Output argument. + + Statistics on the ordering, and error status. + See colamd.h for related definitions. + Symamd returns FALSE if stats is not present. + + stats [0]: number of dense or empty row and columns ignored + (and ordered last in the output permutation + perm). Note that a row/column can become + "empty" if it contains only "dense" and/or + "empty" columns/rows. + + stats [1]: (same as stats [0]) + + stats [2]: number of garbage collections performed. + + stats [3]: status code. < 0 is an error code. + > 1 is a warning or notice. + + 0 OK. Each column of the input matrix contained + row indices in increasing order, with no + duplicates. + + 1 OK, but columns of input matrix were jumbled + (unsorted columns or duplicate entries). Symamd + had to do some extra work to sort the matrix + first and remove duplicate entries, but it + still was able to return a valid permutation + (return value of symamd was TRUE). + + stats [4]: highest numbered column that + is unsorted or has duplicate + entries. + stats [5]: last seen duplicate or + unsorted row index. + stats [6]: number of duplicate or + unsorted row indices. + + -1 A is a null pointer + + -2 p is a null pointer + + -3 (unused, see colamd.c) + + -4 n is negative + + stats [4]: n + + -5 number of nonzeros in matrix is negative + + stats [4]: # of nonzeros (p [n]). + + -6 p [0] is nonzero + + stats [4]: p [0] + + -7 (unused) + + -8 a column has a negative number of entries + + stats [4]: column with < 0 entries + stats [5]: number of entries in col + + -9 a row index is out of bounds + + stats [4]: column with bad row index + stats [5]: bad row index + stats [6]: n_row, # of rows of matrx + + -10 out of memory (unable to allocate temporary + workspace for M or count arrays using the + "allocate" routine passed into symamd). + + Future versions may return more statistics in the stats array. + + void * (*allocate) (size_t, size_t) + + A pointer to a function providing memory allocation. The + allocated memory must be returned initialized to zero. For a + C application, this argument should normally be a pointer to + calloc. For a MATLAB mexFunction, the routine mxCalloc is + passed instead. + + void (*release) (size_t, size_t) + + A pointer to a function that frees memory allocated by the + memory allocation routine above. For a C application, this + argument should normally be a pointer to free. For a MATLAB + mexFunction, the routine mxFree is passed instead. + + + ---------------------------------------------------------------------------- + colamd_report: + ---------------------------------------------------------------------------- + + C syntax: + + #include "colamd.h" + colamd_report (int stats [COLAMD_STATS]) ; + colamd_l_report (SuiteSparse_long stats [COLAMD_STATS]) ; + + Purpose: + + Prints the error status and statistics recorded in the stats + array on the standard error output (for a standard C routine) + or on the MATLAB output (for a mexFunction). + + Arguments: + + int stats [COLAMD_STATS] ; Input only. Statistics from colamd. + + + ---------------------------------------------------------------------------- + symamd_report: + ---------------------------------------------------------------------------- + + C syntax: + + #include "colamd.h" + symamd_report (int stats [COLAMD_STATS]) ; + symamd_l_report (SuiteSparse_long stats [COLAMD_STATS]) ; + + Purpose: + + Prints the error status and statistics recorded in the stats + array on the standard error output (for a standard C routine) + or on the MATLAB output (for a mexFunction). + + Arguments: + + int stats [COLAMD_STATS] ; Input only. Statistics from symamd. + + +*/ + +/* ========================================================================== */ +/* === Scaffolding code definitions ======================================== */ +/* ========================================================================== */ + +/* Ensure that debugging is turned off: */ +#ifndef NDEBUG +#define NDEBUG +#endif + +/* turn on debugging by uncommenting the following line + #undef NDEBUG +*/ + +/* + Our "scaffolding code" philosophy: In our opinion, well-written library + code should keep its "debugging" code, and just normally have it turned off + by the compiler so as not to interfere with performance. This serves + several purposes: + + (1) assertions act as comments to the reader, telling you what the code + expects at that point. All assertions will always be true (unless + there really is a bug, of course). + + (2) leaving in the scaffolding code assists anyone who would like to modify + the code, or understand the algorithm (by reading the debugging output, + one can get a glimpse into what the code is doing). + + (3) (gasp!) for actually finding bugs. This code has been heavily tested + and "should" be fully functional and bug-free ... but you never know... + + The code will become outrageously slow when debugging is + enabled. To control the level of debugging output, set an environment + variable D to 0 (little), 1 (some), 2, 3, or 4 (lots). When debugging, + you should see the following message on the standard output: + + colamd: debug version, D = 1 (THIS WILL BE SLOW!) + + or a similar message for symamd. If you don't, then debugging has not + been enabled. + +*/ + +/* ========================================================================== */ +/* === Include files ======================================================== */ +/* ========================================================================== */ + +#include "colamd.h" +#include <limits.h> +#include <math.h> + +#ifdef MATLAB_MEX_FILE +#include "mex.h" +#include "matrix.h" +#endif /* MATLAB_MEX_FILE */ + +#if !defined (NPRINT) || !defined (NDEBUG) +#include <stdio.h> +#endif + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +/* ========================================================================== */ +/* === int or SuiteSparse_long ============================================== */ +/* ========================================================================== */ + +#ifdef DLONG + +#define Int SuiteSparse_long +#define ID SuiteSparse_long_id +#define Int_MAX SuiteSparse_long_max + +#define COLAMD_recommended colamd_l_recommended +#define COLAMD_set_defaults colamd_l_set_defaults +#define COLAMD_MAIN colamd_l +#define SYMAMD_MAIN symamd_l +#define COLAMD_report colamd_l_report +#define SYMAMD_report symamd_l_report + +#else + +#define Int int +#define ID "%d" +#define Int_MAX INT_MAX + +#define COLAMD_recommended colamd_recommended +#define COLAMD_set_defaults colamd_set_defaults +#define COLAMD_MAIN colamd +#define SYMAMD_MAIN symamd +#define COLAMD_report colamd_report +#define SYMAMD_report symamd_report + +#endif + +/* ========================================================================== */ +/* === Row and Column structures ============================================ */ +/* ========================================================================== */ + +/* User code that makes use of the colamd/symamd routines need not directly */ +/* reference these structures. They are used only for colamd_recommended. */ + +typedef struct Colamd_Col_struct +{ + Int start ; /* index for A of first row in this column, or DEAD */ + /* if column is dead */ + Int length ; /* number of rows in this column */ + union + { + Int thickness ; /* number of original columns represented by this */ + /* col, if the column is alive */ + Int parent ; /* parent in parent tree super-column structure, if */ + /* the column is dead */ + } shared1 ; + union + { + Int score ; /* the score used to maintain heap, if col is alive */ + Int order ; /* pivot ordering of this column, if col is dead */ + } shared2 ; + union + { + Int headhash ; /* head of a hash bucket, if col is at the head of */ + /* a degree list */ + Int hash ; /* hash value, if col is not in a degree list */ + Int prev ; /* previous column in degree list, if col is in a */ + /* degree list (but not at the head of a degree list) */ + } shared3 ; + union + { + Int degree_next ; /* next column, if col is in a degree list */ + Int hash_next ; /* next column, if col is in a hash list */ + } shared4 ; + +} Colamd_Col ; + +typedef struct Colamd_Row_struct +{ + Int start ; /* index for A of first col in this row */ + Int length ; /* number of principal columns in this row */ + union + { + Int degree ; /* number of principal & non-principal columns in row */ + Int p ; /* used as a row pointer in init_rows_cols () */ + } shared1 ; + union + { + Int mark ; /* for computing set differences and marking dead rows*/ + Int first_column ;/* first column in row (used in garbage collection) */ + } shared2 ; + +} Colamd_Row ; + +/* ========================================================================== */ +/* === Definitions ========================================================== */ +/* ========================================================================== */ + +/* Routines are either PUBLIC (user-callable) or PRIVATE (not user-callable) */ +#define PUBLIC +#define PRIVATE static + +#define DENSE_DEGREE(alpha,n) \ + ((Int) MAX (16.0, (alpha) * sqrt ((double) (n)))) + +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +#define ONES_COMPLEMENT(r) (-(r)-1) + +/* -------------------------------------------------------------------------- */ +/* Change for version 2.1: define TRUE and FALSE only if not yet defined */ +/* -------------------------------------------------------------------------- */ + +#ifndef TRUE +#define TRUE (1) +#endif + +#ifndef FALSE +#define FALSE (0) +#endif + +/* -------------------------------------------------------------------------- */ + +#define EMPTY (-1) + +/* Row and column status */ +#define ALIVE (0) +#define DEAD (-1) + +/* Column status */ +#define DEAD_PRINCIPAL (-1) +#define DEAD_NON_PRINCIPAL (-2) + +/* Macros for row and column status update and checking. */ +#define ROW_IS_DEAD(r) ROW_IS_MARKED_DEAD (Row[r].shared2.mark) +#define ROW_IS_MARKED_DEAD(row_mark) (row_mark < ALIVE) +#define ROW_IS_ALIVE(r) (Row [r].shared2.mark >= ALIVE) +#define COL_IS_DEAD(c) (Col [c].start < ALIVE) +#define COL_IS_ALIVE(c) (Col [c].start >= ALIVE) +#define COL_IS_DEAD_PRINCIPAL(c) (Col [c].start == DEAD_PRINCIPAL) +#define KILL_ROW(r) { Row [r].shared2.mark = DEAD ; } +#define KILL_PRINCIPAL_COL(c) { Col [c].start = DEAD_PRINCIPAL ; } +#define KILL_NON_PRINCIPAL_COL(c) { Col [c].start = DEAD_NON_PRINCIPAL ; } + +/* ========================================================================== */ +/* === Colamd reporting mechanism =========================================== */ +/* ========================================================================== */ + +#if defined (MATLAB_MEX_FILE) || defined (MATHWORKS) +/* In MATLAB, matrices are 1-based to the user, but 0-based internally */ +#define INDEX(i) ((i)+1) +#else +/* In C, matrices are 0-based and indices are reported as such in *_report */ +#define INDEX(i) (i) +#endif + +/* ========================================================================== */ +/* === Prototypes of PRIVATE routines ======================================= */ +/* ========================================================================== */ + +PRIVATE Int init_rows_cols +( + Int n_row, + Int n_col, + Colamd_Row Row [], + Colamd_Col Col [], + Int A [], + Int p [], + Int stats [COLAMD_STATS] +) ; + +PRIVATE void init_scoring +( + Int n_row, + Int n_col, + Colamd_Row Row [], + Colamd_Col Col [], + Int A [], + Int head [], + double knobs [COLAMD_KNOBS], + Int *p_n_row2, + Int *p_n_col2, + Int *p_max_deg +) ; + +PRIVATE Int find_ordering +( + Int n_row, + Int n_col, + Int Alen, + Colamd_Row Row [], + Colamd_Col Col [], + Int A [], + Int head [], + Int n_col2, + Int max_deg, + Int pfree, + Int aggressive +) ; + +PRIVATE void order_children +( + Int n_col, + Colamd_Col Col [], + Int p [] +) ; + +PRIVATE void detect_super_cols +( + +#ifndef NDEBUG + Int n_col, + Colamd_Row Row [], +#endif /* NDEBUG */ + + Colamd_Col Col [], + Int A [], + Int head [], + Int row_start, + Int row_length +) ; + +PRIVATE Int garbage_collection +( + Int n_row, + Int n_col, + Colamd_Row Row [], + Colamd_Col Col [], + Int A [], + Int *pfree +) ; + +PRIVATE Int clear_mark +( + Int tag_mark, + Int max_mark, + Int n_row, + Colamd_Row Row [] +) ; + +PRIVATE void print_report +( + char *method, + Int stats [COLAMD_STATS] +) ; + +/* ========================================================================== */ +/* === Debugging prototypes and definitions ================================= */ +/* ========================================================================== */ + +#ifndef NDEBUG + +#include <assert.h> + +/* colamd_debug is the *ONLY* global variable, and is only */ +/* present when debugging */ + +PRIVATE Int colamd_debug = 0 ; /* debug print level */ + +#define DEBUG0(params) { SUITESPARSE_PRINTF (params) ; } +#define DEBUG1(params) { if (colamd_debug >= 1) SUITESPARSE_PRINTF (params) ; } +#define DEBUG2(params) { if (colamd_debug >= 2) SUITESPARSE_PRINTF (params) ; } +#define DEBUG3(params) { if (colamd_debug >= 3) SUITESPARSE_PRINTF (params) ; } +#define DEBUG4(params) { if (colamd_debug >= 4) SUITESPARSE_PRINTF (params) ; } + +#ifdef MATLAB_MEX_FILE +#define ASSERT(expression) (mxAssert ((expression), "")) +#else +#define ASSERT(expression) (assert (expression)) +#endif /* MATLAB_MEX_FILE */ + +PRIVATE void colamd_get_debug /* gets the debug print level from getenv */ +( + char *method +) ; + +PRIVATE void debug_deg_lists +( + Int n_row, + Int n_col, + Colamd_Row Row [], + Colamd_Col Col [], + Int head [], + Int min_score, + Int should, + Int max_deg +) ; + +PRIVATE void debug_mark +( + Int n_row, + Colamd_Row Row [], + Int tag_mark, + Int max_mark +) ; + +PRIVATE void debug_matrix +( + Int n_row, + Int n_col, + Colamd_Row Row [], + Colamd_Col Col [], + Int A [] +) ; + +PRIVATE void debug_structures +( + Int n_row, + Int n_col, + Colamd_Row Row [], + Colamd_Col Col [], + Int A [], + Int n_col2 +) ; + +#else /* NDEBUG */ + +/* === No debugging ========================================================= */ + +#define DEBUG0(params) ; +#define DEBUG1(params) ; +#define DEBUG2(params) ; +#define DEBUG3(params) ; +#define DEBUG4(params) ; + +#define ASSERT(expression) + +#endif /* NDEBUG */ + +/* ========================================================================== */ +/* === USER-CALLABLE ROUTINES: ============================================== */ +/* ========================================================================== */ + +/* ========================================================================== */ +/* === colamd_recommended =================================================== */ +/* ========================================================================== */ + +/* + The colamd_recommended routine returns the suggested size for Alen. This + value has been determined to provide good balance between the number of + garbage collections and the memory requirements for colamd. If any + argument is negative, or if integer overflow occurs, a 0 is returned as an + error condition. 2*nnz space is required for the row and column + indices of the matrix. COLAMD_C (n_col) + COLAMD_R (n_row) space is + required for the Col and Row arrays, respectively, which are internal to + colamd (roughly 6*n_col + 4*n_row). An additional n_col space is the + minimal amount of "elbow room", and nnz/5 more space is recommended for + run time efficiency. + + Alen is approximately 2.2*nnz + 7*n_col + 4*n_row + 10. + + This function is not needed when using symamd. +*/ + +/* add two values of type size_t, and check for integer overflow */ +static size_t t_add (size_t a, size_t b, int *ok) +{ + (*ok) = (*ok) && ((a + b) >= MAX (a,b)) ; + return ((*ok) ? (a + b) : 0) ; +} + +/* compute a*k where k is a small integer, and check for integer overflow */ +static size_t t_mult (size_t a, size_t k, int *ok) +{ + size_t i, s = 0 ; + for (i = 0 ; i < k ; i++) + { + s = t_add (s, a, ok) ; + } + return (s) ; +} + +/* size of the Col and Row structures */ +#define COLAMD_C(n_col,ok) \ + ((t_mult (t_add (n_col, 1, ok), sizeof (Colamd_Col), ok) / sizeof (Int))) + +#define COLAMD_R(n_row,ok) \ + ((t_mult (t_add (n_row, 1, ok), sizeof (Colamd_Row), ok) / sizeof (Int))) + + +PUBLIC size_t COLAMD_recommended /* returns recommended value of Alen. */ +( + /* === Parameters ======================================================= */ + + Int nnz, /* number of nonzeros in A */ + Int n_row, /* number of rows in A */ + Int n_col /* number of columns in A */ +) +{ + size_t s, c, r ; + int ok = TRUE ; + if (nnz < 0 || n_row < 0 || n_col < 0) + { + return (0) ; + } + s = t_mult (nnz, 2, &ok) ; /* 2*nnz */ + c = COLAMD_C (n_col, &ok) ; /* size of column structures */ + r = COLAMD_R (n_row, &ok) ; /* size of row structures */ + s = t_add (s, c, &ok) ; + s = t_add (s, r, &ok) ; + s = t_add (s, n_col, &ok) ; /* elbow room */ + s = t_add (s, nnz/5, &ok) ; /* elbow room */ + ok = ok && (s < Int_MAX) ; + return (ok ? s : 0) ; +} + + +/* ========================================================================== */ +/* === colamd_set_defaults ================================================== */ +/* ========================================================================== */ + +/* + The colamd_set_defaults routine sets the default values of the user- + controllable parameters for colamd and symamd: + + Colamd: rows with more than max (16, knobs [0] * sqrt (n_col)) + entries are removed prior to ordering. Columns with more than + max (16, knobs [1] * sqrt (MIN (n_row,n_col))) entries are removed + prior to ordering, and placed last in the output column ordering. + + Symamd: Rows and columns with more than max (16, knobs [0] * sqrt (n)) + entries are removed prior to ordering, and placed last in the + output ordering. + + knobs [0] dense row control + + knobs [1] dense column control + + knobs [2] if nonzero, do aggresive absorption + + knobs [3..19] unused, but future versions might use this + +*/ + +PUBLIC void COLAMD_set_defaults +( + /* === Parameters ======================================================= */ + + double knobs [COLAMD_KNOBS] /* knob array */ +) +{ + /* === Local variables ================================================== */ + + Int i ; + + if (!knobs) + { + return ; /* no knobs to initialize */ + } + for (i = 0 ; i < COLAMD_KNOBS ; i++) + { + knobs [i] = 0 ; + } + knobs [COLAMD_DENSE_ROW] = 10 ; + knobs [COLAMD_DENSE_COL] = 10 ; + knobs [COLAMD_AGGRESSIVE] = TRUE ; /* default: do aggressive absorption*/ +} + + +/* ========================================================================== */ +/* === symamd =============================================================== */ +/* ========================================================================== */ + +PUBLIC Int SYMAMD_MAIN /* return TRUE if OK, FALSE otherwise */ +( + /* === Parameters ======================================================= */ + + Int n, /* number of rows and columns of A */ + Int A [], /* row indices of A */ + Int p [], /* column pointers of A */ + Int perm [], /* output permutation, size n+1 */ + double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */ + Int stats [COLAMD_STATS], /* output statistics and error codes */ + void * (*allocate) (size_t, size_t), + /* pointer to calloc (ANSI C) or */ + /* mxCalloc (for MATLAB mexFunction) */ + void (*release) (void *) + /* pointer to free (ANSI C) or */ + /* mxFree (for MATLAB mexFunction) */ +) +{ + /* === Local variables ================================================== */ + + Int *count ; /* length of each column of M, and col pointer*/ + Int *mark ; /* mark array for finding duplicate entries */ + Int *M ; /* row indices of matrix M */ + size_t Mlen ; /* length of M */ + Int n_row ; /* number of rows in M */ + Int nnz ; /* number of entries in A */ + Int i ; /* row index of A */ + Int j ; /* column index of A */ + Int k ; /* row index of M */ + Int mnz ; /* number of nonzeros in M */ + Int pp ; /* index into a column of A */ + Int last_row ; /* last row seen in the current column */ + Int length ; /* number of nonzeros in a column */ + + double cknobs [COLAMD_KNOBS] ; /* knobs for colamd */ + double default_knobs [COLAMD_KNOBS] ; /* default knobs for colamd */ + +#ifndef NDEBUG + colamd_get_debug ("symamd") ; +#endif /* NDEBUG */ + + /* === Check the input arguments ======================================== */ + + if (!stats) + { + DEBUG0 (("symamd: stats not present\n")) ; + return (FALSE) ; + } + for (i = 0 ; i < COLAMD_STATS ; i++) + { + stats [i] = 0 ; + } + stats [COLAMD_STATUS] = COLAMD_OK ; + stats [COLAMD_INFO1] = -1 ; + stats [COLAMD_INFO2] = -1 ; + + if (!A) + { + stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ; + DEBUG0 (("symamd: A not present\n")) ; + return (FALSE) ; + } + + if (!p) /* p is not present */ + { + stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ; + DEBUG0 (("symamd: p not present\n")) ; + return (FALSE) ; + } + + if (n < 0) /* n must be >= 0 */ + { + stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ; + stats [COLAMD_INFO1] = n ; + DEBUG0 (("symamd: n negative %d\n", n)) ; + return (FALSE) ; + } + + nnz = p [n] ; + if (nnz < 0) /* nnz must be >= 0 */ + { + stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ; + stats [COLAMD_INFO1] = nnz ; + DEBUG0 (("symamd: number of entries negative %d\n", nnz)) ; + return (FALSE) ; + } + + if (p [0] != 0) + { + stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ; + stats [COLAMD_INFO1] = p [0] ; + DEBUG0 (("symamd: p[0] not zero %d\n", p [0])) ; + return (FALSE) ; + } + + /* === If no knobs, set default knobs =================================== */ + + if (!knobs) + { + COLAMD_set_defaults (default_knobs) ; + knobs = default_knobs ; + } + + /* === Allocate count and mark ========================================== */ + + count = (Int *) ((*allocate) (n+1, sizeof (Int))) ; + if (!count) + { + stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ; + DEBUG0 (("symamd: allocate count (size %d) failed\n", n+1)) ; + return (FALSE) ; + } + + mark = (Int *) ((*allocate) (n+1, sizeof (Int))) ; + if (!mark) + { + stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ; + (*release) ((void *) count) ; + DEBUG0 (("symamd: allocate mark (size %d) failed\n", n+1)) ; + return (FALSE) ; + } + + /* === Compute column counts of M, check if A is valid ================== */ + + stats [COLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/ + + for (i = 0 ; i < n ; i++) + { + mark [i] = -1 ; + } + + for (j = 0 ; j < n ; j++) + { + last_row = -1 ; + + length = p [j+1] - p [j] ; + if (length < 0) + { + /* column pointers must be non-decreasing */ + stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ; + stats [COLAMD_INFO1] = j ; + stats [COLAMD_INFO2] = length ; + (*release) ((void *) count) ; + (*release) ((void *) mark) ; + DEBUG0 (("symamd: col %d negative length %d\n", j, length)) ; + return (FALSE) ; + } + + for (pp = p [j] ; pp < p [j+1] ; pp++) + { + i = A [pp] ; + if (i < 0 || i >= n) + { + /* row index i, in column j, is out of bounds */ + stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ; + stats [COLAMD_INFO1] = j ; + stats [COLAMD_INFO2] = i ; + stats [COLAMD_INFO3] = n ; + (*release) ((void *) count) ; + (*release) ((void *) mark) ; + DEBUG0 (("symamd: row %d col %d out of bounds\n", i, j)) ; + return (FALSE) ; + } + + if (i <= last_row || mark [i] == j) + { + /* row index is unsorted or repeated (or both), thus col */ + /* is jumbled. This is a notice, not an error condition. */ + stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ; + stats [COLAMD_INFO1] = j ; + stats [COLAMD_INFO2] = i ; + (stats [COLAMD_INFO3]) ++ ; + DEBUG1 (("symamd: row %d col %d unsorted/duplicate\n", i, j)) ; + } + + if (i > j && mark [i] != j) + { + /* row k of M will contain column indices i and j */ + count [i]++ ; + count [j]++ ; + } + + /* mark the row as having been seen in this column */ + mark [i] = j ; + + last_row = i ; + } + } + + /* v2.4: removed free(mark) */ + + /* === Compute column pointers of M ===================================== */ + + /* use output permutation, perm, for column pointers of M */ + perm [0] = 0 ; + for (j = 1 ; j <= n ; j++) + { + perm [j] = perm [j-1] + count [j-1] ; + } + for (j = 0 ; j < n ; j++) + { + count [j] = perm [j] ; + } + + /* === Construct M ====================================================== */ + + mnz = perm [n] ; + n_row = mnz / 2 ; + Mlen = COLAMD_recommended (mnz, n_row, n) ; + M = (Int *) ((*allocate) (Mlen, sizeof (Int))) ; + DEBUG0 (("symamd: M is %d-by-%d with %d entries, Mlen = %g\n", + n_row, n, mnz, (double) Mlen)) ; + + if (!M) + { + stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ; + (*release) ((void *) count) ; + (*release) ((void *) mark) ; + DEBUG0 (("symamd: allocate M (size %g) failed\n", (double) Mlen)) ; + return (FALSE) ; + } + + k = 0 ; + + if (stats [COLAMD_STATUS] == COLAMD_OK) + { + /* Matrix is OK */ + for (j = 0 ; j < n ; j++) + { + ASSERT (p [j+1] - p [j] >= 0) ; + for (pp = p [j] ; pp < p [j+1] ; pp++) + { + i = A [pp] ; + ASSERT (i >= 0 && i < n) ; + if (i > j) + { + /* row k of M contains column indices i and j */ + M [count [i]++] = k ; + M [count [j]++] = k ; + k++ ; + } + } + } + } + else + { + /* Matrix is jumbled. Do not add duplicates to M. Unsorted cols OK. */ + DEBUG0 (("symamd: Duplicates in A.\n")) ; + for (i = 0 ; i < n ; i++) + { + mark [i] = -1 ; + } + for (j = 0 ; j < n ; j++) + { + ASSERT (p [j+1] - p [j] >= 0) ; + for (pp = p [j] ; pp < p [j+1] ; pp++) + { + i = A [pp] ; + ASSERT (i >= 0 && i < n) ; + if (i > j && mark [i] != j) + { + /* row k of M contains column indices i and j */ + M [count [i]++] = k ; + M [count [j]++] = k ; + k++ ; + mark [i] = j ; + } + } + } + /* v2.4: free(mark) moved below */ + } + + /* count and mark no longer needed */ + (*release) ((void *) count) ; + (*release) ((void *) mark) ; /* v2.4: free (mark) moved here */ + ASSERT (k == n_row) ; + + /* === Adjust the knobs for M =========================================== */ + + for (i = 0 ; i < COLAMD_KNOBS ; i++) + { + cknobs [i] = knobs [i] ; + } + + /* there are no dense rows in M */ + cknobs [COLAMD_DENSE_ROW] = -1 ; + cknobs [COLAMD_DENSE_COL] = knobs [COLAMD_DENSE_ROW] ; + + /* === Order the columns of M =========================================== */ + + /* v2.4: colamd cannot fail here, so the error check is removed */ + (void) COLAMD_MAIN (n_row, n, (Int) Mlen, M, perm, cknobs, stats) ; + + /* Note that the output permutation is now in perm */ + + /* === get the statistics for symamd from colamd ======================== */ + + /* a dense column in colamd means a dense row and col in symamd */ + stats [COLAMD_DENSE_ROW] = stats [COLAMD_DENSE_COL] ; + + /* === Free M =========================================================== */ + + (*release) ((void *) M) ; + DEBUG0 (("symamd: done.\n")) ; + return (TRUE) ; + +} + +/* ========================================================================== */ +/* === colamd =============================================================== */ +/* ========================================================================== */ + +/* + The colamd routine computes a column ordering Q of a sparse matrix + A such that the LU factorization P(AQ) = LU remains sparse, where P is + selected via partial pivoting. The routine can also be viewed as + providing a permutation Q such that the Cholesky factorization + (AQ)'(AQ) = LL' remains sparse. +*/ + +PUBLIC Int COLAMD_MAIN /* returns TRUE if successful, FALSE otherwise*/ +( + /* === Parameters ======================================================= */ + + Int n_row, /* number of rows in A */ + Int n_col, /* number of columns in A */ + Int Alen, /* length of A */ + Int A [], /* row indices of A */ + Int p [], /* pointers to columns in A */ + double knobs [COLAMD_KNOBS],/* parameters (uses defaults if NULL) */ + Int stats [COLAMD_STATS] /* output statistics and error codes */ +) +{ + /* === Local variables ================================================== */ + + Int i ; /* loop index */ + Int nnz ; /* nonzeros in A */ + size_t Row_size ; /* size of Row [], in integers */ + size_t Col_size ; /* size of Col [], in integers */ + size_t need ; /* minimum required length of A */ + Colamd_Row *Row ; /* pointer into A of Row [0..n_row] array */ + Colamd_Col *Col ; /* pointer into A of Col [0..n_col] array */ + Int n_col2 ; /* number of non-dense, non-empty columns */ + Int n_row2 ; /* number of non-dense, non-empty rows */ + Int ngarbage ; /* number of garbage collections performed */ + Int max_deg ; /* maximum row degree */ + double default_knobs [COLAMD_KNOBS] ; /* default knobs array */ + Int aggressive ; /* do aggressive absorption */ + int ok ; + +#ifndef NDEBUG + colamd_get_debug ("colamd") ; +#endif /* NDEBUG */ + + /* === Check the input arguments ======================================== */ + + if (!stats) + { + DEBUG0 (("colamd: stats not present\n")) ; + return (FALSE) ; + } + for (i = 0 ; i < COLAMD_STATS ; i++) + { + stats [i] = 0 ; + } + stats [COLAMD_STATUS] = COLAMD_OK ; + stats [COLAMD_INFO1] = -1 ; + stats [COLAMD_INFO2] = -1 ; + + if (!A) /* A is not present */ + { + stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ; + DEBUG0 (("colamd: A not present\n")) ; + return (FALSE) ; + } + + if (!p) /* p is not present */ + { + stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ; + DEBUG0 (("colamd: p not present\n")) ; + return (FALSE) ; + } + + if (n_row < 0) /* n_row must be >= 0 */ + { + stats [COLAMD_STATUS] = COLAMD_ERROR_nrow_negative ; + stats [COLAMD_INFO1] = n_row ; + DEBUG0 (("colamd: nrow negative %d\n", n_row)) ; + return (FALSE) ; + } + + if (n_col < 0) /* n_col must be >= 0 */ + { + stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ; + stats [COLAMD_INFO1] = n_col ; + DEBUG0 (("colamd: ncol negative %d\n", n_col)) ; + return (FALSE) ; + } + + nnz = p [n_col] ; + if (nnz < 0) /* nnz must be >= 0 */ + { + stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ; + stats [COLAMD_INFO1] = nnz ; + DEBUG0 (("colamd: number of entries negative %d\n", nnz)) ; + return (FALSE) ; + } + + if (p [0] != 0) + { + stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ; + stats [COLAMD_INFO1] = p [0] ; + DEBUG0 (("colamd: p[0] not zero %d\n", p [0])) ; + return (FALSE) ; + } + + /* === If no knobs, set default knobs =================================== */ + + if (!knobs) + { + COLAMD_set_defaults (default_knobs) ; + knobs = default_knobs ; + } + + aggressive = (knobs [COLAMD_AGGRESSIVE] != FALSE) ; + + /* === Allocate the Row and Col arrays from array A ===================== */ + + ok = TRUE ; + Col_size = COLAMD_C (n_col, &ok) ; /* size of Col array of structs */ + Row_size = COLAMD_R (n_row, &ok) ; /* size of Row array of structs */ + + /* need = 2*nnz + n_col + Col_size + Row_size ; */ + need = t_mult (nnz, 2, &ok) ; + need = t_add (need, n_col, &ok) ; + need = t_add (need, Col_size, &ok) ; + need = t_add (need, Row_size, &ok) ; + + if (!ok || need > (size_t) Alen || need > Int_MAX) + { + /* not enough space in array A to perform the ordering */ + stats [COLAMD_STATUS] = COLAMD_ERROR_A_too_small ; + stats [COLAMD_INFO1] = need ; + stats [COLAMD_INFO2] = Alen ; + DEBUG0 (("colamd: Need Alen >= %d, given only Alen = %d\n", need,Alen)); + return (FALSE) ; + } + + Alen -= Col_size + Row_size ; + Col = (Colamd_Col *) &A [Alen] ; + Row = (Colamd_Row *) &A [Alen + Col_size] ; + + /* === Construct the row and column data structures ===================== */ + + if (!init_rows_cols (n_row, n_col, Row, Col, A, p, stats)) + { + /* input matrix is invalid */ + DEBUG0 (("colamd: Matrix invalid\n")) ; + return (FALSE) ; + } + + /* === Initialize scores, kill dense rows/columns ======================= */ + + init_scoring (n_row, n_col, Row, Col, A, p, knobs, + &n_row2, &n_col2, &max_deg) ; + + /* === Order the supercolumns =========================================== */ + + ngarbage = find_ordering (n_row, n_col, Alen, Row, Col, A, p, + n_col2, max_deg, 2*nnz, aggressive) ; + + /* === Order the non-principal columns ================================== */ + + order_children (n_col, Col, p) ; + + /* === Return statistics in stats ======================================= */ + + stats [COLAMD_DENSE_ROW] = n_row - n_row2 ; + stats [COLAMD_DENSE_COL] = n_col - n_col2 ; + stats [COLAMD_DEFRAG_COUNT] = ngarbage ; + DEBUG0 (("colamd: done.\n")) ; + return (TRUE) ; +} + + +/* ========================================================================== */ +/* === colamd_report ======================================================== */ +/* ========================================================================== */ + +PUBLIC void COLAMD_report +( + Int stats [COLAMD_STATS] +) +{ + print_report ("colamd", stats) ; +} + + +/* ========================================================================== */ +/* === symamd_report ======================================================== */ +/* ========================================================================== */ + +PUBLIC void SYMAMD_report +( + Int stats [COLAMD_STATS] +) +{ + print_report ("symamd", stats) ; +} + + + +/* ========================================================================== */ +/* === NON-USER-CALLABLE ROUTINES: ========================================== */ +/* ========================================================================== */ + +/* There are no user-callable routines beyond this point in the file */ + + +/* ========================================================================== */ +/* === init_rows_cols ======================================================= */ +/* ========================================================================== */ + +/* + Takes the column form of the matrix in A and creates the row form of the + matrix. Also, row and column attributes are stored in the Col and Row + structs. If the columns are un-sorted or contain duplicate row indices, + this routine will also sort and remove duplicate row indices from the + column form of the matrix. Returns FALSE if the matrix is invalid, + TRUE otherwise. Not user-callable. +*/ + +PRIVATE Int init_rows_cols /* returns TRUE if OK, or FALSE otherwise */ +( + /* === Parameters ======================================================= */ + + Int n_row, /* number of rows of A */ + Int n_col, /* number of columns of A */ + Colamd_Row Row [], /* of size n_row+1 */ + Colamd_Col Col [], /* of size n_col+1 */ + Int A [], /* row indices of A, of size Alen */ + Int p [], /* pointers to columns in A, of size n_col+1 */ + Int stats [COLAMD_STATS] /* colamd statistics */ +) +{ + /* === Local variables ================================================== */ + + Int col ; /* a column index */ + Int row ; /* a row index */ + Int *cp ; /* a column pointer */ + Int *cp_end ; /* a pointer to the end of a column */ + Int *rp ; /* a row pointer */ + Int *rp_end ; /* a pointer to the end of a row */ + Int last_row ; /* previous row */ + + /* === Initialize columns, and check column pointers ==================== */ + + for (col = 0 ; col < n_col ; col++) + { + Col [col].start = p [col] ; + Col [col].length = p [col+1] - p [col] ; + + if (Col [col].length < 0) + { + /* column pointers must be non-decreasing */ + stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ; + stats [COLAMD_INFO1] = col ; + stats [COLAMD_INFO2] = Col [col].length ; + DEBUG0 (("colamd: col %d length %d < 0\n", col, Col [col].length)) ; + return (FALSE) ; + } + + Col [col].shared1.thickness = 1 ; + Col [col].shared2.score = 0 ; + Col [col].shared3.prev = EMPTY ; + Col [col].shared4.degree_next = EMPTY ; + } + + /* p [0..n_col] no longer needed, used as "head" in subsequent routines */ + + /* === Scan columns, compute row degrees, and check row indices ========= */ + + stats [COLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/ + + for (row = 0 ; row < n_row ; row++) + { + Row [row].length = 0 ; + Row [row].shared2.mark = -1 ; + } + + for (col = 0 ; col < n_col ; col++) + { + last_row = -1 ; + + cp = &A [p [col]] ; + cp_end = &A [p [col+1]] ; + + while (cp < cp_end) + { + row = *cp++ ; + + /* make sure row indices within range */ + if (row < 0 || row >= n_row) + { + stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ; + stats [COLAMD_INFO1] = col ; + stats [COLAMD_INFO2] = row ; + stats [COLAMD_INFO3] = n_row ; + DEBUG0 (("colamd: row %d col %d out of bounds\n", row, col)) ; + return (FALSE) ; + } + + if (row <= last_row || Row [row].shared2.mark == col) + { + /* row index are unsorted or repeated (or both), thus col */ + /* is jumbled. This is a notice, not an error condition. */ + stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ; + stats [COLAMD_INFO1] = col ; + stats [COLAMD_INFO2] = row ; + (stats [COLAMD_INFO3]) ++ ; + DEBUG1 (("colamd: row %d col %d unsorted/duplicate\n",row,col)); + } + + if (Row [row].shared2.mark != col) + { + Row [row].length++ ; + } + else + { + /* this is a repeated entry in the column, */ + /* it will be removed */ + Col [col].length-- ; + } + + /* mark the row as having been seen in this column */ + Row [row].shared2.mark = col ; + + last_row = row ; + } + } + + /* === Compute row pointers ============================================= */ + + /* row form of the matrix starts directly after the column */ + /* form of matrix in A */ + Row [0].start = p [n_col] ; + Row [0].shared1.p = Row [0].start ; + Row [0].shared2.mark = -1 ; + for (row = 1 ; row < n_row ; row++) + { + Row [row].start = Row [row-1].start + Row [row-1].length ; + Row [row].shared1.p = Row [row].start ; + Row [row].shared2.mark = -1 ; + } + + /* === Create row form ================================================== */ + + if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED) + { + /* if cols jumbled, watch for repeated row indices */ + for (col = 0 ; col < n_col ; col++) + { + cp = &A [p [col]] ; + cp_end = &A [p [col+1]] ; + while (cp < cp_end) + { + row = *cp++ ; + if (Row [row].shared2.mark != col) + { + A [(Row [row].shared1.p)++] = col ; + Row [row].shared2.mark = col ; + } + } + } + } + else + { + /* if cols not jumbled, we don't need the mark (this is faster) */ + for (col = 0 ; col < n_col ; col++) + { + cp = &A [p [col]] ; + cp_end = &A [p [col+1]] ; + while (cp < cp_end) + { + A [(Row [*cp++].shared1.p)++] = col ; + } + } + } + + /* === Clear the row marks and set row degrees ========================== */ + + for (row = 0 ; row < n_row ; row++) + { + Row [row].shared2.mark = 0 ; + Row [row].shared1.degree = Row [row].length ; + } + + /* === See if we need to re-create columns ============================== */ + + if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED) + { + DEBUG0 (("colamd: reconstructing column form, matrix jumbled\n")) ; + +#ifndef NDEBUG + /* make sure column lengths are correct */ + for (col = 0 ; col < n_col ; col++) + { + p [col] = Col [col].length ; + } + for (row = 0 ; row < n_row ; row++) + { + rp = &A [Row [row].start] ; + rp_end = rp + Row [row].length ; + while (rp < rp_end) + { + p [*rp++]-- ; + } + } + for (col = 0 ; col < n_col ; col++) + { + ASSERT (p [col] == 0) ; + } + /* now p is all zero (different than when debugging is turned off) */ +#endif /* NDEBUG */ + + /* === Compute col pointers ========================================= */ + + /* col form of the matrix starts at A [0]. */ + /* Note, we may have a gap between the col form and the row */ + /* form if there were duplicate entries, if so, it will be */ + /* removed upon the first garbage collection */ + Col [0].start = 0 ; + p [0] = Col [0].start ; + for (col = 1 ; col < n_col ; col++) + { + /* note that the lengths here are for pruned columns, i.e. */ + /* no duplicate row indices will exist for these columns */ + Col [col].start = Col [col-1].start + Col [col-1].length ; + p [col] = Col [col].start ; + } + + /* === Re-create col form =========================================== */ + + for (row = 0 ; row < n_row ; row++) + { + rp = &A [Row [row].start] ; + rp_end = rp + Row [row].length ; + while (rp < rp_end) + { + A [(p [*rp++])++] = row ; + } + } + } + + /* === Done. Matrix is not (or no longer) jumbled ====================== */ + + return (TRUE) ; +} + + +/* ========================================================================== */ +/* === init_scoring ========================================================= */ +/* ========================================================================== */ + +/* + Kills dense or empty columns and rows, calculates an initial score for + each column, and places all columns in the degree lists. Not user-callable. +*/ + +PRIVATE void init_scoring +( + /* === Parameters ======================================================= */ + + Int n_row, /* number of rows of A */ + Int n_col, /* number of columns of A */ + Colamd_Row Row [], /* of size n_row+1 */ + Colamd_Col Col [], /* of size n_col+1 */ + Int A [], /* column form and row form of A */ + Int head [], /* of size n_col+1 */ + double knobs [COLAMD_KNOBS],/* parameters */ + Int *p_n_row2, /* number of non-dense, non-empty rows */ + Int *p_n_col2, /* number of non-dense, non-empty columns */ + Int *p_max_deg /* maximum row degree */ +) +{ + /* === Local variables ================================================== */ + + Int c ; /* a column index */ + Int r, row ; /* a row index */ + Int *cp ; /* a column pointer */ + Int deg ; /* degree of a row or column */ + Int *cp_end ; /* a pointer to the end of a column */ + Int *new_cp ; /* new column pointer */ + Int col_length ; /* length of pruned column */ + Int score ; /* current column score */ + Int n_col2 ; /* number of non-dense, non-empty columns */ + Int n_row2 ; /* number of non-dense, non-empty rows */ + Int dense_row_count ; /* remove rows with more entries than this */ + Int dense_col_count ; /* remove cols with more entries than this */ + Int min_score ; /* smallest column score */ + Int max_deg ; /* maximum row degree */ + Int next_col ; /* Used to add to degree list.*/ + +#ifndef NDEBUG + Int debug_count ; /* debug only. */ +#endif /* NDEBUG */ + + /* === Extract knobs ==================================================== */ + + /* Note: if knobs contains a NaN, this is undefined: */ + if (knobs [COLAMD_DENSE_ROW] < 0) + { + /* only remove completely dense rows */ + dense_row_count = n_col-1 ; + } + else + { + dense_row_count = DENSE_DEGREE (knobs [COLAMD_DENSE_ROW], n_col) ; + } + if (knobs [COLAMD_DENSE_COL] < 0) + { + /* only remove completely dense columns */ + dense_col_count = n_row-1 ; + } + else + { + dense_col_count = + DENSE_DEGREE (knobs [COLAMD_DENSE_COL], MIN (n_row, n_col)) ; + } + + DEBUG1 (("colamd: densecount: %d %d\n", dense_row_count, dense_col_count)) ; + max_deg = 0 ; + n_col2 = n_col ; + n_row2 = n_row ; + + /* === Kill empty columns =============================================== */ + + /* Put the empty columns at the end in their natural order, so that LU */ + /* factorization can proceed as far as possible. */ + for (c = n_col-1 ; c >= 0 ; c--) + { + deg = Col [c].length ; + if (deg == 0) + { + /* this is a empty column, kill and order it last */ + Col [c].shared2.order = --n_col2 ; + KILL_PRINCIPAL_COL (c) ; + } + } + DEBUG1 (("colamd: null columns killed: %d\n", n_col - n_col2)) ; + + /* === Kill dense columns =============================================== */ + + /* Put the dense columns at the end, in their natural order */ + for (c = n_col-1 ; c >= 0 ; c--) + { + /* skip any dead columns */ + if (COL_IS_DEAD (c)) + { + continue ; + } + deg = Col [c].length ; + if (deg > dense_col_count) + { + /* this is a dense column, kill and order it last */ + Col [c].shared2.order = --n_col2 ; + /* decrement the row degrees */ + cp = &A [Col [c].start] ; + cp_end = cp + Col [c].length ; + while (cp < cp_end) + { + Row [*cp++].shared1.degree-- ; + } + KILL_PRINCIPAL_COL (c) ; + } + } + DEBUG1 (("colamd: Dense and null columns killed: %d\n", n_col - n_col2)) ; + + /* === Kill dense and empty rows ======================================== */ + + for (r = 0 ; r < n_row ; r++) + { + deg = Row [r].shared1.degree ; + ASSERT (deg >= 0 && deg <= n_col) ; + if (deg > dense_row_count || deg == 0) + { + /* kill a dense or empty row */ + KILL_ROW (r) ; + --n_row2 ; + } + else + { + /* keep track of max degree of remaining rows */ + max_deg = MAX (max_deg, deg) ; + } + } + DEBUG1 (("colamd: Dense and null rows killed: %d\n", n_row - n_row2)) ; + + /* === Compute initial column scores ==================================== */ + + /* At this point the row degrees are accurate. They reflect the number */ + /* of "live" (non-dense) columns in each row. No empty rows exist. */ + /* Some "live" columns may contain only dead rows, however. These are */ + /* pruned in the code below. */ + + /* now find the initial matlab score for each column */ + for (c = n_col-1 ; c >= 0 ; c--) + { + /* skip dead column */ + if (COL_IS_DEAD (c)) + { + continue ; + } + score = 0 ; + cp = &A [Col [c].start] ; + new_cp = cp ; + cp_end = cp + Col [c].length ; + while (cp < cp_end) + { + /* get a row */ + row = *cp++ ; + /* skip if dead */ + if (ROW_IS_DEAD (row)) + { + continue ; + } + /* compact the column */ + *new_cp++ = row ; + /* add row's external degree */ + score += Row [row].shared1.degree - 1 ; + /* guard against integer overflow */ + score = MIN (score, n_col) ; + } + /* determine pruned column length */ + col_length = (Int) (new_cp - &A [Col [c].start]) ; + if (col_length == 0) + { + /* a newly-made null column (all rows in this col are "dense" */ + /* and have already been killed) */ + DEBUG2 (("Newly null killed: %d\n", c)) ; + Col [c].shared2.order = --n_col2 ; + KILL_PRINCIPAL_COL (c) ; + } + else + { + /* set column length and set score */ + ASSERT (score >= 0) ; + ASSERT (score <= n_col) ; + Col [c].length = col_length ; + Col [c].shared2.score = score ; + } + } + DEBUG1 (("colamd: Dense, null, and newly-null columns killed: %d\n", + n_col-n_col2)) ; + + /* At this point, all empty rows and columns are dead. All live columns */ + /* are "clean" (containing no dead rows) and simplicial (no supercolumns */ + /* yet). Rows may contain dead columns, but all live rows contain at */ + /* least one live column. */ + +#ifndef NDEBUG + debug_structures (n_row, n_col, Row, Col, A, n_col2) ; +#endif /* NDEBUG */ + + /* === Initialize degree lists ========================================== */ + +#ifndef NDEBUG + debug_count = 0 ; +#endif /* NDEBUG */ + + /* clear the hash buckets */ + for (c = 0 ; c <= n_col ; c++) + { + head [c] = EMPTY ; + } + min_score = n_col ; + /* place in reverse order, so low column indices are at the front */ + /* of the lists. This is to encourage natural tie-breaking */ + for (c = n_col-1 ; c >= 0 ; c--) + { + /* only add principal columns to degree lists */ + if (COL_IS_ALIVE (c)) + { + DEBUG4 (("place %d score %d minscore %d ncol %d\n", + c, Col [c].shared2.score, min_score, n_col)) ; + + /* === Add columns score to DList =============================== */ + + score = Col [c].shared2.score ; + + ASSERT (min_score >= 0) ; + ASSERT (min_score <= n_col) ; + ASSERT (score >= 0) ; + ASSERT (score <= n_col) ; + ASSERT (head [score] >= EMPTY) ; + + /* now add this column to dList at proper score location */ + next_col = head [score] ; + Col [c].shared3.prev = EMPTY ; + Col [c].shared4.degree_next = next_col ; + + /* if there already was a column with the same score, set its */ + /* previous pointer to this new column */ + if (next_col != EMPTY) + { + Col [next_col].shared3.prev = c ; + } + head [score] = c ; + + /* see if this score is less than current min */ + min_score = MIN (min_score, score) ; + +#ifndef NDEBUG + debug_count++ ; +#endif /* NDEBUG */ + + } + } + +#ifndef NDEBUG + DEBUG1 (("colamd: Live cols %d out of %d, non-princ: %d\n", + debug_count, n_col, n_col-debug_count)) ; + ASSERT (debug_count == n_col2) ; + debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2, max_deg) ; +#endif /* NDEBUG */ + + /* === Return number of remaining columns, and max row degree =========== */ + + *p_n_col2 = n_col2 ; + *p_n_row2 = n_row2 ; + *p_max_deg = max_deg ; +} + + +/* ========================================================================== */ +/* === find_ordering ======================================================== */ +/* ========================================================================== */ + +/* + Order the principal columns of the supercolumn form of the matrix + (no supercolumns on input). Uses a minimum approximate column minimum + degree ordering method. Not user-callable. +*/ + +PRIVATE Int find_ordering /* return the number of garbage collections */ +( + /* === Parameters ======================================================= */ + + Int n_row, /* number of rows of A */ + Int n_col, /* number of columns of A */ + Int Alen, /* size of A, 2*nnz + n_col or larger */ + Colamd_Row Row [], /* of size n_row+1 */ + Colamd_Col Col [], /* of size n_col+1 */ + Int A [], /* column form and row form of A */ + Int head [], /* of size n_col+1 */ + Int n_col2, /* Remaining columns to order */ + Int max_deg, /* Maximum row degree */ + Int pfree, /* index of first free slot (2*nnz on entry) */ + Int aggressive +) +{ + /* === Local variables ================================================== */ + + Int k ; /* current pivot ordering step */ + Int pivot_col ; /* current pivot column */ + Int *cp ; /* a column pointer */ + Int *rp ; /* a row pointer */ + Int pivot_row ; /* current pivot row */ + Int *new_cp ; /* modified column pointer */ + Int *new_rp ; /* modified row pointer */ + Int pivot_row_start ; /* pointer to start of pivot row */ + Int pivot_row_degree ; /* number of columns in pivot row */ + Int pivot_row_length ; /* number of supercolumns in pivot row */ + Int pivot_col_score ; /* score of pivot column */ + Int needed_memory ; /* free space needed for pivot row */ + Int *cp_end ; /* pointer to the end of a column */ + Int *rp_end ; /* pointer to the end of a row */ + Int row ; /* a row index */ + Int col ; /* a column index */ + Int max_score ; /* maximum possible score */ + Int cur_score ; /* score of current column */ + unsigned Int hash ; /* hash value for supernode detection */ + Int head_column ; /* head of hash bucket */ + Int first_col ; /* first column in hash bucket */ + Int tag_mark ; /* marker value for mark array */ + Int row_mark ; /* Row [row].shared2.mark */ + Int set_difference ; /* set difference size of row with pivot row */ + Int min_score ; /* smallest column score */ + Int col_thickness ; /* "thickness" (no. of columns in a supercol) */ + Int max_mark ; /* maximum value of tag_mark */ + Int pivot_col_thickness ; /* number of columns represented by pivot col */ + Int prev_col ; /* Used by Dlist operations. */ + Int next_col ; /* Used by Dlist operations. */ + Int ngarbage ; /* number of garbage collections performed */ + +#ifndef NDEBUG + Int debug_d ; /* debug loop counter */ + Int debug_step = 0 ; /* debug loop counter */ +#endif /* NDEBUG */ + + /* === Initialization and clear mark ==================================== */ + + max_mark = INT_MAX - n_col ; /* INT_MAX defined in <limits.h> */ + tag_mark = clear_mark (0, max_mark, n_row, Row) ; + min_score = 0 ; + ngarbage = 0 ; + DEBUG1 (("colamd: Ordering, n_col2=%d\n", n_col2)) ; + + /* === Order the columns ================================================ */ + + for (k = 0 ; k < n_col2 ; /* 'k' is incremented below */) + { + +#ifndef NDEBUG + if (debug_step % 100 == 0) + { + DEBUG2 (("\n... Step k: %d out of n_col2: %d\n", k, n_col2)) ; + } + else + { + DEBUG3 (("\n----------Step k: %d out of n_col2: %d\n", k, n_col2)) ; + } + debug_step++ ; + debug_deg_lists (n_row, n_col, Row, Col, head, + min_score, n_col2-k, max_deg) ; + debug_matrix (n_row, n_col, Row, Col, A) ; +#endif /* NDEBUG */ + + /* === Select pivot column, and order it ============================ */ + + /* make sure degree list isn't empty */ + ASSERT (min_score >= 0) ; + ASSERT (min_score <= n_col) ; + ASSERT (head [min_score] >= EMPTY) ; + +#ifndef NDEBUG + for (debug_d = 0 ; debug_d < min_score ; debug_d++) + { + ASSERT (head [debug_d] == EMPTY) ; + } +#endif /* NDEBUG */ + + /* get pivot column from head of minimum degree list */ + while (head [min_score] == EMPTY && min_score < n_col) + { + min_score++ ; + } + pivot_col = head [min_score] ; + ASSERT (pivot_col >= 0 && pivot_col <= n_col) ; + next_col = Col [pivot_col].shared4.degree_next ; + head [min_score] = next_col ; + if (next_col != EMPTY) + { + Col [next_col].shared3.prev = EMPTY ; + } + + ASSERT (COL_IS_ALIVE (pivot_col)) ; + + /* remember score for defrag check */ + pivot_col_score = Col [pivot_col].shared2.score ; + + /* the pivot column is the kth column in the pivot order */ + Col [pivot_col].shared2.order = k ; + + /* increment order count by column thickness */ + pivot_col_thickness = Col [pivot_col].shared1.thickness ; + k += pivot_col_thickness ; + ASSERT (pivot_col_thickness > 0) ; + DEBUG3 (("Pivot col: %d thick %d\n", pivot_col, pivot_col_thickness)) ; + + /* === Garbage_collection, if necessary ============================= */ + + needed_memory = MIN (pivot_col_score, n_col - k) ; + if (pfree + needed_memory >= Alen) + { + pfree = garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ; + ngarbage++ ; + /* after garbage collection we will have enough */ + ASSERT (pfree + needed_memory < Alen) ; + /* garbage collection has wiped out the Row[].shared2.mark array */ + tag_mark = clear_mark (0, max_mark, n_row, Row) ; + +#ifndef NDEBUG + debug_matrix (n_row, n_col, Row, Col, A) ; +#endif /* NDEBUG */ + } + + /* === Compute pivot row pattern ==================================== */ + + /* get starting location for this new merged row */ + pivot_row_start = pfree ; + + /* initialize new row counts to zero */ + pivot_row_degree = 0 ; + + /* tag pivot column as having been visited so it isn't included */ + /* in merged pivot row */ + Col [pivot_col].shared1.thickness = -pivot_col_thickness ; + + /* pivot row is the union of all rows in the pivot column pattern */ + cp = &A [Col [pivot_col].start] ; + cp_end = cp + Col [pivot_col].length ; + while (cp < cp_end) + { + /* get a row */ + row = *cp++ ; + DEBUG4 (("Pivot col pattern %d %d\n", ROW_IS_ALIVE (row), row)) ; + /* skip if row is dead */ + if (ROW_IS_ALIVE (row)) + { + rp = &A [Row [row].start] ; + rp_end = rp + Row [row].length ; + while (rp < rp_end) + { + /* get a column */ + col = *rp++ ; + /* add the column, if alive and untagged */ + col_thickness = Col [col].shared1.thickness ; + if (col_thickness > 0 && COL_IS_ALIVE (col)) + { + /* tag column in pivot row */ + Col [col].shared1.thickness = -col_thickness ; + ASSERT (pfree < Alen) ; + /* place column in pivot row */ + A [pfree++] = col ; + pivot_row_degree += col_thickness ; + } + } + } + } + + /* clear tag on pivot column */ + Col [pivot_col].shared1.thickness = pivot_col_thickness ; + max_deg = MAX (max_deg, pivot_row_degree) ; + +#ifndef NDEBUG + DEBUG3 (("check2\n")) ; + debug_mark (n_row, Row, tag_mark, max_mark) ; +#endif /* NDEBUG */ + + /* === Kill all rows used to construct pivot row ==================== */ + + /* also kill pivot row, temporarily */ + cp = &A [Col [pivot_col].start] ; + cp_end = cp + Col [pivot_col].length ; + while (cp < cp_end) + { + /* may be killing an already dead row */ + row = *cp++ ; + DEBUG3 (("Kill row in pivot col: %d\n", row)) ; + KILL_ROW (row) ; + } + + /* === Select a row index to use as the new pivot row =============== */ + + pivot_row_length = pfree - pivot_row_start ; + if (pivot_row_length > 0) + { + /* pick the "pivot" row arbitrarily (first row in col) */ + pivot_row = A [Col [pivot_col].start] ; + DEBUG3 (("Pivotal row is %d\n", pivot_row)) ; + } + else + { + /* there is no pivot row, since it is of zero length */ + pivot_row = EMPTY ; + ASSERT (pivot_row_length == 0) ; + } + ASSERT (Col [pivot_col].length > 0 || pivot_row_length == 0) ; + + /* === Approximate degree computation =============================== */ + + /* Here begins the computation of the approximate degree. The column */ + /* score is the sum of the pivot row "length", plus the size of the */ + /* set differences of each row in the column minus the pattern of the */ + /* pivot row itself. The column ("thickness") itself is also */ + /* excluded from the column score (we thus use an approximate */ + /* external degree). */ + + /* The time taken by the following code (compute set differences, and */ + /* add them up) is proportional to the size of the data structure */ + /* being scanned - that is, the sum of the sizes of each column in */ + /* the pivot row. Thus, the amortized time to compute a column score */ + /* is proportional to the size of that column (where size, in this */ + /* context, is the column "length", or the number of row indices */ + /* in that column). The number of row indices in a column is */ + /* monotonically non-decreasing, from the length of the original */ + /* column on input to colamd. */ + + /* === Compute set differences ====================================== */ + + DEBUG3 (("** Computing set differences phase. **\n")) ; + + /* pivot row is currently dead - it will be revived later. */ + + DEBUG3 (("Pivot row: ")) ; + /* for each column in pivot row */ + rp = &A [pivot_row_start] ; + rp_end = rp + pivot_row_length ; + while (rp < rp_end) + { + col = *rp++ ; + ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ; + DEBUG3 (("Col: %d\n", col)) ; + + /* clear tags used to construct pivot row pattern */ + col_thickness = -Col [col].shared1.thickness ; + ASSERT (col_thickness > 0) ; + Col [col].shared1.thickness = col_thickness ; + + /* === Remove column from degree list =========================== */ + + cur_score = Col [col].shared2.score ; + prev_col = Col [col].shared3.prev ; + next_col = Col [col].shared4.degree_next ; + ASSERT (cur_score >= 0) ; + ASSERT (cur_score <= n_col) ; + ASSERT (cur_score >= EMPTY) ; + if (prev_col == EMPTY) + { + head [cur_score] = next_col ; + } + else + { + Col [prev_col].shared4.degree_next = next_col ; + } + if (next_col != EMPTY) + { + Col [next_col].shared3.prev = prev_col ; + } + + /* === Scan the column ========================================== */ + + cp = &A [Col [col].start] ; + cp_end = cp + Col [col].length ; + while (cp < cp_end) + { + /* get a row */ + row = *cp++ ; + row_mark = Row [row].shared2.mark ; + /* skip if dead */ + if (ROW_IS_MARKED_DEAD (row_mark)) + { + continue ; + } + ASSERT (row != pivot_row) ; + set_difference = row_mark - tag_mark ; + /* check if the row has been seen yet */ + if (set_difference < 0) + { + ASSERT (Row [row].shared1.degree <= max_deg) ; + set_difference = Row [row].shared1.degree ; + } + /* subtract column thickness from this row's set difference */ + set_difference -= col_thickness ; + ASSERT (set_difference >= 0) ; + /* absorb this row if the set difference becomes zero */ + if (set_difference == 0 && aggressive) + { + DEBUG3 (("aggressive absorption. Row: %d\n", row)) ; + KILL_ROW (row) ; + } + else + { + /* save the new mark */ + Row [row].shared2.mark = set_difference + tag_mark ; + } + } + } + +#ifndef NDEBUG + debug_deg_lists (n_row, n_col, Row, Col, head, + min_score, n_col2-k-pivot_row_degree, max_deg) ; +#endif /* NDEBUG */ + + /* === Add up set differences for each column ======================= */ + + DEBUG3 (("** Adding set differences phase. **\n")) ; + + /* for each column in pivot row */ + rp = &A [pivot_row_start] ; + rp_end = rp + pivot_row_length ; + while (rp < rp_end) + { + /* get a column */ + col = *rp++ ; + ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ; + hash = 0 ; + cur_score = 0 ; + cp = &A [Col [col].start] ; + /* compact the column */ + new_cp = cp ; + cp_end = cp + Col [col].length ; + + DEBUG4 (("Adding set diffs for Col: %d.\n", col)) ; + + while (cp < cp_end) + { + /* get a row */ + row = *cp++ ; + ASSERT(row >= 0 && row < n_row) ; + row_mark = Row [row].shared2.mark ; + /* skip if dead */ + if (ROW_IS_MARKED_DEAD (row_mark)) + { + DEBUG4 ((" Row %d, dead\n", row)) ; + continue ; + } + DEBUG4 ((" Row %d, set diff %d\n", row, row_mark-tag_mark)); + ASSERT (row_mark >= tag_mark) ; + /* compact the column */ + *new_cp++ = row ; + /* compute hash function */ + hash += row ; + /* add set difference */ + cur_score += row_mark - tag_mark ; + /* integer overflow... */ + cur_score = MIN (cur_score, n_col) ; + } + + /* recompute the column's length */ + Col [col].length = (Int) (new_cp - &A [Col [col].start]) ; + + /* === Further mass elimination ================================= */ + + if (Col [col].length == 0) + { + DEBUG4 (("further mass elimination. Col: %d\n", col)) ; + /* nothing left but the pivot row in this column */ + KILL_PRINCIPAL_COL (col) ; + pivot_row_degree -= Col [col].shared1.thickness ; + ASSERT (pivot_row_degree >= 0) ; + /* order it */ + Col [col].shared2.order = k ; + /* increment order count by column thickness */ + k += Col [col].shared1.thickness ; + } + else + { + /* === Prepare for supercolumn detection ==================== */ + + DEBUG4 (("Preparing supercol detection for Col: %d.\n", col)) ; + + /* save score so far */ + Col [col].shared2.score = cur_score ; + + /* add column to hash table, for supercolumn detection */ + hash %= n_col + 1 ; + + DEBUG4 ((" Hash = %d, n_col = %d.\n", hash, n_col)) ; + ASSERT (((Int) hash) <= n_col) ; + + head_column = head [hash] ; + if (head_column > EMPTY) + { + /* degree list "hash" is non-empty, use prev (shared3) of */ + /* first column in degree list as head of hash bucket */ + first_col = Col [head_column].shared3.headhash ; + Col [head_column].shared3.headhash = col ; + } + else + { + /* degree list "hash" is empty, use head as hash bucket */ + first_col = - (head_column + 2) ; + head [hash] = - (col + 2) ; + } + Col [col].shared4.hash_next = first_col ; + + /* save hash function in Col [col].shared3.hash */ + Col [col].shared3.hash = (Int) hash ; + ASSERT (COL_IS_ALIVE (col)) ; + } + } + + /* The approximate external column degree is now computed. */ + + /* === Supercolumn detection ======================================== */ + + DEBUG3 (("** Supercolumn detection phase. **\n")) ; + + detect_super_cols ( + +#ifndef NDEBUG + n_col, Row, +#endif /* NDEBUG */ + + Col, A, head, pivot_row_start, pivot_row_length) ; + + /* === Kill the pivotal column ====================================== */ + + KILL_PRINCIPAL_COL (pivot_col) ; + + /* === Clear mark =================================================== */ + + tag_mark = clear_mark (tag_mark+max_deg+1, max_mark, n_row, Row) ; + +#ifndef NDEBUG + DEBUG3 (("check3\n")) ; + debug_mark (n_row, Row, tag_mark, max_mark) ; +#endif /* NDEBUG */ + + /* === Finalize the new pivot row, and column scores ================ */ + + DEBUG3 (("** Finalize scores phase. **\n")) ; + + /* for each column in pivot row */ + rp = &A [pivot_row_start] ; + /* compact the pivot row */ + new_rp = rp ; + rp_end = rp + pivot_row_length ; + while (rp < rp_end) + { + col = *rp++ ; + /* skip dead columns */ + if (COL_IS_DEAD (col)) + { + continue ; + } + *new_rp++ = col ; + /* add new pivot row to column */ + A [Col [col].start + (Col [col].length++)] = pivot_row ; + + /* retrieve score so far and add on pivot row's degree. */ + /* (we wait until here for this in case the pivot */ + /* row's degree was reduced due to mass elimination). */ + cur_score = Col [col].shared2.score + pivot_row_degree ; + + /* calculate the max possible score as the number of */ + /* external columns minus the 'k' value minus the */ + /* columns thickness */ + max_score = n_col - k - Col [col].shared1.thickness ; + + /* make the score the external degree of the union-of-rows */ + cur_score -= Col [col].shared1.thickness ; + + /* make sure score is less or equal than the max score */ + cur_score = MIN (cur_score, max_score) ; + ASSERT (cur_score >= 0) ; + + /* store updated score */ + Col [col].shared2.score = cur_score ; + + /* === Place column back in degree list ========================= */ + + ASSERT (min_score >= 0) ; + ASSERT (min_score <= n_col) ; + ASSERT (cur_score >= 0) ; + ASSERT (cur_score <= n_col) ; + ASSERT (head [cur_score] >= EMPTY) ; + next_col = head [cur_score] ; + Col [col].shared4.degree_next = next_col ; + Col [col].shared3.prev = EMPTY ; + if (next_col != EMPTY) + { + Col [next_col].shared3.prev = col ; + } + head [cur_score] = col ; + + /* see if this score is less than current min */ + min_score = MIN (min_score, cur_score) ; + + } + +#ifndef NDEBUG + debug_deg_lists (n_row, n_col, Row, Col, head, + min_score, n_col2-k, max_deg) ; +#endif /* NDEBUG */ + + /* === Resurrect the new pivot row ================================== */ + + if (pivot_row_degree > 0) + { + /* update pivot row length to reflect any cols that were killed */ + /* during super-col detection and mass elimination */ + Row [pivot_row].start = pivot_row_start ; + Row [pivot_row].length = (Int) (new_rp - &A[pivot_row_start]) ; + ASSERT (Row [pivot_row].length > 0) ; + Row [pivot_row].shared1.degree = pivot_row_degree ; + Row [pivot_row].shared2.mark = 0 ; + /* pivot row is no longer dead */ + + DEBUG1 (("Resurrect Pivot_row %d deg: %d\n", + pivot_row, pivot_row_degree)) ; + } + } + + /* === All principal columns have now been ordered ====================== */ + + return (ngarbage) ; +} + + +/* ========================================================================== */ +/* === order_children ======================================================= */ +/* ========================================================================== */ + +/* + The find_ordering routine has ordered all of the principal columns (the + representatives of the supercolumns). The non-principal columns have not + yet been ordered. This routine orders those columns by walking up the + parent tree (a column is a child of the column which absorbed it). The + final permutation vector is then placed in p [0 ... n_col-1], with p [0] + being the first column, and p [n_col-1] being the last. It doesn't look + like it at first glance, but be assured that this routine takes time linear + in the number of columns. Although not immediately obvious, the time + taken by this routine is O (n_col), that is, linear in the number of + columns. Not user-callable. +*/ + +PRIVATE void order_children +( + /* === Parameters ======================================================= */ + + Int n_col, /* number of columns of A */ + Colamd_Col Col [], /* of size n_col+1 */ + Int p [] /* p [0 ... n_col-1] is the column permutation*/ +) +{ + /* === Local variables ================================================== */ + + Int i ; /* loop counter for all columns */ + Int c ; /* column index */ + Int parent ; /* index of column's parent */ + Int order ; /* column's order */ + + /* === Order each non-principal column ================================== */ + + for (i = 0 ; i < n_col ; i++) + { + /* find an un-ordered non-principal column */ + ASSERT (COL_IS_DEAD (i)) ; + if (!COL_IS_DEAD_PRINCIPAL (i) && Col [i].shared2.order == EMPTY) + { + parent = i ; + /* once found, find its principal parent */ + do + { + parent = Col [parent].shared1.parent ; + } while (!COL_IS_DEAD_PRINCIPAL (parent)) ; + + /* now, order all un-ordered non-principal columns along path */ + /* to this parent. collapse tree at the same time */ + c = i ; + /* get order of parent */ + order = Col [parent].shared2.order ; + + do + { + ASSERT (Col [c].shared2.order == EMPTY) ; + + /* order this column */ + Col [c].shared2.order = order++ ; + /* collaps tree */ + Col [c].shared1.parent = parent ; + + /* get immediate parent of this column */ + c = Col [c].shared1.parent ; + + /* continue until we hit an ordered column. There are */ + /* guarranteed not to be anymore unordered columns */ + /* above an ordered column */ + } while (Col [c].shared2.order == EMPTY) ; + + /* re-order the super_col parent to largest order for this group */ + Col [parent].shared2.order = order ; + } + } + + /* === Generate the permutation ========================================= */ + + for (c = 0 ; c < n_col ; c++) + { + p [Col [c].shared2.order] = c ; + } +} + + +/* ========================================================================== */ +/* === detect_super_cols ==================================================== */ +/* ========================================================================== */ + +/* + Detects supercolumns by finding matches between columns in the hash buckets. + Check amongst columns in the set A [row_start ... row_start + row_length-1]. + The columns under consideration are currently *not* in the degree lists, + and have already been placed in the hash buckets. + + The hash bucket for columns whose hash function is equal to h is stored + as follows: + + if head [h] is >= 0, then head [h] contains a degree list, so: + + head [h] is the first column in degree bucket h. + Col [head [h]].headhash gives the first column in hash bucket h. + + otherwise, the degree list is empty, and: + + -(head [h] + 2) is the first column in hash bucket h. + + For a column c in a hash bucket, Col [c].shared3.prev is NOT a "previous + column" pointer. Col [c].shared3.hash is used instead as the hash number + for that column. The value of Col [c].shared4.hash_next is the next column + in the same hash bucket. + + Assuming no, or "few" hash collisions, the time taken by this routine is + linear in the sum of the sizes (lengths) of each column whose score has + just been computed in the approximate degree computation. + Not user-callable. +*/ + +PRIVATE void detect_super_cols +( + /* === Parameters ======================================================= */ + +#ifndef NDEBUG + /* these two parameters are only needed when debugging is enabled: */ + Int n_col, /* number of columns of A */ + Colamd_Row Row [], /* of size n_row+1 */ +#endif /* NDEBUG */ + + Colamd_Col Col [], /* of size n_col+1 */ + Int A [], /* row indices of A */ + Int head [], /* head of degree lists and hash buckets */ + Int row_start, /* pointer to set of columns to check */ + Int row_length /* number of columns to check */ +) +{ + /* === Local variables ================================================== */ + + Int hash ; /* hash value for a column */ + Int *rp ; /* pointer to a row */ + Int c ; /* a column index */ + Int super_c ; /* column index of the column to absorb into */ + Int *cp1 ; /* column pointer for column super_c */ + Int *cp2 ; /* column pointer for column c */ + Int length ; /* length of column super_c */ + Int prev_c ; /* column preceding c in hash bucket */ + Int i ; /* loop counter */ + Int *rp_end ; /* pointer to the end of the row */ + Int col ; /* a column index in the row to check */ + Int head_column ; /* first column in hash bucket or degree list */ + Int first_col ; /* first column in hash bucket */ + + /* === Consider each column in the row ================================== */ + + rp = &A [row_start] ; + rp_end = rp + row_length ; + while (rp < rp_end) + { + col = *rp++ ; + if (COL_IS_DEAD (col)) + { + continue ; + } + + /* get hash number for this column */ + hash = Col [col].shared3.hash ; + ASSERT (hash <= n_col) ; + + /* === Get the first column in this hash bucket ===================== */ + + head_column = head [hash] ; + if (head_column > EMPTY) + { + first_col = Col [head_column].shared3.headhash ; + } + else + { + first_col = - (head_column + 2) ; + } + + /* === Consider each column in the hash bucket ====================== */ + + for (super_c = first_col ; super_c != EMPTY ; + super_c = Col [super_c].shared4.hash_next) + { + ASSERT (COL_IS_ALIVE (super_c)) ; + ASSERT (Col [super_c].shared3.hash == hash) ; + length = Col [super_c].length ; + + /* prev_c is the column preceding column c in the hash bucket */ + prev_c = super_c ; + + /* === Compare super_c with all columns after it ================ */ + + for (c = Col [super_c].shared4.hash_next ; + c != EMPTY ; c = Col [c].shared4.hash_next) + { + ASSERT (c != super_c) ; + ASSERT (COL_IS_ALIVE (c)) ; + ASSERT (Col [c].shared3.hash == hash) ; + + /* not identical if lengths or scores are different */ + if (Col [c].length != length || + Col [c].shared2.score != Col [super_c].shared2.score) + { + prev_c = c ; + continue ; + } + + /* compare the two columns */ + cp1 = &A [Col [super_c].start] ; + cp2 = &A [Col [c].start] ; + + for (i = 0 ; i < length ; i++) + { + /* the columns are "clean" (no dead rows) */ + ASSERT (ROW_IS_ALIVE (*cp1)) ; + ASSERT (ROW_IS_ALIVE (*cp2)) ; + /* row indices will same order for both supercols, */ + /* no gather scatter nessasary */ + if (*cp1++ != *cp2++) + { + break ; + } + } + + /* the two columns are different if the for-loop "broke" */ + if (i != length) + { + prev_c = c ; + continue ; + } + + /* === Got it! two columns are identical =================== */ + + ASSERT (Col [c].shared2.score == Col [super_c].shared2.score) ; + + Col [super_c].shared1.thickness += Col [c].shared1.thickness ; + Col [c].shared1.parent = super_c ; + KILL_NON_PRINCIPAL_COL (c) ; + /* order c later, in order_children() */ + Col [c].shared2.order = EMPTY ; + /* remove c from hash bucket */ + Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ; + } + } + + /* === Empty this hash bucket ======================================= */ + + if (head_column > EMPTY) + { + /* corresponding degree list "hash" is not empty */ + Col [head_column].shared3.headhash = EMPTY ; + } + else + { + /* corresponding degree list "hash" is empty */ + head [hash] = EMPTY ; + } + } +} + + +/* ========================================================================== */ +/* === garbage_collection =================================================== */ +/* ========================================================================== */ + +/* + Defragments and compacts columns and rows in the workspace A. Used when + all avaliable memory has been used while performing row merging. Returns + the index of the first free position in A, after garbage collection. The + time taken by this routine is linear is the size of the array A, which is + itself linear in the number of nonzeros in the input matrix. + Not user-callable. +*/ + +PRIVATE Int garbage_collection /* returns the new value of pfree */ +( + /* === Parameters ======================================================= */ + + Int n_row, /* number of rows */ + Int n_col, /* number of columns */ + Colamd_Row Row [], /* row info */ + Colamd_Col Col [], /* column info */ + Int A [], /* A [0 ... Alen-1] holds the matrix */ + Int *pfree /* &A [0] ... pfree is in use */ +) +{ + /* === Local variables ================================================== */ + + Int *psrc ; /* source pointer */ + Int *pdest ; /* destination pointer */ + Int j ; /* counter */ + Int r ; /* a row index */ + Int c ; /* a column index */ + Int length ; /* length of a row or column */ + +#ifndef NDEBUG + Int debug_rows ; + DEBUG2 (("Defrag..\n")) ; + for (psrc = &A[0] ; psrc < pfree ; psrc++) ASSERT (*psrc >= 0) ; + debug_rows = 0 ; +#endif /* NDEBUG */ + + /* === Defragment the columns =========================================== */ + + pdest = &A[0] ; + for (c = 0 ; c < n_col ; c++) + { + if (COL_IS_ALIVE (c)) + { + psrc = &A [Col [c].start] ; + + /* move and compact the column */ + ASSERT (pdest <= psrc) ; + Col [c].start = (Int) (pdest - &A [0]) ; + length = Col [c].length ; + for (j = 0 ; j < length ; j++) + { + r = *psrc++ ; + if (ROW_IS_ALIVE (r)) + { + *pdest++ = r ; + } + } + Col [c].length = (Int) (pdest - &A [Col [c].start]) ; + } + } + + /* === Prepare to defragment the rows =================================== */ + + for (r = 0 ; r < n_row ; r++) + { + if (ROW_IS_DEAD (r) || (Row [r].length == 0)) + { + /* This row is already dead, or is of zero length. Cannot compact + * a row of zero length, so kill it. NOTE: in the current version, + * there are no zero-length live rows. Kill the row (for the first + * time, or again) just to be safe. */ + KILL_ROW (r) ; + } + else + { + /* save first column index in Row [r].shared2.first_column */ + psrc = &A [Row [r].start] ; + Row [r].shared2.first_column = *psrc ; + ASSERT (ROW_IS_ALIVE (r)) ; + /* flag the start of the row with the one's complement of row */ + *psrc = ONES_COMPLEMENT (r) ; +#ifndef NDEBUG + debug_rows++ ; +#endif /* NDEBUG */ + } + } + + /* === Defragment the rows ============================================== */ + + psrc = pdest ; + while (psrc < pfree) + { + /* find a negative number ... the start of a row */ + if (*psrc++ < 0) + { + psrc-- ; + /* get the row index */ + r = ONES_COMPLEMENT (*psrc) ; + ASSERT (r >= 0 && r < n_row) ; + /* restore first column index */ + *psrc = Row [r].shared2.first_column ; + ASSERT (ROW_IS_ALIVE (r)) ; + ASSERT (Row [r].length > 0) ; + /* move and compact the row */ + ASSERT (pdest <= psrc) ; + Row [r].start = (Int) (pdest - &A [0]) ; + length = Row [r].length ; + for (j = 0 ; j < length ; j++) + { + c = *psrc++ ; + if (COL_IS_ALIVE (c)) + { + *pdest++ = c ; + } + } + Row [r].length = (Int) (pdest - &A [Row [r].start]) ; + ASSERT (Row [r].length > 0) ; +#ifndef NDEBUG + debug_rows-- ; +#endif /* NDEBUG */ + } + } + /* ensure we found all the rows */ + ASSERT (debug_rows == 0) ; + + /* === Return the new value of pfree ==================================== */ + + return ((Int) (pdest - &A [0])) ; +} + + +/* ========================================================================== */ +/* === clear_mark =========================================================== */ +/* ========================================================================== */ + +/* + Clears the Row [].shared2.mark array, and returns the new tag_mark. + Return value is the new tag_mark. Not user-callable. +*/ + +PRIVATE Int clear_mark /* return the new value for tag_mark */ +( + /* === Parameters ======================================================= */ + + Int tag_mark, /* new value of tag_mark */ + Int max_mark, /* max allowed value of tag_mark */ + + Int n_row, /* number of rows in A */ + Colamd_Row Row [] /* Row [0 ... n_row-1].shared2.mark is set to zero */ +) +{ + /* === Local variables ================================================== */ + + Int r ; + + if (tag_mark <= 0 || tag_mark >= max_mark) + { + for (r = 0 ; r < n_row ; r++) + { + if (ROW_IS_ALIVE (r)) + { + Row [r].shared2.mark = 0 ; + } + } + tag_mark = 1 ; + } + + return (tag_mark) ; +} + + +/* ========================================================================== */ +/* === print_report ========================================================= */ +/* ========================================================================== */ + +PRIVATE void print_report +( + char *method, + Int stats [COLAMD_STATS] +) +{ + + Int i1, i2, i3 ; + + SUITESPARSE_PRINTF (("\n%s version %d.%d, %s: ", method, + COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE)) ; + + if (!stats) + { + SUITESPARSE_PRINTF (("No statistics available.\n")) ; + return ; + } + + i1 = stats [COLAMD_INFO1] ; + i2 = stats [COLAMD_INFO2] ; + i3 = stats [COLAMD_INFO3] ; + + if (stats [COLAMD_STATUS] >= 0) + { + SUITESPARSE_PRINTF (("OK. ")) ; + } + else + { + SUITESPARSE_PRINTF (("ERROR. ")) ; + } + + switch (stats [COLAMD_STATUS]) + { + + case COLAMD_OK_BUT_JUMBLED: + + SUITESPARSE_PRINTF(( + "Matrix has unsorted or duplicate row indices.\n")) ; + + SUITESPARSE_PRINTF(( + "%s: number of duplicate or out-of-order row indices: %d\n", + method, i3)) ; + + SUITESPARSE_PRINTF(( + "%s: last seen duplicate or out-of-order row index: %d\n", + method, INDEX (i2))) ; + + SUITESPARSE_PRINTF(( + "%s: last seen in column: %d", + method, INDEX (i1))) ; + + /* no break - fall through to next case instead */ + + case COLAMD_OK: + + SUITESPARSE_PRINTF(("\n")) ; + + SUITESPARSE_PRINTF(( + "%s: number of dense or empty rows ignored: %d\n", + method, stats [COLAMD_DENSE_ROW])) ; + + SUITESPARSE_PRINTF(( + "%s: number of dense or empty columns ignored: %d\n", + method, stats [COLAMD_DENSE_COL])) ; + + SUITESPARSE_PRINTF(( + "%s: number of garbage collections performed: %d\n", + method, stats [COLAMD_DEFRAG_COUNT])) ; + break ; + + case COLAMD_ERROR_A_not_present: + + SUITESPARSE_PRINTF(( + "Array A (row indices of matrix) not present.\n")) ; + break ; + + case COLAMD_ERROR_p_not_present: + + SUITESPARSE_PRINTF(( + "Array p (column pointers for matrix) not present.\n")) ; + break ; + + case COLAMD_ERROR_nrow_negative: + + SUITESPARSE_PRINTF(("Invalid number of rows (%d).\n", i1)) ; + break ; + + case COLAMD_ERROR_ncol_negative: + + SUITESPARSE_PRINTF(("Invalid number of columns (%d).\n", i1)) ; + break ; + + case COLAMD_ERROR_nnz_negative: + + SUITESPARSE_PRINTF(( + "Invalid number of nonzero entries (%d).\n", i1)) ; + break ; + + case COLAMD_ERROR_p0_nonzero: + + SUITESPARSE_PRINTF(( + "Invalid column pointer, p [0] = %d, must be zero.\n", i1)); + break ; + + case COLAMD_ERROR_A_too_small: + + SUITESPARSE_PRINTF(("Array A too small.\n")) ; + SUITESPARSE_PRINTF(( + " Need Alen >= %d, but given only Alen = %d.\n", + i1, i2)) ; + break ; + + case COLAMD_ERROR_col_length_negative: + + SUITESPARSE_PRINTF + (("Column %d has a negative number of nonzero entries (%d).\n", + INDEX (i1), i2)) ; + break ; + + case COLAMD_ERROR_row_index_out_of_bounds: + + SUITESPARSE_PRINTF + (("Row index (row %d) out of bounds (%d to %d) in column %d.\n", + INDEX (i2), INDEX (0), INDEX (i3-1), INDEX (i1))) ; + break ; + + case COLAMD_ERROR_out_of_memory: + + SUITESPARSE_PRINTF(("Out of memory.\n")) ; + break ; + + /* v2.4: internal-error case deleted */ + } +} + + + + +/* ========================================================================== */ +/* === colamd debugging routines ============================================ */ +/* ========================================================================== */ + +/* When debugging is disabled, the remainder of this file is ignored. */ + +#ifndef NDEBUG + + +/* ========================================================================== */ +/* === debug_structures ===================================================== */ +/* ========================================================================== */ + +/* + At this point, all empty rows and columns are dead. All live columns + are "clean" (containing no dead rows) and simplicial (no supercolumns + yet). Rows may contain dead columns, but all live rows contain at + least one live column. +*/ + +PRIVATE void debug_structures +( + /* === Parameters ======================================================= */ + + Int n_row, + Int n_col, + Colamd_Row Row [], + Colamd_Col Col [], + Int A [], + Int n_col2 +) +{ + /* === Local variables ================================================== */ + + Int i ; + Int c ; + Int *cp ; + Int *cp_end ; + Int len ; + Int score ; + Int r ; + Int *rp ; + Int *rp_end ; + Int deg ; + + /* === Check A, Row, and Col ============================================ */ + + for (c = 0 ; c < n_col ; c++) + { + if (COL_IS_ALIVE (c)) + { + len = Col [c].length ; + score = Col [c].shared2.score ; + DEBUG4 (("initial live col %5d %5d %5d\n", c, len, score)) ; + ASSERT (len > 0) ; + ASSERT (score >= 0) ; + ASSERT (Col [c].shared1.thickness == 1) ; + cp = &A [Col [c].start] ; + cp_end = cp + len ; + while (cp < cp_end) + { + r = *cp++ ; + ASSERT (ROW_IS_ALIVE (r)) ; + } + } + else + { + i = Col [c].shared2.order ; + ASSERT (i >= n_col2 && i < n_col) ; + } + } + + for (r = 0 ; r < n_row ; r++) + { + if (ROW_IS_ALIVE (r)) + { + i = 0 ; + len = Row [r].length ; + deg = Row [r].shared1.degree ; + ASSERT (len > 0) ; + ASSERT (deg > 0) ; + rp = &A [Row [r].start] ; + rp_end = rp + len ; + while (rp < rp_end) + { + c = *rp++ ; + if (COL_IS_ALIVE (c)) + { + i++ ; + } + } + ASSERT (i > 0) ; + } + } +} + + +/* ========================================================================== */ +/* === debug_deg_lists ====================================================== */ +/* ========================================================================== */ + +/* + Prints the contents of the degree lists. Counts the number of columns + in the degree list and compares it to the total it should have. Also + checks the row degrees. +*/ + +PRIVATE void debug_deg_lists +( + /* === Parameters ======================================================= */ + + Int n_row, + Int n_col, + Colamd_Row Row [], + Colamd_Col Col [], + Int head [], + Int min_score, + Int should, + Int max_deg +) +{ + /* === Local variables ================================================== */ + + Int deg ; + Int col ; + Int have ; + Int row ; + + /* === Check the degree lists =========================================== */ + + if (n_col > 10000 && colamd_debug <= 0) + { + return ; + } + have = 0 ; + DEBUG4 (("Degree lists: %d\n", min_score)) ; + for (deg = 0 ; deg <= n_col ; deg++) + { + col = head [deg] ; + if (col == EMPTY) + { + continue ; + } + DEBUG4 (("%d:", deg)) ; + while (col != EMPTY) + { + DEBUG4 ((" %d", col)) ; + have += Col [col].shared1.thickness ; + ASSERT (COL_IS_ALIVE (col)) ; + col = Col [col].shared4.degree_next ; + } + DEBUG4 (("\n")) ; + } + DEBUG4 (("should %d have %d\n", should, have)) ; + ASSERT (should == have) ; + + /* === Check the row degrees ============================================ */ + + if (n_row > 10000 && colamd_debug <= 0) + { + return ; + } + for (row = 0 ; row < n_row ; row++) + { + if (ROW_IS_ALIVE (row)) + { + ASSERT (Row [row].shared1.degree <= max_deg) ; + } + } +} + + +/* ========================================================================== */ +/* === debug_mark =========================================================== */ +/* ========================================================================== */ + +/* + Ensures that the tag_mark is less that the maximum and also ensures that + each entry in the mark array is less than the tag mark. +*/ + +PRIVATE void debug_mark +( + /* === Parameters ======================================================= */ + + Int n_row, + Colamd_Row Row [], + Int tag_mark, + Int max_mark +) +{ + /* === Local variables ================================================== */ + + Int r ; + + /* === Check the Row marks ============================================== */ + + ASSERT (tag_mark > 0 && tag_mark <= max_mark) ; + if (n_row > 10000 && colamd_debug <= 0) + { + return ; + } + for (r = 0 ; r < n_row ; r++) + { + ASSERT (Row [r].shared2.mark < tag_mark) ; + } +} + + +/* ========================================================================== */ +/* === debug_matrix ========================================================= */ +/* ========================================================================== */ + +/* + Prints out the contents of the columns and the rows. +*/ + +PRIVATE void debug_matrix +( + /* === Parameters ======================================================= */ + + Int n_row, + Int n_col, + Colamd_Row Row [], + Colamd_Col Col [], + Int A [] +) +{ + /* === Local variables ================================================== */ + + Int r ; + Int c ; + Int *rp ; + Int *rp_end ; + Int *cp ; + Int *cp_end ; + + /* === Dump the rows and columns of the matrix ========================== */ + + if (colamd_debug < 3) + { + return ; + } + DEBUG3 (("DUMP MATRIX:\n")) ; + for (r = 0 ; r < n_row ; r++) + { + DEBUG3 (("Row %d alive? %d\n", r, ROW_IS_ALIVE (r))) ; + if (ROW_IS_DEAD (r)) + { + continue ; + } + DEBUG3 (("start %d length %d degree %d\n", + Row [r].start, Row [r].length, Row [r].shared1.degree)) ; + rp = &A [Row [r].start] ; + rp_end = rp + Row [r].length ; + while (rp < rp_end) + { + c = *rp++ ; + DEBUG4 ((" %d col %d\n", COL_IS_ALIVE (c), c)) ; + } + } + + for (c = 0 ; c < n_col ; c++) + { + DEBUG3 (("Col %d alive? %d\n", c, COL_IS_ALIVE (c))) ; + if (COL_IS_DEAD (c)) + { + continue ; + } + DEBUG3 (("start %d length %d shared1 %d shared2 %d\n", + Col [c].start, Col [c].length, + Col [c].shared1.thickness, Col [c].shared2.score)) ; + cp = &A [Col [c].start] ; + cp_end = cp + Col [c].length ; + while (cp < cp_end) + { + r = *cp++ ; + DEBUG4 ((" %d row %d\n", ROW_IS_ALIVE (r), r)) ; + } + } +} + +PRIVATE void colamd_get_debug +( + char *method +) +{ + FILE *f ; + colamd_debug = 0 ; /* no debug printing */ + f = fopen ("debug", "r") ; + if (f == (FILE *) NULL) + { + colamd_debug = 0 ; + } + else + { + fscanf (f, "%d", &colamd_debug) ; + fclose (f) ; + } + DEBUG0 (("%s: debug version, D = %d (THIS WILL BE SLOW!)\n", + method, colamd_debug)) ; +} + +#endif /* NDEBUG */ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Demo/klu_simple.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Demo/klu_simple.c new file mode 100644 index 0000000..7530d40 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Demo/klu_simple.c @@ -0,0 +1,27 @@ +/* klu_simple: a simple KLU demo; solution is x = (1,2,3,4,5) */ + +#include <stdio.h> +#include "klu.h" + +int n = 5 ; +int Ap [ ] = {0, 2, 5, 9, 10, 12} ; +int Ai [ ] = { 0, 1, 0, 2, 4, 1, 2, 3, 4, 2, 1, 4} ; +double Ax [ ] = {2., 3., 3., -1., 4., 4., -3., 1., 2., 2., 6., 1.} ; +double b [ ] = {8., 45., -3., 3., 19.} ; + +int main (void) +{ + klu_symbolic *Symbolic ; + klu_numeric *Numeric ; + klu_common Common ; + int i ; + klu_defaults (&Common) ; + Symbolic = klu_analyze (n, Ap, Ai, &Common) ; + Numeric = klu_factor (Ap, Ai, Ax, Symbolic, &Common) ; + klu_solve (Symbolic, Numeric, 5, 1, b, &Common) ; + klu_free_symbolic (&Symbolic, &Common) ; + klu_free_numeric (&Numeric, &Common) ; + for (i = 0 ; i < n ; i++) printf ("x [%d] = %g\n", i, b [i]) ; + return (0) ; +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Demo/kludemo.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Demo/kludemo.c new file mode 100644 index 0000000..b6b2295 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Demo/kludemo.c @@ -0,0 +1,326 @@ +/* ========================================================================== */ +/* === KLU DEMO ============================================================= */ +/* ========================================================================== */ + +/* Read in a Matrix Market matrix (using CHOLMOD) and solve a linear system. */ + +#include <math.h> +#include <stdio.h> +#include "klu.h" + +/* for handling complex matrices */ +#define REAL(X,i) (X [2*(i)]) +#define IMAG(X,i) (X [2*(i)+1]) +#define CABS(X,i) (sqrt (REAL (X,i) * REAL (X,i) + IMAG (X,i) * IMAG (X,i))) + +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +/* ========================================================================== */ +/* === klu_backslash ======================================================== */ +/* ========================================================================== */ + +static int klu_backslash /* return 1 if successful, 0 otherwise */ +( + /* --- input ---- */ + int n, /* A is n-by-n */ + int *Ap, /* size n+1, column pointers */ + int *Ai, /* size nz = Ap [n], row indices */ + double *Ax, /* size nz, numerical values */ + int isreal, /* nonzero if A is real, 0 otherwise */ + double *B, /* size n, right-hand-side */ + + /* --- output ---- */ + double *X, /* size n, solution to Ax=b */ + double *R, /* size n, residual r = b-A*x */ + + /* --- scalar output --- */ + int *lunz, /* nnz (L+U+F) */ + double *rnorm, /* norm (b-A*x,1) / norm (A,1) */ + + /* --- workspace - */ + + klu_common *Common /* default parameters and statistics */ +) +{ + double anorm = 0, asum ; + klu_symbolic *Symbolic ; + klu_numeric *Numeric ; + int i, j, p ; + + if (!Ap || !Ai || !Ax || !B || !X || !B) return (0) ; + + /* ---------------------------------------------------------------------- */ + /* symbolic ordering and analysis */ + /* ---------------------------------------------------------------------- */ + + Symbolic = klu_analyze (n, Ap, Ai, Common) ; + if (!Symbolic) return (0) ; + + if (isreal) + { + + /* ------------------------------------------------------------------ */ + /* factorization */ + /* ------------------------------------------------------------------ */ + + Numeric = klu_factor (Ap, Ai, Ax, Symbolic, Common) ; + if (!Numeric) + { + klu_free_symbolic (&Symbolic, Common) ; + return (0) ; + } + + /* ------------------------------------------------------------------ */ + /* statistics (not required to solve Ax=b) */ + /* ------------------------------------------------------------------ */ + + klu_rgrowth (Ap, Ai, Ax, Symbolic, Numeric, Common) ; + klu_condest (Ap, Ax, Symbolic, Numeric, Common) ; + klu_rcond (Symbolic, Numeric, Common) ; + klu_flops (Symbolic, Numeric, Common) ; + *lunz = Numeric->lnz + Numeric->unz - n + + ((Numeric->Offp) ? (Numeric->Offp [n]) : 0) ; + + /* ------------------------------------------------------------------ */ + /* solve Ax=b */ + /* ------------------------------------------------------------------ */ + + for (i = 0 ; i < n ; i++) + { + X [i] = B [i] ; + } + klu_solve (Symbolic, Numeric, n, 1, X, Common) ; + + /* ------------------------------------------------------------------ */ + /* compute residual, rnorm = norm(b-Ax,1) / norm(A,1) */ + /* ------------------------------------------------------------------ */ + + for (i = 0 ; i < n ; i++) + { + R [i] = B [i] ; + } + for (j = 0 ; j < n ; j++) + { + asum = 0 ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + /* R (i) -= A (i,j) * X (j) */ + R [Ai [p]] -= Ax [p] * X [j] ; + asum += fabs (Ax [p]) ; + } + anorm = MAX (anorm, asum) ; + } + *rnorm = 0 ; + for (i = 0 ; i < n ; i++) + { + *rnorm = MAX (*rnorm, fabs (R [i])) ; + } + + /* ------------------------------------------------------------------ */ + /* free numeric factorization */ + /* ------------------------------------------------------------------ */ + + klu_free_numeric (&Numeric, Common) ; + + } + else + { + + /* ------------------------------------------------------------------ */ + /* statistics (not required to solve Ax=b) */ + /* ------------------------------------------------------------------ */ + + Numeric = klu_z_factor (Ap, Ai, Ax, Symbolic, Common) ; + if (!Numeric) + { + klu_free_symbolic (&Symbolic, Common) ; + return (0) ; + } + + /* ------------------------------------------------------------------ */ + /* statistics */ + /* ------------------------------------------------------------------ */ + + klu_z_rgrowth (Ap, Ai, Ax, Symbolic, Numeric, Common) ; + klu_z_condest (Ap, Ax, Symbolic, Numeric, Common) ; + klu_z_rcond (Symbolic, Numeric, Common) ; + klu_z_flops (Symbolic, Numeric, Common) ; + *lunz = Numeric->lnz + Numeric->unz - n + + ((Numeric->Offp) ? (Numeric->Offp [n]) : 0) ; + + /* ------------------------------------------------------------------ */ + /* solve Ax=b */ + /* ------------------------------------------------------------------ */ + + for (i = 0 ; i < 2*n ; i++) + { + X [i] = B [i] ; + } + klu_z_solve (Symbolic, Numeric, n, 1, X, Common) ; + + /* ------------------------------------------------------------------ */ + /* compute residual, rnorm = norm(b-Ax,1) / norm(A,1) */ + /* ------------------------------------------------------------------ */ + + for (i = 0 ; i < 2*n ; i++) + { + R [i] = B [i] ; + } + for (j = 0 ; j < n ; j++) + { + asum = 0 ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + /* R (i) -= A (i,j) * X (j) */ + i = Ai [p] ; + REAL (R,i) -= REAL(Ax,p) * REAL(X,j) - IMAG(Ax,p) * IMAG(X,j) ; + IMAG (R,i) -= IMAG(Ax,p) * REAL(X,j) + REAL(Ax,p) * IMAG(X,j) ; + asum += CABS (Ax, p) ; + } + anorm = MAX (anorm, asum) ; + } + *rnorm = 0 ; + for (i = 0 ; i < n ; i++) + { + *rnorm = MAX (*rnorm, CABS (R, i)) ; + } + + /* ------------------------------------------------------------------ */ + /* free numeric factorization */ + /* ------------------------------------------------------------------ */ + + klu_z_free_numeric (&Numeric, Common) ; + } + + /* ---------------------------------------------------------------------- */ + /* free symbolic analysis, and residual */ + /* ---------------------------------------------------------------------- */ + + klu_free_symbolic (&Symbolic, Common) ; + return (1) ; +} + + +/* ========================================================================== */ +/* === klu_demo ============================================================= */ +/* ========================================================================== */ + +/* Given a sparse matrix A, set up a right-hand-side and solve X = A\b */ + +static void klu_demo (int n, int *Ap, int *Ai, double *Ax, int isreal) +{ + double rnorm ; + klu_common Common ; + double *B, *X, *R ; + int i, lunz ; + + printf ("KLU: %s, version: %d.%d.%d\n", KLU_DATE, KLU_MAIN_VERSION, + KLU_SUB_VERSION, KLU_SUBSUB_VERSION) ; + + /* ---------------------------------------------------------------------- */ + /* set defaults */ + /* ---------------------------------------------------------------------- */ + + klu_defaults (&Common) ; + + /* ---------------------------------------------------------------------- */ + /* create a right-hand-side */ + /* ---------------------------------------------------------------------- */ + + if (isreal) + { + /* B = 1 + (1:n)/n */ + B = klu_malloc (n, sizeof (double), &Common) ; + X = klu_malloc (n, sizeof (double), &Common) ; + R = klu_malloc (n, sizeof (double), &Common) ; + if (B) + { + for (i = 0 ; i < n ; i++) + { + B [i] = 1 + ((double) i+1) / ((double) n) ; + } + } + } + else + { + /* real (B) = 1 + (1:n)/n, imag(B) = (n:-1:1)/n */ + B = klu_malloc (n, 2 * sizeof (double), &Common) ; + X = klu_malloc (n, 2 * sizeof (double), &Common) ; + R = klu_malloc (n, 2 * sizeof (double), &Common) ; + if (B) + { + for (i = 0 ; i < n ; i++) + { + REAL (B, i) = 1 + ((double) i+1) / ((double) n) ; + IMAG (B, i) = ((double) n-i) / ((double) n) ; + } + } + } + + /* ---------------------------------------------------------------------- */ + /* X = A\b using KLU and print statistics */ + /* ---------------------------------------------------------------------- */ + + if (!klu_backslash (n, Ap, Ai, Ax, isreal, B, X, R, &lunz, &rnorm, &Common)) + { + printf ("KLU failed\n") ; + } + else + { + printf ("n %d nnz(A) %d nnz(L+U+F) %d resid %g\n" + "recip growth %g condest %g rcond %g flops %g\n", + n, Ap [n], lunz, rnorm, Common.rgrowth, Common.condest, + Common.rcond, Common.flops) ; + } + + /* ---------------------------------------------------------------------- */ + /* free the problem */ + /* ---------------------------------------------------------------------- */ + + if (isreal) + { + klu_free (B, n, sizeof (double), &Common) ; + klu_free (X, n, sizeof (double), &Common) ; + klu_free (R, n, sizeof (double), &Common) ; + } + else + { + klu_free (B, 2*n, sizeof (double), &Common) ; + klu_free (X, 2*n, sizeof (double), &Common) ; + klu_free (R, 2*n, sizeof (double), &Common) ; + } + printf ("peak memory usage: %g bytes\n\n", (double) (Common.mempeak)) ; +} + + +/* ========================================================================== */ +/* === main ================================================================= */ +/* ========================================================================== */ + +/* Read in a sparse matrix in Matrix Market format using CHOLMOD, and then + * solve Ax=b with KLU. Note that CHOLMOD is only used to read the matrix. */ + +#include "cholmod.h" + +int main (void) +{ + cholmod_sparse *A ; + cholmod_common ch ; + cholmod_start (&ch) ; + A = cholmod_read_sparse (stdin, &ch) ; + if (A) + { + if (A->nrow != A->ncol || A->stype != 0 + || (!(A->xtype == CHOLMOD_REAL || A->xtype == CHOLMOD_COMPLEX))) + { + printf ("invalid matrix\n") ; + } + else + { + klu_demo (A->nrow, A->p, A->i, A->x, A->xtype == CHOLMOD_REAL) ; + } + cholmod_free_sparse (&A, &ch) ; + } + cholmod_finish (&ch) ; + return (0) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Demo/kluldemo.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Demo/kluldemo.c new file mode 100644 index 0000000..ccf0644 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Demo/kluldemo.c @@ -0,0 +1,329 @@ +/* ========================================================================== */ +/* === KLU DEMO (long integer version) ====================================== */ +/* ========================================================================== */ + +/* Read in a Matrix Market matrix (using CHOLMOD) and solve a linear system. + * SuiteSparse_long is normally a "long", but it becomes "_int64" on Windows 64. */ + +#include <math.h> +#include <stdio.h> +#include "klu.h" +#define Long SuiteSparse_long + +/* for handling complex matrices */ +#define REAL(X,i) (X [2*(i)]) +#define IMAG(X,i) (X [2*(i)+1]) +#define CABS(X,i) (sqrt (REAL (X,i) * REAL (X,i) + IMAG (X,i) * IMAG (X,i))) + +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +/* ========================================================================== */ +/* === klu_l_backslash ====================================================== */ +/* ========================================================================== */ + +static Long klu_l_backslash /* return 1 if successful, 0 otherwise */ +( + /* --- input ---- */ + Long n, /* A is n-by-n */ + Long *Ap, /* size n+1, column pointers */ + Long *Ai, /* size nz = Ap [n], row indices */ + double *Ax, /* size nz, numerical values */ + Long isreal, /* nonzero if A is real, 0 otherwise */ + double *B, /* size n, right-hand-side */ + + /* --- output ---- */ + double *X, /* size n, solution to Ax=b */ + double *R, /* size n, residual r = b-A*x */ + + /* --- scalar output --- */ + Long *lunz, /* nnz (L+U+F) */ + double *rnorm, /* norm (b-A*x,1) / norm (A,1) */ + + /* --- workspace - */ + + klu_l_common *Common /* default parameters and statistics */ +) +{ + double anorm = 0, asum ; + klu_l_symbolic *Symbolic ; + klu_l_numeric *Numeric ; + Long i, j, p ; + + if (!Ap || !Ai || !Ax || !B || !X || !B) return (0) ; + + /* ---------------------------------------------------------------------- */ + /* symbolic ordering and analysis */ + /* ---------------------------------------------------------------------- */ + + Symbolic = klu_l_analyze (n, Ap, Ai, Common) ; + if (!Symbolic) return (0) ; + + if (isreal) + { + + /* ------------------------------------------------------------------ */ + /* factorization */ + /* ------------------------------------------------------------------ */ + + Numeric = klu_l_factor (Ap, Ai, Ax, Symbolic, Common) ; + if (!Numeric) + { + klu_l_free_symbolic (&Symbolic, Common) ; + return (0) ; + } + + /* ------------------------------------------------------------------ */ + /* statistics (not required to solve Ax=b) */ + /* ------------------------------------------------------------------ */ + + klu_l_rgrowth (Ap, Ai, Ax, Symbolic, Numeric, Common) ; + klu_l_condest (Ap, Ax, Symbolic, Numeric, Common) ; + klu_l_rcond (Symbolic, Numeric, Common) ; + klu_l_flops (Symbolic, Numeric, Common) ; + *lunz = Numeric->lnz + Numeric->unz - n + + ((Numeric->Offp) ? (Numeric->Offp [n]) : 0) ; + + /* ------------------------------------------------------------------ */ + /* solve Ax=b */ + /* ------------------------------------------------------------------ */ + + for (i = 0 ; i < n ; i++) + { + X [i] = B [i] ; + } + klu_l_solve (Symbolic, Numeric, n, 1, X, Common) ; + + /* ------------------------------------------------------------------ */ + /* compute residual, rnorm = norm(b-Ax,1) / norm(A,1) */ + /* ------------------------------------------------------------------ */ + + for (i = 0 ; i < n ; i++) + { + R [i] = B [i] ; + } + for (j = 0 ; j < n ; j++) + { + asum = 0 ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + /* R (i) -= A (i,j) * X (j) */ + R [Ai [p]] -= Ax [p] * X [j] ; + asum += fabs (Ax [p]) ; + } + anorm = MAX (anorm, asum) ; + } + *rnorm = 0 ; + for (i = 0 ; i < n ; i++) + { + *rnorm = MAX (*rnorm, fabs (R [i])) ; + } + + /* ------------------------------------------------------------------ */ + /* free numeric factorization */ + /* ------------------------------------------------------------------ */ + + klu_l_free_numeric (&Numeric, Common) ; + + } + else + { + + /* ------------------------------------------------------------------ */ + /* statistics (not required to solve Ax=b) */ + /* ------------------------------------------------------------------ */ + + Numeric = klu_zl_factor (Ap, Ai, Ax, Symbolic, Common) ; + if (!Numeric) + { + klu_l_free_symbolic (&Symbolic, Common) ; + return (0) ; + } + + /* ------------------------------------------------------------------ */ + /* statistics */ + /* ------------------------------------------------------------------ */ + + klu_zl_rgrowth (Ap, Ai, Ax, Symbolic, Numeric, Common) ; + klu_zl_condest (Ap, Ax, Symbolic, Numeric, Common) ; + klu_zl_rcond (Symbolic, Numeric, Common) ; + klu_zl_flops (Symbolic, Numeric, Common) ; + *lunz = Numeric->lnz + Numeric->unz - n + + ((Numeric->Offp) ? (Numeric->Offp [n]) : 0) ; + + /* ------------------------------------------------------------------ */ + /* solve Ax=b */ + /* ------------------------------------------------------------------ */ + + for (i = 0 ; i < 2*n ; i++) + { + X [i] = B [i] ; + } + klu_zl_solve (Symbolic, Numeric, n, 1, X, Common) ; + + /* ------------------------------------------------------------------ */ + /* compute residual, rnorm = norm(b-Ax,1) / norm(A,1) */ + /* ------------------------------------------------------------------ */ + + for (i = 0 ; i < 2*n ; i++) + { + R [i] = B [i] ; + } + for (j = 0 ; j < n ; j++) + { + asum = 0 ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + /* R (i) -= A (i,j) * X (j) */ + i = Ai [p] ; + REAL (R,i) -= REAL(Ax,p) * REAL(X,j) - IMAG(Ax,p) * IMAG(X,j) ; + IMAG (R,i) -= IMAG(Ax,p) * REAL(X,j) + REAL(Ax,p) * IMAG(X,j) ; + asum += CABS (Ax, p) ; + } + anorm = MAX (anorm, asum) ; + } + *rnorm = 0 ; + for (i = 0 ; i < n ; i++) + { + *rnorm = MAX (*rnorm, CABS (R, i)) ; + } + + /* ------------------------------------------------------------------ */ + /* free numeric factorization */ + /* ------------------------------------------------------------------ */ + + klu_zl_free_numeric (&Numeric, Common) ; + } + + /* ---------------------------------------------------------------------- */ + /* free symbolic analysis, and residual */ + /* ---------------------------------------------------------------------- */ + + klu_l_free_symbolic (&Symbolic, Common) ; + return (1) ; +} + + +/* ========================================================================== */ +/* === klu_l_demo =========================================================== */ +/* ========================================================================== */ + +/* Given a sparse matrix A, set up a right-hand-side and solve X = A\b */ + +static void klu_l_demo (Long n, Long *Ap, Long *Ai, double *Ax, Long isreal) +{ + double rnorm ; + klu_l_common Common ; + double *B, *X, *R ; + Long i, lunz ; + + printf ("KLU: %s, version: %d.%d.%d\n", KLU_DATE, KLU_MAIN_VERSION, + KLU_SUB_VERSION, KLU_SUBSUB_VERSION) ; + + /* ---------------------------------------------------------------------- */ + /* set defaults */ + /* ---------------------------------------------------------------------- */ + + klu_l_defaults (&Common) ; + + /* ---------------------------------------------------------------------- */ + /* create a right-hand-side */ + /* ---------------------------------------------------------------------- */ + + if (isreal) + { + /* B = 1 + (1:n)/n */ + B = klu_l_malloc (n, sizeof (double), &Common) ; + X = klu_l_malloc (n, sizeof (double), &Common) ; + R = klu_l_malloc (n, sizeof (double), &Common) ; + if (B) + { + for (i = 0 ; i < n ; i++) + { + B [i] = 1 + ((double) i+1) / ((double) n) ; + } + } + } + else + { + /* real (B) = 1 + (1:n)/n, imag(B) = (n:-1:1)/n */ + B = klu_l_malloc (n, 2 * sizeof (double), &Common) ; + X = klu_l_malloc (n, 2 * sizeof (double), &Common) ; + R = klu_l_malloc (n, 2 * sizeof (double), &Common) ; + if (B) + { + for (i = 0 ; i < n ; i++) + { + REAL (B, i) = 1 + ((double) i+1) / ((double) n) ; + IMAG (B, i) = ((double) n-i) / ((double) n) ; + } + } + } + + /* ---------------------------------------------------------------------- */ + /* X = A\b using KLU and print statistics */ + /* ---------------------------------------------------------------------- */ + + if (!klu_l_backslash (n, Ap, Ai, Ax, isreal, B, X, R, &lunz, &rnorm, + &Common)) + { + printf ("KLU failed\n") ; + } + else + { + printf ("n %ld nnz(A) %ld nnz(L+U+F) %ld resid %g\n" + "recip growth %g condest %g rcond %g flops %g\n", + n, Ap [n], lunz, rnorm, Common.rgrowth, Common.condest, + Common.rcond, Common.flops) ; + } + + /* ---------------------------------------------------------------------- */ + /* free the problem */ + /* ---------------------------------------------------------------------- */ + + if (isreal) + { + klu_l_free (B, n, sizeof (double), &Common) ; + klu_l_free (X, n, sizeof (double), &Common) ; + klu_l_free (R, n, sizeof (double), &Common) ; + } + else + { + klu_l_free (B, 2*n, sizeof (double), &Common) ; + klu_l_free (X, 2*n, sizeof (double), &Common) ; + klu_l_free (R, 2*n, sizeof (double), &Common) ; + } + printf ("peak memory usage: %g bytes\n\n", (double) (Common.mempeak)) ; +} + + +/* ========================================================================== */ +/* === main ================================================================= */ +/* ========================================================================== */ + +/* Read in a sparse matrix in Matrix Market format using CHOLMOD, and then + * solve Ax=b with KLU. Note that CHOLMOD is only used to read the matrix. */ + +#include "cholmod.h" + +int main (void) +{ + cholmod_sparse *A ; + cholmod_common ch ; + cholmod_l_start (&ch) ; + A = cholmod_l_read_sparse (stdin, &ch) ; + if (A) + { + if (A->nrow != A->ncol || A->stype != 0 + || (!(A->xtype == CHOLMOD_REAL || A->xtype == CHOLMOD_COMPLEX))) + { + printf ("invalid matrix\n") ; + } + else + { + klu_l_demo (A->nrow, A->p, A->i, A->x, A->xtype == CHOLMOD_REAL) ; + } + cholmod_l_free_sparse (&A, &ch) ; + } + cholmod_l_finish (&ch) ; + return (0) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Include/klu.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Include/klu.h new file mode 100644 index 0000000..2da483b --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Include/klu.h @@ -0,0 +1,832 @@ +/* ========================================================================== */ +/* === klu include file ===================================================== */ +/* ========================================================================== */ + +/* Include file for user programs that call klu_* routines */ + +#ifndef _KLU_H +#define _KLU_H + +/* make it easy for C++ programs to include KLU */ +#ifdef __cplusplus +extern "C" { +#endif + +#include "amd.h" +#include "colamd.h" +#include "btf.h" + +/* -------------------------------------------------------------------------- */ +/* Symbolic object - contains the pre-ordering computed by klu_analyze */ +/* -------------------------------------------------------------------------- */ + +typedef struct +{ + /* A (P,Q) is in upper block triangular form. The kth block goes from + * row/col index R [k] to R [k+1]-1. The estimated number of nonzeros + * in the L factor of the kth block is Lnz [k]. + */ + + /* only computed if the AMD ordering is chosen: */ + double symmetry ; /* symmetry of largest block */ + double est_flops ; /* est. factorization flop count */ + double lnz, unz ; /* estimated nz in L and U, including diagonals */ + double *Lnz ; /* size n, but only Lnz [0..nblocks-1] is used */ + + /* computed for all orderings: */ + int + n, /* input matrix A is n-by-n */ + nz, /* # entries in input matrix */ + *P, /* size n */ + *Q, /* size n */ + *R, /* size n+1, but only R [0..nblocks] is used */ + nzoff, /* nz in off-diagonal blocks */ + nblocks, /* number of blocks */ + maxblock, /* size of largest block */ + ordering, /* ordering used (AMD, COLAMD, or GIVEN) */ + do_btf ; /* whether or not BTF preordering was requested */ + + /* only computed if BTF preordering requested */ + int structural_rank ; /* 0 to n-1 if the matrix is structurally rank + * deficient. -1 if not computed. n if the matrix has + * full structural rank */ + +} klu_symbolic ; + +typedef struct /* 64-bit version (otherwise same as above) */ +{ + double symmetry, est_flops, lnz, unz ; + double *Lnz ; + SuiteSparse_long n, nz, *P, *Q, *R, nzoff, nblocks, maxblock, ordering, + do_btf, structural_rank ; + +} klu_l_symbolic ; + +/* -------------------------------------------------------------------------- */ +/* Numeric object - contains the factors computed by klu_factor */ +/* -------------------------------------------------------------------------- */ + +typedef struct +{ + /* LU factors of each block, the pivot row permutation, and the + * entries in the off-diagonal blocks */ + + int n ; /* A is n-by-n */ + int nblocks ; /* number of diagonal blocks */ + int lnz ; /* actual nz in L, including diagonal */ + int unz ; /* actual nz in U, including diagonal */ + int max_lnz_block ; /* max actual nz in L in any one block, incl. diag */ + int max_unz_block ; /* max actual nz in U in any one block, incl. diag */ + int *Pnum ; /* size n. final pivot permutation */ + int *Pinv ; /* size n. inverse of final pivot permutation */ + + /* LU factors of each block */ + int *Lip ; /* size n. pointers into LUbx[block] for L */ + int *Uip ; /* size n. pointers into LUbx[block] for U */ + int *Llen ; /* size n. Llen [k] = # of entries in kth column of L */ + int *Ulen ; /* size n. Ulen [k] = # of entries in kth column of U */ + void **LUbx ; /* L and U indices and entries (excl. diagonal of U) */ + size_t *LUsize ; /* size of each LUbx [block], in sizeof (Unit) */ + void *Udiag ; /* diagonal of U */ + + /* scale factors; can be NULL if no scaling */ + double *Rs ; /* size n. Rs [i] is scale factor for row i */ + + /* permanent workspace for factorization and solve */ + size_t worksize ; /* size (in bytes) of Work */ + void *Work ; /* workspace */ + void *Xwork ; /* alias into Numeric->Work */ + int *Iwork ; /* alias into Numeric->Work */ + + /* off-diagonal entries in a conventional compressed-column sparse matrix */ + int *Offp ; /* size n+1, column pointers */ + int *Offi ; /* size nzoff, row indices */ + void *Offx ; /* size nzoff, numerical values */ + int nzoff ; + +} klu_numeric ; + +typedef struct /* 64-bit version (otherwise same as above) */ +{ + SuiteSparse_long n, nblocks, lnz, unz, max_lnz_block, max_unz_block, *Pnum, + *Pinv, *Lip, *Uip, *Llen, *Ulen ; + void **LUbx ; + size_t *LUsize ; + void *Udiag ; + double *Rs ; + size_t worksize ; + void *Work, *Xwork ; + SuiteSparse_long *Iwork ; + SuiteSparse_long *Offp, *Offi ; + void *Offx ; + SuiteSparse_long nzoff ; + +} klu_l_numeric ; + +/* -------------------------------------------------------------------------- */ +/* KLU control parameters and statistics */ +/* -------------------------------------------------------------------------- */ + +/* Common->status values */ +#define KLU_OK 0 +#define KLU_SINGULAR (1) /* status > 0 is a warning, not an error */ +#define KLU_OUT_OF_MEMORY (-2) +#define KLU_INVALID (-3) +#define KLU_TOO_LARGE (-4) /* integer overflow has occured */ + +typedef struct klu_common_struct +{ + + /* ---------------------------------------------------------------------- */ + /* parameters */ + /* ---------------------------------------------------------------------- */ + + double tol ; /* pivot tolerance for diagonal preference */ + double memgrow ; /* realloc memory growth size for LU factors */ + double initmem_amd ; /* init. memory size with AMD: c*nnz(L) + n */ + double initmem ; /* init. memory size: c*nnz(A) + n */ + double maxwork ; /* maxwork for BTF, <= 0 if no limit */ + + int btf ; /* use BTF pre-ordering, or not */ + int ordering ; /* 0: AMD, 1: COLAMD, 2: user P and Q, + * 3: user function */ + int scale ; /* row scaling: -1: none (and no error check), + * 0: none, 1: sum, 2: max */ + + /* pointer to user ordering function */ + int (*user_order) (int, int *, int *, int *, struct klu_common_struct *) ; + + /* pointer to user data, passed unchanged as the last parameter to the + * user ordering function (optional, the user function need not use this + * information). */ + void *user_data ; + + int halt_if_singular ; /* how to handle a singular matrix: + * FALSE: keep going. Return a Numeric object with a zero U(k,k). A + * divide-by-zero may occur when computing L(:,k). The Numeric object + * can be passed to klu_solve (a divide-by-zero will occur). It can + * also be safely passed to klu_refactor. + * TRUE: stop quickly. klu_factor will free the partially-constructed + * Numeric object. klu_refactor will not free it, but will leave the + * numerical values only partially defined. This is the default. */ + + /* ---------------------------------------------------------------------- */ + /* statistics */ + /* ---------------------------------------------------------------------- */ + + int status ; /* KLU_OK if OK, < 0 if error */ + int nrealloc ; /* # of reallocations of L and U */ + + int structural_rank ; /* 0 to n-1 if the matrix is structurally rank + * deficient (as determined by maxtrans). -1 if not computed. n if the + * matrix has full structural rank. This is computed by klu_analyze + * if a BTF preordering is requested. */ + + int numerical_rank ; /* First k for which a zero U(k,k) was found, + * if the matrix was singular (in the range 0 to n-1). n if the matrix + * has full rank. This is not a true rank-estimation. It just reports + * where the first zero pivot was found. -1 if not computed. + * Computed by klu_factor and klu_refactor. */ + + int singular_col ; /* n if the matrix is not singular. If in the + * range 0 to n-1, this is the column index of the original matrix A that + * corresponds to the column of U that contains a zero diagonal entry. + * -1 if not computed. Computed by klu_factor and klu_refactor. */ + + int noffdiag ; /* # of off-diagonal pivots, -1 if not computed */ + + double flops ; /* actual factorization flop count, from klu_flops */ + double rcond ; /* crude reciprocal condition est., from klu_rcond */ + double condest ; /* accurate condition est., from klu_condest */ + double rgrowth ; /* reciprocal pivot rgrowth, from klu_rgrowth */ + double work ; /* actual work done in BTF, in klu_analyze */ + + size_t memusage ; /* current memory usage, in bytes */ + size_t mempeak ; /* peak memory usage, in bytes */ + +} klu_common ; + +typedef struct klu_l_common_struct /* 64-bit version (otherwise same as above)*/ +{ + + double tol, memgrow, initmem_amd, initmem, maxwork ; + SuiteSparse_long btf, ordering, scale ; + SuiteSparse_long (*user_order) (SuiteSparse_long, SuiteSparse_long *, + SuiteSparse_long *, SuiteSparse_long *, + struct klu_l_common_struct *) ; + void *user_data ; + SuiteSparse_long halt_if_singular ; + SuiteSparse_long status, nrealloc, structural_rank, numerical_rank, + singular_col, noffdiag ; + double flops, rcond, condest, rgrowth, work ; + size_t memusage, mempeak ; + +} klu_l_common ; + +/* -------------------------------------------------------------------------- */ +/* klu_defaults: sets default control parameters */ +/* -------------------------------------------------------------------------- */ + +int klu_defaults +( + klu_common *Common +) ; + +SuiteSparse_long klu_l_defaults (klu_l_common *Common) ; + +/* -------------------------------------------------------------------------- */ +/* klu_analyze: orders and analyzes a matrix */ +/* -------------------------------------------------------------------------- */ + +/* Order the matrix with BTF (or not), then order each block with AMD, COLAMD, + * a natural ordering, or with a user-provided ordering function */ + +klu_symbolic *klu_analyze +( + /* inputs, not modified */ + int n, /* A is n-by-n */ + int Ap [ ], /* size n+1, column pointers */ + int Ai [ ], /* size nz, row indices */ + klu_common *Common +) ; + +klu_l_symbolic *klu_l_analyze (SuiteSparse_long, SuiteSparse_long *, + SuiteSparse_long *, klu_l_common *Common) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_analyze_given: analyzes a matrix using given P and Q */ +/* -------------------------------------------------------------------------- */ + +/* Order the matrix with BTF (or not), then use natural or given ordering + * P and Q on the blocks. P and Q are interpretted as identity + * if NULL. */ + +klu_symbolic *klu_analyze_given +( + /* inputs, not modified */ + int n, /* A is n-by-n */ + int Ap [ ], /* size n+1, column pointers */ + int Ai [ ], /* size nz, row indices */ + int P [ ], /* size n, user's row permutation (may be NULL) */ + int Q [ ], /* size n, user's column permutation (may be NULL) */ + klu_common *Common +) ; + +klu_l_symbolic *klu_l_analyze_given (SuiteSparse_long, SuiteSparse_long *, + SuiteSparse_long *, SuiteSparse_long *, SuiteSparse_long *, + klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_factor: factors a matrix using the klu_analyze results */ +/* -------------------------------------------------------------------------- */ + +klu_numeric *klu_factor /* returns KLU_OK if OK, < 0 if error */ +( + /* inputs, not modified */ + int Ap [ ], /* size n+1, column pointers */ + int Ai [ ], /* size nz, row indices */ + double Ax [ ], /* size nz, numerical values */ + klu_symbolic *Symbolic, + klu_common *Common +) ; + +klu_numeric *klu_z_factor /* returns KLU_OK if OK, < 0 if error */ +( + /* inputs, not modified */ + int Ap [ ], /* size n+1, column pointers */ + int Ai [ ], /* size nz, row indices */ + double Ax [ ], /* size 2*nz, numerical values (real,imag pairs) */ + klu_symbolic *Symbolic, + klu_common *Common +) ; + +/* long / real version */ +klu_l_numeric *klu_l_factor (SuiteSparse_long *, SuiteSparse_long *, double *, + klu_l_symbolic *, klu_l_common *) ; + +/* long / complex version */ +klu_l_numeric *klu_zl_factor (SuiteSparse_long *, SuiteSparse_long *, double *, + klu_l_symbolic *, klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_solve: solves Ax=b using the Symbolic and Numeric objects */ +/* -------------------------------------------------------------------------- */ + +int klu_solve +( + /* inputs, not modified */ + klu_symbolic *Symbolic, + klu_numeric *Numeric, + int ldim, /* leading dimension of B */ + int nrhs, /* number of right-hand-sides */ + + /* right-hand-side on input, overwritten with solution to Ax=b on output */ + double B [ ], /* size ldim*nrhs */ + klu_common *Common +) ; + +int klu_z_solve +( + /* inputs, not modified */ + klu_symbolic *Symbolic, + klu_numeric *Numeric, + int ldim, /* leading dimension of B */ + int nrhs, /* number of right-hand-sides */ + + /* right-hand-side on input, overwritten with solution to Ax=b on output */ + double B [ ], /* size 2*ldim*nrhs */ + klu_common *Common +) ; + +SuiteSparse_long klu_l_solve (klu_l_symbolic *, klu_l_numeric *, + SuiteSparse_long, SuiteSparse_long, double *, klu_l_common *) ; + +SuiteSparse_long klu_zl_solve (klu_l_symbolic *, klu_l_numeric *, + SuiteSparse_long, SuiteSparse_long, double *, klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_tsolve: solves A'x=b using the Symbolic and Numeric objects */ +/* -------------------------------------------------------------------------- */ + +int klu_tsolve +( + /* inputs, not modified */ + klu_symbolic *Symbolic, + klu_numeric *Numeric, + int ldim, /* leading dimension of B */ + int nrhs, /* number of right-hand-sides */ + + /* right-hand-side on input, overwritten with solution to Ax=b on output */ + double B [ ], /* size ldim*nrhs */ + klu_common *Common +) ; + +int klu_z_tsolve +( + /* inputs, not modified */ + klu_symbolic *Symbolic, + klu_numeric *Numeric, + int ldim, /* leading dimension of B */ + int nrhs, /* number of right-hand-sides */ + + /* right-hand-side on input, overwritten with solution to Ax=b on output */ + double B [ ], /* size 2*ldim*nrhs */ + int conj_solve, /* TRUE: conjugate solve, FALSE: solve A.'x=b */ + klu_common *Common + +) ; + +SuiteSparse_long klu_l_tsolve (klu_l_symbolic *, klu_l_numeric *, + SuiteSparse_long, SuiteSparse_long, double *, klu_l_common *) ; + +SuiteSparse_long klu_zl_tsolve (klu_l_symbolic *, klu_l_numeric *, + SuiteSparse_long, SuiteSparse_long, double *, SuiteSparse_long, + klu_l_common * ) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_refactor: refactorizes matrix with same ordering as klu_factor */ +/* -------------------------------------------------------------------------- */ + +int klu_refactor /* return TRUE if successful, FALSE otherwise */ +( + /* inputs, not modified */ + int Ap [ ], /* size n+1, column pointers */ + int Ai [ ], /* size nz, row indices */ + double Ax [ ], /* size nz, numerical values */ + klu_symbolic *Symbolic, + /* input, and numerical values modified on output */ + klu_numeric *Numeric, + klu_common *Common +) ; + +int klu_z_refactor /* return TRUE if successful, FALSE otherwise */ +( + /* inputs, not modified */ + int Ap [ ], /* size n+1, column pointers */ + int Ai [ ], /* size nz, row indices */ + double Ax [ ], /* size 2*nz, numerical values */ + klu_symbolic *Symbolic, + /* input, and numerical values modified on output */ + klu_numeric *Numeric, + klu_common *Common +) ; + +SuiteSparse_long klu_l_refactor (SuiteSparse_long *, SuiteSparse_long *, + double *, klu_l_symbolic *, klu_l_numeric *, klu_l_common *) ; + +SuiteSparse_long klu_zl_refactor (SuiteSparse_long *, SuiteSparse_long *, + double *, klu_l_symbolic *, klu_l_numeric *, klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_free_symbolic: destroys the Symbolic object */ +/* -------------------------------------------------------------------------- */ + +int klu_free_symbolic +( + klu_symbolic **Symbolic, + klu_common *Common +) ; + +SuiteSparse_long klu_l_free_symbolic (klu_l_symbolic **, klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_free_numeric: destroys the Numeric object */ +/* -------------------------------------------------------------------------- */ + +/* Note that klu_free_numeric and klu_z_free_numeric are identical; each can + * free both kinds of Numeric objects (real and complex) */ + +int klu_free_numeric +( + klu_numeric **Numeric, + klu_common *Common +) ; + +int klu_z_free_numeric +( + klu_numeric **Numeric, + klu_common *Common +) ; + +SuiteSparse_long klu_l_free_numeric (klu_l_numeric **, klu_l_common *) ; +SuiteSparse_long klu_zl_free_numeric (klu_l_numeric **, klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_sort: sorts the columns of the LU factorization */ +/* -------------------------------------------------------------------------- */ + +/* this is not needed except for the MATLAB interface */ + +int klu_sort +( + /* inputs, not modified */ + klu_symbolic *Symbolic, + /* input/output */ + klu_numeric *Numeric, + klu_common *Common +) ; + +int klu_z_sort +( + /* inputs, not modified */ + klu_symbolic *Symbolic, + /* input/output */ + klu_numeric *Numeric, + klu_common *Common +) ; + +SuiteSparse_long klu_l_sort (klu_l_symbolic *, klu_l_numeric *, + klu_l_common *) ; +SuiteSparse_long klu_zl_sort (klu_l_symbolic *, klu_l_numeric *, + klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_flops: determines # of flops performed in numeric factorzation */ +/* -------------------------------------------------------------------------- */ + +int klu_flops +( + /* inputs, not modified */ + klu_symbolic *Symbolic, + klu_numeric *Numeric, + /* input/output */ + klu_common *Common +) ; + +int klu_z_flops +( + /* inputs, not modified */ + klu_symbolic *Symbolic, + klu_numeric *Numeric, + /* input/output */ + klu_common *Common +) ; + +SuiteSparse_long klu_l_flops (klu_l_symbolic *, klu_l_numeric *, + klu_l_common *) ; +SuiteSparse_long klu_zl_flops (klu_l_symbolic *, klu_l_numeric *, + klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_rgrowth : compute the reciprocal pivot growth */ +/* -------------------------------------------------------------------------- */ + +/* Pivot growth is computed after the input matrix is permuted, scaled, and + * off-diagonal entries pruned. This is because the LU factorization of each + * block takes as input the scaled diagonal blocks of the BTF form. The + * reciprocal pivot growth in column j of an LU factorization of a matrix C + * is the largest entry in C divided by the largest entry in U; then the overall + * reciprocal pivot growth is the smallest such value for all columns j. Note + * that the off-diagonal entries are not scaled, since they do not take part in + * the LU factorization of the diagonal blocks. + * + * In MATLAB notation: + * + * rgrowth = min (max (abs ((R \ A(p,q)) - F)) ./ max (abs (U))) */ + +int klu_rgrowth +( + int Ap [ ], + int Ai [ ], + double Ax [ ], + klu_symbolic *Symbolic, + klu_numeric *Numeric, + klu_common *Common /* Common->rgrowth = reciprocal pivot growth */ +) ; + +int klu_z_rgrowth +( + int Ap [ ], + int Ai [ ], + double Ax [ ], + klu_symbolic *Symbolic, + klu_numeric *Numeric, + klu_common *Common /* Common->rgrowth = reciprocal pivot growth */ +) ; + +SuiteSparse_long klu_l_rgrowth (SuiteSparse_long *, SuiteSparse_long *, + double *, klu_l_symbolic *, klu_l_numeric *, klu_l_common *) ; + +SuiteSparse_long klu_zl_rgrowth (SuiteSparse_long *, SuiteSparse_long *, + double *, klu_l_symbolic *, klu_l_numeric *, klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_condest */ +/* -------------------------------------------------------------------------- */ + +/* Computes a reasonably accurate estimate of the 1-norm condition number, using + * Hager's method, as modified by Higham and Tisseur (same method as used in + * MATLAB's condest */ + +int klu_condest +( + int Ap [ ], /* size n+1, column pointers, not modified */ + double Ax [ ], /* size nz = Ap[n], numerical values, not modified*/ + klu_symbolic *Symbolic, /* symbolic analysis, not modified */ + klu_numeric *Numeric, /* numeric factorization, not modified */ + klu_common *Common /* result returned in Common->condest */ +) ; + +int klu_z_condest +( + int Ap [ ], + double Ax [ ], /* size 2*nz */ + klu_symbolic *Symbolic, + klu_numeric *Numeric, + klu_common *Common /* result returned in Common->condest */ +) ; + +SuiteSparse_long klu_l_condest (SuiteSparse_long *, double *, klu_l_symbolic *, + klu_l_numeric *, klu_l_common *) ; + +SuiteSparse_long klu_zl_condest (SuiteSparse_long *, double *, klu_l_symbolic *, + klu_l_numeric *, klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_rcond: compute min(abs(diag(U))) / max(abs(diag(U))) */ +/* -------------------------------------------------------------------------- */ + +int klu_rcond +( + klu_symbolic *Symbolic, /* input, not modified */ + klu_numeric *Numeric, /* input, not modified */ + klu_common *Common /* result in Common->rcond */ +) ; + +int klu_z_rcond +( + klu_symbolic *Symbolic, /* input, not modified */ + klu_numeric *Numeric, /* input, not modified */ + klu_common *Common /* result in Common->rcond */ +) ; + +SuiteSparse_long klu_l_rcond (klu_l_symbolic *, klu_l_numeric *, + klu_l_common *) ; + +SuiteSparse_long klu_zl_rcond (klu_l_symbolic *, klu_l_numeric *, + klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_scale */ +/* -------------------------------------------------------------------------- */ + +int klu_scale /* return TRUE if successful, FALSE otherwise */ +( + /* inputs, not modified */ + int scale, /* <0: none, no error check; 0: none, 1: sum, 2: max */ + int n, + int Ap [ ], /* size n+1, column pointers */ + int Ai [ ], /* size nz, row indices */ + double Ax [ ], + /* outputs, not defined on input */ + double Rs [ ], + /* workspace, not defined on input or output */ + int W [ ], /* size n, can be NULL */ + klu_common *Common +) ; + +int klu_z_scale /* return TRUE if successful, FALSE otherwise */ +( + /* inputs, not modified */ + int scale, /* <0: none, no error check; 0: none, 1: sum, 2: max */ + int n, + int Ap [ ], /* size n+1, column pointers */ + int Ai [ ], /* size nz, row indices */ + double Ax [ ], + /* outputs, not defined on input */ + double Rs [ ], + /* workspace, not defined on input or output */ + int W [ ], /* size n, can be NULL */ + klu_common *Common +) ; + +SuiteSparse_long klu_l_scale (SuiteSparse_long, SuiteSparse_long, + SuiteSparse_long *, SuiteSparse_long *, double *, + double *, SuiteSparse_long *, klu_l_common *) ; + +SuiteSparse_long klu_zl_scale (SuiteSparse_long, SuiteSparse_long, + SuiteSparse_long *, SuiteSparse_long *, double *, + double *, SuiteSparse_long *, klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_extract */ +/* -------------------------------------------------------------------------- */ + +int klu_extract /* returns TRUE if successful, FALSE otherwise */ +( + /* inputs: */ + klu_numeric *Numeric, + klu_symbolic *Symbolic, + + /* outputs, either allocated on input, or ignored otherwise */ + + /* L */ + int *Lp, /* size n+1 */ + int *Li, /* size Numeric->lnz */ + double *Lx, /* size Numeric->lnz */ + + /* U */ + int *Up, /* size n+1 */ + int *Ui, /* size Numeric->unz */ + double *Ux, /* size Numeric->unz */ + + /* F */ + int *Fp, /* size n+1 */ + int *Fi, /* size Numeric->nzoff */ + double *Fx, /* size Numeric->nzoff */ + + /* P, row permutation */ + int *P, /* size n */ + + /* Q, column permutation */ + int *Q, /* size n */ + + /* Rs, scale factors */ + double *Rs, /* size n */ + + /* R, block boundaries */ + int *R, /* size Symbolic->nblocks+1 (nblocks is at most n) */ + + klu_common *Common +) ; + + +int klu_z_extract /* returns TRUE if successful, FALSE otherwise */ +( + /* inputs: */ + klu_numeric *Numeric, + klu_symbolic *Symbolic, + + /* outputs, all of which must be allocated on input */ + + /* L */ + int *Lp, /* size n+1 */ + int *Li, /* size nnz(L) */ + double *Lx, /* size nnz(L) */ + double *Lz, /* size nnz(L) for the complex case, ignored if real */ + + /* U */ + int *Up, /* size n+1 */ + int *Ui, /* size nnz(U) */ + double *Ux, /* size nnz(U) */ + double *Uz, /* size nnz(U) for the complex case, ignored if real */ + + /* F */ + int *Fp, /* size n+1 */ + int *Fi, /* size nnz(F) */ + double *Fx, /* size nnz(F) */ + double *Fz, /* size nnz(F) for the complex case, ignored if real */ + + /* P, row permutation */ + int *P, /* size n */ + + /* Q, column permutation */ + int *Q, /* size n */ + + /* Rs, scale factors */ + double *Rs, /* size n */ + + /* R, block boundaries */ + int *R, /* size Symbolic->nblocks+1 (nblocks is at most n) */ + + klu_common *Common +) ; + +SuiteSparse_long klu_l_extract (klu_l_numeric *, klu_l_symbolic *, + SuiteSparse_long *, SuiteSparse_long *, double *, + SuiteSparse_long *, SuiteSparse_long *, double *, + SuiteSparse_long *, SuiteSparse_long *, double *, + SuiteSparse_long *, SuiteSparse_long *, double *, + SuiteSparse_long *, klu_l_common *) ; + +SuiteSparse_long klu_zl_extract (klu_l_numeric *, klu_l_symbolic *, + SuiteSparse_long *, SuiteSparse_long *, double *, double *, + SuiteSparse_long *, SuiteSparse_long *, double *, double *, + SuiteSparse_long *, SuiteSparse_long *, double *, double *, + SuiteSparse_long *, SuiteSparse_long *, double *, + SuiteSparse_long *, klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* KLU memory management routines */ +/* -------------------------------------------------------------------------- */ + +void *klu_malloc /* returns pointer to the newly malloc'd block */ +( + /* ---- input ---- */ + size_t n, /* number of items */ + size_t size, /* size of each item */ + /* --------------- */ + klu_common *Common +) ; + +void *klu_free /* always returns NULL */ +( + /* ---- in/out --- */ + void *p, /* block of memory to free */ + size_t n, /* number of items */ + size_t size, /* size of each item */ + /* --------------- */ + klu_common *Common +) ; + +void *klu_realloc /* returns pointer to reallocated block */ +( + /* ---- input ---- */ + size_t nnew, /* requested # of items in reallocated block */ + size_t nold, /* current size of block, in # of items */ + size_t size, /* size of each item */ + /* ---- in/out --- */ + void *p, /* block of memory to realloc */ + /* --------------- */ + klu_common *Common +) ; + +void *klu_l_malloc (size_t, size_t, klu_l_common *) ; +void *klu_l_free (void *, size_t, size_t, klu_l_common *) ; +void *klu_l_realloc (size_t, size_t, size_t, void *, klu_l_common *) ; + + +/* ========================================================================== */ +/* === KLU version ========================================================== */ +/* ========================================================================== */ + +/* All versions of KLU include these definitions. + * As an example, to test if the version you are using is 1.2 or later: + * + * if (KLU_VERSION >= KLU_VERSION_CODE (1,2)) ... + * + * This also works during compile-time: + * + * #if (KLU >= KLU_VERSION_CODE (1,2)) + * printf ("This is version 1.2 or later\n") ; + * #else + * printf ("This is an early version\n") ; + * #endif + */ + +#define KLU_DATE "May 4, 2016" +#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_VERSION KLU_VERSION_CODE(KLU_MAIN_VERSION,KLU_SUB_VERSION) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Include/klu_internal.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Include/klu_internal.h new file mode 100644 index 0000000..f3d63c8 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Include/klu_internal.h @@ -0,0 +1,243 @@ +/* ========================================================================== */ +/* === KLU/Include/klu_internal.h =========================================== */ +/* ========================================================================== */ + +/* For internal use in KLU routines only, not for user programs */ + +#ifndef _KLU_INTERNAL_H +#define _KLU_INTERNAL_H + +#include "klu.h" +#include "btf.h" +#include "klu_version.h" + +/* ========================================================================== */ +/* make sure debugging and printing is turned off */ + +#ifndef NDEBUG +#define NDEBUG +#endif +#ifndef NPRINT +#define NPRINT +#endif + +/* To enable debugging and assertions, uncomment this line: + #undef NDEBUG + */ + +/* To enable diagnostic printing, uncomment this line: + #undef NPRINT + */ + +/* ========================================================================== */ + +#include <stdio.h> +#include <assert.h> +#include <limits.h> +#include <stdlib.h> +#include <math.h> + +#undef ASSERT +#ifndef NDEBUG +#define ASSERT(a) assert(a) +#else +#define ASSERT(a) +#endif + +#define SCALAR_IS_NAN(x) ((x) != (x)) + +/* true if an integer (stored in double x) would overflow (or if x is NaN) */ +#define INT_OVERFLOW(x) ((!((x) * (1.0+1e-8) <= (double) Int_MAX)) \ + || SCALAR_IS_NAN (x)) + +#undef TRUE +#undef FALSE +#undef MAX +#undef MIN +#undef PRINTF +#undef FLIP + +#ifndef NPRINT +#define PRINTF(s) SUITESPARSE_PRINTF (s) +#else +#define PRINTF(s) +#endif + +#define TRUE 1 +#define FALSE 0 +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +/* FLIP is a "negation about -1", and is used to mark an integer i that is + * normally non-negative. FLIP (EMPTY) is EMPTY. FLIP of a number > EMPTY + * is negative, and FLIP of a number < EMTPY is positive. FLIP (FLIP (i)) = i + * for all integers i. UNFLIP (i) is >= EMPTY. */ +#define EMPTY (-1) +#define FLIP(i) (-(i)-2) +#define UNFLIP(i) (((i) < EMPTY) ? FLIP (i) : (i)) + + +size_t KLU_kernel /* final size of LU on output */ +( + /* input, not modified */ + Int n, /* A is n-by-n */ + Int Ap [ ], /* size n+1, column pointers for A */ + Int Ai [ ], /* size nz = Ap [n], row indices for A */ + Entry Ax [ ], /* size nz, values of A */ + Int Q [ ], /* size n, optional input permutation */ + size_t lusize, /* initial size of LU */ + + /* output, not defined on input */ + Int Pinv [ ], /* size n */ + Int P [ ], /* size n */ + Unit **p_LU, /* size lusize on input, size Uxp[n] on output*/ + Entry Udiag [ ], /* size n, diagonal of U */ + Int Llen [ ], /* size n, column length of L */ + Int Ulen [ ], /* size n, column length of U */ + Int Lip [ ], /* size n+1 */ + Int Uip [ ], /* size n+1 */ + Int *lnz, /* size of L */ + Int *unz, /* size of U */ + + /* workspace, not defined on input */ + Entry X [ ], /* size n, zero on output */ + + /* workspace, not defined on input or output */ + Int Stack [ ], /* size n */ + Int Flag [ ], /* size n */ + Int adj_pos [ ], /* size n */ + + /* workspace for pruning only */ + Int Lpend [ ], /* size n workspace */ + + /* inputs, not modified on output */ + Int k1, /* the block of A is from k1 to k2-1 */ + Int PSinv [ ], /* inverse of P from symbolic factorization */ + double Rs [ ], /* scale factors for A */ + + /* inputs, modified on output */ + Int Offp [ ], /* off-diagonal matrix (modified by this routine) */ + Int Offi [ ], + Entry Offx [ ], + KLU_common *Common /* the control input/output structure */ +) ; + + +size_t KLU_kernel_factor /* 0 if failure, size of LU if OK */ +( + /* inputs, not modified */ + Int n, /* A is n-by-n. n must be > 0. */ + Int Ap [ ], /* size n+1, column pointers for A */ + Int Ai [ ], /* size nz = Ap [n], row indices for A */ + Entry Ax [ ], /* size nz, values of A */ + Int Q [ ], /* size n, optional column permutation */ + double Lsize, /* initial size of L and U */ + + /* outputs, not defined on input */ + Unit **p_LU, /* row indices and values of L and U */ + Entry Udiag [ ], /* size n, diagonal of U */ + Int Llen [ ], /* size n, column length of L */ + Int Ulen [ ], /* size n, column length of U */ + Int Lip [ ], /* size n+1, column pointers of L */ + Int Uip [ ], /* size n+1, column pointers of U */ + Int P [ ], /* row permutation, size n */ + Int *lnz, /* size of L */ + Int *unz, /* size of U */ + + /* workspace, undefined on input */ + Entry *X, /* size n entries. Zero on output */ + Int *Work, /* size 5n Int's */ + + /* inputs, not modified on output */ + Int k1, /* the block of A is from k1 to k2-1 */ + Int PSinv [ ], /* inverse of P from symbolic factorization */ + double Rs [ ], /* scale factors for A */ + + /* inputs, modified on output */ + Int Offp [ ], /* off-diagonal matrix (modified by this routine) */ + Int Offi [ ], + Entry Offx [ ], + KLU_common *Common /* the control input/output structure */ +) ; + +void KLU_lsolve +( + /* inputs, not modified: */ + Int n, + Int Lp [ ], + Int Li [ ], + Unit LU [ ], + Int nrhs, + /* right-hand-side on input, solution to Lx=b on output */ + Entry X [ ] +) ; + +void KLU_ltsolve +( + /* inputs, not modified: */ + Int n, + Int Lp [ ], + Int Li [ ], + Unit LU [ ], + Int nrhs, +#ifdef COMPLEX + Int conj_solve, +#endif + /* right-hand-side on input, solution to L'x=b on output */ + Entry X [ ] +) ; + + +void KLU_usolve +( + /* inputs, not modified: */ + Int n, + Int Up [ ], + Int Ui [ ], + Unit LU [ ], + Entry Udiag [ ], + Int nrhs, + /* right-hand-side on input, solution to Ux=b on output */ + Entry X [ ] +) ; + +void KLU_utsolve +( + /* inputs, not modified: */ + Int n, + Int Up [ ], + Int Ui [ ], + Unit LU [ ], + Entry Udiag [ ], + Int nrhs, +#ifdef COMPLEX + Int conj_solve, +#endif + /* right-hand-side on input, solution to U'x=b on output */ + Entry X [ ] +) ; + +Int KLU_valid +( + Int n, + Int Ap [ ], + Int Ai [ ], + Entry Ax [ ] +) ; + +Int KLU_valid_LU +( + Int n, + Int flag_test_start_ptr, + Int Xip [ ], + Int Xlen [ ], + Unit LU [ ] +); + +size_t KLU_add_size_t (size_t a, size_t b, Int *ok) ; + +size_t KLU_mult_size_t (size_t a, size_t k, Int *ok) ; + +KLU_symbolic *KLU_alloc_symbolic (Int n, Int *Ap, Int *Ai, KLU_common *Common) ; + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Include/klu_version.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Include/klu_version.h new file mode 100644 index 0000000..e762a43 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Include/klu_version.h @@ -0,0 +1,694 @@ +#ifndef _KLU_VERSION_H +#define _KLU_VERSION_H + +#ifdef DLONG +#define Int SuiteSparse_long +#define Int_id SuiteSparse_long_id +#define Int_MAX SuiteSparse_long_max +#else +#define Int int +#define Int_id "%d" +#define Int_MAX INT_MAX +#endif + +#define NPRINT + +#define BYTES(type,n) (sizeof (type) * (n)) +#define CEILING(b,u) (((b)+(u)-1) / (u)) +#define UNITS(type,n) (CEILING (BYTES (type,n), sizeof (Unit))) +#define DUNITS(type,n) (ceil (BYTES (type, (double) n) / sizeof (Unit))) + +#define GET_I_POINTER(LU, Xip, Xi, k) \ +{ \ + Xi = (Int *) (LU + Xip [k]) ; \ +} + +#define GET_X_POINTER(LU, Xip, Xlen, Xx, k) \ +{ \ + Xx = (Entry *) (LU + Xip [k] + UNITS (Int, Xlen [k])) ; \ +} + +#define GET_POINTER(LU, Xip, Xlen, Xi, Xx, k, xlen) \ +{ \ + Unit *xp = LU + Xip [k] ; \ + xlen = Xlen [k] ; \ + Xi = (Int *) xp ; \ + Xx = (Entry *) (xp + UNITS (Int, xlen)) ; \ +} + +/* function names */ +#ifdef COMPLEX + +#ifdef DLONG + +#define KLU_scale klu_zl_scale +#define KLU_solve klu_zl_solve +#define KLU_tsolve klu_zl_tsolve +#define KLU_free_numeric klu_zl_free_numeric +#define KLU_factor klu_zl_factor +#define KLU_refactor klu_zl_refactor +#define KLU_kernel_factor klu_zl_kernel_factor +#define KLU_lsolve klu_zl_lsolve +#define KLU_ltsolve klu_zl_ltsolve +#define KLU_usolve klu_zl_usolve +#define KLU_utsolve klu_zl_utsolve +#define KLU_kernel klu_zl_kernel +#define KLU_valid klu_zl_valid +#define KLU_valid_LU klu_zl_valid_LU +#define KLU_sort klu_zl_sort +#define KLU_rgrowth klu_zl_rgrowth +#define KLU_rcond klu_zl_rcond +#define KLU_extract klu_zl_extract +#define KLU_condest klu_zl_condest +#define KLU_flops klu_zl_flops + +#else + +#define KLU_scale klu_z_scale +#define KLU_solve klu_z_solve +#define KLU_tsolve klu_z_tsolve +#define KLU_free_numeric klu_z_free_numeric +#define KLU_factor klu_z_factor +#define KLU_refactor klu_z_refactor +#define KLU_kernel_factor klu_z_kernel_factor +#define KLU_lsolve klu_z_lsolve +#define KLU_ltsolve klu_z_ltsolve +#define KLU_usolve klu_z_usolve +#define KLU_utsolve klu_z_utsolve +#define KLU_kernel klu_z_kernel +#define KLU_valid klu_z_valid +#define KLU_valid_LU klu_z_valid_LU +#define KLU_sort klu_z_sort +#define KLU_rgrowth klu_z_rgrowth +#define KLU_rcond klu_z_rcond +#define KLU_extract klu_z_extract +#define KLU_condest klu_z_condest +#define KLU_flops klu_z_flops + +#endif + +#else + +#ifdef DLONG + +#define KLU_scale klu_l_scale +#define KLU_solve klu_l_solve +#define KLU_tsolve klu_l_tsolve +#define KLU_free_numeric klu_l_free_numeric +#define KLU_factor klu_l_factor +#define KLU_refactor klu_l_refactor +#define KLU_kernel_factor klu_l_kernel_factor +#define KLU_lsolve klu_l_lsolve +#define KLU_ltsolve klu_l_ltsolve +#define KLU_usolve klu_l_usolve +#define KLU_utsolve klu_l_utsolve +#define KLU_kernel klu_l_kernel +#define KLU_valid klu_l_valid +#define KLU_valid_LU klu_l_valid_LU +#define KLU_sort klu_l_sort +#define KLU_rgrowth klu_l_rgrowth +#define KLU_rcond klu_l_rcond +#define KLU_extract klu_l_extract +#define KLU_condest klu_l_condest +#define KLU_flops klu_l_flops + +#else + +#define KLU_scale klu_scale +#define KLU_solve klu_solve +#define KLU_tsolve klu_tsolve +#define KLU_free_numeric klu_free_numeric +#define KLU_factor klu_factor +#define KLU_refactor klu_refactor +#define KLU_kernel_factor klu_kernel_factor +#define KLU_lsolve klu_lsolve +#define KLU_ltsolve klu_ltsolve +#define KLU_usolve klu_usolve +#define KLU_utsolve klu_utsolve +#define KLU_kernel klu_kernel +#define KLU_valid klu_valid +#define KLU_valid_LU klu_valid_LU +#define KLU_sort klu_sort +#define KLU_rgrowth klu_rgrowth +#define KLU_rcond klu_rcond +#define KLU_extract klu_extract +#define KLU_condest klu_condest +#define KLU_flops klu_flops + +#endif + +#endif + + +#ifdef DLONG + +#define KLU_analyze klu_l_analyze +#define KLU_analyze_given klu_l_analyze_given +#define KLU_alloc_symbolic klu_l_alloc_symbolic +#define KLU_free_symbolic klu_l_free_symbolic +#define KLU_defaults klu_l_defaults +#define KLU_free klu_l_free +#define KLU_malloc klu_l_malloc +#define KLU_realloc klu_l_realloc +#define KLU_add_size_t klu_l_add_size_t +#define KLU_mult_size_t klu_l_mult_size_t + +#define KLU_symbolic klu_l_symbolic +#define KLU_numeric klu_l_numeric +#define KLU_common klu_l_common + +#define BTF_order btf_l_order +#define BTF_strongcomp btf_l_strongcomp + +#define AMD_order amd_l_order +#define COLAMD colamd_l +#define COLAMD_recommended colamd_l_recommended + +#else + +#define KLU_analyze klu_analyze +#define KLU_analyze_given klu_analyze_given +#define KLU_alloc_symbolic klu_alloc_symbolic +#define KLU_free_symbolic klu_free_symbolic +#define KLU_defaults klu_defaults +#define KLU_free klu_free +#define KLU_malloc klu_malloc +#define KLU_realloc klu_realloc +#define KLU_add_size_t klu_add_size_t +#define KLU_mult_size_t klu_mult_size_t + +#define KLU_symbolic klu_symbolic +#define KLU_numeric klu_numeric +#define KLU_common klu_common + +#define BTF_order btf_order +#define BTF_strongcomp btf_strongcomp + +#define AMD_order amd_order +#define COLAMD colamd +#define COLAMD_recommended colamd_recommended + +#endif + + +/* -------------------------------------------------------------------------- */ +/* Numerical relop macros for correctly handling the NaN case */ +/* -------------------------------------------------------------------------- */ + +/* +SCALAR_IS_NAN(x): + True if x is NaN. False otherwise. The commonly-existing isnan(x) + function could be used, but it's not in Kernighan & Ritchie 2nd edition + (ANSI C). It may appear in <math.h>, but I'm not certain about + portability. The expression x != x is true if and only if x is NaN, + according to the IEEE 754 floating-point standard. + +SCALAR_IS_ZERO(x): + True if x is zero. False if x is nonzero, NaN, or +/- Inf. + This is (x == 0) if the compiler is IEEE 754 compliant. + +SCALAR_IS_NONZERO(x): + True if x is nonzero, NaN, or +/- Inf. False if x zero. + This is (x != 0) if the compiler is IEEE 754 compliant. + +SCALAR_IS_LTZERO(x): + True if x is < zero or -Inf. False if x is >= 0, NaN, or +Inf. + This is (x < 0) if the compiler is IEEE 754 compliant. +*/ + +/* These all work properly, according to the IEEE 754 standard ... except on */ +/* a PC with windows. Works fine in Linux on the same PC... */ +#define SCALAR_IS_NAN(x) ((x) != (x)) +#define SCALAR_IS_ZERO(x) ((x) == 0.) +#define SCALAR_IS_NONZERO(x) ((x) != 0.) +#define SCALAR_IS_LTZERO(x) ((x) < 0.) + + +/* scalar absolute value macro. If x is NaN, the result is NaN: */ +#define SCALAR_ABS(x) ((SCALAR_IS_LTZERO (x)) ? -(x) : (x)) + +/* print a scalar (avoid printing "-0" for negative zero). */ +#ifdef NPRINT +#define PRINT_SCALAR(a) +#else +#define PRINT_SCALAR(a) \ +{ \ + if (SCALAR_IS_NONZERO (a)) \ + { \ + PRINTF ((" (%g)", (a))) ; \ + } \ + else \ + { \ + PRINTF ((" (0)")) ; \ + } \ +} +#endif + +/* -------------------------------------------------------------------------- */ +/* Real floating-point arithmetic */ +/* -------------------------------------------------------------------------- */ + +#ifndef COMPLEX + +typedef double Unit ; +#define Entry double + +#define SPLIT(s) (1) +#define REAL(c) (c) +#define IMAG(c) (0.) +#define ASSIGN(c,s1,s2,p,split) { (c) = (s1)[p] ; } +#define CLEAR(c) { (c) = 0. ; } +#define CLEAR_AND_INCREMENT(p) { *p++ = 0. ; } +#define IS_NAN(a) SCALAR_IS_NAN (a) +#define IS_ZERO(a) SCALAR_IS_ZERO (a) +#define IS_NONZERO(a) SCALAR_IS_NONZERO (a) +#define SCALE_DIV(c,s) { (c) /= (s) ; } +#define SCALE_DIV_ASSIGN(a,c,s) { a = c / s ; } +#define SCALE(c,s) { (c) *= (s) ; } +#define ASSEMBLE(c,a) { (c) += (a) ; } +#define ASSEMBLE_AND_INCREMENT(c,p) { (c) += *p++ ; } +#define DECREMENT(c,a) { (c) -= (a) ; } +#define MULT(c,a,b) { (c) = (a) * (b) ; } +#define MULT_CONJ(c,a,b) { (c) = (a) * (b) ; } +#define MULT_SUB(c,a,b) { (c) -= (a) * (b) ; } +#define MULT_SUB_CONJ(c,a,b) { (c) -= (a) * (b) ; } +#define DIV(c,a,b) { (c) = (a) / (b) ; } +#define RECIPROCAL(c) { (c) = 1.0 / (c) ; } +#define DIV_CONJ(c,a,b) { (c) = (a) / (b) ; } +#define APPROX_ABS(s,a) { (s) = SCALAR_ABS (a) ; } +#define ABS(s,a) { (s) = SCALAR_ABS (a) ; } +#define PRINT_ENTRY(a) PRINT_SCALAR (a) +#define CONJ(a,x) a = x + +/* for flop counts */ +#define MULTSUB_FLOPS 2. /* c -= a*b */ +#define DIV_FLOPS 1. /* c = a/b */ +#define ABS_FLOPS 0. /* c = abs (a) */ +#define ASSEMBLE_FLOPS 1. /* c += a */ +#define DECREMENT_FLOPS 1. /* c -= a */ +#define MULT_FLOPS 1. /* c = a*b */ +#define SCALE_FLOPS 1. /* c = a/s */ + +#else + +/* -------------------------------------------------------------------------- */ +/* Complex floating-point arithmetic */ +/* -------------------------------------------------------------------------- */ + +/* + Note: An alternative to this Double_Complex type would be to use a + struct { double r ; double i ; }. The problem with that method + (used by the Sun Performance Library, for example) is that ANSI C provides + no guarantee about the layout of a struct. It is possible that the sizeof + the struct above would be greater than 2 * sizeof (double). This would + mean that the complex BLAS could not be used. The method used here avoids + that possibility. ANSI C *does* guarantee that an array of structs has + the same size as n times the size of one struct. + + The ANSI C99 version of the C language includes a "double _Complex" type. + It should be possible in that case to do the following: + + #define Entry double _Complex + + and remove the Double_Complex struct. The macros, below, could then be + replaced with instrinsic operators. Note that the #define Real and + #define Imag should also be removed (they only appear in this file). + + For the MULT, MULT_SUB, MULT_SUB_CONJ, and MULT_CONJ macros, + the output argument c cannot be the same as any input argument. + +*/ + +typedef struct +{ + double component [2] ; /* real and imaginary parts */ + +} Double_Complex ; + +typedef Double_Complex Unit ; +#define Entry Double_Complex +#define Real component [0] +#define Imag component [1] + +/* for flop counts */ +#define MULTSUB_FLOPS 8. /* c -= a*b */ +#define DIV_FLOPS 9. /* c = a/b */ +#define ABS_FLOPS 6. /* c = abs (a), count sqrt as one flop */ +#define ASSEMBLE_FLOPS 2. /* c += a */ +#define DECREMENT_FLOPS 2. /* c -= a */ +#define MULT_FLOPS 6. /* c = a*b */ +#define SCALE_FLOPS 2. /* c = a/s or c = a*s */ + +/* -------------------------------------------------------------------------- */ + +/* real part of c */ +#define REAL(c) ((c).Real) + +/* -------------------------------------------------------------------------- */ + +/* imag part of c */ +#define IMAG(c) ((c).Imag) + +/* -------------------------------------------------------------------------- */ + +/* Return TRUE if a complex number is in split form, FALSE if in packed form */ +#define SPLIT(sz) ((sz) != (double *) NULL) + +/* c = (s1) + (s2)*i, if s2 is null, then X is in "packed" format (compatible + * with Entry and ANSI C99 double _Complex type). */ +/*#define ASSIGN(c,s1,s2,p,split) \ +{ \ + if (split) \ + { \ + (c).Real = (s1)[p] ; \ + (c).Imag = (s2)[p] ; \ + } \ + else \ + { \ + (c) = ((Entry *)(s1))[p] ; \ + } \ +}*/ + +/* -------------------------------------------------------------------------- */ +#define CONJ(a, x) \ +{ \ + a.Real = x.Real ; \ + a.Imag = -x.Imag ; \ +} + +/* c = 0 */ +#define CLEAR(c) \ +{ \ + (c).Real = 0. ; \ + (c).Imag = 0. ; \ +} + +/* -------------------------------------------------------------------------- */ + +/* *p++ = 0 */ +#define CLEAR_AND_INCREMENT(p) \ +{ \ + p->Real = 0. ; \ + p->Imag = 0. ; \ + p++ ; \ +} + +/* -------------------------------------------------------------------------- */ + +/* True if a == 0 */ +#define IS_ZERO(a) \ + (SCALAR_IS_ZERO ((a).Real) && SCALAR_IS_ZERO ((a).Imag)) + +/* -------------------------------------------------------------------------- */ + +/* True if a is NaN */ +#define IS_NAN(a) \ + (SCALAR_IS_NAN ((a).Real) || SCALAR_IS_NAN ((a).Imag)) + +/* -------------------------------------------------------------------------- */ + +/* True if a != 0 */ +#define IS_NONZERO(a) \ + (SCALAR_IS_NONZERO ((a).Real) || SCALAR_IS_NONZERO ((a).Imag)) + +/* -------------------------------------------------------------------------- */ + +/* a = c/s */ +#define SCALE_DIV_ASSIGN(a,c,s) \ +{ \ + a.Real = c.Real / s ; \ + a.Imag = c.Imag / s ; \ +} + +/* c /= s */ +#define SCALE_DIV(c,s) \ +{ \ + (c).Real /= (s) ; \ + (c).Imag /= (s) ; \ +} + +/* -------------------------------------------------------------------------- */ + +/* c *= s */ +#define SCALE(c,s) \ +{ \ + (c).Real *= (s) ; \ + (c).Imag *= (s) ; \ +} + +/* -------------------------------------------------------------------------- */ + +/* c += a */ +#define ASSEMBLE(c,a) \ +{ \ + (c).Real += (a).Real ; \ + (c).Imag += (a).Imag ; \ +} + +/* -------------------------------------------------------------------------- */ + +/* c += *p++ */ +#define ASSEMBLE_AND_INCREMENT(c,p) \ +{ \ + (c).Real += p->Real ; \ + (c).Imag += p->Imag ; \ + p++ ; \ +} + +/* -------------------------------------------------------------------------- */ + +/* c -= a */ +#define DECREMENT(c,a) \ +{ \ + (c).Real -= (a).Real ; \ + (c).Imag -= (a).Imag ; \ +} + +/* -------------------------------------------------------------------------- */ + +/* c = a*b, assert because c cannot be the same as a or b */ +#define MULT(c,a,b) \ +{ \ + ASSERT (&(c) != &(a) && &(c) != &(b)) ; \ + (c).Real = (a).Real * (b).Real - (a).Imag * (b).Imag ; \ + (c).Imag = (a).Imag * (b).Real + (a).Real * (b).Imag ; \ +} + +/* -------------------------------------------------------------------------- */ + +/* c = a*conjugate(b), assert because c cannot be the same as a or b */ +#define MULT_CONJ(c,a,b) \ +{ \ + ASSERT (&(c) != &(a) && &(c) != &(b)) ; \ + (c).Real = (a).Real * (b).Real + (a).Imag * (b).Imag ; \ + (c).Imag = (a).Imag * (b).Real - (a).Real * (b).Imag ; \ +} + +/* -------------------------------------------------------------------------- */ + +/* c -= a*b, assert because c cannot be the same as a or b */ +#define MULT_SUB(c,a,b) \ +{ \ + ASSERT (&(c) != &(a) && &(c) != &(b)) ; \ + (c).Real -= (a).Real * (b).Real - (a).Imag * (b).Imag ; \ + (c).Imag -= (a).Imag * (b).Real + (a).Real * (b).Imag ; \ +} + +/* -------------------------------------------------------------------------- */ + +/* c -= a*conjugate(b), assert because c cannot be the same as a or b */ +#define MULT_SUB_CONJ(c,a,b) \ +{ \ + ASSERT (&(c) != &(a) && &(c) != &(b)) ; \ + (c).Real -= (a).Real * (b).Real + (a).Imag * (b).Imag ; \ + (c).Imag -= (a).Imag * (b).Real - (a).Real * (b).Imag ; \ +} + +/* -------------------------------------------------------------------------- */ + +/* c = a/b, be careful to avoid underflow and overflow */ +#ifdef MATHWORKS +#define DIV(c,a,b) \ +{ \ + (void) utDivideComplex ((a).Real, (a).Imag, (b).Real, (b).Imag, \ + &((c).Real), &((c).Imag)) ; \ +} +#else +/* This uses ACM Algo 116, by R. L. Smith, 1962. */ +/* c can be the same variable as a or b. */ +/* Ignore NaN case for double relop br>=bi. */ +#define DIV(c,a,b) \ +{ \ + double r, den, ar, ai, br, bi ; \ + br = (b).Real ; \ + bi = (b).Imag ; \ + ar = (a).Real ; \ + ai = (a).Imag ; \ + if (SCALAR_ABS (br) >= SCALAR_ABS (bi)) \ + { \ + r = bi / br ; \ + den = br + r * bi ; \ + (c).Real = (ar + ai * r) / den ; \ + (c).Imag = (ai - ar * r) / den ; \ + } \ + else \ + { \ + r = br / bi ; \ + den = r * br + bi ; \ + (c).Real = (ar * r + ai) / den ; \ + (c).Imag = (ai * r - ar) / den ; \ + } \ +} +#endif + +/* -------------------------------------------------------------------------- */ + +/* c = 1/c, be careful to avoid underflow and overflow */ +/* Not used if MATHWORKS is defined. */ +/* This uses ACM Algo 116, by R. L. Smith, 1962. */ +/* Ignore NaN case for double relop cr>=ci. */ +#define RECIPROCAL(c) \ +{ \ + double r, den, cr, ci ; \ + cr = (c).Real ; \ + ci = (c).Imag ; \ + if (SCALAR_ABS (cr) >= SCALAR_ABS (ci)) \ + { \ + r = ci / cr ; \ + den = cr + r * ci ; \ + (c).Real = 1.0 / den ; \ + (c).Imag = - r / den ; \ + } \ + else \ + { \ + r = cr / ci ; \ + den = r * cr + ci ; \ + (c).Real = r / den ; \ + (c).Imag = - 1.0 / den ; \ + } \ +} + + +/* -------------------------------------------------------------------------- */ + +/* c = a/conjugate(b), be careful to avoid underflow and overflow */ +#ifdef MATHWORKS +#define DIV_CONJ(c,a,b) \ +{ \ + (void) utDivideComplex ((a).Real, (a).Imag, (b).Real, (-(b).Imag), \ + &((c).Real), &((c).Imag)) ; \ +} +#else +/* This uses ACM Algo 116, by R. L. Smith, 1962. */ +/* c can be the same variable as a or b. */ +/* Ignore NaN case for double relop br>=bi. */ +#define DIV_CONJ(c,a,b) \ +{ \ + double r, den, ar, ai, br, bi ; \ + br = (b).Real ; \ + bi = (b).Imag ; \ + ar = (a).Real ; \ + ai = (a).Imag ; \ + if (SCALAR_ABS (br) >= SCALAR_ABS (bi)) \ + { \ + r = (-bi) / br ; \ + den = br - r * bi ; \ + (c).Real = (ar + ai * r) / den ; \ + (c).Imag = (ai - ar * r) / den ; \ + } \ + else \ + { \ + r = br / (-bi) ; \ + den = r * br - bi; \ + (c).Real = (ar * r + ai) / den ; \ + (c).Imag = (ai * r - ar) / den ; \ + } \ +} +#endif + +/* -------------------------------------------------------------------------- */ + +/* approximate absolute value, s = |r|+|i| */ +#define APPROX_ABS(s,a) \ +{ \ + (s) = SCALAR_ABS ((a).Real) + SCALAR_ABS ((a).Imag) ; \ +} + +/* -------------------------------------------------------------------------- */ + +/* exact absolute value, s = sqrt (a.real^2 + amag^2) */ +#ifdef MATHWORKS +#define ABS(s,a) \ +{ \ + (s) = utFdlibm_hypot ((a).Real, (a).Imag) ; \ +} +#else +/* Ignore NaN case for the double relops ar>=ai and ar+ai==ar. */ +#define ABS(s,a) \ +{ \ + double r, ar, ai ; \ + ar = SCALAR_ABS ((a).Real) ; \ + ai = SCALAR_ABS ((a).Imag) ; \ + if (ar >= ai) \ + { \ + if (ar + ai == ar) \ + { \ + (s) = ar ; \ + } \ + else \ + { \ + r = ai / ar ; \ + (s) = ar * sqrt (1.0 + r*r) ; \ + } \ + } \ + else \ + { \ + if (ai + ar == ai) \ + { \ + (s) = ai ; \ + } \ + else \ + { \ + r = ar / ai ; \ + (s) = ai * sqrt (1.0 + r*r) ; \ + } \ + } \ +} +#endif + +/* -------------------------------------------------------------------------- */ + +/* print an entry (avoid printing "-0" for negative zero). */ +#ifdef NPRINT +#define PRINT_ENTRY(a) +#else +#define PRINT_ENTRY(a) \ +{ \ + if (SCALAR_IS_NONZERO ((a).Real)) \ + { \ + PRINTF ((" (%g", (a).Real)) ; \ + } \ + else \ + { \ + PRINTF ((" (0")) ; \ + } \ + if (SCALAR_IS_LTZERO ((a).Imag)) \ + { \ + PRINTF ((" - %gi)", -(a).Imag)) ; \ + } \ + else if (SCALAR_IS_ZERO ((a).Imag)) \ + { \ + PRINTF ((" + 0i)")) ; \ + } \ + else \ + { \ + PRINTF ((" + %gi)", (a).Imag)) ; \ + } \ +} +#endif + +/* -------------------------------------------------------------------------- */ + +#endif /* #ifndef COMPLEX */ + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/MATLAB/klu_mex.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/MATLAB/klu_mex.c new file mode 100644 index 0000000..f19f8a3 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/MATLAB/klu_mex.c @@ -0,0 +1,1974 @@ +/* ========================================================================== */ +/* === klu mexFunction ====================================================== */ +/* ========================================================================== */ + +/* KLU: a MATLAB interface to a "Clark Kent" sparse LU factorization algorithm. + + 3 or 4 input arguments: factorize and solve, returning the solution: + + x = klu (A, '\', b) + x = klu (A, '\', b, opts) + x = klu (b, '/', A) + x = klu (b, '/', A, opts) + + A can be the LU struct, instead: + + x = klu (LU, '\', b) + x = klu (LU, '\', b, opts) + x = klu (b, '/', LU) + x = klu (b, '/', LU, opts) + + where LU is a struct containing members: L, U, p, q, R, F, and r. Only L + and U are required. The factorization is L*U+F = R\A(p,q), where r defines + the block boundaries of the BTF form, and F contains the entries in the + upper block triangular part. + + with 1 or 2 input arguments: factorize, returning the LU struct: + + LU = klu (A) + LU = klu (A, opts) + + 2nd optional output: info, which is only meaningful if A was factorized. + + A must be square. b can be a matrix, but it cannot be sparse. + + Obscure options, mainly for testing: + + opts.memgrow 1.2 when L and U need to grow, inc. by this ratio. + valid range: 1 or more. + opts.imemamd 1.2 initial size of L and U with AMD or other + symmetric ordering is 1.2*nnz(L)+n; + valid range 1 or more. + opts.imem 10 initial size of L and U is 10*nnz(A)+n if a + symmetric ordering not used; valid range 1 or + more +*/ + +/* ========================================================================== */ + +#include "klu.h" +#include <string.h> +#define Long SuiteSparse_long + +#ifndef NCHOLMOD +#include "klu_cholmod.h" +#endif + +#include "mex.h" +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define ABS(x) (((x) < 0) ? -(x) : (x)) +#define STRING_MATCH(s1,s2) (strcmp ((s1), (s2)) == 0) + +/* Complex division. This uses ACM Algo 116, by R. L. Smith, 1962. */ +/* Note that c cannot be the same variable as a or b */ +#define DIV(cx,cz,ax,az,bx,bz) \ +{ \ + double r, den ; \ + if (ABS (bx) >= ABS (bz)) \ + { \ + r = bz / bx ; \ + den = bx + r * bz ; \ + cx = (ax + az * r) / den ; \ + cz = (az - ax * r) / den ; \ + } \ + else \ + { \ + r = bx / bz ; \ + den = r * bx + bz ; \ + cx = (ax * r + az) / den ; \ + cz = (az * r - ax) / den ; \ + } \ +} + +/* complex multiply/subtract, c -= a*b */ +/* Note that c cannot be the same variable as a or b */ +#define MULT_SUB(cx,cz,ax,az,bx,bz) \ +{ \ + cx -= ax * bx - az * bz ; \ + cz -= az * bx + ax * bz ; \ +} + +/* complex multiply/subtract, c -= a*conj(b) */ +/* Note that c cannot be the same variable as a or b */ +#define MULT_SUB_CONJ(cx,cz,ax,az,bx,bz) \ +{ \ + cx -= ax * bx + az * bz ; \ + cz -= az * bx - ax * bz ; \ +} + +/* ========================================================================== */ +/* === klu mexFunction ====================================================== */ +/* ========================================================================== */ + +void mexFunction +( + int nargout, + mxArray *pargout [ ], + int nargin, + const mxArray *pargin [ ] +) +{ + double ukk, lkk, rs, s, lik, uik, x [4], offik, z, ukkz, lkkz, sz, wx, wz ; + double *X, *B, *Xz, *Xx, *Bx, *Bz, *A, *Ax, *Az, *Lx, *Ux, *Rs, *Offx, *Wx, + *Uz, *Lz, *Offz, *Wz, *W, *Xi, *Bi ; + Long *Ap, *Ai, *Lp, *Li, *Up, *Ui, *P, *Q, *R, *Rp, *Ri, *Offp, *Offi ; + char *operator ; + mxArray *L_matlab, *U_matlab, *p_matlab, *q_matlab, *R_matlab, *F_matlab, + *r_matlab, *field ; + const mxArray *A_matlab = NULL, *LU_matlab, *B_matlab = NULL, *opts_matlab ; + klu_l_symbolic *Symbolic ; + klu_l_numeric *Numeric ; + klu_l_common Common ; + Long n = 0, k, nrhs = 0, do_solve, do_factorize, symmetric, + A_complex = 0, B_complex, nz, do_transpose = 0, p, pend, nblocks, + R1 [2], chunk, nr, i, j, block, k1, k2, nk, bn = 0, ordering ; + int mx_int ; + static const char *fnames [ ] = { + "noffdiag", /* # of off-diagonal pivots */ + "nrealloc", /* # of memory reallocations */ + "rcond", /* cheap reciprocal number estimate */ + "rgrowth", /* reciprocal pivot growth */ + "flops", /* flop count */ + "nblocks", /* # of blocks in BTF form (1 if not computed) */ + "ordering", /* AMD, COLAMD, natural, cholmod(AA'), cholmod(A+A') */ + "scale", /* scaling (<=0: none, 1: sum, 2: max */ + "lnz", /* nnz(L), including diagonal */ + "unz", /* nnz(U), including diagonal */ + "offnz", /* nnz(F), including diagonal */ + "tol", /* pivot tolerance used */ + "memory" /* peak memory usage */ + }, + *LUnames [ ] = { "L", "U", "p", "q", "R", "F", "r" } ; + + /* ---------------------------------------------------------------------- */ + /* get inputs */ + /* ---------------------------------------------------------------------- */ + + if (nargin < 1 || nargin > 4 || nargout > 3) + { + mexErrMsgTxt ( + "Usage: x = klu(A,'\',b), x = klu(A,'/',b) or LU = klu(A)") ; + } + + /* return the solution x, or just do LU factorization */ + do_solve = (nargin > 2) ; + + /* determine size of the MATLAB integer */ + if (sizeof (Long) == sizeof (INT32_T)) + { + mx_int = mxINT32_CLASS ; + } + else + { + mx_int = mxINT64_CLASS ; + } + + if (do_solve) + { + + /* ------------------------------------------------------------------ */ + /* slash or backslash */ + /* ------------------------------------------------------------------ */ + + /* usage, where opts is the optional 4th input argument: + x = klu (A, '\', b) + x = klu (LU, '\', b) + x = klu (b, '/', A) + x = klu (b, '/', LU) + */ + + /* determine the operator, slash (/) or backslash (\) */ + if (!mxIsChar (pargin [1])) + { + mexErrMsgTxt ("invalid operator") ; + } + operator = mxArrayToString (pargin [1]) ; + if (STRING_MATCH (operator, "\\")) + { + do_transpose = 0 ; + A_matlab = pargin [0] ; + B_matlab = pargin [2] ; + nrhs = mxGetN (B_matlab) ; + bn = mxGetM (B_matlab) ; + } + else if (STRING_MATCH (operator, "/")) + { + do_transpose = 1 ; + A_matlab = pargin [2] ; + B_matlab = pargin [0] ; + nrhs = mxGetM (B_matlab) ; + bn = mxGetN (B_matlab) ; + } + else + { + mexErrMsgTxt ("invalid operator") ; + } + + if (mxIsSparse (B_matlab)) + { + mexErrMsgTxt ("B cannot be sparse") ; + } + + opts_matlab = (nargin > 3) ? pargin [3] : NULL ; + + /* determine if the factorization needs to be performed */ + do_factorize = !mxIsStruct (A_matlab) ; + if (do_factorize) + { + LU_matlab = NULL ; + } + else + { + LU_matlab = A_matlab ; + A_matlab = NULL ; + } + + } + else + { + + /* ------------------------------------------------------------------ */ + /* factorize A and return LU factorization */ + /* ------------------------------------------------------------------ */ + + /* usage, where opts in the optional 2nd input argument: + LU = klu (A) + */ + + LU_matlab = NULL ; + A_matlab = pargin [0] ; + B_matlab = NULL ; + opts_matlab = (nargin > 1) ? pargin [1] : NULL ; + do_factorize = 1 ; + if (mxIsStruct (A_matlab)) + { + mexErrMsgTxt ("invalid input, A must be a sparse matrix") ; + } + } + + /* ---------------------------------------------------------------------- */ + /* get options and set Common defaults */ + /* ---------------------------------------------------------------------- */ + + klu_l_defaults (&Common) ; + + /* factorization options */ + if (opts_matlab != NULL && mxIsStruct (opts_matlab)) + { + if ((field = mxGetField (opts_matlab, 0, "tol")) != NULL) + { + Common.tol = mxGetScalar (field) ; + } + if ((field = mxGetField (opts_matlab, 0, "memgrow")) != NULL) + { + Common.memgrow = mxGetScalar (field) ; + } + if ((field = mxGetField (opts_matlab, 0, "imemamd")) != NULL) + { + Common.initmem_amd = mxGetScalar (field) ; + } + if ((field = mxGetField (opts_matlab, 0, "imem")) != NULL) + { + Common.initmem = mxGetScalar (field) ; + } + if ((field = mxGetField (opts_matlab, 0, "btf")) != NULL) + { + Common.btf = mxGetScalar (field) ; + } + if ((field = mxGetField (opts_matlab, 0, "ordering")) != NULL) + { + Common.ordering = mxGetScalar (field) ; + } + if ((field = mxGetField (opts_matlab, 0, "scale")) != NULL) + { + Common.scale = mxGetScalar (field) ; + } + if ((field = mxGetField (opts_matlab, 0, "maxwork")) != NULL) + { + Common.maxwork = mxGetScalar (field) ; + } + } + + if (Common.ordering < 0 || Common.ordering > 4) + { + mexErrMsgTxt ("invalid ordering option") ; + } + ordering = Common.ordering ; + +#ifndef NCHOLMOD + /* ordering option 3,4 becomes KLU option 3, with symmetric 0 or 1 */ + symmetric = (Common.ordering == 4) ; + if (symmetric) Common.ordering = 3 ; + Common.user_order = klu_l_cholmod ; + Common.user_data = &symmetric ; +#else + /* CHOLMOD, METIS, CAMD, CCOLAMD, not available */ + if (Common.ordering > 2) + { + mexErrMsgTxt ("invalid ordering option") ; + } +#endif + + if (Common.scale < 1 || Common.scale > 2) + { + Common.scale = -1 ; /* no scaling, and no error checking either */ + } + + /* ---------------------------------------------------------------------- */ + /* factorize, if needed */ + /* ---------------------------------------------------------------------- */ + + if (do_factorize) + { + + /* get input matrix A to factorize */ + n = mxGetN (A_matlab) ; + if (!mxIsSparse (A_matlab) || n != mxGetM (A_matlab) || n == 0) + { + mexErrMsgTxt ("A must be sparse, square, and non-empty") ; + } + + Ap = (Long *) mxGetJc (A_matlab) ; + Ai = (Long *) mxGetIr (A_matlab) ; + Ax = mxGetPr (A_matlab) ; + Az = mxGetPi (A_matlab) ; + nz = Ap [n] ; + A_complex = mxIsComplex (A_matlab) ; + + if (do_solve && (n != bn || nrhs == 0)) + { + mexErrMsgTxt ("B must be non-empty with same number of rows as A") ; + } + + /* ------------------------------------------------------------------ */ + /* analyze */ + /* ------------------------------------------------------------------ */ + + Symbolic = klu_l_analyze (n, Ap, Ai, &Common) ; + if (Symbolic == (klu_l_symbolic *) NULL) + { + mexErrMsgTxt ("klu symbolic analysis failed") ; + } + + /* ------------------------------------------------------------------ */ + /* factorize */ + /* ------------------------------------------------------------------ */ + + if (A_complex) + { + /* A is complex */ + A = mxMalloc (nz * 2 * sizeof (double)) ; + for (k = 0 ; k < nz ; k++) + { + A [2*k ] = Ax [k] ; /* real part */ + A [2*k+1] = Az [k] ; /* imaginary part */ + } + Numeric = klu_zl_factor (Ap, Ai, A, Symbolic, &Common) ; + if (nargout > 1) + { + /* flops and rgrowth, if requested */ + klu_zl_flops (Symbolic, Numeric, &Common) ; + klu_zl_rgrowth (Ap, Ai, A, Symbolic, Numeric, &Common) ; + } + mxFree (A) ; + } + else + { + /* A is real */ + Numeric = klu_l_factor (Ap, Ai, Ax, Symbolic, &Common) ; + if (nargout > 1) + { + /* flops, if requested */ + klu_l_flops (Symbolic, Numeric, &Common) ; + klu_l_rgrowth (Ap, Ai, Ax, Symbolic, Numeric, &Common) ; + } + } + if (Common.status != KLU_OK) + { + mexErrMsgTxt ("klu numeric factorization failed") ; + } + + /* ------------------------------------------------------------------ */ + /* compute cheap condition number estimate */ + /* ------------------------------------------------------------------ */ + + if (A_complex) + { + klu_zl_rcond (Symbolic, Numeric, &Common) ; + } + else + { + klu_l_rcond (Symbolic, Numeric, &Common) ; + } + + /* ------------------------------------------------------------------ */ + /* return info, if requested */ + /* ------------------------------------------------------------------ */ + +#define INFO(i,x) \ + mxSetFieldByNumber (pargout [1], 0, i, mxCreateDoubleScalar (x)) + + if (nargout > 1) + { + pargout [1] = mxCreateStructMatrix (1, 1, 13, fnames) ; + INFO (0, Common.noffdiag) ; + INFO (1, Common.nrealloc) ; + INFO (2, Common.rcond) ; + INFO (3, Common.rgrowth) ; + INFO (4, Common.flops) ; + INFO (5, Symbolic->nblocks) ; + INFO (6, ordering) ; + INFO (7, Common.scale) ; + INFO (8, Numeric->lnz) ; + INFO (9, Numeric->unz) ; + INFO (10, Numeric->nzoff) ; + INFO (11, Common.tol) ; + INFO (12, Common.mempeak) ; + } + if (nargout > 2) + { + /* this is done separately, since it's costly */ + klu_l_condest (Ap, Ax, Symbolic, Numeric, &Common) ; + pargout [2] = mxCreateDoubleMatrix (1, 1, mxREAL) ; + Wx = mxGetPr (pargout [2]) ; + Wx [0] = Common.condest ; + } + + } + else + { + /* create an empty "info" and "condest" output */ + if (nargout > 1) + { + pargout [1] = mxCreateDoubleMatrix (0, 0, mxREAL) ; + } + if (nargout > 2) + { + pargout [2] = mxCreateDoubleMatrix (0, 0, mxREAL) ; + } + } + + /* ---------------------------------------------------------------------- */ + /* solve, or return LU factorization */ + /* ---------------------------------------------------------------------- */ + + if (do_solve) + { + + /* ------------------------------------------------------------------ */ + /* solve, x = klu ( ... ) usage */ + /* ------------------------------------------------------------------ */ + + B_complex = mxIsComplex (B_matlab) ; + + if (do_factorize) + { + + /* -------------------------------------------------------------- */ + /* solve using KLU factors computed above */ + /* -------------------------------------------------------------- */ + + /* klu (A,'\',b) or klu (b,'/',A) usage */ + + /* create X */ + if (do_transpose) + { + pargout [0] = mxCreateDoubleMatrix (nrhs, n, + (A_complex || B_complex) ? mxCOMPLEX : mxREAL) ; + } + else + { + pargout [0] = mxCreateDoubleMatrix (n, nrhs, + (A_complex || B_complex) ? mxCOMPLEX : mxREAL) ; + } + + if (A_complex) + { + + /* ---------------------------------------------------------- */ + /* A is complex, but B might be real */ + /* ---------------------------------------------------------- */ + + X = mxMalloc (n * nrhs * 2 * sizeof (double)) ; + Bx = mxGetPr (B_matlab) ; + Bz = mxGetPi (B_matlab) ; + + if (do_transpose) + { + + /* X = B', merge and transpose B */ + for (j = 0 ; j < nrhs ; j++) + { + for (i = 0 ; i < n ; i++) + { + X [2*(i+j*n) ] = Bx [j+i*nrhs] ; /* real */ + X [2*(i+j*n)+1] = Bz ? (-Bz [j+i*nrhs]) : 0 ; + } + } + + /* solve A'x=b (complex conjugate) */ + klu_zl_tsolve (Symbolic, Numeric, n, nrhs, X, 1, &Common) ; + + /* split and transpose the solution */ + Xx = mxGetPr (pargout [0]) ; + Xz = mxGetPi (pargout [0]) ; + for (j = 0 ; j < nrhs ; j++) + { + for (i = 0 ; i < n ; i++) + { + Xx [j+i*nrhs] = X [2*(i+j*n) ] ; /* real part */ + Xz [j+i*nrhs] = -X [2*(i+j*n)+1] ; /* imag part */ + } + } + + } + else + { + + /* X = B, but create merged X from a split B */ + for (k = 0 ; k < n*nrhs ; k++) + { + X [2*k ] = Bx [k] ; /* real part */ + X [2*k+1] = Bz ? (Bz [k]) : 0 ; /* imaginary part */ + } + + /* solve Ax=b */ + klu_zl_solve (Symbolic, Numeric, n, nrhs, X, &Common) ; + + /* split the solution into real and imaginary parts */ + Xx = mxGetPr (pargout [0]) ; + Xz = mxGetPi (pargout [0]) ; + for (k = 0 ; k < n*nrhs ; k++) + { + Xx [k] = X [2*k ] ; /* real part */ + Xz [k] = X [2*k+1] ; /* imaginary part */ + } + } + + mxFree (X) ; + } + else + { + + if (do_transpose) + { + + /* solve in chunks of 4 columns at a time */ + W = mxMalloc (n * MAX (nrhs,4) * sizeof (double)) ; + X = mxGetPr (pargout [0]) ; + B = mxGetPr (B_matlab) ; + Xi = mxGetPi (pargout [0]) ; + Bi = mxGetPi (B_matlab) ; + + for (chunk = 0 ; chunk < nrhs ; chunk += 4) + { + + /* A is real: real(X) = real(b) / real(A) */ + Long chunksize = MIN (nrhs - chunk, 4) ; + for (j = 0 ; j < chunksize ; j++) + { + for (i = 0 ; i < n ; i++) + { + W [i+j*n] = B [i*nrhs+j] ; + } + } + klu_l_tsolve (Symbolic, Numeric, n, chunksize, W, + &Common) ; + for (j = 0 ; j < chunksize ; j++) + { + for (i = 0 ; i < n ; i++) + { + X [i*nrhs+j] = W [i+j*n] ; + } + } + X += 4 ; + B += 4 ; + + if (B_complex) + { + /* B is complex: imag(X) = imag(B) / real(A) */ + + for (j = 0 ; j < chunksize ; j++) + { + for (i = 0 ; i < n ; i++) + { + W [i+j*n] = Bi [i*nrhs+j] ; + } + } + klu_l_tsolve (Symbolic, Numeric, n, chunksize, W, + &Common) ; + for (j = 0 ; j < chunksize ; j++) + { + for (i = 0 ; i < n ; i++) + { + Xi [i*nrhs+j] = W [i+j*n] ; + } + } + Xi += 4 ; + Bi += 4 ; + } + + } + mxFree (W) ; + + } + else + { + + /* A is real: real(X) = real(A) \ real(b) */ + X = mxGetPr (pargout [0]) ; + B = mxGetPr (B_matlab) ; + for (k = 0 ; k < n*nrhs ; k++) + { + X [k] = B [k] ; + } + klu_l_solve (Symbolic, Numeric, n, nrhs, X, &Common) ; + if (B_complex) + { + /* B is complex: imag(X) = real(A) \ imag(B) */ + X = mxGetPi (pargout [0]) ; + B = mxGetPi (B_matlab) ; + for (k = 0 ; k < n*nrhs ; k++) + { + X [k] = B [k] ; + } + klu_l_solve (Symbolic, Numeric, n, nrhs, X, &Common) ; + } + } + } + + /* -------------------------------------------------------------- */ + /* free Symbolic and Numeric objects */ + /* -------------------------------------------------------------- */ + + klu_l_free_symbolic (&Symbolic, &Common) ; + if (A_complex) + { + klu_zl_free_numeric (&Numeric, &Common) ; + } + else + { + klu_l_free_numeric (&Numeric, &Common) ; + } + + } + else + { + + /* -------------------------------------------------------------- */ + /* solve using LU struct given on input */ + /* -------------------------------------------------------------- */ + + /* the factorization is L*U+F = R\A(p,q), where L*U is block + diagonal, and F contains the entries in the upper block + triangular part */ + + L_matlab = mxGetField (LU_matlab, 0, "L") ; + U_matlab = mxGetField (LU_matlab, 0, "U") ; + p_matlab = mxGetField (LU_matlab, 0, "p") ; + q_matlab = mxGetField (LU_matlab, 0, "q") ; + R_matlab = mxGetField (LU_matlab, 0, "R") ; + F_matlab = mxGetField (LU_matlab, 0, "F") ; + r_matlab = mxGetField (LU_matlab, 0, "r") ; + + if (!L_matlab || !U_matlab || !mxIsSparse (L_matlab) || + !mxIsSparse (U_matlab)) + { + mexErrMsgTxt ("invalid LU struct") ; + } + + n = mxGetM (L_matlab) ; + if (n != mxGetN (L_matlab) || + n != mxGetM (U_matlab) || n != mxGetN (U_matlab) + /* ... */ + ) + { + mexErrMsgTxt ("invalid LU struct") ; + } + + if (n != bn || nrhs == 0) + { + mexErrMsgTxt ( + "B must be non-empty with same number of rows as L and U") ; + } + + /* get L */ + if (!mxIsSparse (L_matlab) || + n != mxGetM (L_matlab) || n != mxGetN (L_matlab)) + { + mexErrMsgTxt ("LU.L must be sparse and same size as A") ; + } + + Lp = (Long *) mxGetJc (L_matlab) ; + Li = (Long *) mxGetIr (L_matlab) ; + Lx = mxGetPr (L_matlab) ; + Lz = mxGetPi (L_matlab) ; + + /* get U */ + if (!mxIsSparse (U_matlab) || + n != mxGetM (U_matlab) || n != mxGetN (U_matlab)) + { + mexErrMsgTxt ("LU.U must be sparse and same size as A") ; + } + Up = (Long *) mxGetJc (U_matlab) ; + Ui = (Long *) mxGetIr (U_matlab) ; + Ux = mxGetPr (U_matlab) ; + Uz = mxGetPi (U_matlab) ; + + /* get p */ + if (p_matlab) + { + if (mxGetNumberOfElements (p_matlab) != n + || mxIsSparse (p_matlab) + || mxGetClassID (p_matlab) != mx_int) + { + mexErrMsgTxt ("P invalid") ; + } + P = (Long *) mxGetData (p_matlab) ; + for (k = 0 ; k < n ; k++) + { + if (P [k] < 1 || P [k] > n) mexErrMsgTxt ("P invalid") ; + } + } + else + { + /* no P, use identity instead */ + P = NULL ; + } + + /* get q */ + if (q_matlab) + { + if (mxGetNumberOfElements (q_matlab) != n + || mxIsSparse (q_matlab) + || mxGetClassID (q_matlab) != mx_int) + { + mexErrMsgTxt ("Q invalid") ; + } + Q = (Long *) mxGetData (q_matlab) ; + for (k = 0 ; k < n ; k++) + { + if (Q [k] < 1 || Q [k] > n) mexErrMsgTxt ("Q invalid.") ; + } + } + else + { + /* no Q, use identity instead */ + Q = NULL ; + } + + /* get r */ + R1 [0] = 1 ; + R1 [1] = n+1 ; + if (r_matlab) + { + nblocks = mxGetNumberOfElements (r_matlab) - 1 ; + if (nblocks < 1 || nblocks > n || mxIsSparse (r_matlab) + || mxGetClassID (r_matlab) != mx_int) + { + mexErrMsgTxt ("r invalid") ; + } + R = (Long *) mxGetData (r_matlab) ; + if (R [0] != 1) mexErrMsgTxt ("r invalid") ; + for (k = 1 ; k <= nblocks ; k++) + { + if (R [k] <= R [k-1] || R [k] > n+1) + { + mexErrMsgTxt ("rinvalid") ; + } + } + if (R [nblocks] != n+1) mexErrMsgTxt ("r invalid") ; + } + else + { + /* no r */ + nblocks = 1 ; + R = R1 ; + } + + /* get R, scale factors */ + if (R_matlab) + { + /* ensure R is sparse, real, and has the right size */ + if (!mxIsSparse (R_matlab) || + n != mxGetM (R_matlab) || n != mxGetN (R_matlab)) + { + mexErrMsgTxt ("LU.R must be sparse and same size as A") ; + } + Rp = (Long *) mxGetJc (R_matlab) ; + Rs = mxGetPr (R_matlab) ; + if (Rp [n] != n) + { + mexErrMsgTxt ("LU.R invalid, must be diagonal") ; + } + } + else + { + /* no scale factors */ + Rs = NULL ; + } + + /* get F, off diagonal entries */ + if (F_matlab) + { + if (!mxIsSparse (F_matlab) || + n != mxGetM (F_matlab) || n != mxGetN (F_matlab)) + { + mexErrMsgTxt ("LU.F must be sparse and same size as A") ; + } + Offp = (Long *) mxGetJc (F_matlab) ; + Offi = (Long *) mxGetIr (F_matlab) ; + Offx = mxGetPr (F_matlab) ; + Offz = mxGetPi (F_matlab) ; + } + else + { + /* no off-diagonal entries */ + Offp = NULL ; + Offi = NULL ; + Offx = NULL ; + Offz = NULL ; + } + + /* -------------------------------------------------------------- */ + /* solve */ + /* -------------------------------------------------------------- */ + + if (mxIsComplex (L_matlab) || mxIsComplex (U_matlab) || + (F_matlab && mxIsComplex (F_matlab)) || B_complex) + { + + /* ========================================================== */ + /* === complex case ========================================= */ + /* ========================================================== */ + + /* create X */ + if (do_transpose) + { + pargout [0] = mxCreateDoubleMatrix (nrhs, n, mxCOMPLEX) ; + } + else + { + pargout [0] = mxCreateDoubleMatrix (n, nrhs, mxCOMPLEX) ; + } + Xx = mxGetPr (pargout [0]) ; + Xz = mxGetPi (pargout [0]) ; + + Bx = mxGetPr (B_matlab) ; + Bz = mxGetPi (B_matlab) ; + + /* get workspace */ + Wx = mxMalloc (n * sizeof (double)) ; + Wz = mxMalloc (n * sizeof (double)) ; + + /* ---------------------------------------------------------- */ + /* do just one row/column of the right-hand-side at a time */ + /* ---------------------------------------------------------- */ + + if (do_transpose) + { + + for (chunk = 0 ; chunk < nrhs ; chunk++) + { + + /* -------------------------------------------------- */ + /* transpose and permute right hand side, W = Q'*B' */ + /* -------------------------------------------------- */ + + for (k = 0 ; k < n ; k++) + { + i = Q ? (Q [k] - 1) : k ; + Wx [k] = Bx [i*nrhs] ; + Wz [k] = Bz ? (-Bz [i*nrhs]) : 0 ; + } + + /* -------------------------------------------------- */ + /* solve W = (L*U + Off)'\W */ + /* -------------------------------------------------- */ + + for (block = 0 ; block < nblocks ; block++) + { + + /* ---------------------------------------------- */ + /* block of size nk, rows/columns k1 to k2-1 */ + /* ---------------------------------------------- */ + + k1 = R [block] - 1 ; /* R is 1-based */ + k2 = R [block+1] - 1 ; + nk = k2 - k1 ; + + /* ---------------------------------------------- */ + /* block back-substitution for off-diagonal-block */ + /* ---------------------------------------------- */ + + if (block > 0 && Offp != NULL) + { + for (k = k1 ; k < k2 ; k++) + { + pend = Offp [k+1] ; + for (p = Offp [k] ; p < pend ; p++) + { + i = Offi [p] ; + /* W [k] -= W [i] * conj(Off [p]) ; */ + z = Offz ? Offz [p] : 0 ; + MULT_SUB_CONJ (Wx [k], Wz [k], + Wx [i], Wz [i], Offx [p], z) ; + } + } + } + + + /* solve the block system */ + if (nk == 1) + { + + /* W [k1] /= conj (L(k1,k1)) ; */ + p = Lp [k1] ; + s = Lx [p] ; + sz = Lz ? (-Lz [p]) : 0 ; + DIV (wx, wz, Wx [k1], Wz [k1], s, sz) ; + Wx [k1] = wx ; + Wz [k1] = wz ; + + /* W [k1] /= conj (U(k1,k1)) ; */ + p = Up [k1] ; + s = Ux [p] ; + sz = Uz ? (-Uz [p]) : 0 ; + DIV (wx, wz, Wx [k1], Wz [k1], s, sz) ; + Wx [k1] = wx ; + Wz [k1] = wz ; + + } + else + { + + /* ------------------------------------------ */ + /* W = U'\W and then W=L'\W */ + /* ------------------------------------------ */ + + /* W = U'\W */ + for (k = k1 ; k < k2 ; k++) + { + pend = Up [k+1] - 1 ; + /* w = W [k] */ + wx = Wx [k] ; + wz = Wz [k] ; + for (p = Up [k] ; p < pend ; p++) + { + i = Ui [p] ; + /* w -= W [i] * conj(U [p]) */ + z = Uz ? Uz [p] : 0 ; + MULT_SUB_CONJ (wx, wz, + Wx [i], Wz [i], Ux [p], z) ; + } + /* W [k] = w / conj(ukk) ; */ + ukk = Ux [pend] ; + ukkz = Uz ? (-Uz [pend]) : 0 ; + DIV (Wx [k], Wz [k], wx, wz, ukk, ukkz) ; + } + + /* W = L'\W */ + for (k = k2-1 ; k >= k1 ; k--) + { + p = Lp [k] ; + pend = Lp [k+1] ; + /* w = W [k] */ + wx = Wx [k] ; + wz = Wz [k] ; + lkk = Lx [p] ; + lkkz = Lz ? (-Lz [p]) : 0 ; + for (p++ ; p < pend ; p++) + { + i = Li [p] ; + /* w -= W [i] * conj (Lx [p]) ; */ + z = Lz ? Lz [p] : 0 ; + MULT_SUB_CONJ (wx, wz, + Wx [i], Wz [i], Lx [p], z) ; + } + /* W [k] = w / conj(lkk) ; */ + DIV (Wx [k], Wz [k], wx, wz, lkk, lkkz) ; + } + } + } + + /* -------------------------------------------------- */ + /* scale, permute, and tranpose: X = (P*(R\W))' */ + /* -------------------------------------------------- */ + + if (Rs == NULL) + { + /* no scaling */ + for (k = 0 ; k < n ; k++) + { + i = P ? (P [k] - 1) : k ; + Xx [i*nrhs] = Wx [k] ; + Xz [i*nrhs] = Wz ? (-Wz [k]) : 0 ; + } + } + else + { + /* with scaling */ + for (k = 0 ; k < n ; k++) + { + i = P ? (P [k] - 1) : k ; + rs = Rs [k] ; + Xx [i*nrhs] = Wx [k] / rs ; + Xz [i*nrhs] = Wz ? (-Wz [k] / rs) : 0 ; + } + } + + /* -------------------------------------------------- */ + /* go to the next row of B and X */ + /* -------------------------------------------------- */ + + Xx++ ; + Xz++ ; + Bx++ ; + if (Bz) Bz++ ; + } + + } + else + { + + for (chunk = 0 ; chunk < nrhs ; chunk++) + { + + /* -------------------------------------------------- */ + /* scale and permute the right hand side, W = P*(R\B) */ + /* -------------------------------------------------- */ + + if (Rs == NULL) + { + /* no scaling */ + for (k = 0 ; k < n ; k++) + { + i = P ? (P [k] - 1) : k ; + Wx [k] = Bx [i] ; + Wz [k] = Bz ? Bz [i] : 0 ; + } + } + else + { + /* with scaling */ + for (k = 0 ; k < n ; k++) + { + i = P ? (P [k] - 1) : k ; + rs = Rs [k] ; + Wx [k] = Bx [i] / rs ; + Wz [k] = Bz ? (Bz [i] / rs) : 0 ; + } + } + + /* -------------------------------------------------- */ + /* solve W = (L*U + Off)\W */ + /* -------------------------------------------------- */ + + for (block = nblocks-1 ; block >= 0 ; block--) + { + + /* ---------------------------------------------- */ + /* block of size nk, rows/columns k1 to k2-1 */ + /* ---------------------------------------------- */ + + k1 = R [block] - 1 ; /* R is 1-based */ + k2 = R [block+1] - 1 ; + nk = k2 - k1 ; + + /* solve the block system */ + if (nk == 1) + { + + /* W [k1] /= L(k1,k1) ; */ + p = Lp [k1] ; + s = Lx [p] ; + sz = Lz ? Lz [p] : 0 ; + DIV (wx, wz, Wx [k1], Wz [k1], s, sz) ; + Wx [k1] = wx ; + Wz [k1] = wz ; + + /* W [k1] /= U(k1,k1) ; */ + p = Up [k1] ; + s = Ux [p] ; + sz = Uz ? Uz [p] : 0 ; + DIV (wx, wz, Wx [k1], Wz [k1], s, sz) ; + Wx [k1] = wx ; + Wz [k1] = wz ; + + } + else + { + + /* ------------------------------------------ */ + /* W = L\W and then W=U\W */ + /* ------------------------------------------ */ + + /* W = L\W */ + for (k = k1 ; k < k2 ; k++) + { + p = Lp [k] ; + pend = Lp [k+1] ; + lkk = Lx [p] ; + lkkz = Lz ? Lz [p] : 0 ; + /* w = W [k] / lkk ; */ + DIV (wx, wz, Wx [k], Wz [k], lkk, lkkz) ; + Wx [k] = wx ; + Wz [k] = wz ; + for (p++ ; p < pend ; p++) + { + i = Li [p] ; + /* W [i] -= Lx [p] * w ; */ + z = Lz ? Lz [p] : 0 ; + MULT_SUB (Wx [i], Wz [i], Lx [p], z, + wx, wz) ; + } + } + + /* W = U\W */ + for (k = k2-1 ; k >= k1 ; k--) + { + pend = Up [k+1] - 1 ; + ukk = Ux [pend] ; + ukkz = Uz ? Uz [pend] : 0 ; + /* w = W [k] / ukk ; */ + DIV (wx, wz, Wx [k], Wz [k], ukk, ukkz) ; + Wx [k] = wx ; + Wz [k] = wz ; + for (p = Up [k] ; p < pend ; p++) + { + i = Ui [p] ; + /* W [i] -= U [p] * w ; */ + z = Uz ? Uz [p] : 0 ; + MULT_SUB (Wx [i], Wz [i], Ux [p], z, + wx, wz) ; + } + } + } + + /* ---------------------------------------------- */ + /* block back-substitution for off-diagonal-block */ + /* ---------------------------------------------- */ + + if (block > 0 && Offp != NULL) + { + for (k = k1 ; k < k2 ; k++) + { + pend = Offp [k+1] ; + wx = Wx [k] ; + wz = Wz [k] ; + for (p = Offp [k] ; p < pend ; p++) + { + i = Offi [p] ; + /* W [Offi [p]] -= Offx [p] * w ; */ + z = Offz ? Offz [p] : 0 ; + MULT_SUB (Wx [i], Wz [i], Offx [p], z, + wx, wz) ; + } + } + } + } + + /* -------------------------------------------------- */ + /* permute the result, X = Q*W */ + /* -------------------------------------------------- */ + + for (k = 0 ; k < n ; k++) + { + i = Q ? (Q [k] - 1) : k ; + Xx [i] = Wx [k] ; + Xz [i] = Wz [k] ; + } + + /* -------------------------------------------------- */ + /* go to the next column of B and X */ + /* -------------------------------------------------- */ + + Xx += n ; + Xz += n ; + Bx += n ; + if (Bz) Bz += n ; + } + } + + /* free workspace */ + mxFree (Wx) ; + mxFree (Wz) ; + + } + else + { + + /* ========================================================== */ + /* === real case ============================================ */ + /* ========================================================== */ + + /* create X */ + if (do_transpose) + { + pargout [0] = mxCreateDoubleMatrix (nrhs, n, mxREAL) ; + } + else + { + pargout [0] = mxCreateDoubleMatrix (n, nrhs, mxREAL) ; + } + + Xx = mxGetPr (pargout [0]) ; + Bx = mxGetPr (B_matlab) ; + + if (do_transpose) + { + + /* ------------------------------------------------------ */ + /* solve in chunks of one row at a time */ + /* ------------------------------------------------------ */ + + /* get workspace */ + Wx = mxMalloc (n * sizeof (double)) ; + + for (chunk = 0 ; chunk < nrhs ; chunk++) + { + + /* -------------------------------------------------- */ + /* transpose and permute right hand side, W = Q'*B' */ + /* -------------------------------------------------- */ + + for (k = 0 ; k < n ; k++) + { + i = Q ? (Q [k] - 1) : k ; + Wx [k] = Bx [i*nrhs] ; + } + + /* -------------------------------------------------- */ + /* solve W = (L*U + Off)'\W */ + /* -------------------------------------------------- */ + + for (block = 0 ; block < nblocks ; block++) + { + + /* ---------------------------------------------- */ + /* block of size nk, rows/columns k1 to k2-1 */ + /* ---------------------------------------------- */ + + k1 = R [block] - 1 ; /* R is 1-based */ + k2 = R [block+1] - 1 ; + nk = k2 - k1 ; + + /* ---------------------------------------------- */ + /* block back-substitution for off-diagonal-block */ + /* ---------------------------------------------- */ + + if (block > 0 && Offp != NULL) + { + for (k = k1 ; k < k2 ; k++) + { + pend = Offp [k+1] ; + for (p = Offp [k] ; p < pend ; p++) + { + Wx [k] -= Wx [Offi [p]] * Offx [p] ; + } + } + } + + /* solve the block system */ + if (nk == 1) + { + Wx [k1] /= Lx [Lp [k1]] ; + Wx [k1] /= Ux [Up [k1]] ; + } + else + { + + /* ------------------------------------------ */ + /* W = U'\W and then W=L'\W */ + /* ------------------------------------------ */ + + /* W = U'\W */ + for (k = k1 ; k < k2 ; k++) + { + pend = Up [k+1] - 1 ; + for (p = Up [k] ; p < pend ; p++) + { + Wx [k] -= Wx [Ui [p]] * Ux [p] ; + } + Wx [k] /= Ux [pend] ; + } + + /* W = L'\W */ + for (k = k2-1 ; k >= k1 ; k--) + { + p = Lp [k] ; + pend = Lp [k+1] ; + lkk = Lx [p] ; + for (p++ ; p < pend ; p++) + { + Wx [k] -= Wx [Li [p]] * Lx [p] ; + } + Wx [k] /= lkk ; + } + } + } + + /* -------------------------------------------------- */ + /* scale, permute, and tranpose: X = (P*(R\W))' */ + /* -------------------------------------------------- */ + + if (Rs == NULL) + { + /* no scaling */ + for (k = 0 ; k < n ; k++) + { + i = P ? (P [k] - 1) : k ; + Xx [i*nrhs] = Wx [k] ; + } + } + else + { + /* with scaling */ + for (k = 0 ; k < n ; k++) + { + i = P ? (P [k] - 1) : k ; + rs = Rs [k] ; + Xx [i*nrhs] = Wx [k] / rs ; + } + } + + /* -------------------------------------------------- */ + /* go to the next row of B and X */ + /* -------------------------------------------------- */ + + Xx++ ; + Bx++ ; + } + + } + else + { + + /* ------------------------------------------------------ */ + /* solve in chunks of 4 columns at a time */ + /* ------------------------------------------------------ */ + + /* get workspace */ + Wx = mxMalloc (n * MAX (4, nrhs) * sizeof (double)) ; + + for (chunk = 0 ; chunk < nrhs ; chunk += 4) + { + /* -------------------------------------------------- */ + /* get the size of the current chunk */ + /* -------------------------------------------------- */ + + nr = MIN (nrhs - chunk, 4) ; + + /* -------------------------------------------------- */ + /* scale and permute the right hand side, W = P*(R\B) */ + /* -------------------------------------------------- */ + + if (Rs == NULL) + { + + /* no scaling */ + switch (nr) + { + + case 1: + + for (k = 0 ; k < n ; k++) + { + i = P ? (P [k] - 1) : k ; + Wx [k] = Bx [i] ; + } + break ; + + case 2: + + for (k = 0 ; k < n ; k++) + { + i = P ? (P [k] - 1) : k ; + Wx [2*k ] = Bx [i ] ; + Wx [2*k + 1] = Bx [i + n ] ; + } + break ; + + case 3: + + for (k = 0 ; k < n ; k++) + { + i = P ? (P [k] - 1) : k ; + Wx [3*k ] = Bx [i ] ; + Wx [3*k + 1] = Bx [i + n ] ; + Wx [3*k + 2] = Bx [i + n*2] ; + } + break ; + + case 4: + + for (k = 0 ; k < n ; k++) + { + i = P ? (P [k] - 1) : k ; + Wx [4*k ] = Bx [i ] ; + Wx [4*k + 1] = Bx [i + n ] ; + Wx [4*k + 2] = Bx [i + n*2] ; + Wx [4*k + 3] = Bx [i + n*3] ; + } + break ; + } + + } + else + { + + switch (nr) + { + + case 1: + + for (k = 0 ; k < n ; k++) + { + i = P ? (P [k] - 1) : k ; + rs = Rs [k] ; + Wx [k] = Bx [i] / rs ; + } + break ; + + case 2: + + for (k = 0 ; k < n ; k++) + { + i = P ? (P [k] - 1) : k ; + rs = Rs [k] ; + Wx [2*k ] = Bx [i ] / rs ; + Wx [2*k + 1] = Bx [i + n ] / rs ; + } + break ; + + case 3: + + for (k = 0 ; k < n ; k++) + { + i = P ? (P [k] - 1) : k ; + rs = Rs [k] ; + Wx [3*k ] = Bx [i ] / rs ; + Wx [3*k + 1] = Bx [i + n ] / rs ; + Wx [3*k + 2] = Bx [i + n*2] / rs ; + } + break ; + + case 4: + + for (k = 0 ; k < n ; k++) + { + i = P ? (P [k] - 1) : k ; + rs = Rs [k] ; + Wx [4*k ] = Bx [i ] / rs ; + Wx [4*k + 1] = Bx [i + n ] / rs ; + Wx [4*k + 2] = Bx [i + n*2] / rs ; + Wx [4*k + 3] = Bx [i + n*3] / rs ; + } + break ; + } + } + + /* -------------------------------------------------- */ + /* solve W = (L*U + Off)\W */ + /* -------------------------------------------------- */ + + for (block = nblocks-1 ; block >= 0 ; block--) + { + + /* ---------------------------------------------- */ + /* block of size nk is rows/columns k1 to k2-1 */ + /* ---------------------------------------------- */ + + k1 = R [block] - 1 ; /* R is 1-based */ + k2 = R [block+1] - 1 ; + nk = k2 - k1 ; + + /* solve the block system */ + if (nk == 1) + { + + /* this is not done if L comes from KLU, since + in that case, L is unit lower triangular */ + s = Lx [Lp [k1]] ; + if (s != 1.0) switch (nr) + { + case 1: + Wx [k1] /= s ; + break ; + case 2: + Wx [2*k1] /= s ; + Wx [2*k1 + 1] /= s ; + break ; + case 3: + Wx [3*k1] /= s ; + Wx [3*k1 + 1] /= s ; + Wx [3*k1 + 2] /= s ; + break ; + case 4: + Wx [4*k1] /= s ; + Wx [4*k1 + 1] /= s ; + Wx [4*k1 + 2] /= s ; + Wx [4*k1 + 3] /= s ; + break ; + } + + s = Ux [Up [k1]] ; + if (s != 1.0) switch (nr) + { + case 1: + Wx [k1] /= s ; + break ; + case 2: + Wx [2*k1] /= s ; + Wx [2*k1 + 1] /= s ; + break ; + case 3: + Wx [3*k1] /= s ; + Wx [3*k1 + 1] /= s ; + Wx [3*k1 + 2] /= s ; + break ; + case 4: + Wx [4*k1] /= s ; + Wx [4*k1 + 1] /= s ; + Wx [4*k1 + 2] /= s ; + Wx [4*k1 + 3] /= s ; + break ; + } + + } + else + { + + /* ------------------------------------------ */ + /* W = L\W and then W=U\W */ + /* ------------------------------------------ */ + + switch (nr) + { + + case 1: + /* W = L\W */ + for (k = k1 ; k < k2 ; k++) + { + p = Lp [k] ; + pend = Lp [k+1] ; + lkk = Lx [p++] ; + x [0] = Wx [k] / lkk ; + Wx [k] = x [0] ; + for ( ; p < pend ; p++) + { + Wx [Li [p]] -= Lx [p] * x [0] ; + } + } + + /* W = U\W */ + for (k = k2-1 ; k >= k1 ; k--) + { + pend = Up [k+1] - 1 ; + ukk = Ux [pend] ; + x [0] = Wx [k] / ukk ; + Wx [k] = x [0] ; + for (p = Up [k] ; p < pend ; p++) + { + Wx [Ui [p]] -= Ux [p] * x [0] ; + } + } + break ; + + case 2: + + /* W = L\W */ + for (k = k1 ; k < k2 ; k++) + { + p = Lp [k] ; + pend = Lp [k+1] ; + lkk = Lx [p++] ; + x [0] = Wx [2*k ] / lkk ; + x [1] = Wx [2*k + 1] / lkk ; + Wx [2*k ] = x [0] ; + Wx [2*k + 1] = x [1] ; + for ( ; p < pend ; p++) + { + i = Li [p] ; + lik = Lx [p] ; + Wx [2*i ] -= lik * x [0] ; + Wx [2*i + 1] -= lik * x [1] ; + } + } + + /* W = U\W */ + for (k = k2-1 ; k >= k1 ; k--) + { + pend = Up [k+1] - 1 ; + ukk = Ux [pend] ; + x [0] = Wx [2*k ] / ukk ; + x [1] = Wx [2*k + 1] / ukk ; + Wx [2*k ] = x [0] ; + Wx [2*k + 1] = x [1] ; + for (p = Up [k] ; p < pend ; p++) + { + i = Ui [p] ; + uik = Ux [p] ; + Wx [2*i ] -= uik * x [0] ; + Wx [2*i + 1] -= uik * x [1] ; + } + } + break ; + + case 3: + + /* W = L\W */ + for (k = k1 ; k < k2 ; k++) + { + p = Lp [k] ; + pend = Lp [k+1] ; + lkk = Lx [p++] ; + x [0] = Wx [3*k ] / lkk ; + x [1] = Wx [3*k + 1] / lkk ; + x [2] = Wx [3*k + 2] / lkk ; + Wx [3*k ] = x [0] ; + Wx [3*k + 1] = x [1] ; + Wx [3*k + 2] = x [2] ; + for ( ; p < pend ; p++) + { + i = Li [p] ; + lik = Lx [p] ; + Wx [3*i ] -= lik * x [0] ; + Wx [3*i + 1] -= lik * x [1] ; + Wx [3*i + 2] -= lik * x [2] ; + } + } + + /* W = U\W */ + for (k = k2-1 ; k >= k1 ; k--) + { + pend = Up [k+1] - 1 ; + ukk = Ux [pend] ; + x [0] = Wx [3*k ] / ukk ; + x [1] = Wx [3*k + 1] / ukk ; + x [2] = Wx [3*k + 2] / ukk ; + Wx [3*k ] = x [0] ; + Wx [3*k + 1] = x [1] ; + Wx [3*k + 2] = x [2] ; + for (p = Up [k] ; p < pend ; p++) + { + i = Ui [p] ; + uik = Ux [p] ; + Wx [3*i ] -= uik * x [0] ; + Wx [3*i + 1] -= uik * x [1] ; + Wx [3*i + 2] -= uik * x [2] ; + } + } + break ; + + case 4: + + /* W = L\W */ + for (k = k1 ; k < k2 ; k++) + { + p = Lp [k] ; + pend = Lp [k+1] ; + lkk = Lx [p++] ; + x [0] = Wx [4*k ] / lkk ; + x [1] = Wx [4*k + 1] / lkk ; + x [2] = Wx [4*k + 2] / lkk ; + x [3] = Wx [4*k + 3] / lkk ; + Wx [4*k ] = x [0] ; + Wx [4*k + 1] = x [1] ; + Wx [4*k + 2] = x [2] ; + Wx [4*k + 3] = x [3] ; + for ( ; p < pend ; p++) + { + i = Li [p] ; + lik = Lx [p] ; + Wx [4*i ] -= lik * x [0] ; + Wx [4*i + 1] -= lik * x [1] ; + Wx [4*i + 2] -= lik * x [2] ; + Wx [4*i + 3] -= lik * x [3] ; + } + } + + /* Wx = U\Wx */ + for (k = k2-1 ; k >= k1 ; k--) + { + pend = Up [k+1] - 1 ; + ukk = Ux [pend] ; + x [0] = Wx [4*k ] / ukk ; + x [1] = Wx [4*k + 1] / ukk ; + x [2] = Wx [4*k + 2] / ukk ; + x [3] = Wx [4*k + 3] / ukk ; + Wx [4*k ] = x [0] ; + Wx [4*k + 1] = x [1] ; + Wx [4*k + 2] = x [2] ; + Wx [4*k + 3] = x [3] ; + for (p = Up [k] ; p < pend ; p++) + { + i = Ui [p] ; + uik = Ux [p] ; + Wx [4*i ] -= uik * x [0] ; + Wx [4*i + 1] -= uik * x [1] ; + Wx [4*i + 2] -= uik * x [2] ; + Wx [4*i + 3] -= uik * x [3] ; + } + } + break ; + } + } + + /* ---------------------------------------------- */ + /* block back-substitution for off-diagonal-block */ + /* ---------------------------------------------- */ + + if (block > 0 && Offp != NULL) + { + switch (nr) + { + + case 1: + + for (k = k1 ; k < k2 ; k++) + { + pend = Offp [k+1] ; + x [0] = Wx [k] ; + for (p = Offp [k] ; p < pend ; p++) + { + Wx [Offi [p]] -= Offx[p] * x[0]; + } + } + break ; + + case 2: + + for (k = k1 ; k < k2 ; k++) + { + pend = Offp [k+1] ; + x [0] = Wx [2*k ] ; + x [1] = Wx [2*k + 1] ; + for (p = Offp [k] ; p < pend ; p++) + { + i = Offi [p] ; + offik = Offx [p] ; + Wx [2*i ] -= offik * x [0] ; + Wx [2*i + 1] -= offik * x [1] ; + } + } + break ; + + case 3: + + for (k = k1 ; k < k2 ; k++) + { + pend = Offp [k+1] ; + x [0] = Wx [3*k ] ; + x [1] = Wx [3*k + 1] ; + x [2] = Wx [3*k + 2] ; + for (p = Offp [k] ; p < pend ; p++) + { + i = Offi [p] ; + offik = Offx [p] ; + Wx [3*i ] -= offik * x [0] ; + Wx [3*i + 1] -= offik * x [1] ; + Wx [3*i + 2] -= offik * x [2] ; + } + } + break ; + + case 4: + + for (k = k1 ; k < k2 ; k++) + { + pend = Offp [k+1] ; + x [0] = Wx [4*k ] ; + x [1] = Wx [4*k + 1] ; + x [2] = Wx [4*k + 2] ; + x [3] = Wx [4*k + 3] ; + for (p = Offp [k] ; p < pend ; p++) + { + i = Offi [p] ; + offik = Offx [p] ; + Wx [4*i ] -= offik * x [0] ; + Wx [4*i + 1] -= offik * x [1] ; + Wx [4*i + 2] -= offik * x [2] ; + Wx [4*i + 3] -= offik * x [3] ; + } + } + break ; + } + } + } + + /* -------------------------------------------------- */ + /* permute the result, X = Q*W */ + /* -------------------------------------------------- */ + + switch (nr) + { + + case 1: + + for (k = 0 ; k < n ; k++) + { + i = Q ? (Q [k] - 1) : k ; + Xx [i] = Wx [k] ; + } + break ; + + case 2: + + for (k = 0 ; k < n ; k++) + { + i = Q ? (Q [k] - 1) : k ; + Xx [i ] = Wx [2*k ] ; + Xx [i + n ] = Wx [2*k + 1] ; + } + break ; + + case 3: + + for (k = 0 ; k < n ; k++) + { + i = Q ? (Q [k] - 1) : k ; + Xx [i ] = Wx [3*k ] ; + Xx [i + n ] = Wx [3*k + 1] ; + Xx [i + n*2] = Wx [3*k + 2] ; + } + break ; + + case 4: + + for (k = 0 ; k < n ; k++) + { + i = Q ? (Q [k] - 1) : k ; + Xx [i ] = Wx [4*k ] ; + Xx [i + n ] = Wx [4*k + 1] ; + Xx [i + n*2] = Wx [4*k + 2] ; + Xx [i + n*3] = Wx [4*k + 3] ; + } + break ; + } + + /* -------------------------------------------------- */ + /* go to the next chunk of B and X */ + /* -------------------------------------------------- */ + + Xx += n*4 ; + Bx += n*4 ; + } + } + + /* free workspace */ + mxFree (Wx) ; + } + + } + + } + else + { + + /* ------------------------------------------------------------------ */ + /* LU = klu (A) usage; extract factorization */ + /* ------------------------------------------------------------------ */ + + /* sort the row indices in each column of L and U */ + if (A_complex) + { + klu_zl_sort (Symbolic, Numeric, &Common) ; + } + else + { + klu_l_sort (Symbolic, Numeric, &Common) ; + } + + /* L */ + L_matlab = mxCreateSparse (n, n, Numeric->lnz, + A_complex ? mxCOMPLEX: mxREAL) ; + Lp = (Long *) mxGetJc (L_matlab) ; + Li = (Long *) mxGetIr (L_matlab) ; + Lx = mxGetPr (L_matlab) ; + Lz = mxGetPi (L_matlab) ; + + /* U */ + U_matlab = mxCreateSparse (n, n, Numeric->unz, + A_complex ? mxCOMPLEX: mxREAL) ; + Up = (Long *) mxGetJc (U_matlab) ; + Ui = (Long *) mxGetIr (U_matlab) ; + Ux = mxGetPr (U_matlab) ; + Uz = mxGetPi (U_matlab) ; + + /* p */ + p_matlab = mxCreateNumericMatrix (1, n, mx_int, mxREAL) ; + P = (Long *) mxGetData (p_matlab) ; + + /* q */ + q_matlab = mxCreateNumericMatrix (1, n, mx_int, mxREAL) ; + Q = (Long *) mxGetData (q_matlab) ; + + /* R, as a sparse diagonal matrix */ + R_matlab = mxCreateSparse (n, n, n+1, mxREAL) ; + Rp = (Long *) mxGetJc (R_matlab) ; + Ri = (Long *) mxGetIr (R_matlab) ; + Rs = mxGetPr (R_matlab) ; + for (k = 0 ; k <= n ; k++) + { + Rp [k] = k ; + Ri [k] = k ; + } + + /* F, off diagonal blocks */ + F_matlab = mxCreateSparse (n, n, Numeric->nzoff, + A_complex ? mxCOMPLEX: mxREAL) ; + Offp = (Long *) mxGetJc (F_matlab) ; + Offi = (Long *) mxGetIr (F_matlab) ; + Offx = mxGetPr (F_matlab) ; + Offz = mxGetPi (F_matlab) ; + + /* r, block boundaries */ + nblocks = Symbolic->nblocks ; + r_matlab = mxCreateNumericMatrix (1, nblocks+1, mx_int, mxREAL) ; + R = (Long *) mxGetData (r_matlab) ; + + /* extract the LU factorization from KLU Numeric and Symbolic objects */ + if (A_complex) + { + klu_zl_extract (Numeric, Symbolic, Lp, Li, Lx, Lz, Up, Ui, Ux, Uz, + Offp, Offi, Offx, Offz, P, Q, Rs, R, &Common) ; + } + else + { + klu_l_extract (Numeric, Symbolic, Lp, Li, Lx, Up, Ui, Ux, + Offp, Offi, Offx, P, Q, Rs, R, &Common) ; + } + + /* fix p and q for 1-based indexing */ + for (k = 0 ; k < n ; k++) + { + P [k]++ ; + Q [k]++ ; + } + + /* fix r for 1-based indexing */ + for (k = 0 ; k <= nblocks ; k++) + { + R [k]++ ; + } + + /* create output LU struct */ + pargout [0] = mxCreateStructMatrix (1, 1, 7, LUnames) ; + mxSetFieldByNumber (pargout [0], 0, 0, L_matlab) ; + mxSetFieldByNumber (pargout [0], 0, 1, U_matlab) ; + mxSetFieldByNumber (pargout [0], 0, 2, p_matlab) ; + mxSetFieldByNumber (pargout [0], 0, 3, q_matlab) ; + mxSetFieldByNumber (pargout [0], 0, 4, R_matlab) ; + mxSetFieldByNumber (pargout [0], 0, 5, F_matlab) ; + mxSetFieldByNumber (pargout [0], 0, 6, r_matlab) ; + + /* ------------------------------------------------------------------ */ + /* free Symbolic and Numeric objects */ + /* ------------------------------------------------------------------ */ + + klu_l_free_symbolic (&Symbolic, &Common) ; + klu_l_free_numeric (&Numeric, &Common) ; + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu.c new file mode 100644 index 0000000..6042fcd --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu.c @@ -0,0 +1,773 @@ +/* ========================================================================== */ +/* === klu ================================================================== */ +/* ========================================================================== */ + +/* KLU: factorizes P*A into L*U, using the Gilbert-Peierls algorithm [1], with + * optional symmetric pruning by Eisenstat and Liu [2]. The code is by Tim + * Davis. This algorithm is what appears as the default sparse LU routine in + * MATLAB version 6.0, and still appears in MATLAB 6.5 as [L,U,P] = lu (A). + * Note that no column ordering is provided (see COLAMD or AMD for suitable + * orderings). SuperLU is based on this algorithm, except that it adds the + * use of dense matrix operations on "supernodes" (adjacent columns with + * identical). This code doesn't use supernodes, thus its name ("Kent" LU, + * as in "Clark Kent", in contrast with Super-LU...). This algorithm is slower + * than SuperLU and UMFPACK for large matrices with lots of nonzeros in their + * factors (such as for most finite-element problems). However, for matrices + * with very sparse LU factors, this algorithm is typically faster than both + * SuperLU and UMFPACK, since in this case there is little chance to exploit + * dense matrix kernels (the BLAS). + * + * Only one block of A is factorized, in the BTF form. The input n is the + * size of the block; k1 is the first row and column in the block. + * + * NOTE: no error checking is done on the inputs. This version is not meant to + * be called directly by the user. Use klu_factor instead. + * + * No fill-reducing ordering is provided. The ordering quality of + * klu_kernel_factor is the responsibility of the caller. The input A must + * pre-permuted to reduce fill-in, or fill-reducing input permutation Q must + * be provided. + * + * The input matrix A must be in compressed-column form, with either sorted + * or unsorted row indices. Row indices for column j of A is in + * Ai [Ap [j] ... Ap [j+1]-1] and the same range of indices in Ax holds the + * numerical values. No duplicate entries are allowed. + * + * Copyright 2004-2009, Tim Davis. All rights reserved. See the README + * file for details on permitted use. Note that no code from The MathWorks, + * Inc, or from SuperLU, or from any other source appears here. The code is + * written from scratch, from the algorithmic description in Gilbert & Peierls' + * and Eisenstat & Liu's journal papers [1,2]. + * + * If an input permutation Q is provided, the factorization L*U = A (P,Q) + * is computed, where P is determined by partial pivoting, and Q is the input + * ordering. If the pivot tolerance is less than 1, the "diagonal" entry that + * KLU attempts to choose is the diagonal of A (Q,Q). In other words, the + * input permutation is applied symmetrically to the input matrix. The output + * permutation P includes both the partial pivoting ordering and the input + * permutation. If Q is NULL, then it is assumed to be the identity + * permutation. Q is not modified. + * + * [1] Gilbert, J. R. and Peierls, T., "Sparse Partial Pivoting in Time + * Proportional to Arithmetic Operations," SIAM J. Sci. Stat. Comp., + * vol 9, pp. 862-874, 1988. + * [2] Eisenstat, S. C. and Liu, J. W. H., "Exploiting Structural Symmetry in + * Unsymmetric Sparse Symbolic Factorization," SIAM J. Matrix Analysis & + * Applic., vol 13, pp. 202-211, 1992. + */ + +/* ========================================================================== */ + +#include "klu_internal.h" + +size_t KLU_kernel_factor /* 0 if failure, size of LU if OK */ +( + /* inputs, not modified */ + Int n, /* A is n-by-n. n must be > 0. */ + Int Ap [ ], /* size n+1, column pointers for A */ + Int Ai [ ], /* size nz = Ap [n], row indices for A */ + Entry Ax [ ], /* size nz, values of A */ + Int Q [ ], /* size n, optional column permutation */ + double Lsize, /* estimate of number of nonzeros in L */ + + /* outputs, not defined on input */ + Unit **p_LU, /* row indices and values of L and U */ + Entry Udiag [ ], /* size n, diagonal of U */ + Int Llen [ ], /* size n, column length of L */ + Int Ulen [ ], /* size n, column length of U */ + Int Lip [ ], /* size n, column pointers for L */ + Int Uip [ ], /* size n, column pointers for U */ + Int P [ ], /* row permutation, size n */ + Int *lnz, /* size of L */ + Int *unz, /* size of U */ + + /* workspace, undefined on input */ + Entry *X, /* size n double's, zero on output */ + Int *Work, /* size 5n Int's */ + + /* inputs, not modified on output */ + Int k1, /* the block of A is from k1 to k2-1 */ + Int PSinv [ ], /* inverse of P from symbolic factorization */ + double Rs [ ], /* scale factors for A */ + + /* inputs, modified on output */ + Int Offp [ ], /* off-diagonal matrix (modified by this routine) */ + Int Offi [ ], + Entry Offx [ ], + /* --------------- */ + KLU_common *Common +) +{ + double maxlnz, dunits ; + Unit *LU ; + Int *Pinv, *Lpend, *Stack, *Flag, *Ap_pos, *W ; + Int lsize, usize, anz, ok ; + size_t lusize ; + ASSERT (Common != NULL) ; + + /* ---------------------------------------------------------------------- */ + /* get control parameters, or use defaults */ + /* ---------------------------------------------------------------------- */ + + n = MAX (1, n) ; + anz = Ap [n+k1] - Ap [k1] ; + + if (Lsize <= 0) + { + Lsize = -Lsize ; + Lsize = MAX (Lsize, 1.0) ; + lsize = Lsize * anz + n ; + } + else + { + lsize = Lsize ; + } + + usize = lsize ; + + lsize = MAX (n+1, lsize) ; + usize = MAX (n+1, usize) ; + + maxlnz = (((double) n) * ((double) n) + ((double) n)) / 2. ; + maxlnz = MIN (maxlnz, ((double) Int_MAX)) ; + lsize = MIN (maxlnz, lsize) ; + usize = MIN (maxlnz, usize) ; + + PRINTF (("Welcome to klu: n %d anz %d k1 %d lsize %d usize %d maxlnz %g\n", + n, anz, k1, lsize, usize, maxlnz)) ; + + /* ---------------------------------------------------------------------- */ + /* allocate workspace and outputs */ + /* ---------------------------------------------------------------------- */ + + /* return arguments are not yet assigned */ + *p_LU = (Unit *) NULL ; + + /* these computations are safe from size_t overflow */ + W = Work ; + Pinv = (Int *) W ; W += n ; + Stack = (Int *) W ; W += n ; + Flag = (Int *) W ; W += n ; + Lpend = (Int *) W ; W += n ; + Ap_pos = (Int *) W ; W += n ; + + dunits = DUNITS (Int, lsize) + DUNITS (Entry, lsize) + + DUNITS (Int, usize) + DUNITS (Entry, usize) ; + lusize = (size_t) dunits ; + ok = !INT_OVERFLOW (dunits) ; + LU = ok ? KLU_malloc (lusize, sizeof (Unit), Common) : NULL ; + if (LU == NULL) + { + /* out of memory, or problem too large */ + Common->status = KLU_OUT_OF_MEMORY ; + lusize = 0 ; + return (lusize) ; + } + + /* ---------------------------------------------------------------------- */ + /* factorize */ + /* ---------------------------------------------------------------------- */ + + /* with pruning, and non-recursive depth-first-search */ + lusize = KLU_kernel (n, Ap, Ai, Ax, Q, lusize, + Pinv, P, &LU, Udiag, Llen, Ulen, Lip, Uip, lnz, unz, + X, Stack, Flag, Ap_pos, Lpend, + k1, PSinv, Rs, Offp, Offi, Offx, Common) ; + + /* ---------------------------------------------------------------------- */ + /* return LU factors, or return nothing if an error occurred */ + /* ---------------------------------------------------------------------- */ + + if (Common->status < KLU_OK) + { + LU = KLU_free (LU, lusize, sizeof (Unit), Common) ; + lusize = 0 ; + } + *p_LU = LU ; + PRINTF ((" in klu noffdiag %d\n", Common->noffdiag)) ; + return (lusize) ; +} + + +/* ========================================================================== */ +/* === KLU_lsolve =========================================================== */ +/* ========================================================================== */ + +/* Solve Lx=b. Assumes L is unit lower triangular and where the unit diagonal + * entry is NOT stored. Overwrites B with the solution X. B is n-by-nrhs + * and is stored in ROW form with row dimension nrhs. nrhs must be in the + * range 1 to 4. */ + +void KLU_lsolve +( + /* inputs, not modified: */ + Int n, + Int Lip [ ], + Int Llen [ ], + Unit LU [ ], + Int nrhs, + /* right-hand-side on input, solution to Lx=b on output */ + Entry X [ ] +) +{ + Entry x [4], lik ; + Int *Li ; + Entry *Lx ; + Int k, p, len, i ; + + switch (nrhs) + { + + case 1: + for (k = 0 ; k < n ; k++) + { + x [0] = X [k] ; + GET_POINTER (LU, Lip, Llen, Li, Lx, k, len) ; + /* unit diagonal of L is not stored*/ + for (p = 0 ; p < len ; p++) + { + /* X [Li [p]] -= Lx [p] * x [0] ; */ + MULT_SUB (X [Li [p]], Lx [p], x [0]) ; + } + } + break ; + + case 2: + + for (k = 0 ; k < n ; k++) + { + x [0] = X [2*k ] ; + x [1] = X [2*k + 1] ; + GET_POINTER (LU, Lip, Llen, Li, Lx, k, len) ; + for (p = 0 ; p < len ; p++) + { + i = Li [p] ; + lik = Lx [p] ; + MULT_SUB (X [2*i], lik, x [0]) ; + MULT_SUB (X [2*i + 1], lik, x [1]) ; + } + } + break ; + + case 3: + + for (k = 0 ; k < n ; k++) + { + x [0] = X [3*k ] ; + x [1] = X [3*k + 1] ; + x [2] = X [3*k + 2] ; + GET_POINTER (LU, Lip, Llen, Li, Lx, k, len) ; + for (p = 0 ; p < len ; p++) + { + i = Li [p] ; + lik = Lx [p] ; + MULT_SUB (X [3*i], lik, x [0]) ; + MULT_SUB (X [3*i + 1], lik, x [1]) ; + MULT_SUB (X [3*i + 2], lik, x [2]) ; + } + } + break ; + + case 4: + + for (k = 0 ; k < n ; k++) + { + x [0] = X [4*k ] ; + x [1] = X [4*k + 1] ; + x [2] = X [4*k + 2] ; + x [3] = X [4*k + 3] ; + GET_POINTER (LU, Lip, Llen, Li, Lx, k, len) ; + for (p = 0 ; p < len ; p++) + { + i = Li [p] ; + lik = Lx [p] ; + MULT_SUB (X [4*i], lik, x [0]) ; + MULT_SUB (X [4*i + 1], lik, x [1]) ; + MULT_SUB (X [4*i + 2], lik, x [2]) ; + MULT_SUB (X [4*i + 3], lik, x [3]) ; + } + } + break ; + + } +} + +/* ========================================================================== */ +/* === KLU_usolve =========================================================== */ +/* ========================================================================== */ + +/* Solve Ux=b. Assumes U is non-unit upper triangular and where the diagonal + * entry is NOT stored. Overwrites B with the solution X. B is n-by-nrhs + * and is stored in ROW form with row dimension nrhs. nrhs must be in the + * range 1 to 4. */ + +void KLU_usolve +( + /* inputs, not modified: */ + Int n, + Int Uip [ ], + Int Ulen [ ], + Unit LU [ ], + Entry Udiag [ ], + Int nrhs, + /* right-hand-side on input, solution to Ux=b on output */ + Entry X [ ] +) +{ + Entry x [4], uik, ukk ; + Int *Ui ; + Entry *Ux ; + Int k, p, len, i ; + + switch (nrhs) + { + + case 1: + + for (k = n-1 ; k >= 0 ; k--) + { + GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, len) ; + /* x [0] = X [k] / Udiag [k] ; */ + DIV (x [0], X [k], Udiag [k]) ; + X [k] = x [0] ; + for (p = 0 ; p < len ; p++) + { + /* X [Ui [p]] -= Ux [p] * x [0] ; */ + MULT_SUB (X [Ui [p]], Ux [p], x [0]) ; + + } + } + + break ; + + case 2: + + for (k = n-1 ; k >= 0 ; k--) + { + GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, len) ; + ukk = Udiag [k] ; + /* x [0] = X [2*k ] / ukk ; + x [1] = X [2*k + 1] / ukk ; */ + DIV (x [0], X [2*k], ukk) ; + DIV (x [1], X [2*k + 1], ukk) ; + + X [2*k ] = x [0] ; + X [2*k + 1] = x [1] ; + for (p = 0 ; p < len ; p++) + { + i = Ui [p] ; + uik = Ux [p] ; + /* X [2*i ] -= uik * x [0] ; + X [2*i + 1] -= uik * x [1] ; */ + MULT_SUB (X [2*i], uik, x [0]) ; + MULT_SUB (X [2*i + 1], uik, x [1]) ; + } + } + + break ; + + case 3: + + for (k = n-1 ; k >= 0 ; k--) + { + GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, len) ; + ukk = Udiag [k] ; + + DIV (x [0], X [3*k], ukk) ; + DIV (x [1], X [3*k + 1], ukk) ; + DIV (x [2], X [3*k + 2], ukk) ; + + X [3*k ] = x [0] ; + X [3*k + 1] = x [1] ; + X [3*k + 2] = x [2] ; + for (p = 0 ; p < len ; p++) + { + i = Ui [p] ; + uik = Ux [p] ; + MULT_SUB (X [3*i], uik, x [0]) ; + MULT_SUB (X [3*i + 1], uik, x [1]) ; + MULT_SUB (X [3*i + 2], uik, x [2]) ; + } + } + + break ; + + case 4: + + for (k = n-1 ; k >= 0 ; k--) + { + GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, len) ; + ukk = Udiag [k] ; + + DIV (x [0], X [4*k], ukk) ; + DIV (x [1], X [4*k + 1], ukk) ; + DIV (x [2], X [4*k + 2], ukk) ; + DIV (x [3], X [4*k + 3], ukk) ; + + X [4*k ] = x [0] ; + X [4*k + 1] = x [1] ; + X [4*k + 2] = x [2] ; + X [4*k + 3] = x [3] ; + for (p = 0 ; p < len ; p++) + { + i = Ui [p] ; + uik = Ux [p] ; + + MULT_SUB (X [4*i], uik, x [0]) ; + MULT_SUB (X [4*i + 1], uik, x [1]) ; + MULT_SUB (X [4*i + 2], uik, x [2]) ; + MULT_SUB (X [4*i + 3], uik, x [3]) ; + } + } + + break ; + + } +} + + +/* ========================================================================== */ +/* === KLU_ltsolve ========================================================== */ +/* ========================================================================== */ + +/* Solve L'x=b. Assumes L is unit lower triangular and where the unit diagonal + * entry is NOT stored. Overwrites B with the solution X. B is n-by-nrhs + * and is stored in ROW form with row dimension nrhs. nrhs must in the + * range 1 to 4. */ + +void KLU_ltsolve +( + /* inputs, not modified: */ + Int n, + Int Lip [ ], + Int Llen [ ], + Unit LU [ ], + Int nrhs, +#ifdef COMPLEX + Int conj_solve, +#endif + /* right-hand-side on input, solution to L'x=b on output */ + Entry X [ ] +) +{ + Entry x [4], lik ; + Int *Li ; + Entry *Lx ; + Int k, p, len, i ; + + switch (nrhs) + { + + case 1: + + for (k = n-1 ; k >= 0 ; k--) + { + GET_POINTER (LU, Lip, Llen, Li, Lx, k, len) ; + x [0] = X [k] ; + for (p = 0 ; p < len ; p++) + { +#ifdef COMPLEX + if (conj_solve) + { + /* x [0] -= CONJ (Lx [p]) * X [Li [p]] ; */ + MULT_SUB_CONJ (x [0], X [Li [p]], Lx [p]) ; + } + else +#endif + { + /*x [0] -= Lx [p] * X [Li [p]] ;*/ + MULT_SUB (x [0], Lx [p], X [Li [p]]) ; + } + } + X [k] = x [0] ; + } + break ; + + case 2: + + for (k = n-1 ; k >= 0 ; k--) + { + x [0] = X [2*k ] ; + x [1] = X [2*k + 1] ; + GET_POINTER (LU, Lip, Llen, Li, Lx, k, len) ; + for (p = 0 ; p < len ; p++) + { + i = Li [p] ; +#ifdef COMPLEX + if (conj_solve) + { + CONJ (lik, Lx [p]) ; + } + else +#endif + { + lik = Lx [p] ; + } + MULT_SUB (x [0], lik, X [2*i]) ; + MULT_SUB (x [1], lik, X [2*i + 1]) ; + } + X [2*k ] = x [0] ; + X [2*k + 1] = x [1] ; + } + break ; + + case 3: + + for (k = n-1 ; k >= 0 ; k--) + { + x [0] = X [3*k ] ; + x [1] = X [3*k + 1] ; + x [2] = X [3*k + 2] ; + GET_POINTER (LU, Lip, Llen, Li, Lx, k, len) ; + for (p = 0 ; p < len ; p++) + { + i = Li [p] ; +#ifdef COMPLEX + if (conj_solve) + { + CONJ (lik, Lx [p]) ; + } + else +#endif + { + lik = Lx [p] ; + } + MULT_SUB (x [0], lik, X [3*i]) ; + MULT_SUB (x [1], lik, X [3*i + 1]) ; + MULT_SUB (x [2], lik, X [3*i + 2]) ; + } + X [3*k ] = x [0] ; + X [3*k + 1] = x [1] ; + X [3*k + 2] = x [2] ; + } + break ; + + case 4: + + for (k = n-1 ; k >= 0 ; k--) + { + x [0] = X [4*k ] ; + x [1] = X [4*k + 1] ; + x [2] = X [4*k + 2] ; + x [3] = X [4*k + 3] ; + GET_POINTER (LU, Lip, Llen, Li, Lx, k, len) ; + for (p = 0 ; p < len ; p++) + { + i = Li [p] ; +#ifdef COMPLEX + if (conj_solve) + { + CONJ (lik, Lx [p]) ; + } + else +#endif + { + lik = Lx [p] ; + } + MULT_SUB (x [0], lik, X [4*i]) ; + MULT_SUB (x [1], lik, X [4*i + 1]) ; + MULT_SUB (x [2], lik, X [4*i + 2]) ; + MULT_SUB (x [3], lik, X [4*i + 3]) ; + } + X [4*k ] = x [0] ; + X [4*k + 1] = x [1] ; + X [4*k + 2] = x [2] ; + X [4*k + 3] = x [3] ; + } + break ; + } +} + + +/* ========================================================================== */ +/* === KLU_utsolve ========================================================== */ +/* ========================================================================== */ + +/* Solve U'x=b. Assumes U is non-unit upper triangular and where the diagonal + * entry is stored (and appears last in each column of U). Overwrites B + * with the solution X. B is n-by-nrhs and is stored in ROW form with row + * dimension nrhs. nrhs must be in the range 1 to 4. */ + +void KLU_utsolve +( + /* inputs, not modified: */ + Int n, + Int Uip [ ], + Int Ulen [ ], + Unit LU [ ], + Entry Udiag [ ], + Int nrhs, +#ifdef COMPLEX + Int conj_solve, +#endif + /* right-hand-side on input, solution to Ux=b on output */ + Entry X [ ] +) +{ + Entry x [4], uik, ukk ; + Int k, p, len, i ; + Int *Ui ; + Entry *Ux ; + + switch (nrhs) + { + + case 1: + + for (k = 0 ; k < n ; k++) + { + GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, len) ; + x [0] = X [k] ; + for (p = 0 ; p < len ; p++) + { +#ifdef COMPLEX + if (conj_solve) + { + /* x [0] -= CONJ (Ux [p]) * X [Ui [p]] ; */ + MULT_SUB_CONJ (x [0], X [Ui [p]], Ux [p]) ; + } + else +#endif + { + /* x [0] -= Ux [p] * X [Ui [p]] ; */ + MULT_SUB (x [0], Ux [p], X [Ui [p]]) ; + } + } +#ifdef COMPLEX + if (conj_solve) + { + CONJ (ukk, Udiag [k]) ; + } + else +#endif + { + ukk = Udiag [k] ; + } + DIV (X [k], x [0], ukk) ; + } + break ; + + case 2: + + for (k = 0 ; k < n ; k++) + { + GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, len) ; + x [0] = X [2*k ] ; + x [1] = X [2*k + 1] ; + for (p = 0 ; p < len ; p++) + { + i = Ui [p] ; +#ifdef COMPLEX + if (conj_solve) + { + CONJ (uik, Ux [p]) ; + } + else +#endif + { + uik = Ux [p] ; + } + MULT_SUB (x [0], uik, X [2*i]) ; + MULT_SUB (x [1], uik, X [2*i + 1]) ; + } +#ifdef COMPLEX + if (conj_solve) + { + CONJ (ukk, Udiag [k]) ; + } + else +#endif + { + ukk = Udiag [k] ; + } + DIV (X [2*k], x [0], ukk) ; + DIV (X [2*k + 1], x [1], ukk) ; + } + break ; + + case 3: + + for (k = 0 ; k < n ; k++) + { + GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, len) ; + x [0] = X [3*k ] ; + x [1] = X [3*k + 1] ; + x [2] = X [3*k + 2] ; + for (p = 0 ; p < len ; p++) + { + i = Ui [p] ; +#ifdef COMPLEX + if (conj_solve) + { + CONJ (uik, Ux [p]) ; + } + else +#endif + { + uik = Ux [p] ; + } + MULT_SUB (x [0], uik, X [3*i]) ; + MULT_SUB (x [1], uik, X [3*i + 1]) ; + MULT_SUB (x [2], uik, X [3*i + 2]) ; + } +#ifdef COMPLEX + if (conj_solve) + { + CONJ (ukk, Udiag [k]) ; + } + else +#endif + { + ukk = Udiag [k] ; + } + DIV (X [3*k], x [0], ukk) ; + DIV (X [3*k + 1], x [1], ukk) ; + DIV (X [3*k + 2], x [2], ukk) ; + } + break ; + + case 4: + + for (k = 0 ; k < n ; k++) + { + GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, len) ; + x [0] = X [4*k ] ; + x [1] = X [4*k + 1] ; + x [2] = X [4*k + 2] ; + x [3] = X [4*k + 3] ; + for (p = 0 ; p < len ; p++) + { + i = Ui [p] ; +#ifdef COMPLEX + if (conj_solve) + { + CONJ (uik, Ux [p]) ; + } + else +#endif + { + uik = Ux [p] ; + } + MULT_SUB (x [0], uik, X [4*i]) ; + MULT_SUB (x [1], uik, X [4*i + 1]) ; + MULT_SUB (x [2], uik, X [4*i + 2]) ; + MULT_SUB (x [3], uik, X [4*i + 3]) ; + } +#ifdef COMPLEX + if (conj_solve) + { + CONJ (ukk, Udiag [k]) ; + } + else +#endif + { + ukk = Udiag [k] ; + } + DIV (X [4*k], x [0], ukk) ; + DIV (X [4*k + 1], x [1], ukk) ; + DIV (X [4*k + 2], x [2], ukk) ; + DIV (X [4*k + 3], x [3], ukk) ; + } + break ; + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_analyze.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_analyze.c new file mode 100644 index 0000000..2fe81c1 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_analyze.c @@ -0,0 +1,482 @@ +/* ========================================================================== */ +/* === klu_analyze ========================================================== */ +/* ========================================================================== */ + +/* Order the matrix using BTF (or not), and then AMD, COLAMD, the natural + * ordering, or the user-provided-function on the blocks. Does not support + * using a given ordering (use klu_analyze_given for that case). */ + +#include "klu_internal.h" + +/* ========================================================================== */ +/* === analyze_worker ======================================================= */ +/* ========================================================================== */ + +static Int analyze_worker /* returns KLU_OK or < 0 if error */ +( + /* inputs, not modified */ + Int n, /* A is n-by-n */ + Int Ap [ ], /* size n+1, column pointers */ + Int Ai [ ], /* size nz, row indices */ + Int nblocks, /* # of blocks */ + Int Pbtf [ ], /* BTF row permutation */ + Int Qbtf [ ], /* BTF col permutation */ + Int R [ ], /* size n+1, but only Rbtf [0..nblocks] is used */ + Int ordering, /* what ordering to use (0, 1, or 3 for this routine) */ + + /* output only, not defined on input */ + Int P [ ], /* size n */ + Int Q [ ], /* size n */ + double Lnz [ ], /* size n, but only Lnz [0..nblocks-1] is used */ + + /* workspace, not defined on input or output */ + Int Pblk [ ], /* size maxblock */ + Int Cp [ ], /* size maxblock+1 */ + Int Ci [ ], /* size MAX (nz+1, Cilen) */ + Int Cilen, /* nz+1, or COLAMD_recommend(nz,n,n) for COLAMD */ + Int Pinv [ ], /* size maxblock */ + + /* input/output */ + KLU_symbolic *Symbolic, + KLU_common *Common +) +{ + double amd_Info [AMD_INFO], lnz, lnz1, flops, flops1 ; + Int k1, k2, nk, k, block, oldcol, pend, newcol, result, pc, p, newrow, + maxnz, nzoff, cstats [COLAMD_STATS], ok, err = KLU_INVALID ; + + /* ---------------------------------------------------------------------- */ + /* initializations */ + /* ---------------------------------------------------------------------- */ + + /* compute the inverse of Pbtf */ +#ifndef NDEBUG + for (k = 0 ; k < n ; k++) + { + P [k] = EMPTY ; + Q [k] = EMPTY ; + Pinv [k] = EMPTY ; + } +#endif + for (k = 0 ; k < n ; k++) + { + ASSERT (Pbtf [k] >= 0 && Pbtf [k] < n) ; + Pinv [Pbtf [k]] = k ; + } +#ifndef NDEBUG + for (k = 0 ; k < n ; k++) ASSERT (Pinv [k] != EMPTY) ; +#endif + nzoff = 0 ; + lnz = 0 ; + maxnz = 0 ; + flops = 0 ; + Symbolic->symmetry = EMPTY ; /* only computed by AMD */ + + /* ---------------------------------------------------------------------- */ + /* order each block */ + /* ---------------------------------------------------------------------- */ + + for (block = 0 ; block < nblocks ; block++) + { + + /* ------------------------------------------------------------------ */ + /* the block is from rows/columns k1 to k2-1 */ + /* ------------------------------------------------------------------ */ + + k1 = R [block] ; + k2 = R [block+1] ; + nk = k2 - k1 ; + PRINTF (("BLOCK %d, k1 %d k2-1 %d nk %d\n", block, k1, k2-1, nk)) ; + + /* ------------------------------------------------------------------ */ + /* construct the kth block, C */ + /* ------------------------------------------------------------------ */ + + Lnz [block] = EMPTY ; + pc = 0 ; + for (k = k1 ; k < k2 ; k++) + { + newcol = k-k1 ; + Cp [newcol] = pc ; + oldcol = Qbtf [k] ; + pend = Ap [oldcol+1] ; + for (p = Ap [oldcol] ; p < pend ; p++) + { + newrow = Pinv [Ai [p]] ; + if (newrow < k1) + { + nzoff++ ; + } + else + { + /* (newrow,newcol) is an entry in the block */ + ASSERT (newrow < k2) ; + newrow -= k1 ; + Ci [pc++] = newrow ; + } + } + } + Cp [nk] = pc ; + maxnz = MAX (maxnz, pc) ; + ASSERT (KLU_valid (nk, Cp, Ci, NULL)) ; + + /* ------------------------------------------------------------------ */ + /* order the block C */ + /* ------------------------------------------------------------------ */ + + if (nk <= 3) + { + + /* -------------------------------------------------------------- */ + /* use natural ordering for tiny blocks (3-by-3 or less) */ + /* -------------------------------------------------------------- */ + + for (k = 0 ; k < nk ; k++) + { + Pblk [k] = k ; + } + lnz1 = nk * (nk + 1) / 2 ; + flops1 = nk * (nk - 1) / 2 + (nk-1)*nk*(2*nk-1) / 6 ; + ok = TRUE ; + + } + else if (ordering == 0) + { + + /* -------------------------------------------------------------- */ + /* order the block with AMD (C+C') */ + /* -------------------------------------------------------------- */ + + result = AMD_order (nk, Cp, Ci, Pblk, NULL, amd_Info) ; + ok = (result >= AMD_OK) ; + if (result == AMD_OUT_OF_MEMORY) + { + err = KLU_OUT_OF_MEMORY ; + } + + /* account for memory usage in AMD */ + Common->mempeak = MAX (Common->mempeak, + Common->memusage + amd_Info [AMD_MEMORY]) ; + + /* get the ordering statistics from AMD */ + lnz1 = (Int) (amd_Info [AMD_LNZ]) + nk ; + flops1 = 2 * amd_Info [AMD_NMULTSUBS_LU] + amd_Info [AMD_NDIV] ; + if (pc == maxnz) + { + /* get the symmetry of the biggest block */ + Symbolic->symmetry = amd_Info [AMD_SYMMETRY] ; + } + + } + else if (ordering == 1) + { + + /* -------------------------------------------------------------- */ + /* order the block with COLAMD (C) */ + /* -------------------------------------------------------------- */ + + /* order (and destroy) Ci, returning column permutation in Cp. + * COLAMD "cannot" fail since the matrix has already been checked, + * and Ci allocated. */ + + ok = COLAMD (nk, nk, Cilen, Ci, Cp, NULL, cstats) ; + lnz1 = EMPTY ; + flops1 = EMPTY ; + + /* copy the permutation from Cp to Pblk */ + for (k = 0 ; k < nk ; k++) + { + Pblk [k] = Cp [k] ; + } + + } + else + { + + /* -------------------------------------------------------------- */ + /* pass the block to the user-provided ordering function */ + /* -------------------------------------------------------------- */ + + lnz1 = (Common->user_order) (nk, Cp, Ci, Pblk, Common) ; + flops1 = EMPTY ; + ok = (lnz1 != 0) ; + } + + if (!ok) + { + return (err) ; /* ordering method failed */ + } + + /* ------------------------------------------------------------------ */ + /* keep track of nnz(L) and flops statistics */ + /* ------------------------------------------------------------------ */ + + Lnz [block] = lnz1 ; + lnz = (lnz == EMPTY || lnz1 == EMPTY) ? EMPTY : (lnz + lnz1) ; + flops = (flops == EMPTY || flops1 == EMPTY) ? EMPTY : (flops + flops1) ; + + /* ------------------------------------------------------------------ */ + /* combine the preordering with the BTF ordering */ + /* ------------------------------------------------------------------ */ + + PRINTF (("Pblk, 1-based:\n")) ; + for (k = 0 ; k < nk ; k++) + { + ASSERT (k + k1 < n) ; + ASSERT (Pblk [k] + k1 < n) ; + Q [k + k1] = Qbtf [Pblk [k] + k1] ; + } + for (k = 0 ; k < nk ; k++) + { + ASSERT (k + k1 < n) ; + ASSERT (Pblk [k] + k1 < n) ; + P [k + k1] = Pbtf [Pblk [k] + k1] ; + } + } + + PRINTF (("nzoff %d Ap[n] %d\n", nzoff, Ap [n])) ; + ASSERT (nzoff >= 0 && nzoff <= Ap [n]) ; + + /* return estimates of # of nonzeros in L including diagonal */ + Symbolic->lnz = lnz ; /* EMPTY if COLAMD used */ + Symbolic->unz = lnz ; + Symbolic->nzoff = nzoff ; + Symbolic->est_flops = flops ; /* EMPTY if COLAMD or user-ordering used */ + return (KLU_OK) ; +} + + +/* ========================================================================== */ +/* === order_and_analyze ==================================================== */ +/* ========================================================================== */ + +/* Orders the matrix with or with BTF, then orders each block with AMD, COLAMD, + * or the user ordering function. Does not handle the natural or given + * ordering cases. */ + +static KLU_symbolic *order_and_analyze /* returns NULL if error, or a valid + KLU_symbolic object if successful */ +( + /* inputs, not modified */ + Int n, /* A is n-by-n */ + Int Ap [ ], /* size n+1, column pointers */ + Int Ai [ ], /* size nz, row indices */ + /* --------------------- */ + KLU_common *Common +) +{ + double work ; + KLU_symbolic *Symbolic ; + double *Lnz ; + Int *Qbtf, *Cp, *Ci, *Pinv, *Pblk, *Pbtf, *P, *Q, *R ; + Int nblocks, nz, block, maxblock, k1, k2, nk, do_btf, ordering, k, Cilen, + *Work ; + + /* ---------------------------------------------------------------------- */ + /* allocate the Symbolic object, and check input matrix */ + /* ---------------------------------------------------------------------- */ + + Symbolic = KLU_alloc_symbolic (n, Ap, Ai, Common) ; + if (Symbolic == NULL) + { + return (NULL) ; + } + P = Symbolic->P ; + Q = Symbolic->Q ; + R = Symbolic->R ; + Lnz = Symbolic->Lnz ; + nz = Symbolic->nz ; + + ordering = Common->ordering ; + if (ordering == 1) + { + /* COLAMD */ + Cilen = COLAMD_recommended (nz, n, n) ; + } + else if (ordering == 0 || (ordering == 3 && Common->user_order != NULL)) + { + /* AMD or user ordering function */ + Cilen = nz+1 ; + } + else + { + /* invalid ordering */ + Common->status = KLU_INVALID ; + KLU_free_symbolic (&Symbolic, Common) ; + return (NULL) ; + } + + /* ---------------------------------------------------------------------- */ + /* allocate workspace for BTF permutation */ + /* ---------------------------------------------------------------------- */ + + Pbtf = KLU_malloc (n, sizeof (Int), Common) ; + Qbtf = KLU_malloc (n, sizeof (Int), Common) ; + if (Common->status < KLU_OK) + { + KLU_free (Pbtf, n, sizeof (Int), Common) ; + KLU_free (Qbtf, n, sizeof (Int), Common) ; + KLU_free_symbolic (&Symbolic, Common) ; + return (NULL) ; + } + + /* ---------------------------------------------------------------------- */ + /* get the common parameters for BTF and ordering method */ + /* ---------------------------------------------------------------------- */ + + do_btf = Common->btf ; + do_btf = (do_btf) ? TRUE : FALSE ; + Symbolic->ordering = ordering ; + Symbolic->do_btf = do_btf ; + Symbolic->structural_rank = EMPTY ; + + /* ---------------------------------------------------------------------- */ + /* find the block triangular form (if requested) */ + /* ---------------------------------------------------------------------- */ + + Common->work = 0 ; + + if (do_btf) + { + Work = KLU_malloc (5*n, sizeof (Int), Common) ; + if (Common->status < KLU_OK) + { + /* out of memory */ + KLU_free (Pbtf, n, sizeof (Int), Common) ; + KLU_free (Qbtf, n, sizeof (Int), Common) ; + KLU_free_symbolic (&Symbolic, Common) ; + return (NULL) ; + } + + nblocks = BTF_order (n, Ap, Ai, Common->maxwork, &work, Pbtf, Qbtf, R, + &(Symbolic->structural_rank), Work) ; + Common->structural_rank = Symbolic->structural_rank ; + Common->work += work ; + + KLU_free (Work, 5*n, sizeof (Int), Common) ; + + /* unflip Qbtf if the matrix does not have full structural rank */ + if (Symbolic->structural_rank < n) + { + for (k = 0 ; k < n ; k++) + { + Qbtf [k] = BTF_UNFLIP (Qbtf [k]) ; + } + } + + /* find the size of the largest block */ + maxblock = 1 ; + for (block = 0 ; block < nblocks ; block++) + { + k1 = R [block] ; + k2 = R [block+1] ; + nk = k2 - k1 ; + PRINTF (("block %d size %d\n", block, nk)) ; + maxblock = MAX (maxblock, nk) ; + } + } + else + { + /* BTF not requested */ + nblocks = 1 ; + maxblock = n ; + R [0] = 0 ; + R [1] = n ; + for (k = 0 ; k < n ; k++) + { + Pbtf [k] = k ; + Qbtf [k] = k ; + } + } + + Symbolic->nblocks = nblocks ; + + PRINTF (("maxblock size %d\n", maxblock)) ; + Symbolic->maxblock = maxblock ; + + /* ---------------------------------------------------------------------- */ + /* allocate more workspace, for analyze_worker */ + /* ---------------------------------------------------------------------- */ + + Pblk = KLU_malloc (maxblock, sizeof (Int), Common) ; + Cp = KLU_malloc (maxblock + 1, sizeof (Int), Common) ; + Ci = KLU_malloc (MAX (Cilen, nz+1), sizeof (Int), Common) ; + Pinv = KLU_malloc (n, sizeof (Int), Common) ; + + /* ---------------------------------------------------------------------- */ + /* order each block of the BTF ordering, and a fill-reducing ordering */ + /* ---------------------------------------------------------------------- */ + + if (Common->status == KLU_OK) + { + PRINTF (("calling analyze_worker\n")) ; + Common->status = analyze_worker (n, Ap, Ai, nblocks, Pbtf, Qbtf, R, + ordering, P, Q, Lnz, Pblk, Cp, Ci, Cilen, Pinv, Symbolic, Common) ; + PRINTF (("analyze_worker done\n")) ; + } + + /* ---------------------------------------------------------------------- */ + /* free all workspace */ + /* ---------------------------------------------------------------------- */ + + KLU_free (Pblk, maxblock, sizeof (Int), Common) ; + KLU_free (Cp, maxblock+1, sizeof (Int), Common) ; + KLU_free (Ci, MAX (Cilen, nz+1), sizeof (Int), Common) ; + KLU_free (Pinv, n, sizeof (Int), Common) ; + KLU_free (Pbtf, n, sizeof (Int), Common) ; + KLU_free (Qbtf, n, sizeof (Int), Common) ; + + /* ---------------------------------------------------------------------- */ + /* return the symbolic object */ + /* ---------------------------------------------------------------------- */ + + if (Common->status < KLU_OK) + { + KLU_free_symbolic (&Symbolic, Common) ; + } + return (Symbolic) ; +} + + +/* ========================================================================== */ +/* === KLU_analyze ========================================================== */ +/* ========================================================================== */ + +KLU_symbolic *KLU_analyze /* returns NULL if error, or a valid + KLU_symbolic object if successful */ +( + /* inputs, not modified */ + Int n, /* A is n-by-n */ + Int Ap [ ], /* size n+1, column pointers */ + Int Ai [ ], /* size nz, row indices */ + /* -------------------- */ + KLU_common *Common +) +{ + + /* ---------------------------------------------------------------------- */ + /* get the control parameters for BTF and ordering method */ + /* ---------------------------------------------------------------------- */ + + if (Common == NULL) + { + return (NULL) ; + } + Common->status = KLU_OK ; + Common->structural_rank = EMPTY ; + + /* ---------------------------------------------------------------------- */ + /* order and analyze */ + /* ---------------------------------------------------------------------- */ + + if (Common->ordering == 2) + { + /* natural ordering */ + return (KLU_analyze_given (n, Ap, Ai, NULL, NULL, Common)) ; + } + else + { + /* order with P and Q */ + return (order_and_analyze (n, Ap, Ai, Common)) ; + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_analyze_given.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_analyze_given.c new file mode 100644 index 0000000..bee5473 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_analyze_given.c @@ -0,0 +1,369 @@ +/* ========================================================================== */ +/* === klu_analyze_given ==================================================== */ +/* ========================================================================== */ + +/* Given an input permutation P and Q, create the Symbolic object. BTF can + * be done to modify the user's P and Q (does not perform the max transversal; + * just finds the strongly-connected components). */ + +#include "klu_internal.h" + +/* ========================================================================== */ +/* === klu_alloc_symbolic =================================================== */ +/* ========================================================================== */ + +/* Allocate Symbolic object, and check input matrix. Not user callable. */ + +KLU_symbolic *KLU_alloc_symbolic +( + Int n, + Int *Ap, + Int *Ai, + KLU_common *Common +) +{ + KLU_symbolic *Symbolic ; + Int *P, *Q, *R ; + double *Lnz ; + Int nz, i, j, p, pend ; + + if (Common == NULL) + { + return (NULL) ; + } + Common->status = KLU_OK ; + + /* A is n-by-n, with n > 0. Ap [0] = 0 and nz = Ap [n] >= 0 required. + * Ap [j] <= Ap [j+1] must hold for all j = 0 to n-1. Row indices in Ai + * must be in the range 0 to n-1, and no duplicate entries can be present. + * The list of row indices in each column of A need not be sorted. + */ + + if (n <= 0 || Ap == NULL || Ai == NULL) + { + /* Ap and Ai must be present, and n must be > 0 */ + Common->status = KLU_INVALID ; + return (NULL) ; + } + + nz = Ap [n] ; + if (Ap [0] != 0 || nz < 0) + { + /* nz must be >= 0 and Ap [0] must equal zero */ + Common->status = KLU_INVALID ; + return (NULL) ; + } + + for (j = 0 ; j < n ; j++) + { + if (Ap [j] > Ap [j+1]) + { + /* column pointers must be non-decreasing */ + Common->status = KLU_INVALID ; + return (NULL) ; + } + } + P = KLU_malloc (n, sizeof (Int), Common) ; + if (Common->status < KLU_OK) + { + /* out of memory */ + Common->status = KLU_OUT_OF_MEMORY ; + return (NULL) ; + } + for (i = 0 ; i < n ; i++) + { + P [i] = EMPTY ; + } + for (j = 0 ; j < n ; j++) + { + pend = Ap [j+1] ; + for (p = Ap [j] ; p < pend ; p++) + { + i = Ai [p] ; + if (i < 0 || i >= n || P [i] == j) + { + /* row index out of range, or duplicate entry */ + KLU_free (P, n, sizeof (Int), Common) ; + Common->status = KLU_INVALID ; + return (NULL) ; + } + /* flag row i as appearing in column j */ + P [i] = j ; + } + } + + /* ---------------------------------------------------------------------- */ + /* allocate the Symbolic object */ + /* ---------------------------------------------------------------------- */ + + Symbolic = KLU_malloc (sizeof (KLU_symbolic), 1, Common) ; + if (Common->status < KLU_OK) + { + /* out of memory */ + KLU_free (P, n, sizeof (Int), Common) ; + Common->status = KLU_OUT_OF_MEMORY ; + return (NULL) ; + } + + Q = KLU_malloc (n, sizeof (Int), Common) ; + R = KLU_malloc (n+1, sizeof (Int), Common) ; + Lnz = KLU_malloc (n, sizeof (double), Common) ; + + Symbolic->n = n ; + Symbolic->nz = nz ; + Symbolic->P = P ; + Symbolic->Q = Q ; + Symbolic->R = R ; + Symbolic->Lnz = Lnz ; + + if (Common->status < KLU_OK) + { + /* out of memory */ + KLU_free_symbolic (&Symbolic, Common) ; + Common->status = KLU_OUT_OF_MEMORY ; + return (NULL) ; + } + + return (Symbolic) ; +} + + +/* ========================================================================== */ +/* === KLU_analyze_given ==================================================== */ +/* ========================================================================== */ + +KLU_symbolic *KLU_analyze_given /* returns NULL if error, or a valid + KLU_symbolic object if successful */ +( + /* inputs, not modified */ + Int n, /* A is n-by-n */ + Int Ap [ ], /* size n+1, column pointers */ + Int Ai [ ], /* size nz, row indices */ + Int Puser [ ], /* size n, user's row permutation (may be NULL) */ + Int Quser [ ], /* size n, user's column permutation (may be NULL) */ + /* -------------------- */ + KLU_common *Common +) +{ + KLU_symbolic *Symbolic ; + double *Lnz ; + Int nblocks, nz, block, maxblock, *P, *Q, *R, nzoff, p, pend, do_btf, k ; + + /* ---------------------------------------------------------------------- */ + /* determine if input matrix is valid, and get # of nonzeros */ + /* ---------------------------------------------------------------------- */ + + Symbolic = KLU_alloc_symbolic (n, Ap, Ai, Common) ; + if (Symbolic == NULL) + { + return (NULL) ; + } + P = Symbolic->P ; + Q = Symbolic->Q ; + R = Symbolic->R ; + Lnz = Symbolic->Lnz ; + nz = Symbolic->nz ; + + /* ---------------------------------------------------------------------- */ + /* Q = Quser, or identity if Quser is NULL */ + /* ---------------------------------------------------------------------- */ + + if (Quser == (Int *) NULL) + { + for (k = 0 ; k < n ; k++) + { + Q [k] = k ; + } + } + else + { + for (k = 0 ; k < n ; k++) + { + Q [k] = Quser [k] ; + } + } + + /* ---------------------------------------------------------------------- */ + /* get the control parameters for BTF and ordering method */ + /* ---------------------------------------------------------------------- */ + + do_btf = Common->btf ; + do_btf = (do_btf) ? TRUE : FALSE ; + Symbolic->ordering = 2 ; + Symbolic->do_btf = do_btf ; + + /* ---------------------------------------------------------------------- */ + /* find the block triangular form, if requested */ + /* ---------------------------------------------------------------------- */ + + if (do_btf) + { + + /* ------------------------------------------------------------------ */ + /* get workspace for BTF_strongcomp */ + /* ------------------------------------------------------------------ */ + + Int *Pinv, *Work, *Bi, k1, k2, nk, oldcol ; + + Work = KLU_malloc (4*n, sizeof (Int), Common) ; + Pinv = KLU_malloc (n, sizeof (Int), Common) ; + if (Puser != (Int *) NULL) + { + Bi = KLU_malloc (nz+1, sizeof (Int), Common) ; + } + else + { + Bi = Ai ; + } + + if (Common->status < KLU_OK) + { + /* out of memory */ + KLU_free (Work, 4*n, sizeof (Int), Common) ; + KLU_free (Pinv, n, sizeof (Int), Common) ; + if (Puser != (Int *) NULL) + { + KLU_free (Bi, nz+1, sizeof (Int), Common) ; + } + KLU_free_symbolic (&Symbolic, Common) ; + Common->status = KLU_OUT_OF_MEMORY ; + return (NULL) ; + } + + /* ------------------------------------------------------------------ */ + /* B = Puser * A */ + /* ------------------------------------------------------------------ */ + + if (Puser != (Int *) NULL) + { + for (k = 0 ; k < n ; k++) + { + Pinv [Puser [k]] = k ; + } + for (p = 0 ; p < nz ; p++) + { + Bi [p] = Pinv [Ai [p]] ; + } + } + + /* ------------------------------------------------------------------ */ + /* find the strongly-connected components */ + /* ------------------------------------------------------------------ */ + + /* modifies Q, and determines P and R */ + nblocks = BTF_strongcomp (n, Ap, Bi, Q, P, R, Work) ; + + /* ------------------------------------------------------------------ */ + /* P = P * Puser */ + /* ------------------------------------------------------------------ */ + + if (Puser != (Int *) NULL) + { + for (k = 0 ; k < n ; k++) + { + Work [k] = Puser [P [k]] ; + } + for (k = 0 ; k < n ; k++) + { + P [k] = Work [k] ; + } + } + + /* ------------------------------------------------------------------ */ + /* Pinv = inverse of P */ + /* ------------------------------------------------------------------ */ + + for (k = 0 ; k < n ; k++) + { + Pinv [P [k]] = k ; + } + + /* ------------------------------------------------------------------ */ + /* analyze each block */ + /* ------------------------------------------------------------------ */ + + nzoff = 0 ; /* nz in off-diagonal part */ + maxblock = 1 ; /* size of the largest block */ + + for (block = 0 ; block < nblocks ; block++) + { + + /* -------------------------------------------------------------- */ + /* the block is from rows/columns k1 to k2-1 */ + /* -------------------------------------------------------------- */ + + k1 = R [block] ; + k2 = R [block+1] ; + nk = k2 - k1 ; + PRINTF (("BLOCK %d, k1 %d k2-1 %d nk %d\n", block, k1, k2-1, nk)) ; + maxblock = MAX (maxblock, nk) ; + + /* -------------------------------------------------------------- */ + /* scan the kth block, C */ + /* -------------------------------------------------------------- */ + + for (k = k1 ; k < k2 ; k++) + { + oldcol = Q [k] ; + pend = Ap [oldcol+1] ; + for (p = Ap [oldcol] ; p < pend ; p++) + { + if (Pinv [Ai [p]] < k1) + { + nzoff++ ; + } + } + } + + /* fill-in not estimated */ + Lnz [block] = EMPTY ; + } + + /* ------------------------------------------------------------------ */ + /* free all workspace */ + /* ------------------------------------------------------------------ */ + + KLU_free (Work, 4*n, sizeof (Int), Common) ; + KLU_free (Pinv, n, sizeof (Int), Common) ; + if (Puser != (Int *) NULL) + { + KLU_free (Bi, nz+1, sizeof (Int), Common) ; + } + + } + else + { + + /* ------------------------------------------------------------------ */ + /* BTF not requested */ + /* ------------------------------------------------------------------ */ + + nzoff = 0 ; + nblocks = 1 ; + maxblock = n ; + R [0] = 0 ; + R [1] = n ; + Lnz [0] = EMPTY ; + + /* ------------------------------------------------------------------ */ + /* P = Puser, or identity if Puser is NULL */ + /* ------------------------------------------------------------------ */ + + for (k = 0 ; k < n ; k++) + { + P [k] = (Puser == NULL) ? k : Puser [k] ; + } + } + + /* ---------------------------------------------------------------------- */ + /* return the symbolic object */ + /* ---------------------------------------------------------------------- */ + + Symbolic->nblocks = nblocks ; + Symbolic->maxblock = maxblock ; + Symbolic->lnz = EMPTY ; + Symbolic->unz = EMPTY ; + Symbolic->nzoff = nzoff ; + + return (Symbolic) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_defaults.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_defaults.c new file mode 100644 index 0000000..ba2b77e --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_defaults.c @@ -0,0 +1,54 @@ +/* ========================================================================== */ +/* === KLU_defaults ========================================================= */ +/* ========================================================================== */ + +/* Sets default parameters for KLU */ + +#include "klu_internal.h" + +Int KLU_defaults +( + KLU_common *Common +) +{ + if (Common == NULL) + { + return (FALSE) ; + } + + /* parameters */ + Common->tol = 0.001 ; /* pivot tolerance for diagonal */ + Common->memgrow = 1.2; /* realloc size ratio increase for LU factors */ + Common->initmem_amd = 1.2 ; /* init. mem with AMD: c*nnz(L) + n */ + Common->initmem = 10 ; /* init. mem otherwise: c*nnz(A) + n */ + Common->btf = TRUE ; /* use BTF pre-ordering, or not */ + Common->maxwork = 0 ; /* no limit to work done by btf_order */ + Common->ordering = 0 ; /* 0: AMD, 1: COLAMD, 2: user-provided P and Q, + * 3: user-provided function */ + Common->scale = 2 ; /* scale: -1: none, and do not check for errors + * in the input matrix in KLU_refactor. + * 0: none, but check for errors, + * 1: sum, 2: max */ + Common->halt_if_singular = TRUE ; /* quick halt if matrix is singular */ + + /* user ordering function and optional argument */ + Common->user_order = NULL ; + Common->user_data = NULL ; + + /* statistics */ + Common->status = KLU_OK ; + Common->nrealloc = 0 ; + Common->structural_rank = EMPTY ; + Common->numerical_rank = EMPTY ; + Common->noffdiag = EMPTY ; + Common->flops = EMPTY ; + Common->rcond = EMPTY ; + Common->condest = EMPTY ; + Common->rgrowth = EMPTY ; + Common->work = 0 ; /* work done by btf_order */ + + Common->memusage = 0 ; + Common->mempeak = 0 ; + + return (TRUE) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_diagnostics.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_diagnostics.c new file mode 100644 index 0000000..dc9d288 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_diagnostics.c @@ -0,0 +1,568 @@ +/* ========================================================================== */ +/* === KLU_diagnostics ====================================================== */ +/* ========================================================================== */ + +/* Linear algebraic diagnostics: + * KLU_rgrowth: reciprocal pivot growth, takes O(|A|+|U|) time + * KLU_condest: condition number estimator, takes about O(|A|+5*(|L|+|U|)) time + * KLU_flops: compute # flops required to factorize A into L*U + * KLU_rcond: compute a really cheap estimate of the reciprocal of the + * condition number, min(abs(diag(U))) / max(abs(diag(U))). + * Takes O(n) time. + */ + +#include "klu_internal.h" + +/* ========================================================================== */ +/* === KLU_rgrowth ========================================================== */ +/* ========================================================================== */ + +/* Compute the reciprocal pivot growth factor. In MATLAB notation: + * + * rgrowth = min (max (abs ((R \ A (p,q)) - F))) ./ max (abs (U))) + */ + +Int KLU_rgrowth /* return TRUE if successful, FALSE otherwise */ +( + Int *Ap, + Int *Ai, + double *Ax, + KLU_symbolic *Symbolic, + KLU_numeric *Numeric, + KLU_common *Common +) +{ + double temp, max_ai, max_ui, min_block_rgrowth ; + Entry aik ; + Int *Q, *Ui, *Uip, *Ulen, *Pinv ; + Unit *LU ; + Entry *Aentry, *Ux, *Ukk ; + double *Rs ; + Int i, newrow, oldrow, k1, k2, nk, j, oldcol, k, pend, len ; + + /* ---------------------------------------------------------------------- */ + /* check inputs */ + /* ---------------------------------------------------------------------- */ + + if (Common == NULL) + { + return (FALSE) ; + } + + if (Symbolic == NULL || Ap == NULL || Ai == NULL || Ax == NULL) + { + Common->status = KLU_INVALID ; + return (FALSE) ; + } + + if (Numeric == NULL) + { + /* treat this as a singular matrix */ + Common->rgrowth = 0 ; + Common->status = KLU_SINGULAR ; + return (TRUE) ; + } + Common->status = KLU_OK ; + + /* ---------------------------------------------------------------------- */ + /* compute the reciprocal pivot growth */ + /* ---------------------------------------------------------------------- */ + + Aentry = (Entry *) Ax ; + Pinv = Numeric->Pinv ; + Rs = Numeric->Rs ; + Q = Symbolic->Q ; + Common->rgrowth = 1 ; + + for (i = 0 ; i < Symbolic->nblocks ; i++) + { + k1 = Symbolic->R[i] ; + k2 = Symbolic->R[i+1] ; + nk = k2 - k1 ; + if (nk == 1) + { + continue ; /* skip singleton blocks */ + } + LU = (Unit *) Numeric->LUbx[i] ; + Uip = Numeric->Uip + k1 ; + Ulen = Numeric->Ulen + k1 ; + Ukk = ((Entry *) Numeric->Udiag) + k1 ; + min_block_rgrowth = 1 ; + for (j = 0 ; j < nk ; j++) + { + max_ai = 0 ; + max_ui = 0 ; + oldcol = Q[j + k1] ; + pend = Ap [oldcol + 1] ; + for (k = Ap [oldcol] ; k < pend ; k++) + { + oldrow = Ai [k] ; + newrow = Pinv [oldrow] ; + if (newrow < k1) + { + continue ; /* skip entry outside the block */ + } + ASSERT (newrow < k2) ; + if (Rs != NULL) + { + /* aik = Aentry [k] / Rs [oldrow] */ + SCALE_DIV_ASSIGN (aik, Aentry [k], Rs [newrow]) ; + } + else + { + aik = Aentry [k] ; + } + /* temp = ABS (aik) */ + ABS (temp, aik) ; + if (temp > max_ai) + { + max_ai = temp ; + } + } + + /* Ui is set but not used. This is OK, because otherwise the macro + would have to be redesigned. */ + GET_POINTER (LU, Uip, Ulen, Ui, Ux, j, len) ; + for (k = 0 ; k < len ; k++) + { + /* temp = ABS (Ux [k]) */ + ABS (temp, Ux [k]) ; + if (temp > max_ui) + { + max_ui = temp ; + } + } + /* consider the diagonal element */ + ABS (temp, Ukk [j]) ; + if (temp > max_ui) + { + max_ui = temp ; + } + + /* if max_ui is 0, skip the column */ + if (SCALAR_IS_ZERO (max_ui)) + { + continue ; + } + temp = max_ai / max_ui ; + if (temp < min_block_rgrowth) + { + min_block_rgrowth = temp ; + } + } + + if (min_block_rgrowth < Common->rgrowth) + { + Common->rgrowth = min_block_rgrowth ; + } + } + return (TRUE) ; +} + + +/* ========================================================================== */ +/* === KLU_condest ========================================================== */ +/* ========================================================================== */ + +/* Estimate the condition number. Uses Higham and Tisseur's algorithm + * (A block algorithm for matrix 1-norm estimation, with applications to + * 1-norm pseudospectra, SIAM J. Matrix Anal. Appl., 21(4):1185-1201, 2000. + */ + +Int KLU_condest /* return TRUE if successful, FALSE otherwise */ +( + Int Ap [ ], + double Ax [ ], + KLU_symbolic *Symbolic, + KLU_numeric *Numeric, + KLU_common *Common +) +{ + double xj, Xmax, csum, anorm, ainv_norm, est_old, est_new, abs_value ; + Entry *Udiag, *Aentry, *X, *S ; + Int i, j, jmax, jnew, pend, n ; +#ifndef COMPLEX + Int unchanged ; +#endif + + /* ---------------------------------------------------------------------- */ + /* check inputs */ + /* ---------------------------------------------------------------------- */ + + if (Common == NULL) + { + return (FALSE) ; + } + if (Symbolic == NULL || Ap == NULL || Ax == NULL) + { + Common->status = KLU_INVALID ; + return (FALSE) ; + } + abs_value = 0 ; + if (Numeric == NULL) + { + /* treat this as a singular matrix */ + Common->condest = 1 / abs_value ; + Common->status = KLU_SINGULAR ; + return (TRUE) ; + } + Common->status = KLU_OK ; + + /* ---------------------------------------------------------------------- */ + /* get inputs */ + /* ---------------------------------------------------------------------- */ + + n = Symbolic->n ; + Udiag = Numeric->Udiag ; + + /* ---------------------------------------------------------------------- */ + /* check if diagonal of U has a zero on it */ + /* ---------------------------------------------------------------------- */ + + for (i = 0 ; i < n ; i++) + { + ABS (abs_value, Udiag [i]) ; + if (SCALAR_IS_ZERO (abs_value)) + { + Common->condest = 1 / abs_value ; + Common->status = KLU_SINGULAR ; + return (TRUE) ; + } + } + + /* ---------------------------------------------------------------------- */ + /* compute 1-norm (maximum column sum) of the matrix */ + /* ---------------------------------------------------------------------- */ + + anorm = 0.0 ; + Aentry = (Entry *) Ax ; + for (i = 0 ; i < n ; i++) + { + pend = Ap [i + 1] ; + csum = 0.0 ; + for (j = Ap [i] ; j < pend ; j++) + { + ABS (abs_value, Aentry [j]) ; + csum += abs_value ; + } + if (csum > anorm) + { + anorm = csum ; + } + } + + /* ---------------------------------------------------------------------- */ + /* compute estimate of 1-norm of inv (A) */ + /* ---------------------------------------------------------------------- */ + + /* get workspace (size 2*n Entry's) */ + X = Numeric->Xwork ; /* size n space used in KLU_solve, tsolve */ + X += n ; /* X is size n */ + S = X + n ; /* S is size n */ + + for (i = 0 ; i < n ; i++) + { + CLEAR (S [i]) ; + CLEAR (X [i]) ; + REAL (X [i]) = 1.0 / ((double) n) ; + } + jmax = 0 ; + + ainv_norm = 0.0 ; + for (i = 0 ; i < 5 ; i++) + { + if (i > 0) + { + /* X [jmax] is the largest entry in X */ + for (j = 0 ; j < n ; j++) + { + /* X [j] = 0 ;*/ + CLEAR (X [j]) ; + } + REAL (X [jmax]) = 1 ; + } + + KLU_solve (Symbolic, Numeric, n, 1, (double *) X, Common) ; + est_old = ainv_norm ; + ainv_norm = 0.0 ; + + for (j = 0 ; j < n ; j++) + { + /* ainv_norm += ABS (X [j]) ;*/ + ABS (abs_value, X [j]) ; + ainv_norm += abs_value ; + } + +#ifndef COMPLEX + unchanged = TRUE ; + + for (j = 0 ; j < n ; j++) + { + double s = (X [j] >= 0) ? 1 : -1 ; + if (s != (Int) REAL (S [j])) + { + S [j] = s ; + unchanged = FALSE ; + } + } + + if (i > 0 && (ainv_norm <= est_old || unchanged)) + { + break ; + } +#else + for (j = 0 ; j < n ; j++) + { + if (IS_NONZERO (X [j])) + { + ABS (abs_value, X [j]) ; + SCALE_DIV_ASSIGN (S [j], X [j], abs_value) ; + } + else + { + CLEAR (S [j]) ; + REAL (S [j]) = 1 ; + } + } + + if (i > 0 && ainv_norm <= est_old) + { + break ; + } +#endif + + for (j = 0 ; j < n ; j++) + { + X [j] = S [j] ; + } + +#ifndef COMPLEX + /* do a transpose solve */ + KLU_tsolve (Symbolic, Numeric, n, 1, X, Common) ; +#else + /* do a conjugate transpose solve */ + KLU_tsolve (Symbolic, Numeric, n, 1, (double *) X, 1, Common) ; +#endif + + /* jnew = the position of the largest entry in X */ + jnew = 0 ; + Xmax = 0 ; + for (j = 0 ; j < n ; j++) + { + /* xj = ABS (X [j]) ;*/ + ABS (xj, X [j]) ; + if (xj > Xmax) + { + Xmax = xj ; + jnew = j ; + } + } + if (i > 0 && jnew == jmax) + { + /* the position of the largest entry did not change + * from the previous iteration */ + break ; + } + jmax = jnew ; + } + + /* ---------------------------------------------------------------------- */ + /* compute another estimate of norm(inv(A),1), and take the largest one */ + /* ---------------------------------------------------------------------- */ + + for (j = 0 ; j < n ; j++) + { + CLEAR (X [j]) ; + if (j % 2) + { + REAL (X [j]) = 1 + ((double) j) / ((double) (n-1)) ; + } + else + { + REAL (X [j]) = -1 - ((double) j) / ((double) (n-1)) ; + } + } + + KLU_solve (Symbolic, Numeric, n, 1, (double *) X, Common) ; + + est_new = 0.0 ; + for (j = 0 ; j < n ; j++) + { + /* est_new += ABS (X [j]) ;*/ + ABS (abs_value, X [j]) ; + est_new += abs_value ; + } + est_new = 2 * est_new / (3 * n) ; + ainv_norm = MAX (est_new, ainv_norm) ; + + /* ---------------------------------------------------------------------- */ + /* compute estimate of condition number */ + /* ---------------------------------------------------------------------- */ + + Common->condest = ainv_norm * anorm ; + return (TRUE) ; +} + + +/* ========================================================================== */ +/* === KLU_flops ============================================================ */ +/* ========================================================================== */ + +/* Compute the flop count for the LU factorization (in Common->flops) */ + +Int KLU_flops /* return TRUE if successful, FALSE otherwise */ +( + KLU_symbolic *Symbolic, + KLU_numeric *Numeric, + KLU_common *Common +) +{ + double flops = 0 ; + Int *R, *Ui, *Uip, *Llen, *Ulen ; + Unit **LUbx ; + Unit *LU ; + Int k, ulen, p, nk, block, nblocks, k1 ; + + /* ---------------------------------------------------------------------- */ + /* check inputs */ + /* ---------------------------------------------------------------------- */ + + if (Common == NULL) + { + return (FALSE) ; + } + Common->flops = EMPTY ; + if (Numeric == NULL || Symbolic == NULL) + { + Common->status = KLU_INVALID ; + return (FALSE) ; + } + Common->status = KLU_OK ; + + /* ---------------------------------------------------------------------- */ + /* get the contents of the Symbolic object */ + /* ---------------------------------------------------------------------- */ + + R = Symbolic->R ; + nblocks = Symbolic->nblocks ; + + /* ---------------------------------------------------------------------- */ + /* get the contents of the Numeric object */ + /* ---------------------------------------------------------------------- */ + + LUbx = (Unit **) Numeric->LUbx ; + + /* ---------------------------------------------------------------------- */ + /* compute the flop count */ + /* ---------------------------------------------------------------------- */ + + for (block = 0 ; block < nblocks ; block++) + { + k1 = R [block] ; + nk = R [block+1] - k1 ; + if (nk > 1) + { + Llen = Numeric->Llen + k1 ; + Uip = Numeric->Uip + k1 ; + Ulen = Numeric->Ulen + k1 ; + LU = LUbx [block] ; + for (k = 0 ; k < nk ; k++) + { + /* compute kth column of U, and update kth column of A */ + GET_I_POINTER (LU, Uip, Ui, k) ; + ulen = Ulen [k] ; + for (p = 0 ; p < ulen ; p++) + { + flops += 2 * Llen [Ui [p]] ; + } + /* gather and divide by pivot to get kth column of L */ + flops += Llen [k] ; + } + } + } + Common->flops = flops ; + return (TRUE) ; +} + + +/* ========================================================================== */ +/* === KLU_rcond ============================================================ */ +/* ========================================================================== */ + +/* Compute a really cheap estimate of the reciprocal of the condition number, + * condition number, min(abs(diag(U))) / max(abs(diag(U))). If U has a zero + * pivot, or a NaN pivot, rcond will be zero. Takes O(n) time. + */ + +Int KLU_rcond /* return TRUE if successful, FALSE otherwise */ +( + KLU_symbolic *Symbolic, /* input, not modified */ + KLU_numeric *Numeric, /* input, not modified */ + KLU_common *Common /* result in Common->rcond */ +) +{ + double ukk, umin = 0, umax = 0 ; + Entry *Udiag ; + Int j, n ; + + /* ---------------------------------------------------------------------- */ + /* check inputs */ + /* ---------------------------------------------------------------------- */ + + if (Common == NULL) + { + return (FALSE) ; + } + if (Symbolic == NULL) + { + Common->status = KLU_INVALID ; + return (FALSE) ; + } + if (Numeric == NULL) + { + Common->rcond = 0 ; + Common->status = KLU_SINGULAR ; + return (TRUE) ; + } + Common->status = KLU_OK ; + + /* ---------------------------------------------------------------------- */ + /* compute rcond */ + /* ---------------------------------------------------------------------- */ + + n = Symbolic->n ; + Udiag = Numeric->Udiag ; + for (j = 0 ; j < n ; j++) + { + /* get the magnitude of the pivot */ + ABS (ukk, Udiag [j]) ; + if (SCALAR_IS_NAN (ukk) || SCALAR_IS_ZERO (ukk)) + { + /* if NaN, or zero, the rcond is zero */ + Common->rcond = 0 ; + Common->status = KLU_SINGULAR ; + return (TRUE) ; + } + if (j == 0) + { + /* first pivot entry */ + umin = ukk ; + umax = ukk ; + } + else + { + /* subsequent pivots */ + umin = MIN (umin, ukk) ; + umax = MAX (umax, ukk) ; + } + } + + Common->rcond = umin / umax ; + if (SCALAR_IS_NAN (Common->rcond) || SCALAR_IS_ZERO (Common->rcond)) + { + /* this can occur if umin or umax are Inf or NaN */ + Common->rcond = 0 ; + Common->status = KLU_SINGULAR ; + } + return (TRUE) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_dump.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_dump.c new file mode 100644 index 0000000..8f55900 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_dump.c @@ -0,0 +1,147 @@ +/* ========================================================================== */ +/* === KLU_dump ============================================================= */ +/* ========================================================================== */ + +/* Debug routines for klu. Only used when NDEBUG is not defined at + * compile-time. + */ + +#include "klu_internal.h" + +#ifndef NDEBUG + +/* ========================================================================== */ +/* === KLU_valid ============================================================ */ +/* ========================================================================== */ + +/* Check if a column-form matrix is valid or not. The matrix A is + * n-by-n. The row indices of entries in column j are in + * Ai [Ap [j] ... Ap [j+1]-1]. Required conditions are: + * + * n >= 0 + * nz = Ap [n_col] >= 0 number of entries in the matrix + * Ap [0] == 0 + * Ap [j] <= Ap [j+1] for all j in the range 0 to n_col. + * row indices in Ai [Ap [j] ... Ap [j+1]-1] + * must be in the range 0 to n_row-1, + * and no duplicate entries can exist (duplicates not checked here). + * + * Not user-callable. Only used when debugging. + */ + +Int KLU_valid (Int n, Int Ap [ ], Int Ai [ ], Entry Ax [ ]) +{ + Int nz, j, p1, p2, i, p ; + PRINTF (("\ncolumn oriented matrix, n = %d\n", n)) ; + if (n <= 0) + { + PRINTF (("n must be >= 0: %d\n", n)) ; + return (FALSE) ; + } + nz = Ap [n] ; + if (Ap [0] != 0 || nz < 0) + { + /* column pointers must start at Ap [0] = 0, and Ap [n] must be >= 0 */ + PRINTF (("column 0 pointer bad or nz < 0\n")) ; + return (FALSE) ; + } + for (j = 0 ; j < n ; j++) + { + p1 = Ap [j] ; + p2 = Ap [j+1] ; + PRINTF (("\nColumn: %d p1: %d p2: %d\n", j, p1, p2)) ; + if (p1 > p2) + { + /* column pointers must be ascending */ + PRINTF (("column %d pointer bad\n", j)) ; + return (FALSE) ; + } + for (p = p1 ; p < p2 ; p++) + { + i = Ai [p] ; + PRINTF (("row: %d", i)) ; + if (i < 0 || i >= n) + { + /* row index out of range */ + PRINTF (("index out of range, col %d row %d\n", j, i)) ; + return (FALSE) ; + } + if (Ax != (Entry *) NULL) + { + PRINT_ENTRY (Ax [p]) ; + } + PRINTF (("\n")) ; + } + } + return (TRUE) ; +} + + +/* ========================================================================== */ +/* === KLU_valid_LU ========================================================= */ +/* ========================================================================== */ + +/* This function does the same validity tests as KLU_valid but for the + * LU factor storage format. The flag flag_test_start_ptr is used to + * test if Xip [0] = 0. This is not applicable for U. So when calling this + * function for U, the flag should be set to false. Only used when debugging. + */ + +Int KLU_valid_LU (Int n, Int flag_test_start_ptr, Int Xip [ ], + Int Xlen [ ], Unit LU [ ]) +{ + Int *Xi ; + Entry *Xx ; + Int j, p1, p2, i, p, len ; + + PRINTF (("\ncolumn oriented matrix, n = %d\n", n)) ; + if (n <= 0) + { + PRINTF (("n must be >= 0: %d\n", n)) ; + return (FALSE) ; + } + if (flag_test_start_ptr && Xip [0] != 0) + { + /* column pointers must start at Xip [0] = 0*/ + PRINTF (("column 0 pointer bad\n")) ; + return (FALSE) ; + } + + for (j = 0 ; j < n ; j++) + { + p1 = Xip [j] ; + PRINTF (("\nColumn of factor: %d p1: %d ", j, p1)) ; + if (j < n-1) + { + p2 = Xip [j+1] ; + PRINTF (("p2: %d ", p2)) ; + if (p1 > p2) + { + /* column pointers must be ascending */ + PRINTF (("column %d pointer bad\n", j)) ; + return (FALSE) ; + } + } + PRINTF (("\n")) ; + GET_POINTER (LU, Xip, Xlen, Xi, Xx, j, len) ; + for (p = 0 ; p < len ; p++) + { + i = Xi [p] ; + PRINTF (("row: %d", i)) ; + if (i < 0 || i >= n) + { + /* row index out of range */ + PRINTF (("index out of range, col %d row %d\n", j, i)) ; + return (FALSE) ; + } + if (Xx != (Entry *) NULL) + { + PRINT_ENTRY (Xx [p]) ; + } + PRINTF (("\n")) ; + } + } + + return (TRUE) ; +} +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_extract.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_extract.c new file mode 100644 index 0000000..b009828 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_extract.c @@ -0,0 +1,290 @@ +/* ========================================================================== */ +/* === KLU_extract ========================================================== */ +/* ========================================================================== */ + +/* Extract KLU factorization into conventional compressed-column matrices. + * If any output array is NULL, that part of the LU factorization is not + * extracted (this is not an error condition). + * + * nnz(L) = Numeric->lnz, nnz(U) = Numeric->unz, and nnz(F) = Numeric->Offp [n] + */ + +#include "klu_internal.h" + +Int KLU_extract /* returns TRUE if successful, FALSE otherwise */ +( + /* inputs: */ + KLU_numeric *Numeric, + KLU_symbolic *Symbolic, + + /* outputs, all of which must be allocated on input */ + + /* L */ + Int *Lp, /* size n+1 */ + Int *Li, /* size nnz(L) */ + double *Lx, /* size nnz(L) */ +#ifdef COMPLEX + double *Lz, /* size nnz(L) for the complex case, ignored if real */ +#endif + + /* U */ + Int *Up, /* size n+1 */ + Int *Ui, /* size nnz(U) */ + double *Ux, /* size nnz(U) */ +#ifdef COMPLEX + double *Uz, /* size nnz(U) for the complex case, ignored if real */ +#endif + + /* F */ + Int *Fp, /* size n+1 */ + Int *Fi, /* size nnz(F) */ + double *Fx, /* size nnz(F) */ +#ifdef COMPLEX + double *Fz, /* size nnz(F) for the complex case, ignored if real */ +#endif + + /* P, row permutation */ + Int *P, /* size n */ + + /* Q, column permutation */ + Int *Q, /* size n */ + + /* Rs, scale factors */ + double *Rs, /* size n */ + + /* R, block boundaries */ + Int *R, /* size nblocks+1 */ + + KLU_common *Common +) +{ + Int *Lip, *Llen, *Uip, *Ulen, *Li2, *Ui2 ; + Unit *LU ; + Entry *Lx2, *Ux2, *Ukk ; + Int i, k, block, nblocks, n, nz, k1, k2, nk, len, kk, p ; + + if (Common == NULL) + { + return (FALSE) ; + } + + if (Symbolic == NULL || Numeric == NULL) + { + Common->status = KLU_INVALID ; + return (FALSE) ; + } + + Common->status = KLU_OK ; + n = Symbolic->n ; + nblocks = Symbolic->nblocks ; + + /* ---------------------------------------------------------------------- */ + /* extract scale factors */ + /* ---------------------------------------------------------------------- */ + + if (Rs != NULL) + { + if (Numeric->Rs != NULL) + { + for (i = 0 ; i < n ; i++) + { + Rs [i] = Numeric->Rs [i] ; + } + } + else + { + /* no scaling */ + for (i = 0 ; i < n ; i++) + { + Rs [i] = 1 ; + } + } + } + + /* ---------------------------------------------------------------------- */ + /* extract block boundaries */ + /* ---------------------------------------------------------------------- */ + + if (R != NULL) + { + for (block = 0 ; block <= nblocks ; block++) + { + R [block] = Symbolic->R [block] ; + } + } + + /* ---------------------------------------------------------------------- */ + /* extract final row permutation */ + /* ---------------------------------------------------------------------- */ + + if (P != NULL) + { + for (k = 0 ; k < n ; k++) + { + P [k] = Numeric->Pnum [k] ; + } + } + + /* ---------------------------------------------------------------------- */ + /* extract column permutation */ + /* ---------------------------------------------------------------------- */ + + if (Q != NULL) + { + for (k = 0 ; k < n ; k++) + { + Q [k] = Symbolic->Q [k] ; + } + } + + /* ---------------------------------------------------------------------- */ + /* extract each block of L */ + /* ---------------------------------------------------------------------- */ + + if (Lp != NULL && Li != NULL && Lx != NULL +#ifdef COMPLEX + && Lz != NULL +#endif + ) + { + nz = 0 ; + for (block = 0 ; block < nblocks ; block++) + { + k1 = Symbolic->R [block] ; + k2 = Symbolic->R [block+1] ; + nk = k2 - k1 ; + if (nk == 1) + { + /* singleton block */ + Lp [k1] = nz ; + Li [nz] = k1 ; + Lx [nz] = 1 ; +#ifdef COMPLEX + Lz [nz] = 0 ; +#endif + nz++ ; + } + else + { + /* non-singleton block */ + LU = Numeric->LUbx [block] ; + Lip = Numeric->Lip + k1 ; + Llen = Numeric->Llen + k1 ; + for (kk = 0 ; kk < nk ; kk++) + { + Lp [k1+kk] = nz ; + /* add the unit diagonal entry */ + Li [nz] = k1 + kk ; + Lx [nz] = 1 ; +#ifdef COMPLEX + Lz [nz] = 0 ; +#endif + nz++ ; + GET_POINTER (LU, Lip, Llen, Li2, Lx2, kk, len) ; + for (p = 0 ; p < len ; p++) + { + Li [nz] = k1 + Li2 [p] ; + Lx [nz] = REAL (Lx2 [p]) ; +#ifdef COMPLEX + Lz [nz] = IMAG (Lx2 [p]) ; +#endif + nz++ ; + } + } + } + } + Lp [n] = nz ; + ASSERT (nz == Numeric->lnz) ; + } + + /* ---------------------------------------------------------------------- */ + /* extract each block of U */ + /* ---------------------------------------------------------------------- */ + + if (Up != NULL && Ui != NULL && Ux != NULL +#ifdef COMPLEX + && Uz != NULL +#endif + ) + { + nz = 0 ; + for (block = 0 ; block < nblocks ; block++) + { + k1 = Symbolic->R [block] ; + k2 = Symbolic->R [block+1] ; + nk = k2 - k1 ; + Ukk = ((Entry *) Numeric->Udiag) + k1 ; + if (nk == 1) + { + /* singleton block */ + Up [k1] = nz ; + Ui [nz] = k1 ; + Ux [nz] = REAL (Ukk [0]) ; +#ifdef COMPLEX + Uz [nz] = IMAG (Ukk [0]) ; +#endif + nz++ ; + } + else + { + /* non-singleton block */ + LU = Numeric->LUbx [block] ; + Uip = Numeric->Uip + k1 ; + Ulen = Numeric->Ulen + k1 ; + for (kk = 0 ; kk < nk ; kk++) + { + Up [k1+kk] = nz ; + GET_POINTER (LU, Uip, Ulen, Ui2, Ux2, kk, len) ; + for (p = 0 ; p < len ; p++) + { + Ui [nz] = k1 + Ui2 [p] ; + Ux [nz] = REAL (Ux2 [p]) ; +#ifdef COMPLEX + Uz [nz] = IMAG (Ux2 [p]) ; +#endif + nz++ ; + } + /* add the diagonal entry */ + Ui [nz] = k1 + kk ; + Ux [nz] = REAL (Ukk [kk]) ; +#ifdef COMPLEX + Uz [nz] = IMAG (Ukk [kk]) ; +#endif + nz++ ; + } + } + } + Up [n] = nz ; + ASSERT (nz == Numeric->unz) ; + } + + /* ---------------------------------------------------------------------- */ + /* extract the off-diagonal blocks, F */ + /* ---------------------------------------------------------------------- */ + + if (Fp != NULL && Fi != NULL && Fx != NULL +#ifdef COMPLEX + && Fz != NULL +#endif + ) + { + for (k = 0 ; k <= n ; k++) + { + Fp [k] = Numeric->Offp [k] ; + } + nz = Fp [n] ; + for (k = 0 ; k < nz ; k++) + { + Fi [k] = Numeric->Offi [k] ; + } + for (k = 0 ; k < nz ; k++) + { + Fx [k] = REAL (((Entry *) Numeric->Offx) [k]) ; +#ifdef COMPLEX + Fz [k] = IMAG (((Entry *) Numeric->Offx) [k]) ; +#endif + } + } + + return (TRUE) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_factor.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_factor.c new file mode 100644 index 0000000..8a410e7 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_factor.c @@ -0,0 +1,543 @@ +/* ========================================================================== */ +/* === KLU_factor =========================================================== */ +/* ========================================================================== */ + +/* Factor the matrix, after ordering and analyzing it with KLU_analyze + * or KLU_analyze_given. + */ + +#include "klu_internal.h" + +/* ========================================================================== */ +/* === KLU_factor2 ========================================================== */ +/* ========================================================================== */ + +static void factor2 +( + /* inputs, not modified */ + Int Ap [ ], /* size n+1, column pointers */ + Int Ai [ ], /* size nz, row indices */ + Entry Ax [ ], + KLU_symbolic *Symbolic, + + /* inputs, modified on output: */ + KLU_numeric *Numeric, + KLU_common *Common +) +{ + double lsize ; + double *Lnz, *Rs ; + Int *P, *Q, *R, *Pnum, *Offp, *Offi, *Pblock, *Pinv, *Iwork, + *Lip, *Uip, *Llen, *Ulen ; + Entry *Offx, *X, s, *Udiag ; + Unit **LUbx ; + Int k1, k2, nk, k, block, oldcol, pend, oldrow, n, lnz, unz, p, newrow, + nblocks, poff, nzoff, lnz_block, unz_block, scale, max_lnz_block, + max_unz_block ; + + /* ---------------------------------------------------------------------- */ + /* initializations */ + /* ---------------------------------------------------------------------- */ + + /* get the contents of the Symbolic object */ + n = Symbolic->n ; + P = Symbolic->P ; + Q = Symbolic->Q ; + R = Symbolic->R ; + Lnz = Symbolic->Lnz ; + nblocks = Symbolic->nblocks ; + nzoff = Symbolic->nzoff ; + + Pnum = Numeric->Pnum ; + Offp = Numeric->Offp ; + Offi = Numeric->Offi ; + Offx = (Entry *) Numeric->Offx ; + + Lip = Numeric->Lip ; + Uip = Numeric->Uip ; + Llen = Numeric->Llen ; + Ulen = Numeric->Ulen ; + LUbx = (Unit **) Numeric->LUbx ; + Udiag = Numeric->Udiag ; + + Rs = Numeric->Rs ; + Pinv = Numeric->Pinv ; + X = (Entry *) Numeric->Xwork ; /* X is of size n */ + Iwork = Numeric->Iwork ; /* 5*maxblock for KLU_factor */ + /* 1*maxblock for Pblock */ + Pblock = Iwork + 5*((size_t) Symbolic->maxblock) ; + Common->nrealloc = 0 ; + scale = Common->scale ; + max_lnz_block = 1 ; + max_unz_block = 1 ; + + /* compute the inverse of P from symbolic analysis. Will be updated to + * become the inverse of the numerical factorization when the factorization + * is done, for use in KLU_refactor */ +#ifndef NDEBUG + for (k = 0 ; k < n ; k++) + { + Pinv [k] = EMPTY ; + } +#endif + for (k = 0 ; k < n ; k++) + { + ASSERT (P [k] >= 0 && P [k] < n) ; + Pinv [P [k]] = k ; + } +#ifndef NDEBUG + for (k = 0 ; k < n ; k++) ASSERT (Pinv [k] != EMPTY) ; +#endif + + lnz = 0 ; + unz = 0 ; + Common->noffdiag = 0 ; + Offp [0] = 0 ; + + /* ---------------------------------------------------------------------- */ + /* optionally check input matrix and compute scale factors */ + /* ---------------------------------------------------------------------- */ + + if (scale >= 0) + { + /* use Pnum as workspace. NOTE: scale factors are not yet permuted + * according to the final pivot row ordering, so Rs [oldrow] is the + * scale factor for A (oldrow,:), for the user's matrix A. Pnum is + * used as workspace in KLU_scale. When the factorization is done, + * the scale factors are permuted according to the final pivot row + * permutation, so that Rs [k] is the scale factor for the kth row of + * A(p,q) where p and q are the final row and column permutations. */ + KLU_scale (scale, n, Ap, Ai, (double *) Ax, Rs, Pnum, Common) ; + if (Common->status < KLU_OK) + { + /* matrix is invalid */ + return ; + } + } + +#ifndef NDEBUG + if (scale > 0) + { + for (k = 0 ; k < n ; k++) PRINTF (("Rs [%d] %g\n", k, Rs [k])) ; + } +#endif + + /* ---------------------------------------------------------------------- */ + /* factor each block using klu */ + /* ---------------------------------------------------------------------- */ + + for (block = 0 ; block < nblocks ; block++) + { + + /* ------------------------------------------------------------------ */ + /* the block is from rows/columns k1 to k2-1 */ + /* ------------------------------------------------------------------ */ + + k1 = R [block] ; + k2 = R [block+1] ; + nk = k2 - k1 ; + PRINTF (("FACTOR BLOCK %d, k1 %d k2-1 %d nk %d\n", block, k1,k2-1,nk)) ; + + if (nk == 1) + { + + /* -------------------------------------------------------------- */ + /* singleton case */ + /* -------------------------------------------------------------- */ + + poff = Offp [k1] ; + oldcol = Q [k1] ; + pend = Ap [oldcol+1] ; + CLEAR (s) ; + + if (scale <= 0) + { + /* no scaling */ + for (p = Ap [oldcol] ; p < pend ; p++) + { + oldrow = Ai [p] ; + newrow = Pinv [oldrow] ; + if (newrow < k1) + { + Offi [poff] = oldrow ; + Offx [poff] = Ax [p] ; + poff++ ; + } + else + { + ASSERT (newrow == k1) ; + PRINTF (("singleton block %d", block)) ; + PRINT_ENTRY (Ax [p]) ; + s = Ax [p] ; + } + } + } + else + { + /* row scaling. NOTE: scale factors are not yet permuted + * according to the pivot row permutation, so Rs [oldrow] is + * used below. When the factorization is done, the scale + * factors are permuted, so that Rs [newrow] will be used in + * klu_solve, klu_tsolve, and klu_rgrowth */ + for (p = Ap [oldcol] ; p < pend ; p++) + { + oldrow = Ai [p] ; + newrow = Pinv [oldrow] ; + if (newrow < k1) + { + Offi [poff] = oldrow ; + /* Offx [poff] = Ax [p] / Rs [oldrow] ; */ + SCALE_DIV_ASSIGN (Offx [poff], Ax [p], Rs [oldrow]) ; + poff++ ; + } + else + { + ASSERT (newrow == k1) ; + PRINTF (("singleton block %d ", block)) ; + PRINT_ENTRY (Ax[p]) ; + SCALE_DIV_ASSIGN (s, Ax [p], Rs [oldrow]) ; + } + } + } + + Udiag [k1] = s ; + + if (IS_ZERO (s)) + { + /* singular singleton */ + Common->status = KLU_SINGULAR ; + Common->numerical_rank = k1 ; + Common->singular_col = oldcol ; + if (Common->halt_if_singular) + { + return ; + } + } + + Offp [k1+1] = poff ; + Pnum [k1] = P [k1] ; + lnz++ ; + unz++ ; + + } + else + { + + /* -------------------------------------------------------------- */ + /* construct and factorize the kth block */ + /* -------------------------------------------------------------- */ + + if (Lnz [block] < 0) + { + /* COLAMD was used - no estimate of fill-in */ + /* use 10 times the nnz in A, plus n */ + lsize = -(Common->initmem) ; + } + else + { + lsize = Common->initmem_amd * Lnz [block] + nk ; + } + + /* allocates 1 arrays: LUbx [block] */ + Numeric->LUsize [block] = KLU_kernel_factor (nk, Ap, Ai, Ax, Q, + lsize, &LUbx [block], Udiag + k1, Llen + k1, Ulen + k1, + Lip + k1, Uip + k1, Pblock, &lnz_block, &unz_block, + X, Iwork, k1, Pinv, Rs, Offp, Offi, Offx, Common) ; + + if (Common->status < KLU_OK || + (Common->status == KLU_SINGULAR && Common->halt_if_singular)) + { + /* out of memory, invalid inputs, or singular */ + return ; + } + + PRINTF (("\n----------------------- L %d:\n", block)) ; + ASSERT (KLU_valid_LU (nk, TRUE, Lip+k1, Llen+k1, LUbx [block])) ; + PRINTF (("\n----------------------- U %d:\n", block)) ; + ASSERT (KLU_valid_LU (nk, FALSE, Uip+k1, Ulen+k1, LUbx [block])) ; + + /* -------------------------------------------------------------- */ + /* get statistics */ + /* -------------------------------------------------------------- */ + + lnz += lnz_block ; + unz += unz_block ; + max_lnz_block = MAX (max_lnz_block, lnz_block) ; + max_unz_block = MAX (max_unz_block, unz_block) ; + + if (Lnz [block] == EMPTY) + { + /* revise estimate for subsequent factorization */ + Lnz [block] = MAX (lnz_block, unz_block) ; + } + + /* -------------------------------------------------------------- */ + /* combine the klu row ordering with the symbolic pre-ordering */ + /* -------------------------------------------------------------- */ + + PRINTF (("Pnum, 1-based:\n")) ; + for (k = 0 ; k < nk ; k++) + { + ASSERT (k + k1 < n) ; + ASSERT (Pblock [k] + k1 < n) ; + Pnum [k + k1] = P [Pblock [k] + k1] ; + PRINTF (("Pnum (%d + %d + 1 = %d) = %d + 1 = %d\n", + k, k1, k+k1+1, Pnum [k+k1], Pnum [k+k1]+1)) ; + } + + /* the local pivot row permutation Pblock is no longer needed */ + } + } + ASSERT (nzoff == Offp [n]) ; + PRINTF (("\n------------------- Off diagonal entries:\n")) ; + ASSERT (KLU_valid (n, Offp, Offi, Offx)) ; + + Numeric->lnz = lnz ; + Numeric->unz = unz ; + Numeric->max_lnz_block = max_lnz_block ; + Numeric->max_unz_block = max_unz_block ; + + /* compute the inverse of Pnum */ +#ifndef NDEBUG + for (k = 0 ; k < n ; k++) + { + Pinv [k] = EMPTY ; + } +#endif + for (k = 0 ; k < n ; k++) + { + ASSERT (Pnum [k] >= 0 && Pnum [k] < n) ; + Pinv [Pnum [k]] = k ; + } +#ifndef NDEBUG + for (k = 0 ; k < n ; k++) ASSERT (Pinv [k] != EMPTY) ; +#endif + + /* permute scale factors Rs according to pivotal row order */ + if (scale > 0) + { + for (k = 0 ; k < n ; k++) + { + REAL (X [k]) = Rs [Pnum [k]] ; + } + for (k = 0 ; k < n ; k++) + { + Rs [k] = REAL (X [k]) ; + } + } + + PRINTF (("\n------------------- Off diagonal entries, old:\n")) ; + ASSERT (KLU_valid (n, Offp, Offi, Offx)) ; + + /* apply the pivot row permutations to the off-diagonal entries */ + for (p = 0 ; p < nzoff ; p++) + { + ASSERT (Offi [p] >= 0 && Offi [p] < n) ; + Offi [p] = Pinv [Offi [p]] ; + } + + PRINTF (("\n------------------- Off diagonal entries, new:\n")) ; + ASSERT (KLU_valid (n, Offp, Offi, Offx)) ; + +#ifndef NDEBUG + { + PRINTF (("\n ############# KLU_BTF_FACTOR done, nblocks %d\n",nblocks)); + Entry ss, *Udiag = Numeric->Udiag ; + for (block = 0 ; block < nblocks && Common->status == KLU_OK ; block++) + { + k1 = R [block] ; + k2 = R [block+1] ; + nk = k2 - k1 ; + PRINTF (("\n======================KLU_factor output: k1 %d k2 %d nk %d\n",k1,k2,nk)) ; + if (nk == 1) + { + PRINTF (("singleton ")) ; + /* ENTRY_PRINT (singleton [block]) ; */ + ss = Udiag [k1] ; + PRINT_ENTRY (ss) ; + } + else + { + Int *Lip, *Uip, *Llen, *Ulen ; + Unit *LU ; + Lip = Numeric->Lip + k1 ; + Llen = Numeric->Llen + k1 ; + LU = (Unit *) Numeric->LUbx [block] ; + PRINTF (("\n---- L block %d\n", block)); + ASSERT (KLU_valid_LU (nk, TRUE, Lip, Llen, LU)) ; + Uip = Numeric->Uip + k1 ; + Ulen = Numeric->Ulen + k1 ; + PRINTF (("\n---- U block %d\n", block)) ; + ASSERT (KLU_valid_LU (nk, FALSE, Uip, Ulen, LU)) ; + } + } + } +#endif +} + + + +/* ========================================================================== */ +/* === KLU_factor =========================================================== */ +/* ========================================================================== */ + +KLU_numeric *KLU_factor /* returns NULL if error, or a valid + KLU_numeric object if successful */ +( + /* --- inputs --- */ + Int Ap [ ], /* size n+1, column pointers */ + Int Ai [ ], /* size nz, row indices */ + double Ax [ ], + KLU_symbolic *Symbolic, + /* -------------- */ + KLU_common *Common +) +{ + Int n, nzoff, nblocks, maxblock, k, ok = TRUE ; + KLU_numeric *Numeric ; + size_t n1, nzoff1, s, b6, n3 ; + + if (Common == NULL) + { + return (NULL) ; + } + Common->status = KLU_OK ; + Common->numerical_rank = EMPTY ; + Common->singular_col = EMPTY ; + + /* ---------------------------------------------------------------------- */ + /* get the contents of the Symbolic object */ + /* ---------------------------------------------------------------------- */ + + /* check for a valid Symbolic object */ + if (Symbolic == NULL) + { + Common->status = KLU_INVALID ; + return (NULL) ; + } + + n = Symbolic->n ; + nzoff = Symbolic->nzoff ; + nblocks = Symbolic->nblocks ; + maxblock = Symbolic->maxblock ; + PRINTF (("KLU_factor: n %d nzoff %d nblocks %d maxblock %d\n", + n, nzoff, nblocks, maxblock)) ; + + /* ---------------------------------------------------------------------- */ + /* get control parameters and make sure they are in the proper range */ + /* ---------------------------------------------------------------------- */ + + Common->initmem_amd = MAX (1.0, Common->initmem_amd) ; + Common->initmem = MAX (1.0, Common->initmem) ; + Common->tol = MIN (Common->tol, 1.0) ; + Common->tol = MAX (0.0, Common->tol) ; + Common->memgrow = MAX (1.0, Common->memgrow) ; + + /* ---------------------------------------------------------------------- */ + /* allocate the Numeric object */ + /* ---------------------------------------------------------------------- */ + + /* this will not cause size_t overflow (already checked by KLU_symbolic) */ + n1 = ((size_t) n) + 1 ; + nzoff1 = ((size_t) nzoff) + 1 ; + + Numeric = KLU_malloc (sizeof (KLU_numeric), 1, Common) ; + if (Common->status < KLU_OK) + { + /* out of memory */ + Common->status = KLU_OUT_OF_MEMORY ; + return (NULL) ; + } + Numeric->n = n ; + Numeric->nblocks = nblocks ; + Numeric->nzoff = nzoff ; + Numeric->Pnum = KLU_malloc (n, sizeof (Int), Common) ; + Numeric->Offp = KLU_malloc (n1, sizeof (Int), Common) ; + Numeric->Offi = KLU_malloc (nzoff1, sizeof (Int), Common) ; + Numeric->Offx = KLU_malloc (nzoff1, sizeof (Entry), Common) ; + + Numeric->Lip = KLU_malloc (n, sizeof (Int), Common) ; + Numeric->Uip = KLU_malloc (n, sizeof (Int), Common) ; + Numeric->Llen = KLU_malloc (n, sizeof (Int), Common) ; + Numeric->Ulen = KLU_malloc (n, sizeof (Int), Common) ; + + Numeric->LUsize = KLU_malloc (nblocks, sizeof (size_t), Common) ; + + Numeric->LUbx = KLU_malloc (nblocks, sizeof (Unit *), Common) ; + if (Numeric->LUbx != NULL) + { + for (k = 0 ; k < nblocks ; k++) + { + Numeric->LUbx [k] = NULL ; + } + } + + Numeric->Udiag = KLU_malloc (n, sizeof (Entry), Common) ; + + if (Common->scale > 0) + { + Numeric->Rs = KLU_malloc (n, sizeof (double), Common) ; + } + else + { + /* no scaling */ + Numeric->Rs = NULL ; + } + + Numeric->Pinv = KLU_malloc (n, sizeof (Int), Common) ; + + /* allocate permanent workspace for factorization and solve. Note that the + * solver will use an Xwork of size 4n, whereas the factorization codes use + * an Xwork of size n and integer space (Iwork) of size 6n. KLU_condest + * uses an Xwork of size 2n. Total size is: + * + * n*sizeof(Entry) + max (6*maxblock*sizeof(Int), 3*n*sizeof(Entry)) + */ + s = KLU_mult_size_t (n, sizeof (Entry), &ok) ; + n3 = KLU_mult_size_t (n, 3 * sizeof (Entry), &ok) ; + b6 = KLU_mult_size_t (maxblock, 6 * sizeof (Int), &ok) ; + Numeric->worksize = KLU_add_size_t (s, MAX (n3, b6), &ok) ; + Numeric->Work = KLU_malloc (Numeric->worksize, 1, Common) ; + Numeric->Xwork = Numeric->Work ; + Numeric->Iwork = (Int *) ((Entry *) Numeric->Xwork + n) ; + if (!ok || Common->status < KLU_OK) + { + /* out of memory or problem too large */ + Common->status = ok ? KLU_OUT_OF_MEMORY : KLU_TOO_LARGE ; + KLU_free_numeric (&Numeric, Common) ; + return (NULL) ; + } + + /* ---------------------------------------------------------------------- */ + /* factorize the blocks */ + /* ---------------------------------------------------------------------- */ + + factor2 (Ap, Ai, (Entry *) Ax, Symbolic, Numeric, Common) ; + + /* ---------------------------------------------------------------------- */ + /* return or free the Numeric object */ + /* ---------------------------------------------------------------------- */ + + if (Common->status < KLU_OK) + { + /* out of memory or inputs invalid */ + KLU_free_numeric (&Numeric, Common) ; + } + else if (Common->status == KLU_SINGULAR) + { + if (Common->halt_if_singular) + { + /* Matrix is singular, and the Numeric object is only partially + * defined because we halted early. This is the default case for + * a singular matrix. */ + KLU_free_numeric (&Numeric, Common) ; + } + } + else if (Common->status == KLU_OK) + { + /* successful non-singular factorization */ + Common->numerical_rank = n ; + Common->singular_col = n ; + } + return (Numeric) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_free_numeric.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_free_numeric.c new file mode 100644 index 0000000..cd4f3bd --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_free_numeric.c @@ -0,0 +1,71 @@ +/* ========================================================================== */ +/* === KLU_free_numeric ===================================================== */ +/* ========================================================================== */ + +/* Free the KLU Numeric object. */ + +#include "klu_internal.h" + +Int KLU_free_numeric +( + KLU_numeric **NumericHandle, + KLU_common *Common +) +{ + KLU_numeric *Numeric ; + Unit **LUbx ; + size_t *LUsize ; + Int block, n, nzoff, nblocks ; + + if (Common == NULL) + { + return (FALSE) ; + } + if (NumericHandle == NULL || *NumericHandle == NULL) + { + return (TRUE) ; + } + + Numeric = *NumericHandle ; + + n = Numeric->n ; + nzoff = Numeric->nzoff ; + nblocks = Numeric->nblocks ; + LUsize = Numeric->LUsize ; + + LUbx = (Unit **) Numeric->LUbx ; + if (LUbx != NULL) + { + for (block = 0 ; block < nblocks ; block++) + { + KLU_free (LUbx [block], LUsize ? LUsize [block] : 0, + sizeof (Unit), Common) ; + } + } + + KLU_free (Numeric->Pnum, n, sizeof (Int), Common) ; + KLU_free (Numeric->Offp, n+1, sizeof (Int), Common) ; + KLU_free (Numeric->Offi, nzoff+1, sizeof (Int), Common) ; + KLU_free (Numeric->Offx, nzoff+1, sizeof (Entry), Common) ; + + KLU_free (Numeric->Lip, n, sizeof (Int), Common) ; + KLU_free (Numeric->Llen, n, sizeof (Int), Common) ; + KLU_free (Numeric->Uip, n, sizeof (Int), Common) ; + KLU_free (Numeric->Ulen, n, sizeof (Int), Common) ; + + KLU_free (Numeric->LUsize, nblocks, sizeof (size_t), Common) ; + + KLU_free (Numeric->LUbx, nblocks, sizeof (Unit *), Common) ; + + KLU_free (Numeric->Udiag, n, sizeof (Entry), Common) ; + + KLU_free (Numeric->Rs, n, sizeof (double), Common) ; + KLU_free (Numeric->Pinv, n, sizeof (Int), Common) ; + + KLU_free (Numeric->Work, Numeric->worksize, 1, Common) ; + + KLU_free (Numeric, 1, sizeof (KLU_numeric), Common) ; + + *NumericHandle = NULL ; + return (TRUE) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_free_symbolic.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_free_symbolic.c new file mode 100644 index 0000000..20b4000 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_free_symbolic.c @@ -0,0 +1,34 @@ +/* ========================================================================== */ +/* === KLU_free_symbolic ==================================================== */ +/* ========================================================================== */ + +/* Free the KLU Symbolic object. */ + +#include "klu_internal.h" + +Int KLU_free_symbolic +( + KLU_symbolic **SymbolicHandle, + KLU_common *Common +) +{ + KLU_symbolic *Symbolic ; + Int n ; + if (Common == NULL) + { + return (FALSE) ; + } + if (SymbolicHandle == NULL || *SymbolicHandle == NULL) + { + return (TRUE) ; + } + Symbolic = *SymbolicHandle ; + n = Symbolic->n ; + KLU_free (Symbolic->P, n, sizeof (Int), Common) ; + KLU_free (Symbolic->Q, n, sizeof (Int), Common) ; + KLU_free (Symbolic->R, n+1, sizeof (Int), Common) ; + KLU_free (Symbolic->Lnz, n, sizeof (double), Common) ; + KLU_free (Symbolic, 1, sizeof (KLU_symbolic), Common) ; + *SymbolicHandle = NULL ; + return (TRUE) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_kernel.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_kernel.c new file mode 100644 index 0000000..c3a78b4 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_kernel.c @@ -0,0 +1,1010 @@ +/* ========================================================================== */ +/* === KLU_kernel =========================================================== */ +/* ========================================================================== */ + +/* Sparse left-looking LU factorization, with partial pivoting. Based on + * Gilbert & Peierl's method, with a non-recursive DFS and with Eisenstat & + * Liu's symmetric pruning. No user-callable routines are in this file. + */ + +#include "klu_internal.h" + +/* ========================================================================== */ +/* === dfs ================================================================== */ +/* ========================================================================== */ + +/* Does a depth-first-search, starting at node j. */ + +static Int dfs +( + /* input, not modified on output: */ + Int j, /* node at which to start the DFS */ + Int k, /* mark value, for the Flag array */ + Int Pinv [ ], /* Pinv [i] = k if row i is kth pivot row, or EMPTY if + * row i is not yet pivotal. */ + Int Llen [ ], /* size n, Llen [k] = # nonzeros in column k of L */ + Int Lip [ ], /* size n, Lip [k] is position in LU of column k of L */ + + /* workspace, not defined on input or output */ + Int Stack [ ], /* size n */ + + /* input/output: */ + Int Flag [ ], /* Flag [i] == k means i is marked */ + Int Lpend [ ], /* for symmetric pruning */ + Int top, /* top of stack on input*/ + Unit LU [], + Int *Lik, /* Li row index array of the kth column */ + Int *plength, + + /* other, not defined on input or output */ + Int Ap_pos [ ] /* keeps track of position in adj list during DFS */ +) +{ + Int i, pos, jnew, head, l_length ; + Int *Li ; + + l_length = *plength ; + + head = 0 ; + Stack [0] = j ; + ASSERT (Flag [j] != k) ; + + while (head >= 0) + { + j = Stack [head] ; + jnew = Pinv [j] ; + ASSERT (jnew >= 0 && jnew < k) ; /* j is pivotal */ + + if (Flag [j] != k) /* a node is not yet visited */ + { + /* first time that j has been visited */ + Flag [j] = k ; + PRINTF (("[ start dfs at %d : new %d\n", j, jnew)) ; + /* set Ap_pos [head] to one past the last entry in col j to scan */ + Ap_pos [head] = + (Lpend [jnew] == EMPTY) ? Llen [jnew] : Lpend [jnew] ; + } + + /* add the adjacent nodes to the recursive stack by iterating through + * until finding another non-visited pivotal node */ + Li = (Int *) (LU + Lip [jnew]) ; + for (pos = --Ap_pos [head] ; pos >= 0 ; --pos) + { + i = Li [pos] ; + if (Flag [i] != k) + { + /* node i is not yet visited */ + if (Pinv [i] >= 0) + { + /* keep track of where we left off in the scan of the + * adjacency list of node j so we can restart j where we + * left off. */ + Ap_pos [head] = pos ; + + /* node i is pivotal; push it onto the recursive stack + * and immediately break so we can recurse on node i. */ + Stack [++head] = i ; + break ; + } + else + { + /* node i is not pivotal (no outgoing edges). */ + /* Flag as visited and store directly into L, + * and continue with current node j. */ + Flag [i] = k ; + Lik [l_length] = i ; + l_length++ ; + } + } + } + + if (pos == -1) + { + /* if all adjacent nodes of j are already visited, pop j from + * recursive stack and push j onto output stack */ + head-- ; + Stack[--top] = j ; + PRINTF ((" end dfs at %d ] head : %d\n", j, head)) ; + } + } + + *plength = l_length ; + return (top) ; +} + + +/* ========================================================================== */ +/* === lsolve_symbolic ====================================================== */ +/* ========================================================================== */ + +/* Finds the pattern of x, for the solution of Lx=b */ + +static Int lsolve_symbolic +( + /* input, not modified on output: */ + Int n, /* L is n-by-n, where n >= 0 */ + Int k, /* also used as the mark value, for the Flag array */ + Int Ap [ ], + Int Ai [ ], + Int Q [ ], + Int Pinv [ ], /* Pinv [i] = k if i is kth pivot row, or EMPTY if row i + * is not yet pivotal. */ + + /* workspace, not defined on input or output */ + Int Stack [ ], /* size n */ + + /* workspace, defined on input and output */ + Int Flag [ ], /* size n. Initially, all of Flag [0..n-1] < k. After + * lsolve_symbolic is done, Flag [i] == k if i is in + * the pattern of the output, and Flag [0..n-1] <= k. */ + + /* other */ + Int Lpend [ ], /* for symmetric pruning */ + Int Ap_pos [ ], /* workspace used in dfs */ + + Unit LU [ ], /* LU factors (pattern and values) */ + Int lup, /* pointer to free space in LU */ + Int Llen [ ], /* size n, Llen [k] = # nonzeros in column k of L */ + Int Lip [ ], /* size n, Lip [k] is position in LU of column k of L */ + + /* ---- the following are only used in the BTF case --- */ + + Int k1, /* the block of A is from k1 to k2-1 */ + Int PSinv [ ] /* inverse of P from symbolic factorization */ +) +{ + Int *Lik ; + Int i, p, pend, oldcol, kglobal, top, l_length ; + + top = n ; + l_length = 0 ; + Lik = (Int *) (LU + lup); + + /* ---------------------------------------------------------------------- */ + /* BTF factorization of A (k1:k2-1, k1:k2-1) */ + /* ---------------------------------------------------------------------- */ + + kglobal = k + k1 ; /* column k of the block is col kglobal of A */ + oldcol = Q [kglobal] ; /* Q must be present for BTF case */ + pend = Ap [oldcol+1] ; + for (p = Ap [oldcol] ; p < pend ; p++) + { + i = PSinv [Ai [p]] - k1 ; + if (i < 0) continue ; /* skip entry outside the block */ + + /* (i,k) is an entry in the block. start a DFS at node i */ + PRINTF (("\n ===== DFS at node %d in b, inew: %d\n", i, Pinv [i])) ; + if (Flag [i] != k) + { + if (Pinv [i] >= 0) + { + top = dfs (i, k, Pinv, Llen, Lip, Stack, Flag, + Lpend, top, LU, Lik, &l_length, Ap_pos) ; + } + else + { + /* i is not pivotal, and not flagged. Flag and put in L */ + Flag [i] = k ; + Lik [l_length] = i ; + l_length++; + } + } + } + + /* If Llen [k] is zero, the matrix is structurally singular */ + Llen [k] = l_length ; + return (top) ; +} + + +/* ========================================================================== */ +/* === construct_column ===================================================== */ +/* ========================================================================== */ + +/* Construct the kth column of A, and the off-diagonal part, if requested. + * Scatter the numerical values into the workspace X, and construct the + * corresponding column of the off-diagonal matrix. */ + +static void construct_column +( + /* inputs, not modified on output */ + Int k, /* the column of A (or the column of the block) to get */ + Int Ap [ ], + Int Ai [ ], + Entry Ax [ ], + Int Q [ ], /* column pre-ordering */ + + /* zero on input, modified on output */ + Entry X [ ], + + /* ---- the following are only used in the BTF case --- */ + + /* inputs, not modified on output */ + Int k1, /* the block of A is from k1 to k2-1 */ + Int PSinv [ ], /* inverse of P from symbolic factorization */ + double Rs [ ], /* scale factors for A */ + Int scale, /* 0: no scaling, nonzero: scale the rows with Rs */ + + /* inputs, modified on output */ + Int Offp [ ], /* off-diagonal matrix (modified by this routine) */ + Int Offi [ ], + Entry Offx [ ] +) +{ + Entry aik ; + Int i, p, pend, oldcol, kglobal, poff, oldrow ; + + /* ---------------------------------------------------------------------- */ + /* Scale and scatter the column into X. */ + /* ---------------------------------------------------------------------- */ + + kglobal = k + k1 ; /* column k of the block is col kglobal of A */ + poff = Offp [kglobal] ; /* start of off-diagonal column */ + oldcol = Q [kglobal] ; + pend = Ap [oldcol+1] ; + + if (scale <= 0) + { + /* no scaling */ + for (p = Ap [oldcol] ; p < pend ; p++) + { + oldrow = Ai [p] ; + i = PSinv [oldrow] - k1 ; + aik = Ax [p] ; + if (i < 0) + { + /* this is an entry in the off-diagonal part */ + Offi [poff] = oldrow ; + Offx [poff] = aik ; + poff++ ; + } + else + { + /* (i,k) is an entry in the block. scatter into X */ + X [i] = aik ; + } + } + } + else + { + /* row scaling */ + for (p = Ap [oldcol] ; p < pend ; p++) + { + oldrow = Ai [p] ; + i = PSinv [oldrow] - k1 ; + aik = Ax [p] ; + SCALE_DIV (aik, Rs [oldrow]) ; + if (i < 0) + { + /* this is an entry in the off-diagonal part */ + Offi [poff] = oldrow ; + Offx [poff] = aik ; + poff++ ; + } + else + { + /* (i,k) is an entry in the block. scatter into X */ + X [i] = aik ; + } + } + } + + Offp [kglobal+1] = poff ; /* start of the next col of off-diag part */ +} + + +/* ========================================================================== */ +/* === lsolve_numeric ======================================================= */ +/* ========================================================================== */ + +/* Computes the numerical values of x, for the solution of Lx=b. Note that x + * may include explicit zeros if numerical cancelation occurs. L is assumed + * to be unit-diagonal, with possibly unsorted columns (but the first entry in + * the column must always be the diagonal entry). */ + +static void lsolve_numeric +( + /* input, not modified on output: */ + Int Pinv [ ], /* Pinv [i] = k if i is kth pivot row, or EMPTY if row i + * is not yet pivotal. */ + Unit *LU, /* LU factors (pattern and values) */ + Int Stack [ ], /* stack for dfs */ + Int Lip [ ], /* size n, Lip [k] is position in LU of column k of L */ + Int top, /* top of stack on input */ + Int n, /* A is n-by-n */ + Int Llen [ ], /* size n, Llen [k] = # nonzeros in column k of L */ + + /* output, must be zero on input: */ + Entry X [ ] /* size n, initially zero. On output, + * X [Ui [up1..up-1]] and X [Li [lp1..lp-1]] + * contains the solution. */ + +) +{ + Entry xj ; + Entry *Lx ; + Int *Li ; + Int p, s, j, jnew, len ; + + /* solve Lx=b */ + for (s = top ; s < n ; s++) + { + /* forward solve with column j of L */ + j = Stack [s] ; + jnew = Pinv [j] ; + ASSERT (jnew >= 0) ; + xj = X [j] ; + GET_POINTER (LU, Lip, Llen, Li, Lx, jnew, len) ; + ASSERT (Lip [jnew] <= Lip [jnew+1]) ; + for (p = 0 ; p < len ; p++) + { + /*X [Li [p]] -= Lx [p] * xj ; */ + MULT_SUB (X [Li [p]], Lx [p], xj) ; + } + } +} + + +/* ========================================================================== */ +/* === lpivot =============================================================== */ +/* ========================================================================== */ + +/* Find a pivot via partial pivoting, and scale the column of L. */ + +static Int lpivot +( + Int diagrow, + Int *p_pivrow, + Entry *p_pivot, + double *p_abs_pivot, + double tol, + Entry X [ ], + Unit *LU, /* LU factors (pattern and values) */ + Int Lip [ ], + Int Llen [ ], + Int k, + Int n, + + Int Pinv [ ], /* Pinv [i] = k if row i is kth pivot row, or EMPTY if + * row i is not yet pivotal. */ + + Int *p_firstrow, + KLU_common *Common +) +{ + Entry x, pivot, *Lx ; + double abs_pivot, xabs ; + Int p, i, ppivrow, pdiag, pivrow, *Li, last_row_index, firstrow, len ; + + pivrow = EMPTY ; + if (Llen [k] == 0) + { + /* matrix is structurally singular */ + if (Common->halt_if_singular) + { + return (FALSE) ; + } + for (firstrow = *p_firstrow ; firstrow < n ; firstrow++) + { + PRINTF (("check %d\n", firstrow)) ; + if (Pinv [firstrow] < 0) + { + /* found the lowest-numbered non-pivotal row. Pick it. */ + pivrow = firstrow ; + PRINTF (("Got pivotal row: %d\n", pivrow)) ; + break ; + } + } + ASSERT (pivrow >= 0 && pivrow < n) ; + CLEAR (pivot) ; + *p_pivrow = pivrow ; + *p_pivot = pivot ; + *p_abs_pivot = 0 ; + *p_firstrow = firstrow ; + return (FALSE) ; + } + + pdiag = EMPTY ; + ppivrow = EMPTY ; + abs_pivot = EMPTY ; + i = Llen [k] - 1 ; + GET_POINTER (LU, Lip, Llen, Li, Lx, k, len) ; + last_row_index = Li [i] ; + + /* decrement the length by 1 */ + Llen [k] = i ; + GET_POINTER (LU, Lip, Llen, Li, Lx, k, len) ; + + /* look in Li [0 ..Llen [k] - 1 ] for a pivot row */ + for (p = 0 ; p < len ; p++) + { + /* gather the entry from X and store in L */ + i = Li [p] ; + x = X [i] ; + CLEAR (X [i]) ; + + Lx [p] = x ; + /* xabs = ABS (x) ; */ + ABS (xabs, x) ; + + /* find the diagonal */ + if (i == diagrow) + { + pdiag = p ; + } + + /* find the partial-pivoting choice */ + if (xabs > abs_pivot) + { + abs_pivot = xabs ; + ppivrow = p ; + } + } + + /* xabs = ABS (X [last_row_index]) ;*/ + ABS (xabs, X [last_row_index]) ; + if (xabs > abs_pivot) + { + abs_pivot = xabs ; + ppivrow = EMPTY ; + } + + /* compare the diagonal with the largest entry */ + if (last_row_index == diagrow) + { + if (xabs >= tol * abs_pivot) + { + abs_pivot = xabs ; + ppivrow = EMPTY ; + } + } + else if (pdiag != EMPTY) + { + /* xabs = ABS (Lx [pdiag]) ;*/ + ABS (xabs, Lx [pdiag]) ; + if (xabs >= tol * abs_pivot) + { + /* the diagonal is large enough */ + abs_pivot = xabs ; + ppivrow = pdiag ; + } + } + + if (ppivrow != EMPTY) + { + pivrow = Li [ppivrow] ; + pivot = Lx [ppivrow] ; + /* overwrite the ppivrow values with last index values */ + Li [ppivrow] = last_row_index ; + Lx [ppivrow] = X [last_row_index] ; + } + else + { + pivrow = last_row_index ; + pivot = X [last_row_index] ; + } + CLEAR (X [last_row_index]) ; + + *p_pivrow = pivrow ; + *p_pivot = pivot ; + *p_abs_pivot = abs_pivot ; + ASSERT (pivrow >= 0 && pivrow < n) ; + + if (IS_ZERO (pivot) && Common->halt_if_singular) + { + /* numerically singular case */ + return (FALSE) ; + } + + /* divide L by the pivot value */ + for (p = 0 ; p < Llen [k] ; p++) + { + /* Lx [p] /= pivot ; */ + DIV (Lx [p], Lx [p], pivot) ; + } + + return (TRUE) ; +} + + +/* ========================================================================== */ +/* === prune ================================================================ */ +/* ========================================================================== */ + +/* Prune the columns of L to reduce work in subsequent depth-first searches */ +static void prune +( + /* input/output: */ + Int Lpend [ ], /* Lpend [j] marks symmetric pruning point for L(:,j) */ + + /* input: */ + Int Pinv [ ], /* Pinv [i] = k if row i is kth pivot row, or EMPTY if + * row i is not yet pivotal. */ + Int k, /* prune using column k of U */ + Int pivrow, /* current pivot row */ + + /* input/output: */ + Unit *LU, /* LU factors (pattern and values) */ + + /* input */ + Int Uip [ ], /* size n, column pointers for U */ + Int Lip [ ], /* size n, column pointers for L */ + Int Ulen [ ], /* size n, column length of U */ + Int Llen [ ] /* size n, column length of L */ +) +{ + Entry x ; + Entry *Lx, *Ux ; + Int *Li, *Ui ; + Int p, i, j, p2, phead, ptail, llen, ulen ; + + /* check to see if any column of L can be pruned */ + /* Ux is set but not used. This OK. */ + GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, ulen) ; + for (p = 0 ; p < ulen ; p++) + { + j = Ui [p] ; + ASSERT (j < k) ; + PRINTF (("%d is pruned: %d. Lpend[j] %d Lip[j+1] %d\n", + j, Lpend [j] != EMPTY, Lpend [j], Lip [j+1])) ; + if (Lpend [j] == EMPTY) + { + /* scan column j of L for the pivot row */ + GET_POINTER (LU, Lip, Llen, Li, Lx, j, llen) ; + for (p2 = 0 ; p2 < llen ; p2++) + { + if (pivrow == Li [p2]) + { + /* found it! This column can be pruned */ +#ifndef NDEBUG + PRINTF (("==== PRUNE: col j %d of L\n", j)) ; + { + Int p3 ; + for (p3 = 0 ; p3 < Llen [j] ; p3++) + { + PRINTF (("before: %i pivotal: %d\n", Li [p3], + Pinv [Li [p3]] >= 0)) ; + } + } +#endif + + /* partition column j of L. The unit diagonal of L + * is not stored in the column of L. */ + phead = 0 ; + ptail = Llen [j] ; + while (phead < ptail) + { + i = Li [phead] ; + if (Pinv [i] >= 0) + { + /* leave at the head */ + phead++ ; + } + else + { + /* swap with the tail */ + ptail-- ; + Li [phead] = Li [ptail] ; + Li [ptail] = i ; + x = Lx [phead] ; + Lx [phead] = Lx [ptail] ; + Lx [ptail] = x ; + } + } + + /* set Lpend to one past the last entry in the + * first part of the column of L. Entries in + * Li [0 ... Lpend [j]-1] are the only part of + * column j of L that needs to be scanned in the DFS. + * Lpend [j] was EMPTY; setting it >= 0 also flags + * column j as pruned. */ + Lpend [j] = ptail ; + +#ifndef NDEBUG + { + Int p3 ; + for (p3 = 0 ; p3 < Llen [j] ; p3++) + { + if (p3 == Lpend [j]) PRINTF (("----\n")) ; + PRINTF (("after: %i pivotal: %d\n", Li [p3], + Pinv [Li [p3]] >= 0)) ; + } + } +#endif + + break ; + } + } + } + } +} + + +/* ========================================================================== */ +/* === KLU_kernel =========================================================== */ +/* ========================================================================== */ + +size_t KLU_kernel /* final size of LU on output */ +( + /* input, not modified */ + Int n, /* A is n-by-n */ + Int Ap [ ], /* size n+1, column pointers for A */ + Int Ai [ ], /* size nz = Ap [n], row indices for A */ + Entry Ax [ ], /* size nz, values of A */ + Int Q [ ], /* size n, optional input permutation */ + size_t lusize, /* initial size of LU on input */ + + /* output, not defined on input */ + Int Pinv [ ], /* size n, inverse row permutation, where Pinv [i] = k if + * row i is the kth pivot row */ + Int P [ ], /* size n, row permutation, where P [k] = i if row i is the + * kth pivot row. */ + Unit **p_LU, /* LU array, size lusize on input */ + Entry Udiag [ ], /* size n, diagonal of U */ + Int Llen [ ], /* size n, column length of L */ + Int Ulen [ ], /* size n, column length of U */ + Int Lip [ ], /* size n, column pointers for L */ + Int Uip [ ], /* size n, column pointers for U */ + Int *lnz, /* size of L*/ + Int *unz, /* size of U*/ + /* workspace, not defined on input */ + Entry X [ ], /* size n, undefined on input, zero on output */ + + /* workspace, not defined on input or output */ + Int Stack [ ], /* size n */ + Int Flag [ ], /* size n */ + Int Ap_pos [ ], /* size n */ + + /* other workspace: */ + Int Lpend [ ], /* size n workspace, for pruning only */ + + /* inputs, not modified on output */ + Int k1, /* the block of A is from k1 to k2-1 */ + Int PSinv [ ], /* inverse of P from symbolic factorization */ + double Rs [ ], /* scale factors for A */ + + /* inputs, modified on output */ + Int Offp [ ], /* off-diagonal matrix (modified by this routine) */ + Int Offi [ ], + Entry Offx [ ], + /* --------------- */ + KLU_common *Common +) +{ + Entry pivot ; + double abs_pivot, xsize, nunits, tol, memgrow ; + Entry *Ux ; + Int *Li, *Ui ; + Unit *LU ; /* LU factors (pattern and values) */ + Int k, p, i, j, pivrow = 0, kbar, diagrow, firstrow, lup, top, scale, len ; + size_t newlusize ; + +#ifndef NDEBUG + Entry *Lx ; +#endif + + ASSERT (Common != NULL) ; + scale = Common->scale ; + tol = Common->tol ; + memgrow = Common->memgrow ; + *lnz = 0 ; + *unz = 0 ; + CLEAR (pivot) ; + + /* ---------------------------------------------------------------------- */ + /* get initial Li, Lx, Ui, and Ux */ + /* ---------------------------------------------------------------------- */ + + PRINTF (("input: lusize %d \n", lusize)) ; + ASSERT (lusize > 0) ; + LU = *p_LU ; + + /* ---------------------------------------------------------------------- */ + /* initializations */ + /* ---------------------------------------------------------------------- */ + + firstrow = 0 ; + lup = 0 ; + + for (k = 0 ; k < n ; k++) + { + /* X [k] = 0 ; */ + CLEAR (X [k]) ; + Flag [k] = EMPTY ; + Lpend [k] = EMPTY ; /* flag k as not pruned */ + } + + /* ---------------------------------------------------------------------- */ + /* mark all rows as non-pivotal and determine initial diagonal mapping */ + /* ---------------------------------------------------------------------- */ + + /* PSinv does the symmetric permutation, so don't do it here */ + for (k = 0 ; k < n ; k++) + { + P [k] = k ; + Pinv [k] = FLIP (k) ; /* mark all rows as non-pivotal */ + } + /* initialize the construction of the off-diagonal matrix */ + Offp [0] = 0 ; + + /* P [k] = row means that UNFLIP (Pinv [row]) = k, and visa versa. + * If row is pivotal, then Pinv [row] >= 0. A row is initially "flipped" + * (Pinv [k] < EMPTY), and then marked "unflipped" when it becomes + * pivotal. */ + +#ifndef NDEBUG + for (k = 0 ; k < n ; k++) + { + PRINTF (("Initial P [%d] = %d\n", k, P [k])) ; + } +#endif + + /* ---------------------------------------------------------------------- */ + /* factorize */ + /* ---------------------------------------------------------------------- */ + + for (k = 0 ; k < n ; k++) + { + + PRINTF (("\n\n==================================== k: %d\n", k)) ; + + /* ------------------------------------------------------------------ */ + /* determine if LU factors have grown too big */ + /* ------------------------------------------------------------------ */ + + /* (n - k) entries for L and k entries for U */ + nunits = DUNITS (Int, n - k) + DUNITS (Int, k) + + DUNITS (Entry, n - k) + DUNITS (Entry, k) ; + + /* LU can grow by at most 'nunits' entries if the column is dense */ + PRINTF (("lup %d lusize %g lup+nunits: %g\n", lup, (double) lusize, + lup+nunits)); + xsize = ((double) lup) + nunits ; + if (xsize > (double) lusize) + { + /* check here how much to grow */ + xsize = (memgrow * ((double) lusize) + 4*n + 1) ; + if (INT_OVERFLOW (xsize)) + { + PRINTF (("Matrix is too large (Int overflow)\n")) ; + Common->status = KLU_TOO_LARGE ; + return (lusize) ; + } + newlusize = memgrow * lusize + 2*n + 1 ; + /* Future work: retry mechanism in case of malloc failure */ + LU = KLU_realloc (newlusize, lusize, sizeof (Unit), LU, Common) ; + Common->nrealloc++ ; + *p_LU = LU ; + if (Common->status == KLU_OUT_OF_MEMORY) + { + PRINTF (("Matrix is too large (LU)\n")) ; + return (lusize) ; + } + lusize = newlusize ; + PRINTF (("inc LU to %d done\n", lusize)) ; + } + + /* ------------------------------------------------------------------ */ + /* start the kth column of L and U */ + /* ------------------------------------------------------------------ */ + + Lip [k] = lup ; + + /* ------------------------------------------------------------------ */ + /* compute the nonzero pattern of the kth column of L and U */ + /* ------------------------------------------------------------------ */ + +#ifndef NDEBUG + for (i = 0 ; i < n ; i++) + { + ASSERT (Flag [i] < k) ; + /* ASSERT (X [i] == 0) ; */ + ASSERT (IS_ZERO (X [i])) ; + } +#endif + + top = lsolve_symbolic (n, k, Ap, Ai, Q, Pinv, Stack, Flag, + Lpend, Ap_pos, LU, lup, Llen, Lip, k1, PSinv) ; + +#ifndef NDEBUG + PRINTF (("--- in U:\n")) ; + for (p = top ; p < n ; p++) + { + PRINTF (("pattern of X for U: %d : %d pivot row: %d\n", + p, Stack [p], Pinv [Stack [p]])) ; + ASSERT (Flag [Stack [p]] == k) ; + } + PRINTF (("--- in L:\n")) ; + Li = (Int *) (LU + Lip [k]); + for (p = 0 ; p < Llen [k] ; p++) + { + PRINTF (("pattern of X in L: %d : %d pivot row: %d\n", + p, Li [p], Pinv [Li [p]])) ; + ASSERT (Flag [Li [p]] == k) ; + } + p = 0 ; + for (i = 0 ; i < n ; i++) + { + ASSERT (Flag [i] <= k) ; + if (Flag [i] == k) p++ ; + } +#endif + + /* ------------------------------------------------------------------ */ + /* get the column of the matrix to factorize and scatter into X */ + /* ------------------------------------------------------------------ */ + + construct_column (k, Ap, Ai, Ax, Q, X, + k1, PSinv, Rs, scale, Offp, Offi, Offx) ; + + /* ------------------------------------------------------------------ */ + /* compute the numerical values of the kth column (s = L \ A (:,k)) */ + /* ------------------------------------------------------------------ */ + + lsolve_numeric (Pinv, LU, Stack, Lip, top, n, Llen, X) ; + +#ifndef NDEBUG + for (p = top ; p < n ; p++) + { + PRINTF (("X for U %d : ", Stack [p])) ; + PRINT_ENTRY (X [Stack [p]]) ; + } + Li = (Int *) (LU + Lip [k]) ; + for (p = 0 ; p < Llen [k] ; p++) + { + PRINTF (("X for L %d : ", Li [p])) ; + PRINT_ENTRY (X [Li [p]]) ; + } +#endif + + /* ------------------------------------------------------------------ */ + /* partial pivoting with diagonal preference */ + /* ------------------------------------------------------------------ */ + + /* determine what the "diagonal" is */ + diagrow = P [k] ; /* might already be pivotal */ + PRINTF (("k %d, diagrow = %d, UNFLIP (diagrow) = %d\n", + k, diagrow, UNFLIP (diagrow))) ; + + /* find a pivot and scale the pivot column */ + if (!lpivot (diagrow, &pivrow, &pivot, &abs_pivot, tol, X, LU, Lip, + Llen, k, n, Pinv, &firstrow, Common)) + { + /* matrix is structurally or numerically singular */ + Common->status = KLU_SINGULAR ; + if (Common->numerical_rank == EMPTY) + { + Common->numerical_rank = k+k1 ; + Common->singular_col = Q [k+k1] ; + } + if (Common->halt_if_singular) + { + /* do not continue the factorization */ + return (lusize) ; + } + } + + /* we now have a valid pivot row, even if the column has NaN's or + * has no entries on or below the diagonal at all. */ + PRINTF (("\nk %d : Pivot row %d : ", k, pivrow)) ; + PRINT_ENTRY (pivot) ; + ASSERT (pivrow >= 0 && pivrow < n) ; + ASSERT (Pinv [pivrow] < 0) ; + + /* set the Uip pointer */ + Uip [k] = Lip [k] + UNITS (Int, Llen [k]) + UNITS (Entry, Llen [k]) ; + + /* move the lup pointer to the position where indices of U + * should be stored */ + lup += UNITS (Int, Llen [k]) + UNITS (Entry, Llen [k]) ; + + Ulen [k] = n - top ; + + /* extract Stack [top..n-1] to Ui and the values to Ux and clear X */ + GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, len) ; + for (p = top, i = 0 ; p < n ; p++, i++) + { + j = Stack [p] ; + Ui [i] = Pinv [j] ; + Ux [i] = X [j] ; + CLEAR (X [j]) ; + } + + /* position the lu index at the starting point for next column */ + lup += UNITS (Int, Ulen [k]) + UNITS (Entry, Ulen [k]) ; + + /* U(k,k) = pivot */ + Udiag [k] = pivot ; + + /* ------------------------------------------------------------------ */ + /* log the pivot permutation */ + /* ------------------------------------------------------------------ */ + + ASSERT (UNFLIP (Pinv [diagrow]) < n) ; + ASSERT (P [UNFLIP (Pinv [diagrow])] == diagrow) ; + + if (pivrow != diagrow) + { + /* an off-diagonal pivot has been chosen */ + Common->noffdiag++ ; + PRINTF ((">>>>>>>>>>>>>>>>> pivrow %d k %d off-diagonal\n", + pivrow, k)) ; + if (Pinv [diagrow] < 0) + { + /* the former diagonal row index, diagrow, has not yet been + * chosen as a pivot row. Log this diagrow as the "diagonal" + * entry in the column kbar for which the chosen pivot row, + * pivrow, was originally logged as the "diagonal" */ + kbar = FLIP (Pinv [pivrow]) ; + P [kbar] = diagrow ; + Pinv [diagrow] = FLIP (kbar) ; + } + } + P [k] = pivrow ; + Pinv [pivrow] = k ; + +#ifndef NDEBUG + for (i = 0 ; i < n ; i++) { ASSERT (IS_ZERO (X [i])) ;} + GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, len) ; + for (p = 0 ; p < len ; p++) + { + PRINTF (("Column %d of U: %d : ", k, Ui [p])) ; + PRINT_ENTRY (Ux [p]) ; + } + GET_POINTER (LU, Lip, Llen, Li, Lx, k, len) ; + for (p = 0 ; p < len ; p++) + { + PRINTF (("Column %d of L: %d : ", k, Li [p])) ; + PRINT_ENTRY (Lx [p]) ; + } +#endif + + /* ------------------------------------------------------------------ */ + /* symmetric pruning */ + /* ------------------------------------------------------------------ */ + + prune (Lpend, Pinv, k, pivrow, LU, Uip, Lip, Ulen, Llen) ; + + *lnz += Llen [k] + 1 ; /* 1 added to lnz for diagonal */ + *unz += Ulen [k] + 1 ; /* 1 added to unz for diagonal */ + } + + /* ---------------------------------------------------------------------- */ + /* finalize column pointers for L and U, and put L in the pivotal order */ + /* ---------------------------------------------------------------------- */ + + for (p = 0 ; p < n ; p++) + { + Li = (Int *) (LU + Lip [p]) ; + for (i = 0 ; i < Llen [p] ; i++) + { + Li [i] = Pinv [Li [i]] ; + } + } + +#ifndef NDEBUG + for (i = 0 ; i < n ; i++) + { + PRINTF (("P [%d] = %d Pinv [%d] = %d\n", i, P [i], i, Pinv [i])) ; + } + for (i = 0 ; i < n ; i++) + { + ASSERT (Pinv [i] >= 0 && Pinv [i] < n) ; + ASSERT (P [i] >= 0 && P [i] < n) ; + ASSERT (P [Pinv [i]] == i) ; + ASSERT (IS_ZERO (X [i])) ; + } +#endif + + /* ---------------------------------------------------------------------- */ + /* shrink the LU factors to just the required size */ + /* ---------------------------------------------------------------------- */ + + newlusize = lup ; + ASSERT ((size_t) newlusize <= lusize) ; + + /* this cannot fail, since the block is descreasing in size */ + LU = KLU_realloc (newlusize, lusize, sizeof (Unit), LU, Common) ; + *p_LU = LU ; + return (newlusize) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_memory.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_memory.c new file mode 100644 index 0000000..d391a08 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_memory.c @@ -0,0 +1,216 @@ +/* ========================================================================== */ +/* === KLU_memory =========================================================== */ +/* ========================================================================== */ + +/* KLU memory management routines: + * + * KLU_malloc malloc wrapper + * KLU_free free wrapper + * KLU_realloc realloc wrapper + */ + +#include "klu_internal.h" + +/* ========================================================================== */ +/* === KLU_add_size_t ======================================================= */ +/* ========================================================================== */ + +/* Safely compute a+b, and check for size_t overflow */ + +size_t KLU_add_size_t (size_t a, size_t b, Int *ok) +{ + (*ok) = (*ok) && ((a + b) >= MAX (a,b)) ; + return ((*ok) ? (a + b) : ((size_t) -1)) ; +} + +/* ========================================================================== */ +/* === KLU_mult_size_t ====================================================== */ +/* ========================================================================== */ + +/* Safely compute a*k, where k should be small, and check for size_t overflow */ + +size_t KLU_mult_size_t (size_t a, size_t k, Int *ok) +{ + size_t i, s = 0 ; + for (i = 0 ; i < k ; i++) + { + s = KLU_add_size_t (s, a, ok) ; + } + return ((*ok) ? s : ((size_t) -1)) ; +} + +/* ========================================================================== */ +/* === KLU_malloc =========================================================== */ +/* ========================================================================== */ + +/* Wrapper around malloc routine (mxMalloc for a mexFunction). Allocates + * space of size MAX(1,n)*size, where size is normally a sizeof (...). + * + * This routine and KLU_realloc do not set Common->status to KLU_OK on success, + * so that a sequence of KLU_malloc's or KLU_realloc's can be used. If any of + * them fails, the Common->status will hold the most recent error status. + * + * Usage, for a pointer to Int: + * + * p = KLU_malloc (n, sizeof (Int), Common) + * + * Uses a pointer to the malloc routine (or its equivalent) defined in Common. + */ + +void *KLU_malloc /* returns pointer to the newly malloc'd block */ +( + /* ---- input ---- */ + size_t n, /* number of items */ + size_t size, /* size of each item */ + /* --------------- */ + KLU_common *Common +) +{ + void *p ; + + if (Common == NULL) + { + p = NULL ; + } + else if (size == 0) + { + /* size must be > 0 */ + Common->status = KLU_INVALID ; + p = NULL ; + } + else if (n >= Int_MAX) + { + /* object is too big to allocate; p[i] where i is an Int will not + * be enough. */ + Common->status = KLU_TOO_LARGE ; + p = NULL ; + } + else + { + /* call malloc, or its equivalent */ + p = SuiteSparse_malloc (n, size) ; + if (p == NULL) + { + /* failure: out of memory */ + Common->status = KLU_OUT_OF_MEMORY ; + } + else + { + Common->memusage += (MAX (1,n) * size) ; + Common->mempeak = MAX (Common->mempeak, Common->memusage) ; + } + } + return (p) ; +} + + +/* ========================================================================== */ +/* === KLU_free ============================================================= */ +/* ========================================================================== */ + +/* Wrapper around free routine (mxFree for a mexFunction). Returns NULL, + * which can be assigned to the pointer being freed, as in: + * + * p = KLU_free (p, n, sizeof (int), Common) ; + */ + +void *KLU_free /* always returns NULL */ +( + /* ---- in/out --- */ + void *p, /* block of memory to free */ + /* ---- input --- */ + size_t n, /* size of block to free, in # of items */ + size_t size, /* size of each item */ + /* --------------- */ + KLU_common *Common +) +{ + if (p != NULL && Common != NULL) + { + /* only free the object if the pointer is not NULL */ + /* call free, or its equivalent */ + SuiteSparse_free (p) ; + Common->memusage -= (MAX (1,n) * size) ; + } + /* return NULL, and the caller should assign this to p. This avoids + * freeing the same pointer twice. */ + return (NULL) ; +} + + +/* ========================================================================== */ +/* === KLU_realloc ========================================================== */ +/* ========================================================================== */ + +/* Wrapper around realloc routine (mxRealloc for a mexFunction). Given a + * pointer p to a block allocated by KLU_malloc, it changes the size of the + * block pointed to by p to be MAX(1,nnew)*size in size. It may return a + * pointer different than p. This should be used as (for a pointer to Int): + * + * p = KLU_realloc (nnew, nold, sizeof (Int), p, Common) ; + * + * If p is NULL, this is the same as p = KLU_malloc (...). + * A size of nnew=0 is treated as nnew=1. + * + * If the realloc fails, p is returned unchanged and Common->status is set + * to KLU_OUT_OF_MEMORY. If successful, Common->status is not modified, + * and p is returned (possibly changed) and pointing to a large block of memory. + * + * Uses a pointer to the realloc routine (or its equivalent) defined in Common. + */ + +void *KLU_realloc /* returns pointer to reallocated block */ +( + /* ---- input ---- */ + size_t nnew, /* requested # of items in reallocated block */ + size_t nold, /* old # of items */ + size_t size, /* size of each item */ + /* ---- in/out --- */ + void *p, /* block of memory to realloc */ + /* --------------- */ + KLU_common *Common +) +{ + void *pnew ; + int ok = TRUE ; + + if (Common == NULL) + { + p = NULL ; + } + else if (size == 0) + { + /* size must be > 0 */ + Common->status = KLU_INVALID ; + p = NULL ; + } + else if (p == NULL) + { + /* A fresh object is being allocated. */ + p = KLU_malloc (nnew, size, Common) ; + } + else if (nnew >= Int_MAX) + { + /* failure: nnew is too big. Do not change p */ + Common->status = KLU_TOO_LARGE ; + } + else + { + /* The object exists, and is changing to some other nonzero size. */ + /* call realloc, or its equivalent */ + pnew = SuiteSparse_realloc (nnew, nold, size, p, &ok) ; + if (ok) + { + /* success: return the new p and change the size of the block */ + Common->memusage += ((nnew-nold) * size) ; + Common->mempeak = MAX (Common->mempeak, Common->memusage) ; + p = pnew ; + } + else + { + /* Do not change p, since it still points to allocated memory */ + Common->status = KLU_OUT_OF_MEMORY ; + } + } + return (p) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_refactor.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_refactor.c new file mode 100644 index 0000000..02539be --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_refactor.c @@ -0,0 +1,474 @@ +/* ========================================================================== */ +/* === KLU_refactor ========================================================= */ +/* ========================================================================== */ + +/* Factor the matrix, after ordering and analyzing it with KLU_analyze, and + * factoring it once with KLU_factor. This routine cannot do any numerical + * pivoting. The pattern of the input matrix (Ap, Ai) must be identical to + * the pattern given to KLU_factor. + */ + +#include "klu_internal.h" + + +/* ========================================================================== */ +/* === KLU_refactor ========================================================= */ +/* ========================================================================== */ + +Int KLU_refactor /* returns TRUE if successful, FALSE otherwise */ +( + /* inputs, not modified */ + Int Ap [ ], /* size n+1, column pointers */ + Int Ai [ ], /* size nz, row indices */ + double Ax [ ], + KLU_symbolic *Symbolic, + + /* input/output */ + KLU_numeric *Numeric, + KLU_common *Common +) +{ + Entry ukk, ujk, s ; + Entry *Offx, *Lx, *Ux, *X, *Az, *Udiag ; + double *Rs ; + Int *Q, *R, *Pnum, *Ui, *Li, *Pinv, *Lip, *Uip, *Llen, *Ulen ; + Unit **LUbx ; + Unit *LU ; + Int k1, k2, nk, k, block, oldcol, pend, oldrow, n, p, newrow, scale, + nblocks, poff, i, j, up, ulen, llen, maxblock, nzoff ; + + /* ---------------------------------------------------------------------- */ + /* check inputs */ + /* ---------------------------------------------------------------------- */ + + if (Common == NULL) + { + return (FALSE) ; + } + Common->status = KLU_OK ; + + if (Numeric == NULL) + { + /* invalid Numeric object */ + Common->status = KLU_INVALID ; + return (FALSE) ; + } + + Common->numerical_rank = EMPTY ; + Common->singular_col = EMPTY ; + + Az = (Entry *) Ax ; + + /* ---------------------------------------------------------------------- */ + /* get the contents of the Symbolic object */ + /* ---------------------------------------------------------------------- */ + + n = Symbolic->n ; + Q = Symbolic->Q ; + R = Symbolic->R ; + nblocks = Symbolic->nblocks ; + maxblock = Symbolic->maxblock ; + + /* ---------------------------------------------------------------------- */ + /* get the contents of the Numeric object */ + /* ---------------------------------------------------------------------- */ + + Pnum = Numeric->Pnum ; + Offx = (Entry *) Numeric->Offx ; + + LUbx = (Unit **) Numeric->LUbx ; + + scale = Common->scale ; + if (scale > 0) + { + /* factorization was not scaled, but refactorization is scaled */ + if (Numeric->Rs == NULL) + { + Numeric->Rs = KLU_malloc (n, sizeof (double), Common) ; + if (Common->status < KLU_OK) + { + Common->status = KLU_OUT_OF_MEMORY ; + return (FALSE) ; + } + } + } + else + { + /* no scaling for refactorization; ensure Numeric->Rs is freed. This + * does nothing if Numeric->Rs is already NULL. */ + Numeric->Rs = KLU_free (Numeric->Rs, n, sizeof (double), Common) ; + } + Rs = Numeric->Rs ; + + Pinv = Numeric->Pinv ; + X = (Entry *) Numeric->Xwork ; + Common->nrealloc = 0 ; + Udiag = Numeric->Udiag ; + nzoff = Symbolic->nzoff ; + + /* ---------------------------------------------------------------------- */ + /* check the input matrix compute the row scale factors, Rs */ + /* ---------------------------------------------------------------------- */ + + /* do no scale, or check the input matrix, if scale < 0 */ + if (scale >= 0) + { + /* check for out-of-range indices, but do not check for duplicates */ + if (!KLU_scale (scale, n, Ap, Ai, Ax, Rs, NULL, Common)) + { + return (FALSE) ; + } + } + + /* ---------------------------------------------------------------------- */ + /* clear workspace X */ + /* ---------------------------------------------------------------------- */ + + for (k = 0 ; k < maxblock ; k++) + { + /* X [k] = 0 */ + CLEAR (X [k]) ; + } + + poff = 0 ; + + /* ---------------------------------------------------------------------- */ + /* factor each block */ + /* ---------------------------------------------------------------------- */ + + if (scale <= 0) + { + + /* ------------------------------------------------------------------ */ + /* no scaling */ + /* ------------------------------------------------------------------ */ + + for (block = 0 ; block < nblocks ; block++) + { + + /* -------------------------------------------------------------- */ + /* the block is from rows/columns k1 to k2-1 */ + /* -------------------------------------------------------------- */ + + k1 = R [block] ; + k2 = R [block+1] ; + nk = k2 - k1 ; + + if (nk == 1) + { + + /* ---------------------------------------------------------- */ + /* singleton case */ + /* ---------------------------------------------------------- */ + + oldcol = Q [k1] ; + pend = Ap [oldcol+1] ; + CLEAR (s) ; + for (p = Ap [oldcol] ; p < pend ; p++) + { + newrow = Pinv [Ai [p]] - k1 ; + if (newrow < 0 && poff < nzoff) + { + /* entry in off-diagonal block */ + Offx [poff] = Az [p] ; + poff++ ; + } + else + { + /* singleton */ + s = Az [p] ; + } + } + Udiag [k1] = s ; + + } + else + { + + /* ---------------------------------------------------------- */ + /* construct and factor the kth block */ + /* ---------------------------------------------------------- */ + + Lip = Numeric->Lip + k1 ; + Llen = Numeric->Llen + k1 ; + Uip = Numeric->Uip + k1 ; + Ulen = Numeric->Ulen + k1 ; + LU = LUbx [block] ; + + for (k = 0 ; k < nk ; k++) + { + + /* ------------------------------------------------------ */ + /* scatter kth column of the block into workspace X */ + /* ------------------------------------------------------ */ + + oldcol = Q [k+k1] ; + pend = Ap [oldcol+1] ; + for (p = Ap [oldcol] ; p < pend ; p++) + { + newrow = Pinv [Ai [p]] - k1 ; + if (newrow < 0 && poff < nzoff) + { + /* entry in off-diagonal block */ + Offx [poff] = Az [p] ; + poff++ ; + } + else + { + /* (newrow,k) is an entry in the block */ + X [newrow] = Az [p] ; + } + } + + /* ------------------------------------------------------ */ + /* compute kth column of U, and update kth column of A */ + /* ------------------------------------------------------ */ + + GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, ulen) ; + for (up = 0 ; up < ulen ; up++) + { + j = Ui [up] ; + ujk = X [j] ; + /* X [j] = 0 */ + CLEAR (X [j]) ; + Ux [up] = ujk ; + GET_POINTER (LU, Lip, Llen, Li, Lx, j, llen) ; + for (p = 0 ; p < llen ; p++) + { + /* X [Li [p]] -= Lx [p] * ujk */ + MULT_SUB (X [Li [p]], Lx [p], ujk) ; + } + } + /* get the diagonal entry of U */ + ukk = X [k] ; + /* X [k] = 0 */ + CLEAR (X [k]) ; + /* singular case */ + if (IS_ZERO (ukk)) + { + /* matrix is numerically singular */ + Common->status = KLU_SINGULAR ; + if (Common->numerical_rank == EMPTY) + { + Common->numerical_rank = k+k1 ; + Common->singular_col = Q [k+k1] ; + } + if (Common->halt_if_singular) + { + /* do not continue the factorization */ + return (FALSE) ; + } + } + Udiag [k+k1] = ukk ; + /* gather and divide by pivot to get kth column of L */ + GET_POINTER (LU, Lip, Llen, Li, Lx, k, llen) ; + for (p = 0 ; p < llen ; p++) + { + i = Li [p] ; + DIV (Lx [p], X [i], ukk) ; + CLEAR (X [i]) ; + } + + } + } + } + + } + else + { + + /* ------------------------------------------------------------------ */ + /* scaling */ + /* ------------------------------------------------------------------ */ + + for (block = 0 ; block < nblocks ; block++) + { + + /* -------------------------------------------------------------- */ + /* the block is from rows/columns k1 to k2-1 */ + /* -------------------------------------------------------------- */ + + k1 = R [block] ; + k2 = R [block+1] ; + nk = k2 - k1 ; + + if (nk == 1) + { + + /* ---------------------------------------------------------- */ + /* singleton case */ + /* ---------------------------------------------------------- */ + + oldcol = Q [k1] ; + pend = Ap [oldcol+1] ; + CLEAR (s) ; + for (p = Ap [oldcol] ; p < pend ; p++) + { + oldrow = Ai [p] ; + newrow = Pinv [oldrow] - k1 ; + if (newrow < 0 && poff < nzoff) + { + /* entry in off-diagonal block */ + /* Offx [poff] = Az [p] / Rs [oldrow] */ + SCALE_DIV_ASSIGN (Offx [poff], Az [p], Rs [oldrow]) ; + poff++ ; + } + else + { + /* singleton */ + /* s = Az [p] / Rs [oldrow] */ + SCALE_DIV_ASSIGN (s, Az [p], Rs [oldrow]) ; + } + } + Udiag [k1] = s ; + + } + else + { + + /* ---------------------------------------------------------- */ + /* construct and factor the kth block */ + /* ---------------------------------------------------------- */ + + Lip = Numeric->Lip + k1 ; + Llen = Numeric->Llen + k1 ; + Uip = Numeric->Uip + k1 ; + Ulen = Numeric->Ulen + k1 ; + LU = LUbx [block] ; + + for (k = 0 ; k < nk ; k++) + { + + /* ------------------------------------------------------ */ + /* scatter kth column of the block into workspace X */ + /* ------------------------------------------------------ */ + + oldcol = Q [k+k1] ; + pend = Ap [oldcol+1] ; + for (p = Ap [oldcol] ; p < pend ; p++) + { + oldrow = Ai [p] ; + newrow = Pinv [oldrow] - k1 ; + if (newrow < 0 && poff < nzoff) + { + /* entry in off-diagonal part */ + /* Offx [poff] = Az [p] / Rs [oldrow] */ + SCALE_DIV_ASSIGN (Offx [poff], Az [p], Rs [oldrow]); + poff++ ; + } + else + { + /* (newrow,k) is an entry in the block */ + /* X [newrow] = Az [p] / Rs [oldrow] */ + SCALE_DIV_ASSIGN (X [newrow], Az [p], Rs [oldrow]) ; + } + } + + /* ------------------------------------------------------ */ + /* compute kth column of U, and update kth column of A */ + /* ------------------------------------------------------ */ + + GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, ulen) ; + for (up = 0 ; up < ulen ; up++) + { + j = Ui [up] ; + ujk = X [j] ; + /* X [j] = 0 */ + CLEAR (X [j]) ; + Ux [up] = ujk ; + GET_POINTER (LU, Lip, Llen, Li, Lx, j, llen) ; + for (p = 0 ; p < llen ; p++) + { + /* X [Li [p]] -= Lx [p] * ujk */ + MULT_SUB (X [Li [p]], Lx [p], ujk) ; + } + } + /* get the diagonal entry of U */ + ukk = X [k] ; + /* X [k] = 0 */ + CLEAR (X [k]) ; + /* singular case */ + if (IS_ZERO (ukk)) + { + /* matrix is numerically singular */ + Common->status = KLU_SINGULAR ; + if (Common->numerical_rank == EMPTY) + { + Common->numerical_rank = k+k1 ; + Common->singular_col = Q [k+k1] ; + } + if (Common->halt_if_singular) + { + /* do not continue the factorization */ + return (FALSE) ; + } + } + Udiag [k+k1] = ukk ; + /* gather and divide by pivot to get kth column of L */ + GET_POINTER (LU, Lip, Llen, Li, Lx, k, llen) ; + for (p = 0 ; p < llen ; p++) + { + i = Li [p] ; + DIV (Lx [p], X [i], ukk) ; + CLEAR (X [i]) ; + } + } + } + } + } + + /* ---------------------------------------------------------------------- */ + /* permute scale factors Rs according to pivotal row order */ + /* ---------------------------------------------------------------------- */ + + if (scale > 0) + { + for (k = 0 ; k < n ; k++) + { + REAL (X [k]) = Rs [Pnum [k]] ; + } + for (k = 0 ; k < n ; k++) + { + Rs [k] = REAL (X [k]) ; + } + } + +#ifndef NDEBUG + ASSERT (Numeric->Offp [n] == poff) ; + ASSERT (Symbolic->nzoff == poff) ; + PRINTF (("\n------------------- Off diagonal entries, new:\n")) ; + ASSERT (KLU_valid (n, Numeric->Offp, Numeric->Offi, Offx)) ; + if (Common->status == KLU_OK) + { + PRINTF (("\n ########### KLU_BTF_REFACTOR done, nblocks %d\n",nblocks)); + for (block = 0 ; block < nblocks ; block++) + { + k1 = R [block] ; + k2 = R [block+1] ; + nk = k2 - k1 ; + PRINTF (( + "\n================KLU_refactor output: k1 %d k2 %d nk %d\n", + k1, k2, nk)) ; + if (nk == 1) + { + PRINTF (("singleton ")) ; + PRINT_ENTRY (Udiag [k1]) ; + } + else + { + Lip = Numeric->Lip + k1 ; + Llen = Numeric->Llen + k1 ; + LU = (Unit *) Numeric->LUbx [block] ; + PRINTF (("\n---- L block %d\n", block)) ; + ASSERT (KLU_valid_LU (nk, TRUE, Lip, Llen, LU)) ; + Uip = Numeric->Uip + k1 ; + Ulen = Numeric->Ulen + k1 ; + PRINTF (("\n---- U block %d\n", block)) ; + ASSERT (KLU_valid_LU (nk, FALSE, Uip, Ulen, LU)) ; + } + } + } +#endif + + return (TRUE) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_scale.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_scale.c new file mode 100644 index 0000000..4796120 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_scale.c @@ -0,0 +1,159 @@ +/* ========================================================================== */ +/* === KLU_scale ============================================================ */ +/* ========================================================================== */ + +/* Scale a matrix and check to see if it is valid. Can be called by the user. + * This is called by KLU_factor and KLU_refactor. Returns TRUE if the input + * matrix is valid, FALSE otherwise. If the W input argument is non-NULL, + * then the input matrix is checked for duplicate entries. + * + * scaling methods: + * <0: no scaling, do not compute Rs, and do not check input matrix. + * 0: no scaling + * 1: the scale factor for row i is sum (abs (A (i,:))) + * 2 or more: the scale factor for row i is max (abs (A (i,:))) + */ + +#include "klu_internal.h" + +Int KLU_scale /* return TRUE if successful, FALSE otherwise */ +( + /* inputs, not modified */ + Int scale, /* 0: none, 1: sum, 2: max */ + Int n, + Int Ap [ ], /* size n+1, column pointers */ + Int Ai [ ], /* size nz, row indices */ + double Ax [ ], + /* outputs, not defined on input */ + double Rs [ ], /* size n, can be NULL if scale <= 0 */ + /* workspace, not defined on input or output */ + Int W [ ], /* size n, can be NULL */ + /* --------------- */ + KLU_common *Common +) +{ + double a ; + Entry *Az ; + Int row, col, p, pend, check_duplicates ; + + /* ---------------------------------------------------------------------- */ + /* check inputs */ + /* ---------------------------------------------------------------------- */ + + if (Common == NULL) + { + return (FALSE) ; + } + Common->status = KLU_OK ; + + if (scale < 0) + { + /* return without checking anything and without computing the + * scale factors */ + return (TRUE) ; + } + + Az = (Entry *) Ax ; + + if (n <= 0 || Ap == NULL || Ai == NULL || Az == NULL || + (scale > 0 && Rs == NULL)) + { + /* Ap, Ai, Ax and Rs must be present, and n must be > 0 */ + Common->status = KLU_INVALID ; + return (FALSE) ; + } + if (Ap [0] != 0 || Ap [n] < 0) + { + /* nz = Ap [n] must be >= 0 and Ap [0] must equal zero */ + Common->status = KLU_INVALID ; + return (FALSE) ; + } + for (col = 0 ; col < n ; col++) + { + if (Ap [col] > Ap [col+1]) + { + /* column pointers must be non-decreasing */ + Common->status = KLU_INVALID ; + return (FALSE) ; + } + } + + /* ---------------------------------------------------------------------- */ + /* scale */ + /* ---------------------------------------------------------------------- */ + + if (scale > 0) + { + /* initialize row sum or row max */ + for (row = 0 ; row < n ; row++) + { + Rs [row] = 0 ; + } + } + + /* check for duplicates only if W is present */ + check_duplicates = (W != (Int *) NULL) ; + if (check_duplicates) + { + for (row = 0 ; row < n ; row++) + { + W [row] = EMPTY ; + } + } + + for (col = 0 ; col < n ; col++) + { + pend = Ap [col+1] ; + for (p = Ap [col] ; p < pend ; p++) + { + row = Ai [p] ; + if (row < 0 || row >= n) + { + /* row index out of range, or duplicate entry */ + Common->status = KLU_INVALID ; + return (FALSE) ; + } + if (check_duplicates) + { + if (W [row] == col) + { + /* duplicate entry */ + Common->status = KLU_INVALID ; + return (FALSE) ; + } + /* flag row i as appearing in column col */ + W [row] = col ; + } + /* a = ABS (Az [p]) ;*/ + ABS (a, Az [p]) ; + if (scale == 1) + { + /* accumulate the abs. row sum */ + Rs [row] += a ; + } + else if (scale > 1) + { + /* find the max abs. value in the row */ + Rs [row] = MAX (Rs [row], a) ; + } + } + } + + if (scale > 0) + { + /* do not scale empty rows */ + for (row = 0 ; row < n ; row++) + { + /* matrix is singular */ + PRINTF (("Rs [%d] = %g\n", row, Rs [row])) ; + + if (Rs [row] == 0.0) + { + PRINTF (("Row %d of A is all zero\n", row)) ; + Rs [row] = 1.0 ; + } + } + } + + return (TRUE) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_solve.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_solve.c new file mode 100644 index 0000000..d23a140 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_solve.c @@ -0,0 +1,396 @@ +/* ========================================================================== */ +/* === KLU_solve ============================================================ */ +/* ========================================================================== */ + +/* Solve Ax=b using the symbolic and numeric objects from KLU_analyze + * (or KLU_analyze_given) and KLU_factor. Note that no iterative refinement is + * performed. Uses Numeric->Xwork as workspace (undefined on input and output), + * of size 4n Entry's (note that columns 2 to 4 of Xwork overlap with + * Numeric->Iwork). + */ + +#include "klu_internal.h" + +Int KLU_solve +( + /* inputs, not modified */ + KLU_symbolic *Symbolic, + KLU_numeric *Numeric, + Int d, /* leading dimension of B */ + Int nrhs, /* number of right-hand-sides */ + + /* right-hand-side on input, overwritten with solution to Ax=b on output */ + double B [ ], /* size n*nrhs, in column-oriented form, with + * leading dimension d. */ + /* --------------- */ + KLU_common *Common +) +{ + Entry x [4], offik, s ; + double rs, *Rs ; + Entry *Offx, *X, *Bz, *Udiag ; + Int *Q, *R, *Pnum, *Offp, *Offi, *Lip, *Uip, *Llen, *Ulen ; + Unit **LUbx ; + Int k1, k2, nk, k, block, pend, n, p, nblocks, chunk, nr, i ; + + /* ---------------------------------------------------------------------- */ + /* check inputs */ + /* ---------------------------------------------------------------------- */ + + if (Common == NULL) + { + return (FALSE) ; + } + if (Numeric == NULL || Symbolic == NULL || d < Symbolic->n || nrhs < 0 || + B == NULL) + { + Common->status = KLU_INVALID ; + return (FALSE) ; + } + Common->status = KLU_OK ; + + /* ---------------------------------------------------------------------- */ + /* get the contents of the Symbolic object */ + /* ---------------------------------------------------------------------- */ + + Bz = (Entry *) B ; + n = Symbolic->n ; + nblocks = Symbolic->nblocks ; + Q = Symbolic->Q ; + R = Symbolic->R ; + + /* ---------------------------------------------------------------------- */ + /* get the contents of the Numeric object */ + /* ---------------------------------------------------------------------- */ + + ASSERT (nblocks == Numeric->nblocks) ; + Pnum = Numeric->Pnum ; + Offp = Numeric->Offp ; + Offi = Numeric->Offi ; + Offx = (Entry *) Numeric->Offx ; + + Lip = Numeric->Lip ; + Llen = Numeric->Llen ; + Uip = Numeric->Uip ; + Ulen = Numeric->Ulen ; + LUbx = (Unit **) Numeric->LUbx ; + Udiag = Numeric->Udiag ; + + Rs = Numeric->Rs ; + X = (Entry *) Numeric->Xwork ; + + ASSERT (KLU_valid (n, Offp, Offi, Offx)) ; + + /* ---------------------------------------------------------------------- */ + /* solve in chunks of 4 columns at a time */ + /* ---------------------------------------------------------------------- */ + + for (chunk = 0 ; chunk < nrhs ; chunk += 4) + { + + /* ------------------------------------------------------------------ */ + /* get the size of the current chunk */ + /* ------------------------------------------------------------------ */ + + nr = MIN (nrhs - chunk, 4) ; + + /* ------------------------------------------------------------------ */ + /* scale and permute the right hand side, X = P*(R\B) */ + /* ------------------------------------------------------------------ */ + + if (Rs == NULL) + { + + /* no scaling */ + switch (nr) + { + + case 1: + + for (k = 0 ; k < n ; k++) + { + X [k] = Bz [Pnum [k]] ; + } + break ; + + case 2: + + for (k = 0 ; k < n ; k++) + { + i = Pnum [k] ; + X [2*k ] = Bz [i ] ; + X [2*k + 1] = Bz [i + d ] ; + } + break ; + + case 3: + + for (k = 0 ; k < n ; k++) + { + i = Pnum [k] ; + X [3*k ] = Bz [i ] ; + X [3*k + 1] = Bz [i + d ] ; + X [3*k + 2] = Bz [i + d*2] ; + } + break ; + + case 4: + + for (k = 0 ; k < n ; k++) + { + i = Pnum [k] ; + X [4*k ] = Bz [i ] ; + X [4*k + 1] = Bz [i + d ] ; + X [4*k + 2] = Bz [i + d*2] ; + X [4*k + 3] = Bz [i + d*3] ; + } + break ; + } + + } + else + { + + switch (nr) + { + + case 1: + + for (k = 0 ; k < n ; k++) + { + SCALE_DIV_ASSIGN (X [k], Bz [Pnum [k]], Rs [k]) ; + } + break ; + + case 2: + + for (k = 0 ; k < n ; k++) + { + i = Pnum [k] ; + rs = Rs [k] ; + SCALE_DIV_ASSIGN (X [2*k], Bz [i], rs) ; + SCALE_DIV_ASSIGN (X [2*k + 1], Bz [i + d], rs) ; + } + break ; + + case 3: + + for (k = 0 ; k < n ; k++) + { + i = Pnum [k] ; + rs = Rs [k] ; + SCALE_DIV_ASSIGN (X [3*k], Bz [i], rs) ; + SCALE_DIV_ASSIGN (X [3*k + 1], Bz [i + d], rs) ; + SCALE_DIV_ASSIGN (X [3*k + 2], Bz [i + d*2], rs) ; + } + break ; + + case 4: + + for (k = 0 ; k < n ; k++) + { + i = Pnum [k] ; + rs = Rs [k] ; + SCALE_DIV_ASSIGN (X [4*k], Bz [i], rs) ; + SCALE_DIV_ASSIGN (X [4*k + 1], Bz [i + d], rs) ; + SCALE_DIV_ASSIGN (X [4*k + 2], Bz [i + d*2], rs) ; + SCALE_DIV_ASSIGN (X [4*k + 3], Bz [i + d*3], rs) ; + } + break ; + } + } + + /* ------------------------------------------------------------------ */ + /* solve X = (L*U + Off)\X */ + /* ------------------------------------------------------------------ */ + + for (block = nblocks-1 ; block >= 0 ; block--) + { + + /* -------------------------------------------------------------- */ + /* the block of size nk is from rows/columns k1 to k2-1 */ + /* -------------------------------------------------------------- */ + + k1 = R [block] ; + k2 = R [block+1] ; + nk = k2 - k1 ; + PRINTF (("solve %d, k1 %d k2-1 %d nk %d\n", block, k1,k2-1,nk)) ; + + /* solve the block system */ + if (nk == 1) + { + s = Udiag [k1] ; + switch (nr) + { + + case 1: + DIV (X [k1], X [k1], s) ; + break ; + + case 2: + DIV (X [2*k1], X [2*k1], s) ; + DIV (X [2*k1 + 1], X [2*k1 + 1], s) ; + break ; + + case 3: + DIV (X [3*k1], X [3*k1], s) ; + DIV (X [3*k1 + 1], X [3*k1 + 1], s) ; + DIV (X [3*k1 + 2], X [3*k1 + 2], s) ; + break ; + + case 4: + DIV (X [4*k1], X [4*k1], s) ; + DIV (X [4*k1 + 1], X [4*k1 + 1], s) ; + DIV (X [4*k1 + 2], X [4*k1 + 2], s) ; + DIV (X [4*k1 + 3], X [4*k1 + 3], s) ; + break ; + + } + } + else + { + KLU_lsolve (nk, Lip + k1, Llen + k1, LUbx [block], nr, + X + nr*k1) ; + KLU_usolve (nk, Uip + k1, Ulen + k1, LUbx [block], + Udiag + k1, nr, X + nr*k1) ; + } + + /* -------------------------------------------------------------- */ + /* block back-substitution for the off-diagonal-block entries */ + /* -------------------------------------------------------------- */ + + if (block > 0) + { + switch (nr) + { + + case 1: + + for (k = k1 ; k < k2 ; k++) + { + pend = Offp [k+1] ; + x [0] = X [k] ; + for (p = Offp [k] ; p < pend ; p++) + { + MULT_SUB (X [Offi [p]], Offx [p], x [0]) ; + } + } + break ; + + case 2: + + for (k = k1 ; k < k2 ; k++) + { + pend = Offp [k+1] ; + x [0] = X [2*k ] ; + x [1] = X [2*k + 1] ; + for (p = Offp [k] ; p < pend ; p++) + { + i = Offi [p] ; + offik = Offx [p] ; + MULT_SUB (X [2*i], offik, x [0]) ; + MULT_SUB (X [2*i + 1], offik, x [1]) ; + } + } + break ; + + case 3: + + for (k = k1 ; k < k2 ; k++) + { + pend = Offp [k+1] ; + x [0] = X [3*k ] ; + x [1] = X [3*k + 1] ; + x [2] = X [3*k + 2] ; + for (p = Offp [k] ; p < pend ; p++) + { + i = Offi [p] ; + offik = Offx [p] ; + MULT_SUB (X [3*i], offik, x [0]) ; + MULT_SUB (X [3*i + 1], offik, x [1]) ; + MULT_SUB (X [3*i + 2], offik, x [2]) ; + } + } + break ; + + case 4: + + for (k = k1 ; k < k2 ; k++) + { + pend = Offp [k+1] ; + x [0] = X [4*k ] ; + x [1] = X [4*k + 1] ; + x [2] = X [4*k + 2] ; + x [3] = X [4*k + 3] ; + for (p = Offp [k] ; p < pend ; p++) + { + i = Offi [p] ; + offik = Offx [p] ; + MULT_SUB (X [4*i], offik, x [0]) ; + MULT_SUB (X [4*i + 1], offik, x [1]) ; + MULT_SUB (X [4*i + 2], offik, x [2]) ; + MULT_SUB (X [4*i + 3], offik, x [3]) ; + } + } + break ; + } + } + } + + /* ------------------------------------------------------------------ */ + /* permute the result, Bz = Q*X */ + /* ------------------------------------------------------------------ */ + + switch (nr) + { + + case 1: + + for (k = 0 ; k < n ; k++) + { + Bz [Q [k]] = X [k] ; + } + break ; + + case 2: + + for (k = 0 ; k < n ; k++) + { + i = Q [k] ; + Bz [i ] = X [2*k ] ; + Bz [i + d ] = X [2*k + 1] ; + } + break ; + + case 3: + + for (k = 0 ; k < n ; k++) + { + i = Q [k] ; + Bz [i ] = X [3*k ] ; + Bz [i + d ] = X [3*k + 1] ; + Bz [i + d*2] = X [3*k + 2] ; + } + break ; + + case 4: + + for (k = 0 ; k < n ; k++) + { + i = Q [k] ; + Bz [i ] = X [4*k ] ; + Bz [i + d ] = X [4*k + 1] ; + Bz [i + d*2] = X [4*k + 2] ; + Bz [i + d*3] = X [4*k + 3] ; + } + break ; + } + + /* ------------------------------------------------------------------ */ + /* go to the next chunk of B */ + /* ------------------------------------------------------------------ */ + + Bz += d*4 ; + } + return (TRUE) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_sort.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_sort.c new file mode 100644 index 0000000..a3ce98f --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_sort.c @@ -0,0 +1,156 @@ +/* ========================================================================== */ +/* === KLU_sort ============================================================= */ +/* ========================================================================== */ + +/* sorts the columns of L and U so that the row indices appear in strictly + * increasing order. + */ + +#include "klu_internal.h" + +/* ========================================================================== */ +/* === sort ================================================================= */ +/* ========================================================================== */ + +/* Sort L or U using a double-transpose */ + +static void sort (Int n, Int *Xip, Int *Xlen, Unit *LU, Int *Tp, Int *Tj, + Entry *Tx, Int *W) +{ + Int *Xi ; + Entry *Xx ; + Int p, i, j, len, nz, tp, xlen, pend ; + + ASSERT (KLU_valid_LU (n, FALSE, Xip, Xlen, LU)) ; + + /* count the number of entries in each row of L or U */ + for (i = 0 ; i < n ; i++) + { + W [i] = 0 ; + } + for (j = 0 ; j < n ; j++) + { + GET_POINTER (LU, Xip, Xlen, Xi, Xx, j, len) ; + for (p = 0 ; p < len ; p++) + { + W [Xi [p]]++ ; + } + } + + /* construct the row pointers for T */ + nz = 0 ; + for (i = 0 ; i < n ; i++) + { + Tp [i] = nz ; + nz += W [i] ; + } + Tp [n] = nz ; + for (i = 0 ; i < n ; i++) + { + W [i] = Tp [i] ; + } + + /* transpose the matrix into Tp, Ti, Tx */ + for (j = 0 ; j < n ; j++) + { + GET_POINTER (LU, Xip, Xlen, Xi, Xx, j, len) ; + for (p = 0 ; p < len ; p++) + { + tp = W [Xi [p]]++ ; + Tj [tp] = j ; + Tx [tp] = Xx [p] ; + } + } + + /* transpose the matrix back into Xip, Xlen, Xi, Xx */ + for (j = 0 ; j < n ; j++) + { + W [j] = 0 ; + } + for (i = 0 ; i < n ; i++) + { + pend = Tp [i+1] ; + for (p = Tp [i] ; p < pend ; p++) + { + j = Tj [p] ; + GET_POINTER (LU, Xip, Xlen, Xi, Xx, j, len) ; + xlen = W [j]++ ; + Xi [xlen] = i ; + Xx [xlen] = Tx [p] ; + } + } + + ASSERT (KLU_valid_LU (n, FALSE, Xip, Xlen, LU)) ; +} + + +/* ========================================================================== */ +/* === KLU_sort ============================================================= */ +/* ========================================================================== */ + +Int KLU_sort +( + KLU_symbolic *Symbolic, + KLU_numeric *Numeric, + KLU_common *Common +) +{ + Int *R, *W, *Tp, *Ti, *Lip, *Uip, *Llen, *Ulen ; + Entry *Tx ; + Unit **LUbx ; + Int n, nk, nz, block, nblocks, maxblock, k1 ; + size_t m1 ; + + if (Common == NULL) + { + return (FALSE) ; + } + Common->status = KLU_OK ; + + n = Symbolic->n ; + R = Symbolic->R ; + nblocks = Symbolic->nblocks ; + maxblock = Symbolic->maxblock ; + + Lip = Numeric->Lip ; + Llen = Numeric->Llen ; + Uip = Numeric->Uip ; + Ulen = Numeric->Ulen ; + LUbx = (Unit **) Numeric->LUbx ; + + m1 = ((size_t) maxblock) + 1 ; + + /* allocate workspace */ + nz = MAX (Numeric->max_lnz_block, Numeric->max_unz_block) ; + W = KLU_malloc (maxblock, sizeof (Int), Common) ; + Tp = KLU_malloc (m1, sizeof (Int), Common) ; + Ti = KLU_malloc (nz, sizeof (Int), Common) ; + Tx = KLU_malloc (nz, sizeof (Entry), Common) ; + + PRINTF (("\n======================= Start sort:\n")) ; + + if (Common->status == KLU_OK) + { + /* sort each block of L and U */ + for (block = 0 ; block < nblocks ; block++) + { + k1 = R [block] ; + nk = R [block+1] - k1 ; + if (nk > 1) + { + PRINTF (("\n-------------------block: %d nk %d\n", block, nk)) ; + sort (nk, Lip + k1, Llen + k1, LUbx [block], Tp, Ti, Tx, W) ; + sort (nk, Uip + k1, Ulen + k1, LUbx [block], Tp, Ti, Tx, W) ; + } + } + } + + PRINTF (("\n======================= sort done.\n")) ; + + /* free workspace */ + KLU_free (W, maxblock, sizeof (Int), Common) ; + KLU_free (Tp, m1, sizeof (Int), Common) ; + KLU_free (Ti, nz, sizeof (Int), Common) ; + KLU_free (Tx, nz, sizeof (Entry), Common) ; + return (Common->status == KLU_OK) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_tsolve.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_tsolve.c new file mode 100644 index 0000000..c1f10f7 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Source/klu_tsolve.c @@ -0,0 +1,465 @@ +/* ========================================================================== */ +/* === KLU_tsolve =========================================================== */ +/* ========================================================================== */ + +/* Solve A'x=b using the symbolic and numeric objects from KLU_analyze + * (or KLU_analyze_given) and KLU_factor. Note that no iterative refinement is + * performed. Uses Numeric->Xwork as workspace (undefined on input and output), + * of size 4n Entry's (note that columns 2 to 4 of Xwork overlap with + * Numeric->Iwork). + */ + +#include "klu_internal.h" + +Int KLU_tsolve +( + /* inputs, not modified */ + KLU_symbolic *Symbolic, + KLU_numeric *Numeric, + Int d, /* leading dimension of B */ + Int nrhs, /* number of right-hand-sides */ + + /* right-hand-side on input, overwritten with solution to Ax=b on output */ + double B [ ], /* size n*nrhs, in column-oriented form, with + * leading dimension d. */ +#ifdef COMPLEX + Int conj_solve, /* TRUE for conjugate transpose solve, FALSE for + * array transpose solve. Used for the complex + * case only. */ +#endif + /* --------------- */ + KLU_common *Common +) +{ + Entry x [4], offik, s ; + double rs, *Rs ; + Entry *Offx, *X, *Bz, *Udiag ; + Int *Q, *R, *Pnum, *Offp, *Offi, *Lip, *Uip, *Llen, *Ulen ; + Unit **LUbx ; + Int k1, k2, nk, k, block, pend, n, p, nblocks, chunk, nr, i ; + + /* ---------------------------------------------------------------------- */ + /* check inputs */ + /* ---------------------------------------------------------------------- */ + + if (Common == NULL) + { + return (FALSE) ; + } + if (Numeric == NULL || Symbolic == NULL || d < Symbolic->n || nrhs < 0 || + B == NULL) + { + Common->status = KLU_INVALID ; + return (FALSE) ; + } + Common->status = KLU_OK ; + + /* ---------------------------------------------------------------------- */ + /* get the contents of the Symbolic object */ + /* ---------------------------------------------------------------------- */ + + Bz = (Entry *) B ; + n = Symbolic->n ; + nblocks = Symbolic->nblocks ; + Q = Symbolic->Q ; + R = Symbolic->R ; + + /* ---------------------------------------------------------------------- */ + /* get the contents of the Numeric object */ + /* ---------------------------------------------------------------------- */ + + ASSERT (nblocks == Numeric->nblocks) ; + Pnum = Numeric->Pnum ; + Offp = Numeric->Offp ; + Offi = Numeric->Offi ; + Offx = (Entry *) Numeric->Offx ; + + Lip = Numeric->Lip ; + Llen = Numeric->Llen ; + Uip = Numeric->Uip ; + Ulen = Numeric->Ulen ; + LUbx = (Unit **) Numeric->LUbx ; + Udiag = Numeric->Udiag ; + + Rs = Numeric->Rs ; + X = (Entry *) Numeric->Xwork ; + ASSERT (KLU_valid (n, Offp, Offi, Offx)) ; + + /* ---------------------------------------------------------------------- */ + /* solve in chunks of 4 columns at a time */ + /* ---------------------------------------------------------------------- */ + + for (chunk = 0 ; chunk < nrhs ; chunk += 4) + { + + /* ------------------------------------------------------------------ */ + /* get the size of the current chunk */ + /* ------------------------------------------------------------------ */ + + nr = MIN (nrhs - chunk, 4) ; + + /* ------------------------------------------------------------------ */ + /* permute the right hand side, X = Q'*B */ + /* ------------------------------------------------------------------ */ + + switch (nr) + { + + case 1: + + for (k = 0 ; k < n ; k++) + { + X [k] = Bz [Q [k]] ; + } + break ; + + case 2: + + for (k = 0 ; k < n ; k++) + { + i = Q [k] ; + X [2*k ] = Bz [i ] ; + X [2*k + 1] = Bz [i + d ] ; + } + break ; + + case 3: + + for (k = 0 ; k < n ; k++) + { + i = Q [k] ; + X [3*k ] = Bz [i ] ; + X [3*k + 1] = Bz [i + d ] ; + X [3*k + 2] = Bz [i + d*2] ; + } + break ; + + case 4: + + for (k = 0 ; k < n ; k++) + { + i = Q [k] ; + X [4*k ] = Bz [i ] ; + X [4*k + 1] = Bz [i + d ] ; + X [4*k + 2] = Bz [i + d*2] ; + X [4*k + 3] = Bz [i + d*3] ; + } + break ; + + } + + /* ------------------------------------------------------------------ */ + /* solve X = (L*U + Off)'\X */ + /* ------------------------------------------------------------------ */ + + for (block = 0 ; block < nblocks ; block++) + { + + /* -------------------------------------------------------------- */ + /* the block of size nk is from rows/columns k1 to k2-1 */ + /* -------------------------------------------------------------- */ + + k1 = R [block] ; + k2 = R [block+1] ; + nk = k2 - k1 ; + PRINTF (("tsolve %d, k1 %d k2-1 %d nk %d\n", block, k1,k2-1,nk)) ; + + /* -------------------------------------------------------------- */ + /* block back-substitution for the off-diagonal-block entries */ + /* -------------------------------------------------------------- */ + + if (block > 0) + { + switch (nr) + { + + case 1: + + for (k = k1 ; k < k2 ; k++) + { + pend = Offp [k+1] ; + for (p = Offp [k] ; p < pend ; p++) + { +#ifdef COMPLEX + if (conj_solve) + { + MULT_SUB_CONJ (X [k], X [Offi [p]], + Offx [p]) ; + } + else +#endif + { + MULT_SUB (X [k], Offx [p], X [Offi [p]]) ; + } + } + } + break ; + + case 2: + + for (k = k1 ; k < k2 ; k++) + { + pend = Offp [k+1] ; + x [0] = X [2*k ] ; + x [1] = X [2*k + 1] ; + for (p = Offp [k] ; p < pend ; p++) + { + i = Offi [p] ; +#ifdef COMPLEX + if (conj_solve) + { + CONJ (offik, Offx [p]) ; + } + else +#endif + { + offik = Offx [p] ; + } + MULT_SUB (x [0], offik, X [2*i]) ; + MULT_SUB (x [1], offik, X [2*i + 1]) ; + } + X [2*k ] = x [0] ; + X [2*k + 1] = x [1] ; + } + break ; + + case 3: + + for (k = k1 ; k < k2 ; k++) + { + pend = Offp [k+1] ; + x [0] = X [3*k ] ; + x [1] = X [3*k + 1] ; + x [2] = X [3*k + 2] ; + for (p = Offp [k] ; p < pend ; p++) + { + i = Offi [p] ; +#ifdef COMPLEX + if (conj_solve) + { + CONJ (offik, Offx [p]) ; + } + else +#endif + { + offik = Offx [p] ; + } + MULT_SUB (x [0], offik, X [3*i]) ; + MULT_SUB (x [1], offik, X [3*i + 1]) ; + MULT_SUB (x [2], offik, X [3*i + 2]) ; + } + X [3*k ] = x [0] ; + X [3*k + 1] = x [1] ; + X [3*k + 2] = x [2] ; + } + break ; + + case 4: + + for (k = k1 ; k < k2 ; k++) + { + pend = Offp [k+1] ; + x [0] = X [4*k ] ; + x [1] = X [4*k + 1] ; + x [2] = X [4*k + 2] ; + x [3] = X [4*k + 3] ; + for (p = Offp [k] ; p < pend ; p++) + { + i = Offi [p] ; +#ifdef COMPLEX + if (conj_solve) + { + CONJ(offik, Offx [p]) ; + } + else +#endif + { + offik = Offx [p] ; + } + MULT_SUB (x [0], offik, X [4*i]) ; + MULT_SUB (x [1], offik, X [4*i + 1]) ; + MULT_SUB (x [2], offik, X [4*i + 2]) ; + MULT_SUB (x [3], offik, X [4*i + 3]) ; + } + X [4*k ] = x [0] ; + X [4*k + 1] = x [1] ; + X [4*k + 2] = x [2] ; + X [4*k + 3] = x [3] ; + } + break ; + } + } + + /* -------------------------------------------------------------- */ + /* solve the block system */ + /* -------------------------------------------------------------- */ + + if (nk == 1) + { +#ifdef COMPLEX + if (conj_solve) + { + CONJ (s, Udiag [k1]) ; + } + else +#endif + { + s = Udiag [k1] ; + } + switch (nr) + { + + case 1: + DIV (X [k1], X [k1], s) ; + break ; + + case 2: + DIV (X [2*k1], X [2*k1], s) ; + DIV (X [2*k1 + 1], X [2*k1 + 1], s) ; + break ; + + case 3: + DIV (X [3*k1], X [3*k1], s) ; + DIV (X [3*k1 + 1], X [3*k1 + 1], s) ; + DIV (X [3*k1 + 2], X [3*k1 + 2], s) ; + break ; + + case 4: + DIV (X [4*k1], X [4*k1], s) ; + DIV (X [4*k1 + 1], X [4*k1 + 1], s) ; + DIV (X [4*k1 + 2], X [4*k1 + 2], s) ; + DIV (X [4*k1 + 3], X [4*k1 + 3], s) ; + break ; + + } + } + else + { + KLU_utsolve (nk, Uip + k1, Ulen + k1, LUbx [block], + Udiag + k1, nr, +#ifdef COMPLEX + conj_solve, +#endif + X + nr*k1) ; + KLU_ltsolve (nk, Lip + k1, Llen + k1, LUbx [block], nr, +#ifdef COMPLEX + conj_solve, +#endif + X + nr*k1) ; + } + } + + /* ------------------------------------------------------------------ */ + /* scale and permute the result, Bz = P'(R\X) */ + /* ------------------------------------------------------------------ */ + + if (Rs == NULL) + { + + /* no scaling */ + switch (nr) + { + + case 1: + + for (k = 0 ; k < n ; k++) + { + Bz [Pnum [k]] = X [k] ; + } + break ; + + case 2: + + for (k = 0 ; k < n ; k++) + { + i = Pnum [k] ; + Bz [i ] = X [2*k ] ; + Bz [i + d ] = X [2*k + 1] ; + } + break ; + + case 3: + + for (k = 0 ; k < n ; k++) + { + i = Pnum [k] ; + Bz [i ] = X [3*k ] ; + Bz [i + d ] = X [3*k + 1] ; + Bz [i + d*2] = X [3*k + 2] ; + } + break ; + + case 4: + + for (k = 0 ; k < n ; k++) + { + i = Pnum [k] ; + Bz [i ] = X [4*k ] ; + Bz [i + d ] = X [4*k + 1] ; + Bz [i + d*2] = X [4*k + 2] ; + Bz [i + d*3] = X [4*k + 3] ; + } + break ; + } + + } + else + { + + switch (nr) + { + + case 1: + + for (k = 0 ; k < n ; k++) + { + SCALE_DIV_ASSIGN (Bz [Pnum [k]], X [k], Rs [k]) ; + } + break ; + + case 2: + + for (k = 0 ; k < n ; k++) + { + i = Pnum [k] ; + rs = Rs [k] ; + SCALE_DIV_ASSIGN (Bz [i], X [2*k], rs) ; + SCALE_DIV_ASSIGN (Bz [i + d], X [2*k + 1], rs) ; + } + break ; + + case 3: + + for (k = 0 ; k < n ; k++) + { + i = Pnum [k] ; + rs = Rs [k] ; + SCALE_DIV_ASSIGN (Bz [i], X [3*k], rs) ; + SCALE_DIV_ASSIGN (Bz [i + d], X [3*k + 1], rs) ; + SCALE_DIV_ASSIGN (Bz [i + d*2], X [3*k + 2], rs) ; + } + break ; + + case 4: + + for (k = 0 ; k < n ; k++) + { + i = Pnum [k] ; + rs = Rs [k] ; + SCALE_DIV_ASSIGN (Bz [i], X [4*k], rs) ; + SCALE_DIV_ASSIGN (Bz [i + d], X [4*k + 1], rs) ; + SCALE_DIV_ASSIGN (Bz [i + d*2], X [4*k + 2], rs) ; + SCALE_DIV_ASSIGN (Bz [i + d*3], X [4*k + 3], rs) ; + } + break ; + } + } + + /* ------------------------------------------------------------------ */ + /* go to the next chunk of B */ + /* ------------------------------------------------------------------ */ + + Bz += d*4 ; + } + return (TRUE) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Tcov/klutest.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Tcov/klutest.c new file mode 100644 index 0000000..c097814 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/Tcov/klutest.c @@ -0,0 +1,1384 @@ +/* ========================================================================== */ +/* === KLU test ============================================================= */ +/* ========================================================================== */ + +/* Exhaustive test for KLU and BTF (int, long, real, and complex versions) */ + +#include <string.h> +#include "cholmod.h" +#include "klu_cholmod.h" +#include "klu_internal.h" + +#define ID Int_id + +#define NRHS 6 + +#define HALT { fprintf (stderr, "Test failure: %d\n", __LINE__) ; abort () ; } +#define OK(a) { if (!(a)) HALT ; } +#define FAIL(a) { if (a) HALT ; } + +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + + +#ifdef DLONG + +#define klu_z_scale klu_zl_scale +#define klu_z_solve klu_zl_solve +#define klu_z_tsolve klu_zl_tsolve +#define klu_z_free_numeric klu_zl_free_numeric +#define klu_z_factor klu_zl_factor +#define klu_z_refactor klu_zl_refactor +#define klu_z_lsolve klu_zl_lsolve +#define klu_z_ltsolve klu_zl_ltsolve +#define klu_z_usolve klu_zl_usolve +#define klu_z_utsolve klu_zl_utsolve +#define klu_z_defaults klu_zl_defaults +#define klu_z_rgrowth klu_zl_rgrowth +#define klu_z_rcond klu_zl_rcond +#define klu_z_extract klu_zl_extract +#define klu_z_condest klu_zl_condest +#define klu_z_flops klu_zl_flops + +#define klu_scale klu_l_scale +#define klu_solve klu_l_solve +#define klu_tsolve klu_l_tsolve +#define klu_free_numeric klu_l_free_numeric +#define klu_factor klu_l_factor +#define klu_refactor klu_l_refactor +#define klu_lsolve klu_l_lsolve +#define klu_ltsolve klu_l_ltsolve +#define klu_usolve klu_l_usolve +#define klu_utsolve klu_l_utsolve +#define klu_defaults klu_l_defaults +#define klu_rgrowth klu_l_rgrowth +#define klu_rcond klu_l_rcond +#define klu_extract klu_l_extract +#define klu_condest klu_l_condest +#define klu_flops klu_l_flops + +#define klu_analyze klu_l_analyze +#define klu_analyze_given klu_l_analyze_given +#define klu_malloc klu_l_malloc +#define klu_free klu_l_free +#define klu_realloc klu_l_realloc +#define klu_free_symbolic klu_l_free_symbolic +#define klu_free_numeric klu_l_free_numeric +#define klu_defaults klu_l_defaults + +#define klu_cholmod klu_l_cholmod + +#endif + + +#ifdef DLONG + +#define CHOLMOD_print_sparse cholmod_l_print_sparse +#define CHOLMOD_print_dense cholmod_l_print_dense +#define CHOLMOD_copy_sparse cholmod_l_copy_sparse +#define CHOLMOD_copy_dense cholmod_l_copy_dense +#define CHOLMOD_transpose cholmod_l_transpose +#define CHOLMOD_sdmult cholmod_l_sdmult +#define CHOLMOD_norm_dense cholmod_l_norm_dense +#define CHOLMOD_norm_sparse cholmod_l_norm_sparse +#define CHOLMOD_free_sparse cholmod_l_free_sparse +#define CHOLMOD_free_dense cholmod_l_free_dense +#define CHOLMOD_start cholmod_l_start +#define CHOLMOD_read_sparse cholmod_l_read_sparse +#define CHOLMOD_allocate_dense cholmod_l_allocate_dense +#define CHOLMOD_finish cholmod_l_finish + +#else + +#define CHOLMOD_print_sparse cholmod_print_sparse +#define CHOLMOD_print_dense cholmod_print_dense +#define CHOLMOD_copy_sparse cholmod_copy_sparse +#define CHOLMOD_copy_dense cholmod_copy_dense +#define CHOLMOD_transpose cholmod_transpose +#define CHOLMOD_sdmult cholmod_sdmult +#define CHOLMOD_norm_dense cholmod_norm_dense +#define CHOLMOD_norm_sparse cholmod_norm_sparse +#define CHOLMOD_free_sparse cholmod_free_sparse +#define CHOLMOD_free_dense cholmod_free_dense +#define CHOLMOD_start cholmod_start +#define CHOLMOD_read_sparse cholmod_read_sparse +#define CHOLMOD_allocate_dense cholmod_allocate_dense +#define CHOLMOD_finish cholmod_finish + +#endif + +/* ========================================================================== */ +/* === random numbers ======================================================= */ +/* ========================================================================== */ + +#define MY_RAND_MAX 32767 + +static unsigned long next = 1 ; + +static Int my_rand (void) +{ + next = next * 1103515245 + 12345 ; + return ((unsigned)(next/65536) % (MY_RAND_MAX+1)) ; +} + +static void my_srand (unsigned seed) +{ + next = seed ; +} + +/* ========================================================================== */ +/* === memory management ==================================================== */ +/* ========================================================================== */ + +void *my_malloc (size_t size) ; +void *my_calloc (size_t n, size_t size) ; +void *my_realloc (void *p, size_t size) ; +void my_free (void *p) ; + +Int my_tries = -1 ; + +void *my_malloc (size_t size) +{ + if (my_tries == 0) return (NULL) ; /* pretend to fail */ + if (my_tries > 0) my_tries-- ; + return (malloc (size)) ; +} + +void *my_calloc (size_t n, size_t size) +{ + if (my_tries == 0) return (NULL) ; /* pretend to fail */ + if (my_tries > 0) my_tries-- ; + return (calloc (n, size)) ; +} + +void *my_realloc (void *p, size_t size) +{ + if (my_tries == 0) return (NULL) ; /* pretend to fail */ + if (my_tries > 0) my_tries-- ; + return (realloc (p, size)) ; +} + +void my_free (void *p) +{ + if (p) free (p) ; +} + +static void normal_memory_handler ( void ) +{ + SuiteSparse_config.malloc_func = malloc ; + SuiteSparse_config.calloc_func = calloc ; + SuiteSparse_config.realloc_func = realloc ; + SuiteSparse_config.free_func = free ; + + my_tries = -1 ; +} + +static void test_memory_handler ( void ) +{ + SuiteSparse_config.malloc_func = my_malloc ; + SuiteSparse_config.calloc_func = my_calloc ; + SuiteSparse_config.realloc_func = my_realloc ; + SuiteSparse_config.free_func = my_free ; + my_tries = -1 ; +} + + +/* ========================================================================== */ +/* === print_sparse ========================================================= */ +/* ========================================================================== */ + +/* print a sparse matrix */ + +static void print_sparse (Int n, Int isreal, Int *Ap, Int *Ai, double *Ax, + double *Az) +{ + double ax, az ; + Int i, j, p ; + for (j = 0 ; j < n ; j++) + { + printf ("column "ID":\n", j) ; + for (p = Ap [j] ; p < Ap [j+1] ; p++) + { + i = Ai [p] ; + if (isreal) + { + ax = Ax [p] ; + az = 0 ; + } + else if (Az) + { + /* split complex */ + ax = Ax [p] ; + az = Az [p] ; + } + else + { + /* merged complex */ + ax = Ax [2*p ] ; + az = Ax [2*p+1] ; + } + printf (" row "ID" : %g", i, ax) ; + if (!isreal) + { + printf (" + (%g)i", az) ; + } + printf ("\n") ; + } + } + fflush (stdout) ; +} + + +/* ========================================================================== */ +/* === print_int ============================================================ */ +/* ========================================================================== */ + +/* print an Int vector */ + +static void print_int (Int n, Int *P) +{ + Int j ; + for (j = 0 ; j < n ; j++) + { + printf (" "ID" : "ID"\n", j, P [j]) ; + } + fflush (stdout) ; +} + + +/* ========================================================================== */ +/* === print_double ========================================================= */ +/* ========================================================================== */ + +/* print a double vector */ + +static void print_double (Int n, double *X) +{ + Int j ; + for (j = 0 ; j < n ; j++) + { + printf (" "ID" : %g\n", j, X [j]) ; + } + fflush (stdout) ; +} + + +/* ========================================================================== */ +/* === ludump =============================================================== */ +/* ========================================================================== */ + +/* extract and print the LU factors */ + +static void ludump (KLU_symbolic *Symbolic, KLU_numeric *Numeric, Int isreal, + cholmod_common *ch, KLU_common *Common) +{ + Int *Lp, *Li, *Up, *Ui, *Fp, *Fi, *P, *Q, *R ; + double *Lx, *Ux, *Fx, *Lz, *Uz, *Fz, *Rs ; + Int n, lnz, unz, fnz, nb, result ; + + if (Symbolic == NULL || Numeric == NULL) + { + return ; + } + + n = Symbolic->n ; + lnz = Numeric->lnz ; + unz = Numeric->unz ; + fnz = Numeric->Offp [n] ; + nb = Symbolic->nblocks ; + + printf ("n "ID" lnz "ID" unz "ID" fnz "ID" nblocks "ID" isreal "ID"\n", + n, lnz, unz, fnz, nb, isreal) ; + fflush (stdout) ; + + Lp = malloc ((n+1) * sizeof (Int)) ; + Li = malloc (lnz * sizeof (Int)) ; + Lx = malloc (lnz * sizeof (double)) ; + Lz = malloc (lnz * sizeof (double)) ; + + Up = malloc ((n+1) * sizeof (Int)) ; + Ui = malloc (unz * sizeof (Int)) ; + Ux = malloc (unz * sizeof (double)) ; + Uz = malloc (unz * sizeof (double)) ; + + Fp = malloc ((n+1) * sizeof (Int)) ; + Fi = malloc (fnz * sizeof (Int)) ; + Fx = malloc (fnz * sizeof (double)) ; + Fz = malloc (fnz * sizeof (double)) ; + + P = malloc (n * sizeof (Int)) ; + Q = malloc (n * sizeof (Int)) ; + Rs = malloc (n * sizeof (double)) ; + R = malloc ((nb+1) * sizeof (double)) ; + + if (isreal) + { + result = klu_extract (Numeric, Symbolic, Lp, Li, Lx, + Up, Ui, Ux, Fp, Fi, Fx, P, Q, Rs, R, Common) ; + } + else + { + result = klu_z_extract (Numeric, Symbolic, Lp, Li, Lx, Lz, + Up, Ui, Ux, Uz, Fp, Fi, Fx, Fz, P, Q, Rs, R, Common) ; + } + + if (my_tries != 0) OK (result) ; + + if (ch->print >= 5) + { + printf ("------ L:\n") ; print_sparse (n, isreal, Lp, Li, Lx, Lz) ; + printf ("------ U:\n") ; print_sparse (n, isreal, Up, Ui, Ux, Uz) ; + printf ("------ F:\n") ; print_sparse (n, isreal, Fp, Fi, Fx, Fz) ; + printf ("------ P:\n") ; print_int (n, P) ; + printf ("------ Q:\n") ; print_int (n, Q) ; + printf ("------ Rs:\n") ; print_double (n, Rs) ; + printf ("------ R:\n") ; print_int (nb+1, R) ; + } + + free (Lp) ; + free (Li) ; + free (Lx) ; + free (Lz) ; + + free (Up) ; + free (Ui) ; + free (Ux) ; + free (Uz) ; + + free (Fp) ; + free (Fi) ; + free (Fx) ; + free (Fz) ; + + free (P) ; + free (Q) ; + free (Rs) ; + free (R) ; +} + + +/* ========================================================================== */ +/* === randperm ============================================================= */ +/* ========================================================================== */ + +/* return a random permutation vector */ + +static Int *randperm (Int n, Int seed) +{ + Int *p, k, j, t ; + p = malloc (n * sizeof (Int)) ; + for (k = 0 ; k < n ; k++) + { + p [k] = k ; + } + my_srand (seed) ; /* get new random number seed */ + for (k = 0 ; k < n ; k++) + { + j = k + (my_rand ( ) % (n-k)) ; /* j = my_rand in range k to n-1 */ + t = p [j] ; /* swap p[k] and p[j] */ + p [j] = p [k] ; + p [k] = t ; + } + return (p) ; +} + + +/* ========================================================================== */ +/* === do_1_solve =========================================================== */ +/* ========================================================================== */ + +static double do_1_solve (cholmod_sparse *A, cholmod_dense *B, + cholmod_dense *Xknown, Int *Puser, Int *Quser, + KLU_common *Common, cholmod_common *ch, Int *isnan) +{ + Int *Ai, *Ap ; + double *Ax, *Xknownx, *Xx, *Ax2, *Axx ; + KLU_symbolic *Symbolic = NULL ; + KLU_numeric *Numeric = NULL ; + cholmod_dense *X = NULL, *R = NULL ; + cholmod_sparse *AT = NULL, *A2 = NULL, *AT2 = NULL ; + double one [2], minusone [2], + rnorm, anorm, xnorm, relresid, relerr, err = 0. ; + Int i, j, nrhs2, isreal, n, nrhs, transpose, step, k, save, tries ; + + printf ("\ndo_1_solve: btf "ID" maxwork %g scale "ID" ordering "ID" user: " + ID" P,Q: %d halt: "ID"\n", + Common->btf, Common->maxwork, Common->scale, Common->ordering, + Common->user_data ? (*((Int *) Common->user_data)) : -1, + (Puser != NULL || Quser != NULL), Common->halt_if_singular) ; + fflush (stdout) ; + fflush (stderr) ; + + CHOLMOD_print_sparse (A, "A", ch) ; + CHOLMOD_print_dense (B, "B", ch) ; + + Ap = A->p ; + Ai = A->i ; + Ax = A->x ; + n = A->nrow ; + isreal = (A->xtype == CHOLMOD_REAL) ; + /* Bx = B->x ; */ + Xknownx = Xknown->x ; + nrhs = B->ncol ; + + one [0] = 1 ; + one [1] = 0 ; + + minusone [0] = -1 ; + minusone [1] = 0 ; + + /* ---------------------------------------------------------------------- */ + /* symbolic analysis */ + /* ---------------------------------------------------------------------- */ + + Symbolic = NULL ; + my_tries = 0 ; + for (tries = 0 ; Symbolic == NULL && my_tries == 0 ; tries++) + { + my_tries = tries ; + if (Puser != NULL || Quser != NULL) + { + Symbolic = klu_analyze_given (n, Ap, Ai, Puser, Quser, Common) ; + } + else + { + Symbolic = klu_analyze (n, Ap, Ai, Common) ; + } + } + printf ("sym try "ID" btf "ID" ordering "ID"\n", + tries, Common->btf, Common->ordering) ; + if (Symbolic == NULL) + { + printf ("Symbolic is null\n") ; + return (998) ; + } + my_tries = -1 ; + + /* create a modified version of A */ + + A2 = CHOLMOD_copy_sparse (A, ch) ; + Ax2 = A2->x ; + my_srand (42) ; + for (k = 0 ; k < Ap [n] * (isreal ? 1:2) ; k++) + { + Ax2 [k] = Ax [k] * + (1 + 1e-4 * ((double) my_rand ( )) / ((double) MY_RAND_MAX)) ; + } + + AT = isreal ? NULL : CHOLMOD_transpose (A, 1, ch) ; + AT2 = isreal ? NULL : CHOLMOD_transpose (A2, 1, ch) ; + + /* ---------------------------------------------------------------------- */ + /* factorize then solve */ + /* ---------------------------------------------------------------------- */ + + for (step = 1 ; step <= 3 ; step++) + { + printf ("step: "ID"\n", step) ; + fflush (stdout) ; + + /* ------------------------------------------------------------------ */ + /* factorization or refactorization */ + /* ------------------------------------------------------------------ */ + + /* step 1: factor + step 2: refactor with same A + step 3: refactor with modified A, and scaling forced on + and solve each time + */ + + if (step == 1) + { + /* numeric factorization */ + + Numeric = NULL ; + my_tries = 0 ; + for (tries = 0 ; Numeric == NULL && my_tries == 0 ; tries++) + { + my_tries = tries ; + if (isreal) + { + Numeric = klu_factor (Ap, Ai, Ax, Symbolic, Common) ; + } + else + { + Numeric = klu_z_factor (Ap, Ai, Ax, Symbolic, Common) ; + } + } + printf ("num try "ID" btf "ID"\n", tries, Common->btf) ; + my_tries = -1 ; + + if (Common->status == KLU_OK || + (Common->status == KLU_SINGULAR && !Common->halt_if_singular)) + { + OK (Numeric) ; + } + else + { + FAIL (Numeric) ; + } + + if (Common->status < KLU_OK) + { + printf ("factor failed: "ID"\n", Common->status) ; + } + + } + else if (step == 2) + { + + /* numeric refactorization with same values, same scaling */ + if (isreal) + { + klu_refactor (Ap, Ai, Ax, Symbolic, Numeric, Common) ; + } + else + { + klu_z_refactor (Ap, Ai, Ax, Symbolic, Numeric, Common) ; + } + + } + else + { + + /* numeric refactorization with different values */ + save = Common->scale ; + if (Common->scale == 0) + { + Common->scale = 1 ; + } + for (tries = 0 ; tries <= 1 ; tries++) + { + my_tries = tries ; + if (isreal) + { + klu_refactor (Ap, Ai, Ax2, Symbolic, Numeric, Common) ; + } + else + { + klu_z_refactor (Ap, Ai, Ax2, Symbolic, Numeric, Common) ; + } + } + my_tries = -1 ; + Common->scale = save ; + } + + if (Common->status == KLU_SINGULAR) + { + printf ("# singular column : "ID"\n", Common->singular_col) ; + } + + /* ------------------------------------------------------------------ */ + /* diagnostics */ + /* ------------------------------------------------------------------ */ + + Axx = (step == 3) ? Ax2 : Ax ; + + if (isreal) + { + klu_rgrowth (Ap, Ai, Axx, Symbolic, Numeric, Common) ; + klu_condest (Ap, Axx, Symbolic, Numeric, Common) ; + klu_rcond (Symbolic, Numeric, Common) ; + klu_flops (Symbolic, Numeric, Common) ; + } + else + { + klu_z_rgrowth (Ap, Ai, Axx, Symbolic, Numeric, Common) ; + klu_z_condest (Ap, Axx, Symbolic, Numeric, Common) ; + klu_z_rcond (Symbolic, Numeric, Common) ; + klu_z_flops (Symbolic, Numeric, Common) ; + } + + printf ("growth %g condest %g rcond %g flops %g\n", + Common->rgrowth, Common->condest, Common->rcond, Common->flops) ; + + ludump (Symbolic, Numeric, isreal, ch, Common) ; + + if (Numeric == NULL || Common->status < KLU_OK) + { + continue ; + } + + /* ------------------------------------------------------------------ */ + /* solve */ + /* ------------------------------------------------------------------ */ + + /* forward/backsolve to solve A*X=B or A'*X=B */ + for (transpose = (isreal ? 0 : -1) ; transpose <= 1 ; transpose++) + { + + for (nrhs2 = 1 ; nrhs2 <= nrhs ; nrhs2++) + { + /* mangle B so that it has only nrhs2 columns */ + B->ncol = nrhs2 ; + + X = CHOLMOD_copy_dense (B, ch) ; + CHOLMOD_print_dense (X, "X before solve", ch) ; + Xx = X->x ; + + if (isreal) + { + if (transpose) + { + /* solve A'x=b */ + klu_tsolve (Symbolic, Numeric, n, nrhs2, Xx, Common) ; + } + else + { + /* solve A*x=b */ + klu_solve (Symbolic, Numeric, n, nrhs2, Xx, Common) ; + } + } + else + { + if (transpose) + { + /* solve A'x=b (if 1) or A.'x=b (if -1) */ + klu_z_tsolve (Symbolic, Numeric, n, nrhs2, Xx, + (transpose == 1), Common) ; + } + else + { + /* solve A*x=b */ + klu_z_solve (Symbolic, Numeric, n, nrhs2, Xx, Common) ; + } + } + + CHOLMOD_print_dense (X, "X", ch) ; + + /* compute the residual, R = B-A*X, B-A'*X, or B-A.'*X */ + R = CHOLMOD_copy_dense (B, ch) ; + if (transpose == -1) + { + /* R = B-A.'*X (use A.' explicitly) */ + CHOLMOD_sdmult ((step == 3) ? AT2 : AT, + 0, minusone, one, X, R, ch) ; + } + else + { + /* R = B-A*X or B-A'*X */ + CHOLMOD_sdmult ((step == 3) ? A2 :A, + transpose, minusone, one, X, R, ch) ; + } + + CHOLMOD_print_dense (R, "R", ch) ; + + /* compute the norms of R, A, X, and B */ + rnorm = CHOLMOD_norm_dense (R, 1, ch) ; + anorm = CHOLMOD_norm_sparse ((step == 3) ? A2 : A, 1, ch) ; + xnorm = CHOLMOD_norm_dense (X, 1, ch) ; + /* bnorm = CHOLMOD_norm_dense (B, 1, ch) ; */ + + CHOLMOD_free_dense (&R, ch) ; + + /* relative residual = norm (r) / (norm (A) * norm (x)) */ + relresid = rnorm ; + if (anorm > 0) + { + relresid /= anorm ; + } + if (xnorm > 0) + { + relresid /= xnorm ; + } + + if (SCALAR_IS_NAN (relresid)) + { + *isnan = TRUE ; + } + else + { + err = MAX (err, relresid) ; + } + + /* relative error = norm (x - xknown) / norm (xknown) */ + /* overwrite X with X - Xknown */ + if (transpose || step == 3) + { + /* not computed */ + relerr = -1 ; + } + else + { + for (j = 0 ; j < nrhs2 ; j++) + { + for (i = 0 ; i < n ; i++) + { + if (isreal) + { + Xx [i+j*n] -= Xknownx [i+j*n] ; + } + else + { + Xx [2*(i+j*n) ] -= Xknownx [2*(i+j*n) ] ; + Xx [2*(i+j*n)+1] -= Xknownx [2*(i+j*n)+1] ; + } + } + } + relerr = CHOLMOD_norm_dense (X, 1, ch) ; + xnorm = CHOLMOD_norm_dense (Xknown, 1, ch) ; + if (xnorm > 0) + { + relerr /= xnorm ; + } + + if (SCALAR_IS_NAN (relerr)) + { + *isnan = TRUE ; + } + else + { + err = MAX (relerr, err) ; + } + + } + + CHOLMOD_free_dense (&X, ch) ; + + printf (ID" "ID" relresid %10.3g relerr %10.3g %g\n", + transpose, nrhs2, relresid, relerr, err) ; + + B->ncol = nrhs ; /* restore B */ + } + } + } + + /* ---------------------------------------------------------------------- */ + /* free factorization and temporary matrices, and return */ + /* ---------------------------------------------------------------------- */ + + klu_free_symbolic (&Symbolic, Common) ; + if (isreal) + { + klu_free_numeric (&Numeric, Common) ; + } + else + { + klu_z_free_numeric (&Numeric, Common) ; + } + CHOLMOD_free_sparse (&A2, ch) ; + CHOLMOD_free_sparse (&AT, ch) ; + CHOLMOD_free_sparse (&AT2, ch) ; + fflush (stdout) ; + fflush (stderr) ; + return (err) ; +} + + +/* ========================================================================== */ +/* === do_solves ============================================================ */ +/* ========================================================================== */ + +/* test KLU with many options */ + +static double do_solves (cholmod_sparse *A, cholmod_dense *B, cholmod_dense *X, + Int *Puser, Int *Quser, KLU_common *Common, cholmod_common *ch, Int *isnan) +{ + double err, maxerr = 0 ; + Int n = A->nrow, sflag ; + *isnan = FALSE ; + + /* ---------------------------------------------------------------------- */ + /* test KLU with the system A*X=B and default options */ + /* ---------------------------------------------------------------------- */ + + maxerr = do_1_solve (A, B, X, NULL, NULL, Common, ch, isnan) ; + + /* ---------------------------------------------------------------------- */ + /* test with non-default options */ + /* ---------------------------------------------------------------------- */ + + Common->user_order = klu_cholmod ; + for (Common->btf = 0 ; Common->btf <= 2 ; Common->btf++) + { + Common->maxwork = (Common->btf == 2) ? 0.001 : 0 ; + + for (Common->halt_if_singular = 0 ; Common->halt_if_singular <= 1 ; + Common->halt_if_singular++) + { + for (Common->scale = 0 ; Common->scale <= 2 ; Common->scale++) + + { + fprintf (stderr, ".") ; + fflush (stderr) ; + + /* orderings: 0: AMD, 1: COLAMD, 2: natural, 3: user function */ + for (Common->ordering = 0 ; Common->ordering <= 3 ; + Common->ordering++) + { + err = do_1_solve (A, B, X, NULL, NULL, Common, ch, isnan) ; + maxerr = MAX (maxerr, err) ; + } + + /* user-ordering, unsymmetric case */ + Common->ordering = 3 ; + Common->user_data = &sflag ; + sflag = 0 ; + err = do_1_solve (A, B, X, NULL, NULL, Common, ch, isnan) ; + maxerr = MAX (maxerr, err) ; + Common->user_data = NULL ; + + /* Puser and Quser, but only for small matrices */ + Common->ordering = 2 ; + if (n < 200) + { + err = do_1_solve (A, B, X, Puser, Quser, Common, ch, isnan); + maxerr = MAX (maxerr, err) ; + } + } + } + } + + /* restore defaults */ + Common->btf = TRUE ; + Common->maxwork = 0 ; + Common->ordering = 0 ; + Common->scale = -1 ; + Common->halt_if_singular = TRUE ; + Common->user_order = NULL ; + + my_tries = -1 ; + return (maxerr) ; +} + + +/* ========================================================================== */ +/* === main ================================================================= */ +/* ========================================================================== */ + +int main (void) +{ + KLU_common Common ; + cholmod_sparse *A, *A2 ; + cholmod_dense *X, *B ; + cholmod_common ch ; + Int *Ap, *Ai, *Puser, *Quser, *Gunk ; + double *Ax, *Xx, *A2x ; + double one [2], zero [2], xsave, maxerr ; + Int n, i, j, nz, save, isreal, k, isnan ; + KLU_symbolic *Symbolic, *Symbolic2 ; + KLU_numeric *Numeric ; + + one [0] = 1 ; + one [1] = 0 ; + zero [0] = 0 ; + zero [1] = 0 ; + + printf ("klu test: -------------------------------------------------\n") ; + OK (klu_defaults (&Common)) ; + CHOLMOD_start (&ch) ; + ch.print = 0 ; + normal_memory_handler ( ) ; + + /* ---------------------------------------------------------------------- */ + /* read in a sparse matrix from stdin */ + /* ---------------------------------------------------------------------- */ + + A = CHOLMOD_read_sparse (stdin, &ch) ; + + if (A->nrow != A->ncol || A->stype != 0) + { + fprintf (stderr, "error: only square unsymmetric matrices handled\n") ; + CHOLMOD_free_sparse (&A, &ch) ; + return (0) ; + } + if (!(A->xtype == CHOLMOD_REAL || A->xtype == CHOLMOD_COMPLEX)) + { + fprintf (stderr, "error: only real or complex matrices hanlded\n") ; + CHOLMOD_free_sparse (&A, &ch) ; + return (0) ; + } + + n = A->nrow ; + Ap = A->p ; + Ai = A->i ; + Ax = A->x ; + nz = Ap [n] ; + isreal = (A->xtype == CHOLMOD_REAL) ; + + /* ---------------------------------------------------------------------- */ + /* construct random permutations */ + /* ---------------------------------------------------------------------- */ + + Puser = randperm (n, n) ; + Quser = randperm (n, n) ; + + /* ---------------------------------------------------------------------- */ + /* select known solution to Ax=b */ + /* ---------------------------------------------------------------------- */ + + X = CHOLMOD_allocate_dense (n, NRHS, n, A->xtype, &ch) ; + Xx = X->x ; + for (j = 0 ; j < NRHS ; j++) + { + for (i = 0 ; i < n ; i++) + { + if (isreal) + { + Xx [i] = 1 + ((double) i) / ((double) n) + j * 100; + } + else + { + Xx [2*i ] = 1 + ((double) i) / ((double) n) + j * 100 ; + Xx [2*i+1] = - ((double) i+1) / ((double) n + j) ; + if (j == NRHS-1) + { + Xx [2*i+1] = 0 ; /* zero imaginary part */ + } + else if (j == NRHS-2) + { + Xx [2*i] = 0 ; /* zero real part */ + } + } + } + Xx += isreal ? n : 2*n ; + } + + /* B = A*X */ + B = CHOLMOD_allocate_dense (n, NRHS, n, A->xtype, &ch) ; + CHOLMOD_sdmult (A, 0, one, zero, X, B, &ch) ; + /* Bx = B->x ; */ + + /* ---------------------------------------------------------------------- */ + /* test KLU */ + /* ---------------------------------------------------------------------- */ + + test_memory_handler ( ) ; + maxerr = do_solves (A, B, X, Puser, Quser, &Common, &ch, &isnan) ; + + /* ---------------------------------------------------------------------- */ + /* basic error checking */ + /* ---------------------------------------------------------------------- */ + + FAIL (klu_defaults (NULL)) ; + + FAIL (klu_extract (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL)) ; + FAIL (klu_extract (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, &Common)) ; + + FAIL (klu_z_extract (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) ; + FAIL (klu_z_extract (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &Common)) ; + + FAIL (klu_analyze (0, NULL, NULL, NULL)) ; + FAIL (klu_analyze (0, NULL, NULL, &Common)) ; + + FAIL (klu_analyze_given (0, NULL, NULL, NULL, NULL, NULL)) ; + FAIL (klu_analyze_given (0, NULL, NULL, NULL, NULL, &Common)) ; + + FAIL (klu_cholmod (0, NULL, NULL, NULL, NULL)) ; + + FAIL (klu_factor (NULL, NULL, NULL, NULL, NULL)) ; + FAIL (klu_factor (NULL, NULL, NULL, NULL, &Common)) ; + + FAIL (klu_z_factor (NULL, NULL, NULL, NULL, NULL)) ; + FAIL (klu_z_factor (NULL, NULL, NULL, NULL, &Common)) ; + + FAIL (klu_refactor (NULL, NULL, NULL, NULL, NULL, NULL)) ; + FAIL (klu_refactor (NULL, NULL, NULL, NULL, NULL, &Common)) ; + + FAIL (klu_z_refactor (NULL, NULL, NULL, NULL, NULL, NULL)) ; + FAIL (klu_z_refactor (NULL, NULL, NULL, NULL, NULL, &Common)) ; + + FAIL (klu_rgrowth (NULL, NULL, NULL, NULL, NULL, NULL)) ; + FAIL (klu_rgrowth (NULL, NULL, NULL, NULL, NULL, &Common)) ; + + FAIL (klu_z_rgrowth (NULL, NULL, NULL, NULL, NULL, NULL)) ; + FAIL (klu_z_rgrowth (NULL, NULL, NULL, NULL, NULL, &Common)) ; + + FAIL (klu_condest (NULL, NULL, NULL, NULL, NULL)) ; + FAIL (klu_condest (NULL, NULL, NULL, NULL, &Common)) ; + + FAIL (klu_z_condest (NULL, NULL, NULL, NULL, NULL)) ; + FAIL (klu_z_condest (NULL, NULL, NULL, NULL, &Common)) ; + + FAIL (klu_flops (NULL, NULL, NULL)) ; + FAIL (klu_flops (NULL, NULL, &Common)) ; + + FAIL (klu_z_flops (NULL, NULL, NULL)) ; + FAIL (klu_z_flops (NULL, NULL, &Common)) ; + + FAIL (klu_rcond (NULL, NULL, NULL)) ; + FAIL (klu_rcond (NULL, NULL, &Common)) ; + + FAIL (klu_z_rcond (NULL, NULL, NULL)) ; + FAIL (klu_z_rcond (NULL, NULL, &Common)) ; + + FAIL (klu_free_symbolic (NULL, NULL)) ; + OK (klu_free_symbolic (NULL, &Common)) ; + + FAIL (klu_free_numeric (NULL, NULL)) ; + OK (klu_free_numeric (NULL, &Common)) ; + + FAIL (klu_z_free_numeric (NULL, NULL)) ; + OK (klu_z_free_numeric (NULL, &Common)) ; + + FAIL (klu_scale (0, 0, NULL, NULL, NULL, NULL, NULL, NULL)) ; + FAIL (klu_scale (0, 0, NULL, NULL, NULL, NULL, NULL, &Common)) ; + OK (klu_scale (-1, 0, NULL, NULL, NULL, NULL, NULL, &Common)) ; + + FAIL (klu_z_scale (0, 0, NULL, NULL, NULL, NULL, NULL, NULL)) ; + FAIL (klu_z_scale (0, 0, NULL, NULL, NULL, NULL, NULL, &Common)) ; + OK (klu_z_scale (-1, 0, NULL, NULL, NULL, NULL, NULL, &Common)) ; + + FAIL (klu_solve (NULL, NULL, 0, 0, NULL, NULL)) ; + FAIL (klu_solve (NULL, NULL, 0, 0, NULL, &Common)) ; + + FAIL (klu_z_solve (NULL, NULL, 0, 0, NULL, NULL)) ; + FAIL (klu_z_solve (NULL, NULL, 0, 0, NULL, &Common)) ; + + FAIL (klu_tsolve (NULL, NULL, 0, 0, NULL, NULL)) ; + FAIL (klu_tsolve (NULL, NULL, 0, 0, NULL, &Common)) ; + + FAIL (klu_z_tsolve (NULL, NULL, 0, 0, NULL, 0, NULL)) ; + FAIL (klu_z_tsolve (NULL, NULL, 0, 0, NULL, 0, &Common)) ; + + FAIL (klu_malloc (0, 0, NULL)) ; + FAIL (klu_malloc (0, 0, &Common)) ; + FAIL (klu_malloc (Int_MAX, 1, &Common)) ; + + FAIL (klu_realloc (0, 0, 0, NULL, NULL)) ; + FAIL (klu_realloc (0, 0, 0, NULL, &Common)) ; + FAIL (klu_realloc (Int_MAX, 1, 0, NULL, &Common)) ; + Gunk = (Int *) klu_realloc (1, 0, sizeof (Int), NULL, &Common) ; + OK (Gunk) ; + OK (klu_realloc (Int_MAX, 1, sizeof (Int), Gunk, &Common)) ; + OK (Common.status == KLU_TOO_LARGE) ; + klu_free (Gunk, 1, sizeof (Int), &Common) ; + + /* ---------------------------------------------------------------------- */ + /* mangle the matrix, and other error checking */ + /* ---------------------------------------------------------------------- */ + + printf ("\nerror handling:\n") ; + Symbolic = klu_analyze (n, Ap, Ai, &Common) ; + OK (Symbolic) ; + + Xx = X->x ; + if (nz > 0) + { + + /* ------------------------------------------------------------------ */ + /* row index out of bounds */ + /* ------------------------------------------------------------------ */ + + save = Ai [0] ; + Ai [0] = -1 ; + FAIL (klu_analyze (n, Ap, Ai, &Common)) ; + if (isreal) + { + FAIL (klu_scale (1, n, Ap, Ai, Ax, Xx, Puser, &Common)) ; + } + else + { + FAIL (klu_z_scale (1, n, Ap, Ai, Ax, Xx, Puser, &Common)) ; + } + Ai [0] = save ; + + /* ------------------------------------------------------------------ */ + /* row index out of bounds */ + /* ------------------------------------------------------------------ */ + + save = Ai [0] ; + Ai [0] = Int_MAX ; + FAIL (klu_analyze (n, Ap, Ai, &Common)) ; + if (isreal) + { + FAIL (klu_scale (1, n, Ap, Ai, Ax, Xx, Puser, &Common)) ; + } + else + { + FAIL (klu_z_scale (1, n, Ap, Ai, Ax, Xx, Puser, &Common)) ; + } + Ai [0] = save ; + + /* ------------------------------------------------------------------ */ + /* column pointers mangled */ + /* ------------------------------------------------------------------ */ + + save = Ap [n] ; + Ap [n] = -1 ; + FAIL (klu_analyze (n, Ap, Ai, &Common)) ; + if (isreal) + { + FAIL (klu_scale (1, n, Ap, Ai, Ax, Xx, Puser, &Common)) ; + } + else + { + FAIL (klu_z_scale (1, n, Ap, Ai, Ax, Xx, Puser, &Common)) ; + } + Ap [n] = save ; + + /* ------------------------------------------------------------------ */ + /* column pointers mangled */ + /* ------------------------------------------------------------------ */ + + save = Ap [n] ; + Ap [n] = Ap [n-1] - 1 ; + FAIL (klu_analyze (n, Ap, Ai, &Common)) ; + if (isreal) + { + FAIL (klu_scale (1, n, Ap, Ai, Ax, Xx, Puser, &Common)) ; + } + else + { + FAIL (klu_z_scale (1, n, Ap, Ai, Ax, Xx, Puser, &Common)) ; + } + Ap [n] = save ; + + /* ------------------------------------------------------------------ */ + /* duplicates */ + /* ------------------------------------------------------------------ */ + + if (n > 1 && Ap [1] - Ap [0] > 1) + { + save = Ai [1] ; + Ai [1] = Ai [0] ; + FAIL (klu_analyze (n, Ap, Ai, &Common)) ; + if (isreal) + { + FAIL (klu_scale (1, n, Ap, Ai, Ax, Xx, Puser, &Common)) ; + } + else + { + FAIL (klu_z_scale (1, n, Ap, Ai, Ax, Xx, Puser, &Common)) ; + } + Ai [1] = save ; + } + + /* ------------------------------------------------------------------ */ + /* invalid ordering */ + /* ------------------------------------------------------------------ */ + + save = Common.ordering ; + Common.ordering = 42 ; + FAIL (klu_analyze (n, Ap, Ai, &Common)) ; + Common.ordering = save ; + + /* ------------------------------------------------------------------ */ + /* invalid ordering (klu_cholmod, with NULL user_ordering) */ + /* ------------------------------------------------------------------ */ + + save = Common.ordering ; + Common.user_order = NULL ; + Common.ordering = 3 ; + FAIL (klu_analyze (n, Ap, Ai, &Common)) ; + Common.ordering = save ; + } + + /* ---------------------------------------------------------------------- */ + /* tests with valid symbolic factorization */ + /* ---------------------------------------------------------------------- */ + + Common.halt_if_singular = FALSE ; + Common.scale = 0 ; + Numeric = NULL ; + + if (nz > 0) + { + + /* ------------------------------------------------------------------ */ + /* Int overflow */ + /* ------------------------------------------------------------------ */ + + if (n == 100) + { + Common.ordering = 2 ; + Symbolic2 = klu_analyze (n, Ap, Ai, &Common) ; + OK (Symbolic2) ; + Common.memgrow = Int_MAX ; + if (isreal) + { + Numeric = klu_factor (Ap, Ai, Ax, Symbolic2, &Common) ; + } + else + { + Numeric = klu_z_factor (Ap, Ai, Ax, Symbolic2, &Common) ; + } + Common.memgrow = 1.2 ; + Common.ordering = 0 ; + klu_free_symbolic (&Symbolic2, &Common) ; + klu_free_numeric (&Numeric, &Common) ; + } + + /* ------------------------------------------------------------------ */ + /* Int overflow again */ + /* ------------------------------------------------------------------ */ + + Common.initmem = Int_MAX ; + Common.initmem_amd = Int_MAX ; + if (isreal) + { + Numeric = klu_factor (Ap, Ai, Ax, Symbolic, &Common) ; + } + else + { + Numeric = klu_z_factor (Ap, Ai, Ax, Symbolic, &Common) ; + } + Common.initmem = 10 ; + Common.initmem_amd = 1.2 ; + klu_free_numeric (&Numeric, &Common) ; + + /* ------------------------------------------------------------------ */ + /* mangle the matrix */ + /* ------------------------------------------------------------------ */ + + save = Ai [0] ; + Ai [0] = -1 ; + + if (isreal) + { + Numeric = klu_factor (Ap, Ai, Ax, Symbolic, &Common) ; + } + else + { + Numeric = klu_z_factor (Ap, Ai, Ax, Symbolic, &Common) ; + } + FAIL (Numeric) ; + Ai [0] = save ; + + /* ------------------------------------------------------------------ */ + /* nan and inf handling */ + /* ------------------------------------------------------------------ */ + + xsave = Ax [0] ; + Ax [0] = one [0] / zero [0] ; + if (isreal) + { + Numeric = klu_factor (Ap, Ai, Ax, Symbolic, &Common) ; + klu_rcond (Symbolic, Numeric, &Common) ; + klu_condest (Ap, Ax, Symbolic, Numeric, &Common) ; + } + else + { + Numeric = klu_z_factor (Ap, Ai, Ax, Symbolic, &Common) ; + klu_z_rcond (Symbolic, Numeric, &Common) ; + klu_z_condest (Ap, Ax, Symbolic, Numeric, &Common) ; + } + printf ("Nan case: rcond %g condest %g\n", + Common.rcond, Common.condest) ; + OK (Numeric) ; + Ax [0] = xsave ; + + /* ------------------------------------------------------------------ */ + /* mangle the matrix again */ + /* ------------------------------------------------------------------ */ + + save = Ai [0] ; + Ai [0] = -1 ; + if (isreal) + { + FAIL (klu_refactor (Ap, Ai, Ax, Symbolic, Numeric, &Common)) ; + } + else + { + FAIL (klu_z_refactor (Ap, Ai, Ax, Symbolic, Numeric, &Common)) ; + } + Ai [0] = save ; + + /* ------------------------------------------------------------------ */ + /* all zero */ + /* ------------------------------------------------------------------ */ + + A2 = CHOLMOD_copy_sparse (A, &ch) ; + A2x = A2->x ; + for (k = 0 ; k < nz * (isreal ? 1:2) ; k++) + { + A2x [k] = 0 ; + } + for (Common.halt_if_singular = 0 ; Common.halt_if_singular <= 1 ; + Common.halt_if_singular++) + { + for (Common.scale = -1 ; Common.scale <= 2 ; Common.scale++) + { + if (isreal) + { + klu_refactor (Ap, Ai, A2x, Symbolic, Numeric, &Common) ; + klu_condest (Ap, A2x, Symbolic, Numeric, &Common) ; + } + else + { + klu_z_refactor (Ap, Ai, A2x, Symbolic, Numeric, &Common) ; + klu_z_condest (Ap, A2x, Symbolic, Numeric, &Common) ; + } + OK (Common.status = KLU_SINGULAR) ; + } + } + CHOLMOD_free_sparse (&A2, &ch) ; + + /* ------------------------------------------------------------------ */ + /* all one, or all 1i for complex case */ + /* ------------------------------------------------------------------ */ + + A2 = CHOLMOD_copy_sparse (A, &ch) ; + A2x = A2->x ; + for (k = 0 ; k < nz ; k++) + { + if (isreal) + { + A2x [k] = 1 ; + } + else + { + A2x [2*k ] = 0 ; + A2x [2*k+1] = 1 ; + } + } + Common.halt_if_singular = 0 ; + Common.scale = 0 ; + if (isreal) + { + klu_refactor (Ap, Ai, A2x, Symbolic, Numeric, &Common) ; + klu_condest (Ap, A2x, Symbolic, Numeric, &Common) ; + } + else + { + klu_z_refactor (Ap, Ai, A2x, Symbolic, Numeric, &Common) ; + klu_z_condest (Ap, A2x, Symbolic, Numeric, &Common) ; + } + OK (Common.status = KLU_SINGULAR) ; + CHOLMOD_free_sparse (&A2, &ch) ; + } + + klu_free_symbolic (&Symbolic, &Common) ; + if (isreal) + { + klu_free_numeric (&Numeric, &Common) ; + } + else + { + klu_z_free_numeric (&Numeric, &Common) ; + } + + /* ---------------------------------------------------------------------- */ + /* free problem and quit */ + /* ---------------------------------------------------------------------- */ + + CHOLMOD_free_dense (&X, &ch) ; + CHOLMOD_free_dense (&B, &ch) ; + CHOLMOD_free_sparse (&A, &ch) ; + free (Puser) ; + free (Quser) ; + CHOLMOD_finish (&ch) ; + fprintf (stderr, " maxerr %10.3e", maxerr) ; + printf (" maxerr %10.3e", maxerr) ; + if (maxerr < 1e-8) + { + fprintf (stderr, " test passed") ; + printf (" test passed") ; + } + else + { + fprintf (stderr, " test FAILED") ; + printf (" test FAILED") ; + } + if (isnan) + { + fprintf (stderr, " *") ; + printf (" *") ; + } + fprintf (stderr, "\n") ; + printf ("\n-----------------------------------------------------------\n") ; + return (0) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/User/klu_cholmod.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/User/klu_cholmod.c new file mode 100644 index 0000000..c1c1872 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/User/klu_cholmod.c @@ -0,0 +1,108 @@ +/* ========================================================================== */ +/* === klu_cholmod ========================================================== */ +/* ========================================================================== */ + +/* klu_cholmod: user-defined ordering function to interface KLU to CHOLMOD. + * + * This routine is an example of a user-provided ordering function for KLU. + * Its return value is klu_cholmod's estimate of max (nnz(L),nnz(U)): + * 0 if error, + * -1 if OK, but estimate of max (nnz(L),nnz(U)) not computed + * > 0 if OK and estimate computed. + * + * This function can be assigned to KLU's Common->user_order function pointer. + */ + +#include "klu_cholmod.h" +#include "cholmod.h" +#define TRUE 1 +#define FALSE 0 + +int klu_cholmod +( + /* inputs */ + int n, /* A is n-by-n */ + int Ap [ ], /* column pointers */ + int Ai [ ], /* row indices */ + /* outputs */ + int Perm [ ], /* fill-reducing permutation */ + /* user-defined */ + klu_common *Common /* user-defined data is in Common->user_data */ +) +{ + double one [2] = {1,0}, zero [2] = {0,0}, lnz = 0 ; + cholmod_sparse Amatrix, *A, *AT, *S ; + cholmod_factor *L ; + cholmod_common cm ; + int *P ; + int k, symmetric ; + + if (Ap == NULL || Ai == NULL || Perm == NULL || n < 0) + { + /* invalid inputs */ + return (0) ; + } + + /* start CHOLMOD */ + cholmod_start (&cm) ; + cm.supernodal = CHOLMOD_SIMPLICIAL ; + cm.print = 0 ; + + /* construct a CHOLMOD version of the input matrix A */ + A = &Amatrix ; + A->nrow = n ; /* A is n-by-n */ + A->ncol = n ; + A->nzmax = Ap [n] ; /* with nzmax entries */ + A->packed = TRUE ; /* there is no A->nz array */ + A->stype = 0 ; /* A is unsymmetric */ + A->itype = CHOLMOD_INT ; + A->xtype = CHOLMOD_PATTERN ; + A->dtype = CHOLMOD_DOUBLE ; + A->nz = NULL ; + A->p = Ap ; /* column pointers */ + A->i = Ai ; /* row indices */ + A->x = NULL ; /* no numerical values */ + A->z = NULL ; + A->sorted = FALSE ; /* columns of A are not sorted */ + + /* get the user_data; default is symmetric if user_data is NULL */ + symmetric = (Common->user_data == NULL) ? TRUE : + (((int *) (Common->user_data)) [0] != 0) ; + + /* AT = pattern of A' */ + AT = cholmod_transpose (A, 0, &cm) ; + if (symmetric) + { + /* S = the symmetric pattern of A+A' */ + S = cholmod_add (A, AT, one, zero, FALSE, FALSE, &cm) ; + cholmod_free_sparse (&AT, &cm) ; + if (S != NULL) + { + S->stype = 1 ; + } + } + else + { + /* S = A'. CHOLMOD will order S*S', which is A'*A */ + S = AT ; + } + + /* order and analyze S or S*S' */ + L = cholmod_analyze (S, &cm) ; + + /* copy the permutation from L to the output */ + if (L != NULL) + { + P = L->Perm ; + for (k = 0 ; k < n ; k++) + { + Perm [k] = P [k] ; + } + lnz = cm.lnz ; + } + + cholmod_free_sparse (&S, &cm) ; + cholmod_free_factor (&L, &cm) ; + cholmod_finish (&cm) ; + return (lnz) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/User/klu_cholmod.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/User/klu_cholmod.h new file mode 100644 index 0000000..8f532a2 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/User/klu_cholmod.h @@ -0,0 +1,7 @@ +#include "klu.h" + +int klu_cholmod (int n, int Ap [ ], int Ai [ ], int Perm [ ], klu_common *) ; + +SuiteSparse_long klu_l_cholmod (SuiteSparse_long n, SuiteSparse_long Ap [ ], + SuiteSparse_long Ai [ ], SuiteSparse_long Perm [ ], klu_l_common *) ; + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/User/klu_l_cholmod.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/User/klu_l_cholmod.c new file mode 100644 index 0000000..0307546 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/KLU/User/klu_l_cholmod.c @@ -0,0 +1,108 @@ +/* ========================================================================== */ +/* === klu_cholmod ========================================================== */ +/* ========================================================================== */ + +/* klu_l_cholmod: user-defined ordering function to interface KLU to CHOLMOD. + * + * This routine is an example of a user-provided ordering function for KLU. + * Its return value is klu_l_cholmod's estimate of max (nnz(L),nnz(U)): + * 0 if error, + * -1 if OK, but estimate of max (nnz(L),nnz(U)) not computed + * > 0 if OK and estimate computed. + * + * This function can be assigned to KLU's Common->user_order function pointer. + */ + +#include "klu_cholmod.h" +#include "cholmod.h" +#define TRUE 1 +#define FALSE 0 + +SuiteSparse_long klu_l_cholmod +( + /* inputs */ + SuiteSparse_long n, /* A is n-by-n */ + SuiteSparse_long Ap [ ], /* column pointers */ + SuiteSparse_long Ai [ ], /* row indices */ + /* outputs */ + SuiteSparse_long Perm [ ], /* fill-reducing permutation */ + /* user-defined */ + klu_l_common *Common /* user-defined data is in Common->user_data */ +) +{ + double one [2] = {1,0}, zero [2] = {0,0}, lnz = 0 ; + cholmod_sparse Amatrix, *A, *AT, *S ; + cholmod_factor *L ; + cholmod_common cm ; + SuiteSparse_long *P ; + SuiteSparse_long k, symmetric ; + + if (Ap == NULL || Ai == NULL || Perm == NULL || n < 0) + { + /* invalid inputs */ + return (0) ; + } + + /* start CHOLMOD */ + cholmod_l_start (&cm) ; + cm.supernodal = CHOLMOD_SIMPLICIAL ; + cm.print = 0 ; + + /* construct a CHOLMOD version of the input matrix A */ + A = &Amatrix ; + A->nrow = n ; /* A is n-by-n */ + A->ncol = n ; + A->nzmax = Ap [n] ; /* with nzmax entries */ + A->packed = TRUE ; /* there is no A->nz array */ + A->stype = 0 ; /* A is unsymmetric */ + A->itype = CHOLMOD_INT ; + A->xtype = CHOLMOD_PATTERN ; + A->dtype = CHOLMOD_DOUBLE ; + A->nz = NULL ; + A->p = Ap ; /* column pointers */ + A->i = Ai ; /* row indices */ + A->x = NULL ; /* no numerical values */ + A->z = NULL ; + A->sorted = FALSE ; /* columns of A are not sorted */ + + /* get the user_data; default is symmetric if user_data is NULL */ + symmetric = (Common->user_data == NULL) ? TRUE : + (((SuiteSparse_long *) (Common->user_data)) [0] != 0) ; + + /* AT = pattern of A' */ + AT = cholmod_l_transpose (A, 0, &cm) ; + if (symmetric) + { + /* S = the symmetric pattern of A+A' */ + S = cholmod_l_add (A, AT, one, zero, FALSE, FALSE, &cm) ; + cholmod_l_free_sparse (&AT, &cm) ; + if (S != NULL) + { + S->stype = 1 ; + } + } + else + { + /* S = A'. CHOLMOD will order S*S', which is A'*A */ + S = AT ; + } + + /* order and analyze S or S*S' */ + L = cholmod_l_analyze (S, &cm) ; + + /* copy the permutation from L to the output */ + if (L != NULL) + { + P = L->Perm ; + for (k = 0 ; k < n ; k++) + { + Perm [k] = P [k] ; + } + lnz = cm.lnz ; + } + + cholmod_l_free_sparse (&S, &cm) ; + cholmod_l_free_factor (&L, &cm) ; + cholmod_l_finish (&cm) ; + return (lnz) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.c new file mode 100644 index 0000000..b491539 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.c @@ -0,0 +1,531 @@ +/* ========================================================================== */ +/* === SuiteSparse_config =================================================== */ +/* ========================================================================== */ + +/* SuiteSparse configuration : memory manager and printf functions. */ + +/* Copyright (c) 2013, Timothy A. Davis. No licensing restrictions + * apply to this file or to the SuiteSparse_config directory. + * Author: Timothy A. Davis. + */ + +#include <math.h> +#include <stdlib.h> + +#ifndef NPRINT +#include <stdio.h> +#endif + +#ifdef MATLAB_MEX_FILE +#include "mex.h" +#include "matrix.h" +#endif + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#include "SuiteSparse_config.h" + +/* -------------------------------------------------------------------------- */ +/* SuiteSparse_config : a global extern struct */ +/* -------------------------------------------------------------------------- */ + +/* The SuiteSparse_config struct is available to all SuiteSparse functions and + to all applications that use those functions. It must be modified with + care, particularly in a multithreaded context. Normally, the application + will initialize this object once, via SuiteSparse_start, possibily followed + by application-specific modifications if the applications wants to use + alternative memory manager functions. + + The user can redefine these global pointers at run-time to change the + memory manager and printf function used by SuiteSparse. + + If -DNMALLOC is defined at compile-time, then no memory-manager is + specified. You must define them at run-time, after calling + SuiteSparse_start. + + If -DPRINT is defined a compile time, then printf is disabled, and + SuiteSparse will not use printf. + */ + +struct SuiteSparse_config_struct SuiteSparse_config = +{ + + /* memory management functions */ + #ifndef NMALLOC + #ifdef MATLAB_MEX_FILE + /* MATLAB mexFunction: */ + mxMalloc, mxCalloc, mxRealloc, mxFree, + #else + /* standard ANSI C: */ + malloc, calloc, realloc, free, + #endif + #else + /* no memory manager defined; you must define one at run-time: */ + NULL, NULL, NULL, NULL, + #endif + + /* printf function */ + #ifndef NPRINT + #ifdef MATLAB_MEX_FILE + /* MATLAB mexFunction: */ + mexPrintf, + #else + /* standard ANSI C: */ + printf, + #endif + #else + /* printf is disabled */ + NULL, + #endif + + SuiteSparse_hypot, + SuiteSparse_divcomplex + +} ; + +/* -------------------------------------------------------------------------- */ +/* SuiteSparse_start */ +/* -------------------------------------------------------------------------- */ + +/* All applications that use SuiteSparse should call SuiteSparse_start prior + to using any SuiteSparse function. Only a single thread should call this + function, in a multithreaded application. Currently, this function is + optional, since all this function currently does is to set the four memory + function pointers to NULL (which tells SuiteSparse to use the default + functions). In a multi- threaded application, only a single thread should + call this function. + + Future releases of SuiteSparse might enforce a requirement that + SuiteSparse_start be called prior to calling any SuiteSparse function. + */ + +void SuiteSparse_start ( void ) +{ + + /* memory management functions */ + #ifndef NMALLOC + #ifdef MATLAB_MEX_FILE + /* MATLAB mexFunction: */ + SuiteSparse_config.malloc_func = mxMalloc ; + SuiteSparse_config.calloc_func = mxCalloc ; + SuiteSparse_config.realloc_func = mxRealloc ; + SuiteSparse_config.free_func = mxFree ; + #else + /* standard ANSI C: */ + SuiteSparse_config.malloc_func = malloc ; + SuiteSparse_config.calloc_func = calloc ; + SuiteSparse_config.realloc_func = realloc ; + SuiteSparse_config.free_func = free ; + #endif + #else + /* no memory manager defined; you must define one after calling + SuiteSparse_start */ + SuiteSparse_config.malloc_func = NULL ; + SuiteSparse_config.calloc_func = NULL ; + SuiteSparse_config.realloc_func = NULL ; + SuiteSparse_config.free_func = NULL ; + #endif + + /* printf function */ + #ifndef NPRINT + #ifdef MATLAB_MEX_FILE + /* MATLAB mexFunction: */ + SuiteSparse_config.printf_func = mexPrintf ; + #else + /* standard ANSI C: */ + SuiteSparse_config.printf_func = printf ; + #endif + #else + /* printf is disabled */ + SuiteSparse_config.printf_func = NULL ; + #endif + + /* math functions */ + SuiteSparse_config.hypot_func = SuiteSparse_hypot ; + SuiteSparse_config.divcomplex_func = SuiteSparse_divcomplex ; +} + +/* -------------------------------------------------------------------------- */ +/* SuiteSparse_finish */ +/* -------------------------------------------------------------------------- */ + +/* This currently does nothing, but in the future, applications should call + SuiteSparse_start before calling any SuiteSparse function, and then + SuiteSparse_finish after calling the last SuiteSparse function, just before + exiting. In a multithreaded application, only a single thread should call + this function. + + Future releases of SuiteSparse might use this function for any + SuiteSparse-wide cleanup operations or finalization of statistics. + */ + +void SuiteSparse_finish ( void ) +{ + /* do nothing */ ; +} + +/* -------------------------------------------------------------------------- */ +/* SuiteSparse_malloc: malloc wrapper */ +/* -------------------------------------------------------------------------- */ + +void *SuiteSparse_malloc /* pointer to allocated block of memory */ +( + size_t nitems, /* number of items to malloc */ + size_t size_of_item /* sizeof each item */ +) +{ + void *p ; + size_t size ; + if (nitems < 1) nitems = 1 ; + if (size_of_item < 1) size_of_item = 1 ; + size = nitems * size_of_item ; + + if (size != ((double) nitems) * size_of_item) + { + /* size_t overflow */ + p = NULL ; + } + else + { + p = (void *) (SuiteSparse_config.malloc_func) (size) ; + } + return (p) ; +} + + +/* -------------------------------------------------------------------------- */ +/* SuiteSparse_calloc: calloc wrapper */ +/* -------------------------------------------------------------------------- */ + +void *SuiteSparse_calloc /* pointer to allocated block of memory */ +( + size_t nitems, /* number of items to calloc */ + size_t size_of_item /* sizeof each item */ +) +{ + void *p ; + size_t size ; + if (nitems < 1) nitems = 1 ; + if (size_of_item < 1) size_of_item = 1 ; + size = nitems * size_of_item ; + + if (size != ((double) nitems) * size_of_item) + { + /* size_t overflow */ + p = NULL ; + } + else + { + p = (void *) (SuiteSparse_config.calloc_func) (nitems, size_of_item) ; + } + return (p) ; +} + +/* -------------------------------------------------------------------------- */ +/* SuiteSparse_realloc: realloc wrapper */ +/* -------------------------------------------------------------------------- */ + +/* If p is non-NULL on input, it points to a previously allocated object of + size nitems_old * size_of_item. The object is reallocated to be of size + nitems_new * size_of_item. If p is NULL on input, then a new object of that + size is allocated. On success, a pointer to the new object is returned, + and ok is returned as 1. If the allocation fails, ok is set to 0 and a + pointer to the old (unmodified) object is returned. + */ + +void *SuiteSparse_realloc /* pointer to reallocated block of memory, or + to original block if the realloc failed. */ +( + size_t nitems_new, /* new number of items in the object */ + size_t nitems_old, /* old number of items in the object */ + size_t size_of_item, /* sizeof each item */ + void *p, /* old object to reallocate */ + int *ok /* 1 if successful, 0 otherwise */ +) +{ + size_t size ; + if (nitems_old < 1) nitems_old = 1 ; + if (nitems_new < 1) nitems_new = 1 ; + if (size_of_item < 1) size_of_item = 1 ; + size = nitems_new * size_of_item ; + + if (size != ((double) nitems_new) * size_of_item) + { + /* size_t overflow */ + (*ok) = 0 ; + } + else if (p == NULL) + { + /* a fresh object is being allocated */ + p = SuiteSparse_malloc (nitems_new, size_of_item) ; + (*ok) = (p != NULL) ; + } + else if (nitems_old == nitems_new) + { + /* the object does not change; do nothing */ + (*ok) = 1 ; + } + else + { + /* change the size of the object from nitems_old to nitems_new */ + void *pnew ; + pnew = (void *) (SuiteSparse_config.realloc_func) (p, size) ; + if (pnew == NULL) + { + if (nitems_new < nitems_old) + { + /* the attempt to reduce the size of the block failed, but + the old block is unchanged. So pretend to succeed. */ + (*ok) = 1 ; + } + else + { + /* out of memory */ + (*ok) = 0 ; + } + } + else + { + /* success */ + p = pnew ; + (*ok) = 1 ; + } + } + return (p) ; +} + +/* -------------------------------------------------------------------------- */ +/* SuiteSparse_free: free wrapper */ +/* -------------------------------------------------------------------------- */ + +void *SuiteSparse_free /* always returns NULL */ +( + void *p /* block to free */ +) +{ + if (p) + { + (SuiteSparse_config.free_func) (p) ; + } + return (NULL) ; +} + + +/* -------------------------------------------------------------------------- */ +/* SuiteSparse_tic: return current wall clock time */ +/* -------------------------------------------------------------------------- */ + +/* Returns the number of seconds (tic [0]) and nanoseconds (tic [1]) since some + * unspecified but fixed time in the past. If no timer is installed, zero is + * returned. A scalar double precision value for 'tic' could be used, but this + * might cause loss of precision because clock_getttime returns the time from + * some distant time in the past. Thus, an array of size 2 is used. + * + * The timer is enabled by default. To disable the timer, compile with + * -DNTIMER. If enabled on a POSIX C 1993 system, the timer requires linking + * with the -lrt library. + * + * example: + * + * double tic [2], r, s, t ; + * SuiteSparse_tic (tic) ; // start the timer + * // do some work A + * t = SuiteSparse_toc (tic) ; // t is time for work A, in seconds + * // do some work B + * s = SuiteSparse_toc (tic) ; // s is time for work A and B, in seconds + * SuiteSparse_tic (tic) ; // restart the timer + * // do some work C + * r = SuiteSparse_toc (tic) ; // s is time for work C, in seconds + * + * A double array of size 2 is used so that this routine can be more easily + * ported to non-POSIX systems. The caller does not rely on the POSIX + * <time.h> include file. + */ + +#ifdef SUITESPARSE_TIMER_ENABLED + +#include <time.h> + +void SuiteSparse_tic +( + double tic [2] /* output, contents undefined on input */ +) +{ + /* POSIX C 1993 timer, requires -librt */ + struct timespec t ; + clock_gettime (CLOCK_MONOTONIC, &t) ; + tic [0] = (double) (t.tv_sec) ; + tic [1] = (double) (t.tv_nsec) ; +} + +#else + +void SuiteSparse_tic +( + double tic [2] /* output, contents undefined on input */ +) +{ + /* no timer installed */ + tic [0] = 0 ; + tic [1] = 0 ; +} + +#endif + + +/* -------------------------------------------------------------------------- */ +/* SuiteSparse_toc: return time since last tic */ +/* -------------------------------------------------------------------------- */ + +/* Assuming SuiteSparse_tic is accurate to the nanosecond, this function is + * accurate down to the nanosecond for 2^53 nanoseconds since the last call to + * SuiteSparse_tic, which is sufficient for SuiteSparse (about 104 days). If + * additional accuracy is required, the caller can use two calls to + * SuiteSparse_tic and do the calculations differently. + */ + +double SuiteSparse_toc /* returns time in seconds since last tic */ +( + double tic [2] /* input, not modified from last call to SuiteSparse_tic */ +) +{ + double toc [2] ; + SuiteSparse_tic (toc) ; + return ((toc [0] - tic [0]) + 1e-9 * (toc [1] - tic [1])) ; +} + + +/* -------------------------------------------------------------------------- */ +/* SuiteSparse_time: return current wallclock time in seconds */ +/* -------------------------------------------------------------------------- */ + +/* This function might not be accurate down to the nanosecond. */ + +double SuiteSparse_time /* returns current wall clock time in seconds */ +( + void +) +{ + double toc [2] ; + SuiteSparse_tic (toc) ; + return (toc [0] + 1e-9 * toc [1]) ; +} + + +/* -------------------------------------------------------------------------- */ +/* SuiteSparse_version: return the current version of SuiteSparse */ +/* -------------------------------------------------------------------------- */ + +int SuiteSparse_version +( + int version [3] +) +{ + if (version != NULL) + { + version [0] = SUITESPARSE_MAIN_VERSION ; + version [1] = SUITESPARSE_SUB_VERSION ; + version [2] = SUITESPARSE_SUBSUB_VERSION ; + } + return (SUITESPARSE_VERSION) ; +} + +/* -------------------------------------------------------------------------- */ +/* SuiteSparse_hypot */ +/* -------------------------------------------------------------------------- */ + +/* There is an equivalent routine called hypot in <math.h>, which conforms + * to ANSI C99. However, SuiteSparse does not assume that ANSI C99 is + * available. You can use the ANSI C99 hypot routine with: + * + * #include <math.h> + *i SuiteSparse_config.hypot_func = hypot ; + * + * Default value of the SuiteSparse_config.hypot_func pointer is + * SuiteSparse_hypot, defined below. + * + * s = hypot (x,y) computes s = sqrt (x*x + y*y) but does so more accurately. + * The NaN cases for the double relops x >= y and x+y == x are safely ignored. + * + * Source: Algorithm 312, "Absolute value and square root of a complex number," + * P. Friedland, Comm. ACM, vol 10, no 10, October 1967, page 665. + */ + +double SuiteSparse_hypot (double x, double y) +{ + double s, r ; + x = fabs (x) ; + y = fabs (y) ; + if (x >= y) + { + if (x + y == x) + { + s = x ; + } + else + { + r = y / x ; + s = x * sqrt (1.0 + r*r) ; + } + } + else + { + if (y + x == y) + { + s = y ; + } + else + { + r = x / y ; + s = y * sqrt (1.0 + r*r) ; + } + } + return (s) ; +} + +/* -------------------------------------------------------------------------- */ +/* SuiteSparse_divcomplex */ +/* -------------------------------------------------------------------------- */ + +/* c = a/b where c, a, and b are complex. The real and imaginary parts are + * passed as separate arguments to this routine. The NaN case is ignored + * for the double relop br >= bi. Returns 1 if the denominator is zero, + * 0 otherwise. + * + * This uses ACM Algo 116, by R. L. Smith, 1962, which tries to avoid + * underflow and overflow. + * + * c can be the same variable as a or b. + * + * Default value of the SuiteSparse_config.divcomplex_func pointer is + * SuiteSparse_divcomplex. + */ + +int SuiteSparse_divcomplex +( + double ar, double ai, /* real and imaginary parts of a */ + double br, double bi, /* real and imaginary parts of b */ + double *cr, double *ci /* real and imaginary parts of c */ +) +{ + double tr, ti, r, den ; + if (fabs (br) >= fabs (bi)) + { + r = bi / br ; + den = br + r * bi ; + tr = (ar + ai * r) / den ; + ti = (ai - ar * r) / den ; + } + else + { + r = br / bi ; + den = r * br + bi ; + tr = (ar * r + ai) / den ; + ti = (ai * r - ar) / den ; + } + *cr = tr ; + *ci = ti ; + return (den == 0.) ; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.h new file mode 100644 index 0000000..6d1bc2d --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.h @@ -0,0 +1,247 @@ +/* ========================================================================== */ +/* === SuiteSparse_config =================================================== */ +/* ========================================================================== */ + +/* Configuration file for SuiteSparse: a Suite of Sparse matrix packages + * (AMD, COLAMD, CCOLAMD, CAMD, CHOLMOD, UMFPACK, CXSparse, and others). + * + * SuiteSparse_config.h provides the definition of the long integer. On most + * systems, a C program can be compiled in LP64 mode, in which long's and + * pointers are both 64-bits, and int's are 32-bits. Windows 64, however, uses + * the LLP64 model, in which int's and long's are 32-bits, and long long's and + * pointers are 64-bits. + * + * SuiteSparse packages that include long integer versions are + * intended for the LP64 mode. However, as a workaround for Windows 64 + * (and perhaps other systems), the long integer can be redefined. + * + * If _WIN64 is defined, then the __int64 type is used instead of long. + * + * The long integer can also be defined at compile time. For example, this + * could be added to SuiteSparse_config.mk: + * + * CFLAGS = -O -D'SuiteSparse_long=long long' \ + * -D'SuiteSparse_long_max=9223372036854775801' -D'SuiteSparse_long_idd="lld"' + * + * This file defines SuiteSparse_long as either long (on all but _WIN64) or + * __int64 on Windows 64. The intent is that a SuiteSparse_long is always a + * 64-bit integer in a 64-bit code. ptrdiff_t might be a better choice than + * long; it is always the same size as a pointer. + * + * This file also defines the SUITESPARSE_VERSION and related definitions. + * + * Copyright (c) 2012, Timothy A. Davis. No licensing restrictions apply + * to this file or to the SuiteSparse_config directory. + * Author: Timothy A. Davis. + */ + +#ifndef SUITESPARSE_CONFIG_H +#define SUITESPARSE_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <limits.h> +#include <stdlib.h> + +/* ========================================================================== */ +/* === SuiteSparse_long ===================================================== */ +/* ========================================================================== */ + +#ifndef SuiteSparse_long + +#ifdef _WIN64 + +#define SuiteSparse_long __int64 +#define SuiteSparse_long_max _I64_MAX +#define SuiteSparse_long_idd "I64d" + +#else + +#define SuiteSparse_long long +#define SuiteSparse_long_max LONG_MAX +#define SuiteSparse_long_idd "ld" + +#endif +#define SuiteSparse_long_id "%" SuiteSparse_long_idd +#endif + +/* ========================================================================== */ +/* === SuiteSparse_config parameters and functions ========================== */ +/* ========================================================================== */ + +/* SuiteSparse-wide parameters are placed in this struct. It is meant to be + an extern, globally-accessible struct. It is not meant to be updated + frequently by multiple threads. Rather, if an application needs to modify + SuiteSparse_config, it should do it once at the beginning of the application, + before multiple threads are launched. + + The intent of these function pointers is that they not be used in your + application directly, except to assign them to the desired user-provided + functions. Rather, you should use the + */ + +struct SuiteSparse_config_struct +{ + void *(*malloc_func) (size_t) ; /* pointer to malloc */ + void *(*calloc_func) (size_t, size_t) ; /* pointer to calloc */ + void *(*realloc_func) (void *, size_t) ; /* pointer to realloc */ + void (*free_func) (void *) ; /* pointer to free */ + int (*printf_func) (const char *, ...) ; /* pointer to printf */ + double (*hypot_func) (double, double) ; /* pointer to hypot */ + int (*divcomplex_func) (double, double, double, double, double *, double *); +} ; + +extern struct SuiteSparse_config_struct SuiteSparse_config ; + +void SuiteSparse_start ( void ) ; /* called to start SuiteSparse */ + +void SuiteSparse_finish ( void ) ; /* called to finish SuiteSparse */ + +void *SuiteSparse_malloc /* pointer to allocated block of memory */ +( + size_t nitems, /* number of items to malloc (>=1 is enforced) */ + size_t size_of_item /* sizeof each item */ +) ; + +void *SuiteSparse_calloc /* pointer to allocated block of memory */ +( + size_t nitems, /* number of items to calloc (>=1 is enforced) */ + size_t size_of_item /* sizeof each item */ +) ; + +void *SuiteSparse_realloc /* pointer to reallocated block of memory, or + to original block if the realloc failed. */ +( + size_t nitems_new, /* new number of items in the object */ + size_t nitems_old, /* old number of items in the object */ + size_t size_of_item, /* sizeof each item */ + void *p, /* old object to reallocate */ + int *ok /* 1 if successful, 0 otherwise */ +) ; + +void *SuiteSparse_free /* always returns NULL */ +( + void *p /* block to free */ +) ; + +void SuiteSparse_tic /* start the timer */ +( + double tic [2] /* output, contents undefined on input */ +) ; + +double SuiteSparse_toc /* return time in seconds since last tic */ +( + double tic [2] /* input: from last call to SuiteSparse_tic */ +) ; + +double SuiteSparse_time /* returns current wall clock time in seconds */ +( + void +) ; + +/* returns sqrt (x^2 + y^2), computed reliably */ +double SuiteSparse_hypot (double x, double y) ; + +/* complex division of c = a/b */ +int SuiteSparse_divcomplex +( + double ar, double ai, /* real and imaginary parts of a */ + double br, double bi, /* real and imaginary parts of b */ + double *cr, double *ci /* real and imaginary parts of c */ +) ; + +/* determine which timer to use, if any */ +#ifndef NTIMER +#ifdef _POSIX_C_SOURCE +#if _POSIX_C_SOURCE >= 199309L +#define SUITESPARSE_TIMER_ENABLED +#endif +#endif +#endif + +/* SuiteSparse printf macro */ +#define SUITESPARSE_PRINTF(params) \ +{ \ + if (SuiteSparse_config.printf_func != NULL) \ + { \ + (void) (SuiteSparse_config.printf_func) params ; \ + } \ +} + +/* ========================================================================== */ +/* === SuiteSparse version ================================================== */ +/* ========================================================================== */ + +/* 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. + */ + +int SuiteSparse_version /* returns SUITESPARSE_VERSION */ +( + /* output, not defined on input. Not used if NULL. Returns + the three version codes in version [0..2]: + version [0] is SUITESPARSE_MAIN_VERSION + version [1] is SUITESPARSE_SUB_VERSION + version [2] is SUITESPARSE_SUBSUB_VERSION + */ + int version [3] +) ; + +/* Versions prior to 4.2.0 do not have the above function. The following + code fragment will work with any version of SuiteSparse: + + #ifdef SUITESPARSE_HAS_VERSION_FUNCTION + v = SuiteSparse_version (NULL) ; + #else + v = SUITESPARSE_VERSION ; + #endif +*/ +#define SUITESPARSE_HAS_VERSION_FUNCTION + +#define SUITESPARSE_DATE "May 4, 2016" +#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_VERSION \ + SUITESPARSE_VER_CODE(SUITESPARSE_MAIN_VERSION,SUITESPARSE_SUB_VERSION) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/SuiteSparse_config/xerbla/xerbla.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/SuiteSparse_config/xerbla/xerbla.c new file mode 100644 index 0000000..5107f03 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/SuiteSparse_config/xerbla/xerbla.c @@ -0,0 +1,12 @@ + +void xerbla_ (char *srname, int *info) +{ + /* do nothing */ ; +} + + +void xerbla (char *srname, int *info) +{ + /* do nothing */ ; +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/SuiteSparse_config/xerbla/xerbla.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/SuiteSparse_config/xerbla/xerbla.h new file mode 100644 index 0000000..b332eb3 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/SuiteSparse_config/xerbla/xerbla.h @@ -0,0 +1,2 @@ +void xerbla_ (char *srname, int *info) ; +void xerbla (char *srname, int *info) ; diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/SuiteSparse_config.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/SuiteSparse_config.h new file mode 100644 index 0000000..6d1bc2d --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/SuiteSparse_config.h @@ -0,0 +1,247 @@ +/* ========================================================================== */ +/* === SuiteSparse_config =================================================== */ +/* ========================================================================== */ + +/* Configuration file for SuiteSparse: a Suite of Sparse matrix packages + * (AMD, COLAMD, CCOLAMD, CAMD, CHOLMOD, UMFPACK, CXSparse, and others). + * + * SuiteSparse_config.h provides the definition of the long integer. On most + * systems, a C program can be compiled in LP64 mode, in which long's and + * pointers are both 64-bits, and int's are 32-bits. Windows 64, however, uses + * the LLP64 model, in which int's and long's are 32-bits, and long long's and + * pointers are 64-bits. + * + * SuiteSparse packages that include long integer versions are + * intended for the LP64 mode. However, as a workaround for Windows 64 + * (and perhaps other systems), the long integer can be redefined. + * + * If _WIN64 is defined, then the __int64 type is used instead of long. + * + * The long integer can also be defined at compile time. For example, this + * could be added to SuiteSparse_config.mk: + * + * CFLAGS = -O -D'SuiteSparse_long=long long' \ + * -D'SuiteSparse_long_max=9223372036854775801' -D'SuiteSparse_long_idd="lld"' + * + * This file defines SuiteSparse_long as either long (on all but _WIN64) or + * __int64 on Windows 64. The intent is that a SuiteSparse_long is always a + * 64-bit integer in a 64-bit code. ptrdiff_t might be a better choice than + * long; it is always the same size as a pointer. + * + * This file also defines the SUITESPARSE_VERSION and related definitions. + * + * Copyright (c) 2012, Timothy A. Davis. No licensing restrictions apply + * to this file or to the SuiteSparse_config directory. + * Author: Timothy A. Davis. + */ + +#ifndef SUITESPARSE_CONFIG_H +#define SUITESPARSE_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <limits.h> +#include <stdlib.h> + +/* ========================================================================== */ +/* === SuiteSparse_long ===================================================== */ +/* ========================================================================== */ + +#ifndef SuiteSparse_long + +#ifdef _WIN64 + +#define SuiteSparse_long __int64 +#define SuiteSparse_long_max _I64_MAX +#define SuiteSparse_long_idd "I64d" + +#else + +#define SuiteSparse_long long +#define SuiteSparse_long_max LONG_MAX +#define SuiteSparse_long_idd "ld" + +#endif +#define SuiteSparse_long_id "%" SuiteSparse_long_idd +#endif + +/* ========================================================================== */ +/* === SuiteSparse_config parameters and functions ========================== */ +/* ========================================================================== */ + +/* SuiteSparse-wide parameters are placed in this struct. It is meant to be + an extern, globally-accessible struct. It is not meant to be updated + frequently by multiple threads. Rather, if an application needs to modify + SuiteSparse_config, it should do it once at the beginning of the application, + before multiple threads are launched. + + The intent of these function pointers is that they not be used in your + application directly, except to assign them to the desired user-provided + functions. Rather, you should use the + */ + +struct SuiteSparse_config_struct +{ + void *(*malloc_func) (size_t) ; /* pointer to malloc */ + void *(*calloc_func) (size_t, size_t) ; /* pointer to calloc */ + void *(*realloc_func) (void *, size_t) ; /* pointer to realloc */ + void (*free_func) (void *) ; /* pointer to free */ + int (*printf_func) (const char *, ...) ; /* pointer to printf */ + double (*hypot_func) (double, double) ; /* pointer to hypot */ + int (*divcomplex_func) (double, double, double, double, double *, double *); +} ; + +extern struct SuiteSparse_config_struct SuiteSparse_config ; + +void SuiteSparse_start ( void ) ; /* called to start SuiteSparse */ + +void SuiteSparse_finish ( void ) ; /* called to finish SuiteSparse */ + +void *SuiteSparse_malloc /* pointer to allocated block of memory */ +( + size_t nitems, /* number of items to malloc (>=1 is enforced) */ + size_t size_of_item /* sizeof each item */ +) ; + +void *SuiteSparse_calloc /* pointer to allocated block of memory */ +( + size_t nitems, /* number of items to calloc (>=1 is enforced) */ + size_t size_of_item /* sizeof each item */ +) ; + +void *SuiteSparse_realloc /* pointer to reallocated block of memory, or + to original block if the realloc failed. */ +( + size_t nitems_new, /* new number of items in the object */ + size_t nitems_old, /* old number of items in the object */ + size_t size_of_item, /* sizeof each item */ + void *p, /* old object to reallocate */ + int *ok /* 1 if successful, 0 otherwise */ +) ; + +void *SuiteSparse_free /* always returns NULL */ +( + void *p /* block to free */ +) ; + +void SuiteSparse_tic /* start the timer */ +( + double tic [2] /* output, contents undefined on input */ +) ; + +double SuiteSparse_toc /* return time in seconds since last tic */ +( + double tic [2] /* input: from last call to SuiteSparse_tic */ +) ; + +double SuiteSparse_time /* returns current wall clock time in seconds */ +( + void +) ; + +/* returns sqrt (x^2 + y^2), computed reliably */ +double SuiteSparse_hypot (double x, double y) ; + +/* complex division of c = a/b */ +int SuiteSparse_divcomplex +( + double ar, double ai, /* real and imaginary parts of a */ + double br, double bi, /* real and imaginary parts of b */ + double *cr, double *ci /* real and imaginary parts of c */ +) ; + +/* determine which timer to use, if any */ +#ifndef NTIMER +#ifdef _POSIX_C_SOURCE +#if _POSIX_C_SOURCE >= 199309L +#define SUITESPARSE_TIMER_ENABLED +#endif +#endif +#endif + +/* SuiteSparse printf macro */ +#define SUITESPARSE_PRINTF(params) \ +{ \ + if (SuiteSparse_config.printf_func != NULL) \ + { \ + (void) (SuiteSparse_config.printf_func) params ; \ + } \ +} + +/* ========================================================================== */ +/* === SuiteSparse version ================================================== */ +/* ========================================================================== */ + +/* 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. + */ + +int SuiteSparse_version /* returns SUITESPARSE_VERSION */ +( + /* output, not defined on input. Not used if NULL. Returns + the three version codes in version [0..2]: + version [0] is SUITESPARSE_MAIN_VERSION + version [1] is SUITESPARSE_SUB_VERSION + version [2] is SUITESPARSE_SUBSUB_VERSION + */ + int version [3] +) ; + +/* Versions prior to 4.2.0 do not have the above function. The following + code fragment will work with any version of SuiteSparse: + + #ifdef SUITESPARSE_HAS_VERSION_FUNCTION + v = SuiteSparse_version (NULL) ; + #else + v = SUITESPARSE_VERSION ; + #endif +*/ +#define SUITESPARSE_HAS_VERSION_FUNCTION + +#define SUITESPARSE_DATE "May 4, 2016" +#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_VERSION \ + SUITESPARSE_VER_CODE(SUITESPARSE_MAIN_VERSION,SUITESPARSE_SUB_VERSION) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/amd.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/amd.h new file mode 100644 index 0000000..a72851f --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/amd.h @@ -0,0 +1,400 @@ +/* ========================================================================= */ +/* === AMD: approximate minimum degree ordering =========================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* AMD Version 2.4, Copyright (c) 1996-2013 by Timothy A. Davis, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* AMD finds a symmetric ordering P of a matrix A so that the Cholesky + * factorization of P*A*P' has fewer nonzeros and takes less work than the + * Cholesky factorization of A. If A is not symmetric, then it performs its + * ordering on the matrix A+A'. Two sets of user-callable routines are + * provided, one for int integers and the other for SuiteSparse_long integers. + * + * The method is based on the approximate minimum degree algorithm, discussed + * in Amestoy, Davis, and Duff, "An approximate degree ordering algorithm", + * SIAM Journal of Matrix Analysis and Applications, vol. 17, no. 4, pp. + * 886-905, 1996. This package can perform both the AMD ordering (with + * aggressive absorption), and the AMDBAR ordering (without aggressive + * absorption) discussed in the above paper. This package differs from the + * Fortran codes discussed in the paper: + * + * (1) it can ignore "dense" rows and columns, leading to faster run times + * (2) it computes the ordering of A+A' if A is not symmetric + * (3) it is followed by a depth-first post-ordering of the assembly tree + * (or supernodal elimination tree) + * + * For historical reasons, the Fortran versions, amd.f and amdbar.f, have + * been left (nearly) unchanged. They compute the identical ordering as + * described in the above paper. + */ + +#ifndef AMD_H +#define AMD_H + +/* make it easy for C++ programs to include AMD */ +#ifdef __cplusplus +extern "C" { +#endif + +/* get the definition of size_t: */ +#include <stddef.h> + +#include "SuiteSparse_config.h" + +int amd_order /* returns AMD_OK, AMD_OK_BUT_JUMBLED, + * AMD_INVALID, or AMD_OUT_OF_MEMORY */ +( + int n, /* A is n-by-n. n must be >= 0. */ + const int Ap [ ], /* column pointers for A, of size n+1 */ + const int Ai [ ], /* row indices of A, of size nz = Ap [n] */ + int P [ ], /* output permutation, of size n */ + double Control [ ], /* input Control settings, of size AMD_CONTROL */ + double Info [ ] /* output Info statistics, of size AMD_INFO */ +) ; + +SuiteSparse_long amd_l_order /* see above for description of arguments */ +( + SuiteSparse_long n, + const SuiteSparse_long Ap [ ], + const SuiteSparse_long Ai [ ], + SuiteSparse_long P [ ], + double Control [ ], + double Info [ ] +) ; + +/* Input arguments (not modified): + * + * n: the matrix A is n-by-n. + * Ap: an int/SuiteSparse_long array of size n+1, containing column + * pointers of A. + * Ai: an int/SuiteSparse_long array of size nz, containing the row + * indices of A, where nz = Ap [n]. + * Control: a double array of size AMD_CONTROL, containing control + * parameters. Defaults are used if Control is NULL. + * + * Output arguments (not defined on input): + * + * P: an int/SuiteSparse_long array of size n, containing the output + * permutation. If row i is the kth pivot row, then P [k] = i. In + * MATLAB notation, the reordered matrix is A (P,P). + * Info: a double array of size AMD_INFO, containing statistical + * information. Ignored if Info is NULL. + * + * On input, the matrix A is stored in column-oriented form. The row indices + * of nonzero entries in column j are stored in Ai [Ap [j] ... Ap [j+1]-1]. + * + * If the row indices appear in ascending order in each column, and there + * are no duplicate entries, then amd_order is slightly more efficient in + * terms of time and memory usage. If this condition does not hold, a copy + * of the matrix is created (where these conditions do hold), and the copy is + * ordered. This feature is new to v2.0 (v1.2 and earlier required this + * condition to hold for the input matrix). + * + * Row indices must be in the range 0 to + * n-1. Ap [0] must be zero, and thus nz = Ap [n] is the number of nonzeros + * in A. The array Ap is of size n+1, and the array Ai is of size nz = Ap [n]. + * The matrix does not need to be symmetric, and the diagonal does not need to + * be present (if diagonal entries are present, they are ignored except for + * the output statistic Info [AMD_NZDIAG]). The arrays Ai and Ap are not + * modified. This form of the Ap and Ai arrays to represent the nonzero + * pattern of the matrix A is the same as that used internally by MATLAB. + * If you wish to use a more flexible input structure, please see the + * umfpack_*_triplet_to_col routines in the UMFPACK package, at + * http://www.suitesparse.com. + * + * Restrictions: n >= 0. Ap [0] = 0. Ap [j] <= Ap [j+1] for all j in the + * range 0 to n-1. nz = Ap [n] >= 0. Ai [0..nz-1] must be in the range 0 + * to n-1. Finally, Ai, Ap, and P must not be NULL. If any of these + * restrictions are not met, AMD returns AMD_INVALID. + * + * AMD returns: + * + * AMD_OK if the matrix is valid and sufficient memory can be allocated to + * perform the ordering. + * + * AMD_OUT_OF_MEMORY if not enough memory can be allocated. + * + * AMD_INVALID if the input arguments n, Ap, Ai are invalid, or if P is + * NULL. + * + * AMD_OK_BUT_JUMBLED if the matrix had unsorted columns, and/or duplicate + * entries, but was otherwise valid. + * + * The AMD routine first forms the pattern of the matrix A+A', and then + * computes a fill-reducing ordering, P. If P [k] = i, then row/column i of + * the original is the kth pivotal row. In MATLAB notation, the permuted + * matrix is A (P,P), except that 0-based indexing is used instead of the + * 1-based indexing in MATLAB. + * + * The Control array is used to set various parameters for AMD. If a NULL + * pointer is passed, default values are used. The Control array is not + * modified. + * + * Control [AMD_DENSE]: controls the threshold for "dense" rows/columns. + * A dense row/column in A+A' can cause AMD to spend a lot of time in + * ordering the matrix. If Control [AMD_DENSE] >= 0, rows/columns + * with more than Control [AMD_DENSE] * sqrt (n) entries are ignored + * during the ordering, and placed last in the output order. The + * default value of Control [AMD_DENSE] is 10. If negative, no + * rows/columns are treated as "dense". Rows/columns with 16 or + * fewer off-diagonal entries are never considered "dense". + * + * Control [AMD_AGGRESSIVE]: controls whether or not to use aggressive + * absorption, in which a prior element is absorbed into the current + * element if is a subset of the current element, even if it is not + * adjacent to the current pivot element (refer to Amestoy, Davis, + * & Duff, 1996, for more details). The default value is nonzero, + * which means to perform aggressive absorption. This nearly always + * leads to a better ordering (because the approximate degrees are + * more accurate) and a lower execution time. There are cases where + * it can lead to a slightly worse ordering, however. To turn it off, + * set Control [AMD_AGGRESSIVE] to 0. + * + * Control [2..4] are not used in the current version, but may be used in + * future versions. + * + * The Info array provides statistics about the ordering on output. If it is + * not present, the statistics are not returned. This is not an error + * condition. + * + * Info [AMD_STATUS]: the return value of AMD, either AMD_OK, + * AMD_OK_BUT_JUMBLED, AMD_OUT_OF_MEMORY, or AMD_INVALID. + * + * Info [AMD_N]: n, the size of the input matrix + * + * Info [AMD_NZ]: the number of nonzeros in A, nz = Ap [n] + * + * Info [AMD_SYMMETRY]: the symmetry of the matrix A. It is the number + * of "matched" off-diagonal entries divided by the total number of + * off-diagonal entries. An entry A(i,j) is matched if A(j,i) is also + * an entry, for any pair (i,j) for which i != j. In MATLAB notation, + * S = spones (A) ; + * B = tril (S, -1) + triu (S, 1) ; + * symmetry = nnz (B & B') / nnz (B) ; + * + * Info [AMD_NZDIAG]: the number of entries on the diagonal of A. + * + * Info [AMD_NZ_A_PLUS_AT]: the number of nonzeros in A+A', excluding the + * diagonal. If A is perfectly symmetric (Info [AMD_SYMMETRY] = 1) + * with a fully nonzero diagonal, then Info [AMD_NZ_A_PLUS_AT] = nz-n + * (the smallest possible value). If A is perfectly unsymmetric + * (Info [AMD_SYMMETRY] = 0, for an upper triangular matrix, for + * example) with no diagonal, then Info [AMD_NZ_A_PLUS_AT] = 2*nz + * (the largest possible value). + * + * Info [AMD_NDENSE]: the number of "dense" rows/columns of A+A' that were + * removed from A prior to ordering. These are placed last in the + * output order P. + * + * Info [AMD_MEMORY]: the amount of memory used by AMD, in bytes. In the + * current version, this is 1.2 * Info [AMD_NZ_A_PLUS_AT] + 9*n + * times the size of an integer. This is at most 2.4nz + 9n. This + * excludes the size of the input arguments Ai, Ap, and P, which have + * a total size of nz + 2*n + 1 integers. + * + * Info [AMD_NCMPA]: the number of garbage collections performed. + * + * Info [AMD_LNZ]: the number of nonzeros in L (excluding the diagonal). + * This is a slight upper bound because mass elimination is combined + * with the approximate degree update. It is a rough upper bound if + * there are many "dense" rows/columns. The rest of the statistics, + * below, are also slight or rough upper bounds, for the same reasons. + * The post-ordering of the assembly tree might also not exactly + * correspond to a true elimination tree postordering. + * + * Info [AMD_NDIV]: the number of divide operations for a subsequent LDL' + * or LU factorization of the permuted matrix A (P,P). + * + * Info [AMD_NMULTSUBS_LDL]: the number of multiply-subtract pairs for a + * subsequent LDL' factorization of A (P,P). + * + * Info [AMD_NMULTSUBS_LU]: the number of multiply-subtract pairs for a + * subsequent LU factorization of A (P,P), assuming that no numerical + * pivoting is required. + * + * Info [AMD_DMAX]: the maximum number of nonzeros in any column of L, + * including the diagonal. + * + * Info [14..19] are not used in the current version, but may be used in + * future versions. + */ + +/* ------------------------------------------------------------------------- */ +/* direct interface to AMD */ +/* ------------------------------------------------------------------------- */ + +/* amd_2 is the primary AMD ordering routine. It is not meant to be + * user-callable because of its restrictive inputs and because it destroys + * the user's input matrix. It does not check its inputs for errors, either. + * However, if you can work with these restrictions it can be faster than + * amd_order and use less memory (assuming that you can create your own copy + * of the matrix for AMD to destroy). Refer to AMD/Source/amd_2.c for a + * description of each parameter. */ + +void amd_2 +( + int n, + int Pe [ ], + int Iw [ ], + int Len [ ], + int iwlen, + int pfree, + int Nv [ ], + int Next [ ], + int Last [ ], + int Head [ ], + int Elen [ ], + int Degree [ ], + int W [ ], + double Control [ ], + double Info [ ] +) ; + +void amd_l2 +( + SuiteSparse_long n, + SuiteSparse_long Pe [ ], + SuiteSparse_long Iw [ ], + SuiteSparse_long Len [ ], + SuiteSparse_long iwlen, + SuiteSparse_long pfree, + SuiteSparse_long Nv [ ], + SuiteSparse_long Next [ ], + SuiteSparse_long Last [ ], + SuiteSparse_long Head [ ], + SuiteSparse_long Elen [ ], + SuiteSparse_long Degree [ ], + SuiteSparse_long W [ ], + double Control [ ], + double Info [ ] +) ; + +/* ------------------------------------------------------------------------- */ +/* amd_valid */ +/* ------------------------------------------------------------------------- */ + +/* Returns AMD_OK or AMD_OK_BUT_JUMBLED if the matrix is valid as input to + * amd_order; the latter is returned if the matrix has unsorted and/or + * duplicate row indices in one or more columns. Returns AMD_INVALID if the + * matrix cannot be passed to amd_order. For amd_order, the matrix must also + * be square. The first two arguments are the number of rows and the number + * of columns of the matrix. For its use in AMD, these must both equal n. + * + * NOTE: this routine returned TRUE/FALSE in v1.2 and earlier. + */ + +int amd_valid +( + int n_row, /* # of rows */ + int n_col, /* # of columns */ + const int Ap [ ], /* column pointers, of size n_col+1 */ + const int Ai [ ] /* row indices, of size Ap [n_col] */ +) ; + +SuiteSparse_long amd_l_valid +( + SuiteSparse_long n_row, + SuiteSparse_long n_col, + const SuiteSparse_long Ap [ ], + const SuiteSparse_long Ai [ ] +) ; + +/* ------------------------------------------------------------------------- */ +/* AMD memory manager and printf routines */ +/* ------------------------------------------------------------------------- */ + + /* moved to SuiteSparse_config.c */ + +/* ------------------------------------------------------------------------- */ +/* AMD Control and Info arrays */ +/* ------------------------------------------------------------------------- */ + +/* amd_defaults: sets the default control settings */ +void amd_defaults (double Control [ ]) ; +void amd_l_defaults (double Control [ ]) ; + +/* amd_control: prints the control settings */ +void amd_control (double Control [ ]) ; +void amd_l_control (double Control [ ]) ; + +/* amd_info: prints the statistics */ +void amd_info (double Info [ ]) ; +void amd_l_info (double Info [ ]) ; + +#define AMD_CONTROL 5 /* size of Control array */ +#define AMD_INFO 20 /* size of Info array */ + +/* contents of Control */ +#define AMD_DENSE 0 /* "dense" if degree > Control [0] * sqrt (n) */ +#define AMD_AGGRESSIVE 1 /* do aggressive absorption if Control [1] != 0 */ + +/* default Control settings */ +#define AMD_DEFAULT_DENSE 10.0 /* default "dense" degree 10*sqrt(n) */ +#define AMD_DEFAULT_AGGRESSIVE 1 /* do aggressive absorption by default */ + +/* contents of Info */ +#define AMD_STATUS 0 /* return value of amd_order and amd_l_order */ +#define AMD_N 1 /* A is n-by-n */ +#define AMD_NZ 2 /* number of nonzeros in A */ +#define AMD_SYMMETRY 3 /* symmetry of pattern (1 is sym., 0 is unsym.) */ +#define AMD_NZDIAG 4 /* # of entries on diagonal */ +#define AMD_NZ_A_PLUS_AT 5 /* nz in A+A' */ +#define AMD_NDENSE 6 /* number of "dense" rows/columns in A */ +#define AMD_MEMORY 7 /* amount of memory used by AMD */ +#define AMD_NCMPA 8 /* number of garbage collections in AMD */ +#define AMD_LNZ 9 /* approx. nz in L, excluding the diagonal */ +#define AMD_NDIV 10 /* number of fl. point divides for LU and LDL' */ +#define AMD_NMULTSUBS_LDL 11 /* number of fl. point (*,-) pairs for LDL' */ +#define AMD_NMULTSUBS_LU 12 /* number of fl. point (*,-) pairs for LU */ +#define AMD_DMAX 13 /* max nz. in any column of L, incl. diagonal */ + +/* ------------------------------------------------------------------------- */ +/* return values of AMD */ +/* ------------------------------------------------------------------------- */ + +#define AMD_OK 0 /* success */ +#define AMD_OUT_OF_MEMORY -1 /* malloc failed, or problem too large */ +#define AMD_INVALID -2 /* input arguments are not valid */ +#define AMD_OK_BUT_JUMBLED 1 /* input matrix is OK for amd_order, but + * columns were not sorted, and/or duplicate entries were present. AMD had + * to do extra work before ordering the matrix. This is a warning, not an + * error. */ + +/* ========================================================================== */ +/* === AMD version ========================================================== */ +/* ========================================================================== */ + +/* AMD Version 1.2 and later include the following definitions. + * As an example, to test if the version you are using is 1.2 or later: + * + * #ifdef AMD_VERSION + * if (AMD_VERSION >= AMD_VERSION_CODE (1,2)) ... + * #endif + * + * This also works during compile-time: + * + * #if defined(AMD_VERSION) && (AMD_VERSION >= AMD_VERSION_CODE (1,2)) + * printf ("This is version 1.2 or later\n") ; + * #else + * printf ("This is an early version\n") ; + * #endif + * + * Versions 1.1 and earlier of AMD do not include a #define'd version number. + */ + +#define AMD_DATE "May 4, 2016" +#define AMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) +#define AMD_MAIN_VERSION 2 +#define AMD_SUB_VERSION 4 +#define AMD_SUBSUB_VERSION 6 +#define AMD_VERSION AMD_VERSION_CODE(AMD_MAIN_VERSION,AMD_SUB_VERSION) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/btf.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/btf.h new file mode 100644 index 0000000..c36de94 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/btf.h @@ -0,0 +1,267 @@ +/* ========================================================================== */ +/* === BTF package ========================================================== */ +/* ========================================================================== */ + +/* BTF_MAXTRANS: find a column permutation Q to give A*Q a zero-free diagonal + * BTF_STRONGCOMP: find a symmetric permutation P to put P*A*P' into block + * upper triangular form. + * BTF_ORDER: do both of the above (btf_maxtrans then btf_strongcomp). + * + * By Tim Davis. Copyright (c) 2004-2007, University of Florida. + * with support from Sandia National Laboratories. All Rights Reserved. + */ + + +/* ========================================================================== */ +/* === BTF_MAXTRANS ========================================================= */ +/* ========================================================================== */ + +/* BTF_MAXTRANS: finds a permutation of the columns of a matrix so that it has a + * zero-free diagonal. The input is an m-by-n sparse matrix in compressed + * column form. The array Ap of size n+1 gives the starting and ending + * positions of the columns in the array Ai. Ap[0] must be zero. The array Ai + * contains the row indices of the nonzeros of the matrix A, and is of size + * Ap[n]. The row indices of column j are located in Ai[Ap[j] ... Ap[j+1]-1]. + * Row indices must be in the range 0 to m-1. Duplicate entries may be present + * in any given column. The input matrix is not checked for validity (row + * indices out of the range 0 to m-1 will lead to an undeterminate result - + * possibly a core dump, for example). Row indices in any given column need + * not be in sorted order. However, if they are sorted and the matrix already + * has a zero-free diagonal, then the identity permutation is returned. + * + * The output of btf_maxtrans is an array Match of size n. If row i is matched + * with column j, then A(i,j) is nonzero, and then Match[i] = j. If the matrix + * is structurally nonsingular, all entries in the Match array are unique, and + * Match can be viewed as a column permutation if A is square. That is, column + * k of the original matrix becomes column Match[k] of the permuted matrix. In + * MATLAB, this can be expressed as (for non-structurally singular matrices): + * + * Match = maxtrans (A) ; + * B = A (:, Match) ; + * + * except of course here the A matrix and Match vector are all 0-based (rows + * and columns in the range 0 to n-1), not 1-based (rows/cols in range 1 to n). + * The MATLAB dmperm routine returns a row permutation. See the maxtrans + * mexFunction for more details. + * + * If row i is not matched to any column, then Match[i] is == -1. The + * btf_maxtrans routine returns the number of nonzeros on diagonal of the + * permuted matrix. + * + * In the MATLAB mexFunction interface to btf_maxtrans, 1 is added to the Match + * array to obtain a 1-based permutation. Thus, in MATLAB where A is m-by-n: + * + * q = maxtrans (A) ; % has entries in the range 0:n + * q % a column permutation (only if sprank(A)==n) + * B = A (:, q) ; % permuted matrix (only if sprank(A)==n) + * sum (q > 0) ; % same as "sprank (A)" + * + * This behaviour differs from p = dmperm (A) in MATLAB, which returns the + * matching as p(j)=i if row i and column j are matched, and p(j)=0 if column j + * is unmatched. + * + * p = dmperm (A) ; % has entries in the range 0:m + * p % a row permutation (only if sprank(A)==m) + * B = A (p, :) ; % permuted matrix (only if sprank(A)==m) + * sum (p > 0) ; % definition of sprank (A) + * + * This algorithm is based on the paper "On Algorithms for obtaining a maximum + * transversal" by Iain Duff, ACM Trans. Mathematical Software, vol 7, no. 1, + * pp. 315-330, and "Algorithm 575: Permutations for a zero-free diagonal", + * same issue, pp. 387-390. Algorithm 575 is MC21A in the Harwell Subroutine + * Library. This code is not merely a translation of the Fortran code into C. + * It is a completely new implementation of the basic underlying method (depth + * first search over a subgraph with nodes corresponding to columns matched so + * far, and cheap matching). This code was written with minimal observation of + * the MC21A/B code itself. See comments below for a comparison between the + * maxtrans and MC21A/B codes. + * + * This routine operates on a column-form matrix and produces a column + * permutation. MC21A uses a row-form matrix and produces a row permutation. + * The difference is merely one of convention in the comments and interpretation + * of the inputs and outputs. If you want a row permutation, simply pass a + * compressed-row sparse matrix to this routine and you will get a row + * permutation (just like MC21A). Similarly, you can pass a column-oriented + * matrix to MC21A and it will happily return a column permutation. + */ + +#ifndef _BTF_H +#define _BTF_H + +/* make it easy for C++ programs to include BTF */ +#ifdef __cplusplus +extern "C" { +#endif + +#include "SuiteSparse_config.h" + +int btf_maxtrans /* returns # of columns matched */ +( + /* --- input, not modified: --- */ + int nrow, /* A is nrow-by-ncol in compressed column form */ + int ncol, + int Ap [ ], /* size ncol+1 */ + int Ai [ ], /* size nz = Ap [ncol] */ + double maxwork, /* maximum amount of work to do is maxwork*nnz(A); no limit + * if <= 0 */ + + /* --- output, not defined on input --- */ + double *work, /* work = -1 if maxwork > 0 and the total work performed + * reached the maximum of maxwork*nnz(A). + * Otherwise, work = the total work performed. */ + + int Match [ ], /* size nrow. Match [i] = j if column j matched to row i + * (see above for the singular-matrix case) */ + + /* --- workspace, not defined on input or output --- */ + int Work [ ] /* size 5*ncol */ +) ; + +/* long integer version (all "int" parameters become "SuiteSparse_long") */ +SuiteSparse_long btf_l_maxtrans (SuiteSparse_long, SuiteSparse_long, + SuiteSparse_long *, SuiteSparse_long *, double, double *, + SuiteSparse_long *, SuiteSparse_long *) ; + + +/* ========================================================================== */ +/* === BTF_STRONGCOMP ======================================================= */ +/* ========================================================================== */ + +/* BTF_STRONGCOMP finds the strongly connected components of a graph, returning + * a symmetric permutation. The matrix A must be square, and is provided on + * input in compressed-column form (see BTF_MAXTRANS, above). The diagonal of + * the input matrix A (or A*Q if Q is provided on input) is ignored. + * + * If Q is not NULL on input, then the strongly connected components of A*Q are + * found. Q may be flagged on input, where Q[k] < 0 denotes a flagged column k. + * The permutation is j = BTF_UNFLIP (Q [k]). On output, Q is modified (the + * flags are preserved) so that P*A*Q is in block upper triangular form. + * + * If Q is NULL, then the permutation P is returned so that P*A*P' is in upper + * block triangular form. + * + * The vector R gives the block boundaries, where block b is in rows/columns + * R[b] to R[b+1]-1 of the permuted matrix, and where b ranges from 1 to the + * number of strongly connected components found. + */ + +int btf_strongcomp /* return # of strongly connected components */ +( + /* input, not modified: */ + int n, /* A is n-by-n in compressed column form */ + int Ap [ ], /* size n+1 */ + int Ai [ ], /* size nz = Ap [n] */ + + /* optional input, modified (if present) on output: */ + int Q [ ], /* size n, input column permutation */ + + /* output, not defined on input */ + int P [ ], /* size n. P [k] = j if row and column j are kth row/col + * in permuted matrix. */ + + int R [ ], /* size n+1. block b is in rows/cols R[b] ... R[b+1]-1 */ + + /* workspace, not defined on input or output */ + int Work [ ] /* size 4n */ +) ; + +SuiteSparse_long btf_l_strongcomp (SuiteSparse_long, SuiteSparse_long *, + SuiteSparse_long *, SuiteSparse_long *, SuiteSparse_long *, + SuiteSparse_long *, SuiteSparse_long *) ; + + +/* ========================================================================== */ +/* === BTF_ORDER ============================================================ */ +/* ========================================================================== */ + +/* BTF_ORDER permutes a square matrix into upper block triangular form. It + * does this by first finding a maximum matching (or perhaps a limited matching + * if the work is limited), via the btf_maxtrans function. If a complete + * matching is not found, BTF_ORDER completes the permutation, but flags the + * columns of P*A*Q to denote which columns are not matched. If the matrix is + * structurally rank deficient, some of the entries on the diagonal of the + * permuted matrix will be zero. BTF_ORDER then calls btf_strongcomp to find + * the strongly-connected components. + * + * On output, P and Q are the row and column permutations, where i = P[k] if + * row i of A is the kth row of P*A*Q, and j = BTF_UNFLIP(Q[k]) if column j of + * A is the kth column of P*A*Q. If Q[k] < 0, then the (k,k)th entry in P*A*Q + * is structurally zero. + * + * The vector R gives the block boundaries, where block b is in rows/columns + * R[b] to R[b+1]-1 of the permuted matrix, and where b ranges from 1 to the + * number of strongly connected components found. + */ + +int btf_order /* returns number of blocks found */ +( + /* --- input, not modified: --- */ + int n, /* A is n-by-n in compressed column form */ + int Ap [ ], /* size n+1 */ + int Ai [ ], /* size nz = Ap [n] */ + double maxwork, /* do at most maxwork*nnz(A) work in the maximum + * transversal; no limit if <= 0 */ + + /* --- output, not defined on input --- */ + double *work, /* return value from btf_maxtrans */ + int P [ ], /* size n, row permutation */ + int Q [ ], /* size n, column permutation */ + int R [ ], /* size n+1. block b is in rows/cols R[b] ... R[b+1]-1 */ + int *nmatch, /* # nonzeros on diagonal of P*A*Q */ + + /* --- workspace, not defined on input or output --- */ + int Work [ ] /* size 5n */ +) ; + +SuiteSparse_long btf_l_order (SuiteSparse_long, SuiteSparse_long *, + SuiteSparse_long *, double , double *, SuiteSparse_long *, + SuiteSparse_long *, SuiteSparse_long *, SuiteSparse_long *, + SuiteSparse_long *) ; + + +/* ========================================================================== */ +/* === BTF marking of singular columns ====================================== */ +/* ========================================================================== */ + +/* BTF_FLIP is a "negation about -1", and is used to mark an integer j + * that is normally non-negative. BTF_FLIP (-1) is -1. BTF_FLIP of + * a number > -1 is negative, and BTF_FLIP of a number < -1 is positive. + * BTF_FLIP (BTF_FLIP (j)) = j for all integers j. UNFLIP (j) acts + * like an "absolute value" operation, and is always >= -1. You can test + * whether or not an integer j is "flipped" with the BTF_ISFLIPPED (j) + * macro. + */ + +#define BTF_FLIP(j) (-(j)-2) +#define BTF_ISFLIPPED(j) ((j) < -1) +#define BTF_UNFLIP(j) ((BTF_ISFLIPPED (j)) ? BTF_FLIP (j) : (j)) + +/* ========================================================================== */ +/* === BTF version ========================================================== */ +/* ========================================================================== */ + +/* All versions of BTF include these definitions. + * As an example, to test if the version you are using is 1.2 or later: + * + * if (BTF_VERSION >= BTF_VERSION_CODE (1,2)) ... + * + * This also works during compile-time: + * + * #if (BTF >= BTF_VERSION_CODE (1,2)) + * printf ("This is version 1.2 or later\n") ; + * #else + * printf ("This is an early version\n") ; + * #endif + */ + +#define BTF_DATE "May 4, 2016" +#define BTF_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) +#define BTF_MAIN_VERSION 1 +#define BTF_SUB_VERSION 2 +#define BTF_SUBSUB_VERSION 6 +#define BTF_VERSION BTF_VERSION_CODE(BTF_MAIN_VERSION,BTF_SUB_VERSION) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/camd.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/camd.h new file mode 100644 index 0000000..21898e0 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/camd.h @@ -0,0 +1,407 @@ +/* ========================================================================= */ +/* === CAMD: approximate minimum degree ordering ========================== */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* CAMD Version 2.4, Copyright (c) 2013 by Timothy A. Davis, Yanqing Chen, */ +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ +/* email: DrTimothyAldenDavis@gmail.com */ +/* ------------------------------------------------------------------------- */ + +/* CAMD finds a symmetric ordering P of a matrix A so that the Cholesky + * factorization of P*A*P' has fewer nonzeros and takes less work than the + * Cholesky factorization of A. If A is not symmetric, then it performs its + * ordering on the matrix A+A'. Two sets of user-callable routines are + * provided, one for int integers and the other for SuiteSparse_long integers. + * + * The method is based on the approximate minimum degree algorithm, discussed + * in Amestoy, Davis, and Duff, "An approximate degree ordering algorithm", + * SIAM Journal of Matrix Analysis and Applications, vol. 17, no. 4, pp. + * 886-905, 1996. + */ + +#ifndef CAMD_H +#define CAMD_H + +/* make it easy for C++ programs to include CAMD */ +#ifdef __cplusplus +extern "C" { +#endif + +/* get the definition of size_t: */ +#include <stddef.h> + +#include "SuiteSparse_config.h" + +int camd_order /* returns CAMD_OK, CAMD_OK_BUT_JUMBLED, + * CAMD_INVALID, or CAMD_OUT_OF_MEMORY */ +( + int n, /* A is n-by-n. n must be >= 0. */ + const int Ap [ ], /* column pointers for A, of size n+1 */ + const int Ai [ ], /* row indices of A, of size nz = Ap [n] */ + int P [ ], /* output permutation, of size n */ + double Control [ ], /* input Control settings, of size CAMD_CONTROL */ + double Info [ ], /* output Info statistics, of size CAMD_INFO */ + const int C [ ] /* Constraint set of A, of size n; can be NULL */ +) ; + +SuiteSparse_long camd_l_order /* see above for description of arguments */ +( + SuiteSparse_long n, + const SuiteSparse_long Ap [ ], + const SuiteSparse_long Ai [ ], + SuiteSparse_long P [ ], + double Control [ ], + double Info [ ], + const SuiteSparse_long C [ ] +) ; + +/* Input arguments (not modified): + * + * n: the matrix A is n-by-n. + * Ap: an int/SuiteSparse_long array of size n+1, containing column + * pointers of A. + * Ai: an int/SuiteSparse_long array of size nz, containing the row + * indices of A, where nz = Ap [n]. + * Control: a double array of size CAMD_CONTROL, containing control + * parameters. Defaults are used if Control is NULL. + * + * Output arguments (not defined on input): + * + * P: an int/SuiteSparse_long array of size n, containing the output + * permutation. If row i is the kth pivot row, then P [k] = i. In + * MATLAB notation, the reordered matrix is A (P,P). + * Info: a double array of size CAMD_INFO, containing statistical + * information. Ignored if Info is NULL. + * + * On input, the matrix A is stored in column-oriented form. The row indices + * of nonzero entries in column j are stored in Ai [Ap [j] ... Ap [j+1]-1]. + * + * If the row indices appear in ascending order in each column, and there + * are no duplicate entries, then camd_order is slightly more efficient in + * terms of time and memory usage. If this condition does not hold, a copy + * of the matrix is created (where these conditions do hold), and the copy is + * ordered. + * + * Row indices must be in the range 0 to + * n-1. Ap [0] must be zero, and thus nz = Ap [n] is the number of nonzeros + * in A. The array Ap is of size n+1, and the array Ai is of size nz = Ap [n]. + * The matrix does not need to be symmetric, and the diagonal does not need to + * be present (if diagonal entries are present, they are ignored except for + * the output statistic Info [CAMD_NZDIAG]). The arrays Ai and Ap are not + * modified. This form of the Ap and Ai arrays to represent the nonzero + * pattern of the matrix A is the same as that used internally by MATLAB. + * If you wish to use a more flexible input structure, please see the + * umfpack_*_triplet_to_col routines in the UMFPACK package, at + * http://www.suitesparse.com. + * + * Restrictions: n >= 0. Ap [0] = 0. Ap [j] <= Ap [j+1] for all j in the + * range 0 to n-1. nz = Ap [n] >= 0. Ai [0..nz-1] must be in the range 0 + * to n-1. Finally, Ai, Ap, and P must not be NULL. If any of these + * restrictions are not met, CAMD returns CAMD_INVALID. + * + * CAMD returns: + * + * CAMD_OK if the matrix is valid and sufficient memory can be allocated to + * perform the ordering. + * + * CAMD_OUT_OF_MEMORY if not enough memory can be allocated. + * + * CAMD_INVALID if the input arguments n, Ap, Ai are invalid, or if P is + * NULL. + * + * CAMD_OK_BUT_JUMBLED if the matrix had unsorted columns, and/or duplicate + * entries, but was otherwise valid. + * + * The CAMD routine first forms the pattern of the matrix A+A', and then + * computes a fill-reducing ordering, P. If P [k] = i, then row/column i of + * the original is the kth pivotal row. In MATLAB notation, the permuted + * matrix is A (P,P), except that 0-based indexing is used instead of the + * 1-based indexing in MATLAB. + * + * The Control array is used to set various parameters for CAMD. If a NULL + * pointer is passed, default values are used. The Control array is not + * modified. + * + * Control [CAMD_DENSE]: controls the threshold for "dense" rows/columns. + * A dense row/column in A+A' can cause CAMD to spend a lot of time in + * ordering the matrix. If Control [CAMD_DENSE] >= 0, rows/columns + * with more than Control [CAMD_DENSE] * sqrt (n) entries are ignored + * during the ordering, and placed last in the output order. The + * default value of Control [CAMD_DENSE] is 10. If negative, no + * rows/columns are treated as "dense". Rows/columns with 16 or + * fewer off-diagonal entries are never considered "dense". + * + * Control [CAMD_AGGRESSIVE]: controls whether or not to use aggressive + * absorption, in which a prior element is absorbed into the current + * element if is a subset of the current element, even if it is not + * adjacent to the current pivot element (refer to Amestoy, Davis, + * & Duff, 1996, for more details). The default value is nonzero, + * which means to perform aggressive absorption. This nearly always + * leads to a better ordering (because the approximate degrees are + * more accurate) and a lower execution time. There are cases where + * it can lead to a slightly worse ordering, however. To turn it off, + * set Control [CAMD_AGGRESSIVE] to 0. + * + * Control [2..4] are not used in the current version, but may be used in + * future versions. + * + * The Info array provides statistics about the ordering on output. If it is + * not present, the statistics are not returned. This is not an error + * condition. + * + * Info [CAMD_STATUS]: the return value of CAMD, either CAMD_OK, + * CAMD_OK_BUT_JUMBLED, CAMD_OUT_OF_MEMORY, or CAMD_INVALID. + * + * Info [CAMD_N]: n, the size of the input matrix + * + * Info [CAMD_NZ]: the number of nonzeros in A, nz = Ap [n] + * + * Info [CAMD_SYMMETRY]: the symmetry of the matrix A. It is the number + * of "matched" off-diagonal entries divided by the total number of + * off-diagonal entries. An entry A(i,j) is matched if A(j,i) is also + * an entry, for any pair (i,j) for which i != j. In MATLAB notation, + * S = spones (A) ; + * B = tril (S, -1) + triu (S, 1) ; + * symmetry = nnz (B & B') / nnz (B) ; + * + * Info [CAMD_NZDIAG]: the number of entries on the diagonal of A. + * + * Info [CAMD_NZ_A_PLUS_AT]: the number of nonzeros in A+A', excluding the + * diagonal. If A is perfectly symmetric (Info [CAMD_SYMMETRY] = 1) + * with a fully nonzero diagonal, then Info [CAMD_NZ_A_PLUS_AT] = nz-n + * (the smallest possible value). If A is perfectly unsymmetric + * (Info [CAMD_SYMMETRY] = 0, for an upper triangular matrix, for + * example) with no diagonal, then Info [CAMD_NZ_A_PLUS_AT] = 2*nz + * (the largest possible value). + * + * Info [CAMD_NDENSE]: the number of "dense" rows/columns of A+A' that were + * removed from A prior to ordering. These are placed last in the + * output order P. + * + * Info [CAMD_MEMORY]: the amount of memory used by CAMD, in bytes. In the + * current version, this is 1.2 * Info [CAMD_NZ_A_PLUS_AT] + 9*n + * times the size of an integer. This is at most 2.4nz + 9n. This + * excludes the size of the input arguments Ai, Ap, and P, which have + * a total size of nz + 2*n + 1 integers. + * + * Info [CAMD_NCMPA]: the number of garbage collections performed. + * + * Info [CAMD_LNZ]: the number of nonzeros in L (excluding the diagonal). + * This is a slight upper bound because mass elimination is combined + * with the approximate degree update. It is a rough upper bound if + * there are many "dense" rows/columns. The rest of the statistics, + * below, are also slight or rough upper bounds, for the same reasons. + * The post-ordering of the assembly tree might also not exactly + * correspond to a true elimination tree postordering. + * + * Info [CAMD_NDIV]: the number of divide operations for a subsequent LDL' + * or LU factorization of the permuted matrix A (P,P). + * + * Info [CAMD_NMULTSUBS_LDL]: the number of multiply-subtract pairs for a + * subsequent LDL' factorization of A (P,P). + * + * Info [CAMD_NMULTSUBS_LU]: the number of multiply-subtract pairs for a + * subsequent LU factorization of A (P,P), assuming that no numerical + * pivoting is required. + * + * Info [CAMD_DMAX]: the maximum number of nonzeros in any column of L, + * including the diagonal. + * + * Info [14..19] are not used in the current version, but may be used in + * future versions. + */ + +/* ------------------------------------------------------------------------- */ +/* direct interface to CAMD */ +/* ------------------------------------------------------------------------- */ + +/* camd_2 is the primary CAMD ordering routine. It is not meant to be + * user-callable because of its restrictive inputs and because it destroys + * the user's input matrix. It does not check its inputs for errors, either. + * However, if you can work with these restrictions it can be faster than + * camd_order and use less memory (assuming that you can create your own copy + * of the matrix for CAMD to destroy). Refer to CAMD/Source/camd_2.c for a + * description of each parameter. */ + +void camd_2 +( + int n, + int Pe [ ], + int Iw [ ], + int Len [ ], + int iwlen, + int pfree, + int Nv [ ], + int Next [ ], + int Last [ ], + int Head [ ], + int Elen [ ], + int Degree [ ], + int W [ ], + double Control [ ], + double Info [ ], + const int C [ ], + int BucketSet [ ] +) ; + +void camd_l2 +( + SuiteSparse_long n, + SuiteSparse_long Pe [ ], + SuiteSparse_long Iw [ ], + SuiteSparse_long Len [ ], + SuiteSparse_long iwlen, + SuiteSparse_long pfree, + SuiteSparse_long Nv [ ], + SuiteSparse_long Next [ ], + SuiteSparse_long Last [ ], + SuiteSparse_long Head [ ], + SuiteSparse_long Elen [ ], + SuiteSparse_long Degree [ ], + SuiteSparse_long W [ ], + double Control [ ], + double Info [ ], + const SuiteSparse_long C [ ], + SuiteSparse_long BucketSet [ ] + +) ; + +/* ------------------------------------------------------------------------- */ +/* camd_valid */ +/* ------------------------------------------------------------------------- */ + +/* Returns CAMD_OK or CAMD_OK_BUT_JUMBLED if the matrix is valid as input to + * camd_order; the latter is returned if the matrix has unsorted and/or + * duplicate row indices in one or more columns. Returns CAMD_INVALID if the + * matrix cannot be passed to camd_order. For camd_order, the matrix must also + * be square. The first two arguments are the number of rows and the number + * of columns of the matrix. For its use in CAMD, these must both equal n. + */ + +int camd_valid +( + int n_row, /* # of rows */ + int n_col, /* # of columns */ + const int Ap [ ], /* column pointers, of size n_col+1 */ + const int Ai [ ] /* row indices, of size Ap [n_col] */ +) ; + +SuiteSparse_long camd_l_valid +( + SuiteSparse_long n_row, + SuiteSparse_long n_col, + const SuiteSparse_long Ap [ ], + const SuiteSparse_long Ai [ ] +) ; + +/* ------------------------------------------------------------------------- */ +/* camd_cvalid */ +/* ------------------------------------------------------------------------- */ + +/* Returns TRUE if the constraint set is valid as input to camd_order, + * FALSE otherwise. */ + +int camd_cvalid +( + int n, + const int C [ ] +) ; + +SuiteSparse_long camd_l_cvalid +( + SuiteSparse_long n, + const SuiteSparse_long C [ ] +) ; + +/* ------------------------------------------------------------------------- */ +/* CAMD memory manager and printf routines */ +/* ------------------------------------------------------------------------- */ + + /* moved to SuiteSparse_config.c */ + +/* ------------------------------------------------------------------------- */ +/* CAMD Control and Info arrays */ +/* ------------------------------------------------------------------------- */ + +/* camd_defaults: sets the default control settings */ +void camd_defaults (double Control [ ]) ; +void camd_l_defaults (double Control [ ]) ; + +/* camd_control: prints the control settings */ +void camd_control (double Control [ ]) ; +void camd_l_control (double Control [ ]) ; + +/* camd_info: prints the statistics */ +void camd_info (double Info [ ]) ; +void camd_l_info (double Info [ ]) ; + +#define CAMD_CONTROL 5 /* size of Control array */ +#define CAMD_INFO 20 /* size of Info array */ + +/* contents of Control */ +#define CAMD_DENSE 0 /* "dense" if degree > Control [0] * sqrt (n) */ +#define CAMD_AGGRESSIVE 1 /* do aggressive absorption if Control [1] != 0 */ + +/* default Control settings */ +#define CAMD_DEFAULT_DENSE 10.0 /* default "dense" degree 10*sqrt(n) */ +#define CAMD_DEFAULT_AGGRESSIVE 1 /* do aggressive absorption by default */ + +/* contents of Info */ +#define CAMD_STATUS 0 /* return value of camd_order and camd_l_order */ +#define CAMD_N 1 /* A is n-by-n */ +#define CAMD_NZ 2 /* number of nonzeros in A */ +#define CAMD_SYMMETRY 3 /* symmetry of pattern (1 is sym., 0 is unsym.) */ +#define CAMD_NZDIAG 4 /* # of entries on diagonal */ +#define CAMD_NZ_A_PLUS_AT 5 /* nz in A+A' */ +#define CAMD_NDENSE 6 /* number of "dense" rows/columns in A */ +#define CAMD_MEMORY 7 /* amount of memory used by CAMD */ +#define CAMD_NCMPA 8 /* number of garbage collections in CAMD */ +#define CAMD_LNZ 9 /* approx. nz in L, excluding the diagonal */ +#define CAMD_NDIV 10 /* number of fl. point divides for LU and LDL' */ +#define CAMD_NMULTSUBS_LDL 11 /* number of fl. point (*,-) pairs for LDL' */ +#define CAMD_NMULTSUBS_LU 12 /* number of fl. point (*,-) pairs for LU */ +#define CAMD_DMAX 13 /* max nz. in any column of L, incl. diagonal */ + +/* ------------------------------------------------------------------------- */ +/* return values of CAMD */ +/* ------------------------------------------------------------------------- */ + +#define CAMD_OK 0 /* success */ +#define CAMD_OUT_OF_MEMORY -1 /* malloc failed, or problem too large */ +#define CAMD_INVALID -2 /* input arguments are not valid */ +#define CAMD_OK_BUT_JUMBLED 1 /* input matrix is OK for camd_order, but + * columns were not sorted, and/or duplicate entries were present. CAMD had + * to do extra work before ordering the matrix. This is a warning, not an + * error. */ + +/* ========================================================================== */ +/* === CAMD version ========================================================= */ +/* ========================================================================== */ + +/* + * As an example, to test if the version you are using is 1.2 or later: + * + * if (CAMD_VERSION >= CAMD_VERSION_CODE (1,2)) ... + * + * This also works during compile-time: + * + * #if (CAMD_VERSION >= CAMD_VERSION_CODE (1,2)) + * printf ("This is version 1.2 or later\n") ; + * #else + * printf ("This is an early version\n") ; + * #endif + */ + +#define CAMD_DATE "May 4, 2016" +#define CAMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) +#define CAMD_MAIN_VERSION 2 +#define CAMD_SUB_VERSION 4 +#define CAMD_SUBSUB_VERSION 6 +#define CAMD_VERSION CAMD_VERSION_CODE(CAMD_MAIN_VERSION,CAMD_SUB_VERSION) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/colamd.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/colamd.h new file mode 100644 index 0000000..fbe9593 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/colamd.h @@ -0,0 +1,237 @@ +/* ========================================================================== */ +/* === colamd/symamd prototypes and definitions ============================= */ +/* ========================================================================== */ + +/* COLAMD / SYMAMD include file + + You must include this file (colamd.h) in any routine that uses colamd, + symamd, or the related macros and definitions. + + Authors: + + The authors of the code itself are Stefan I. Larimore and Timothy A. + Davis (DrTimothyAldenDavis@gmail.com). The algorithm was + developed in collaboration with John Gilbert, Xerox PARC, and Esmond + Ng, Oak Ridge National Laboratory. + + Acknowledgements: + + This work was supported by the National Science Foundation, under + grants DMS-9504974 and DMS-9803599. + + Notice: + + Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved. + See COLAMD/Doc/License.txt for the license. + + Availability: + + The colamd/symamd library is available at http://www.suitesparse.com + This file is required by the colamd.c, colamdmex.c, and symamdmex.c + files, and by any C code that calls the routines whose prototypes are + listed below, or that uses the colamd/symamd definitions listed below. + +*/ + +#ifndef COLAMD_H +#define COLAMD_H + +/* make it easy for C++ programs to include COLAMD */ +#ifdef __cplusplus +extern "C" { +#endif + +/* ========================================================================== */ +/* === Include files ======================================================== */ +/* ========================================================================== */ + +#include <stdlib.h> + +/* ========================================================================== */ +/* === COLAMD version ======================================================= */ +/* ========================================================================== */ + +/* COLAMD Version 2.4 and later will include the following definitions. + * As an example, to test if the version you are using is 2.4 or later: + * + * #ifdef COLAMD_VERSION + * if (COLAMD_VERSION >= COLAMD_VERSION_CODE (2,4)) ... + * #endif + * + * This also works during compile-time: + * + * #if defined(COLAMD_VERSION) && (COLAMD_VERSION >= COLAMD_VERSION_CODE (2,4)) + * printf ("This is version 2.4 or later\n") ; + * #else + * printf ("This is an early version\n") ; + * #endif + * + * Versions 2.3 and earlier of COLAMD do not include a #define'd version number. + */ + +#define COLAMD_DATE "May 4, 2016" +#define COLAMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) +#define COLAMD_MAIN_VERSION 2 +#define COLAMD_SUB_VERSION 9 +#define COLAMD_SUBSUB_VERSION 6 +#define COLAMD_VERSION \ + COLAMD_VERSION_CODE(COLAMD_MAIN_VERSION,COLAMD_SUB_VERSION) + +/* ========================================================================== */ +/* === Knob and statistics definitions ====================================== */ +/* ========================================================================== */ + +/* size of the knobs [ ] array. Only knobs [0..1] are currently used. */ +#define COLAMD_KNOBS 20 + +/* number of output statistics. Only stats [0..6] are currently used. */ +#define COLAMD_STATS 20 + +/* knobs [0] and stats [0]: dense row knob and output statistic. */ +#define COLAMD_DENSE_ROW 0 + +/* knobs [1] and stats [1]: dense column knob and output statistic. */ +#define COLAMD_DENSE_COL 1 + +/* knobs [2]: aggressive absorption */ +#define COLAMD_AGGRESSIVE 2 + +/* stats [2]: memory defragmentation count output statistic */ +#define COLAMD_DEFRAG_COUNT 2 + +/* stats [3]: colamd status: zero OK, > 0 warning or notice, < 0 error */ +#define COLAMD_STATUS 3 + +/* stats [4..6]: error info, or info on jumbled columns */ +#define COLAMD_INFO1 4 +#define COLAMD_INFO2 5 +#define COLAMD_INFO3 6 + +/* error codes returned in stats [3]: */ +#define COLAMD_OK (0) +#define COLAMD_OK_BUT_JUMBLED (1) +#define COLAMD_ERROR_A_not_present (-1) +#define COLAMD_ERROR_p_not_present (-2) +#define COLAMD_ERROR_nrow_negative (-3) +#define COLAMD_ERROR_ncol_negative (-4) +#define COLAMD_ERROR_nnz_negative (-5) +#define COLAMD_ERROR_p0_nonzero (-6) +#define COLAMD_ERROR_A_too_small (-7) +#define COLAMD_ERROR_col_length_negative (-8) +#define COLAMD_ERROR_row_index_out_of_bounds (-9) +#define COLAMD_ERROR_out_of_memory (-10) +#define COLAMD_ERROR_internal_error (-999) + + +/* ========================================================================== */ +/* === Prototypes of user-callable routines ================================= */ +/* ========================================================================== */ + +#include "SuiteSparse_config.h" + +size_t colamd_recommended /* returns recommended value of Alen, */ + /* or 0 if input arguments are erroneous */ +( + int nnz, /* nonzeros in A */ + int n_row, /* number of rows in A */ + int n_col /* number of columns in A */ +) ; + +size_t colamd_l_recommended /* returns recommended value of Alen, */ + /* or 0 if input arguments are erroneous */ +( + SuiteSparse_long nnz, /* nonzeros in A */ + SuiteSparse_long n_row, /* number of rows in A */ + SuiteSparse_long n_col /* number of columns in A */ +) ; + +void colamd_set_defaults /* sets default parameters */ +( /* knobs argument is modified on output */ + double knobs [COLAMD_KNOBS] /* parameter settings for colamd */ +) ; + +void colamd_l_set_defaults /* sets default parameters */ +( /* knobs argument is modified on output */ + double knobs [COLAMD_KNOBS] /* parameter settings for colamd */ +) ; + +int colamd /* returns (1) if successful, (0) otherwise*/ +( /* A and p arguments are modified on output */ + int n_row, /* number of rows in A */ + int n_col, /* number of columns in A */ + int Alen, /* size of the array A */ + int A [], /* row indices of A, of size Alen */ + int p [], /* column pointers of A, of size n_col+1 */ + double knobs [COLAMD_KNOBS],/* parameter settings for colamd */ + int stats [COLAMD_STATS] /* colamd output statistics and error codes */ +) ; + +SuiteSparse_long colamd_l /* returns (1) if successful, (0) otherwise*/ +( /* A and p arguments are modified on output */ + SuiteSparse_long n_row, /* number of rows in A */ + SuiteSparse_long n_col, /* number of columns in A */ + SuiteSparse_long Alen, /* size of the array A */ + SuiteSparse_long A [], /* row indices of A, of size Alen */ + SuiteSparse_long p [], /* column pointers of A, of size n_col+1 */ + double knobs [COLAMD_KNOBS],/* parameter settings for colamd */ + SuiteSparse_long stats [COLAMD_STATS] /* colamd output statistics + * and error codes */ +) ; + +int symamd /* return (1) if OK, (0) otherwise */ +( + int n, /* number of rows and columns of A */ + int A [], /* row indices of A */ + int p [], /* column pointers of A */ + int perm [], /* output permutation, size n_col+1 */ + double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */ + int stats [COLAMD_STATS], /* output statistics and error codes */ + void * (*allocate) (size_t, size_t), + /* pointer to calloc (ANSI C) or */ + /* mxCalloc (for MATLAB mexFunction) */ + void (*release) (void *) + /* pointer to free (ANSI C) or */ + /* mxFree (for MATLAB mexFunction) */ +) ; + +SuiteSparse_long symamd_l /* return (1) if OK, (0) otherwise */ +( + SuiteSparse_long n, /* number of rows and columns of A */ + SuiteSparse_long A [], /* row indices of A */ + SuiteSparse_long p [], /* column pointers of A */ + SuiteSparse_long perm [], /* output permutation, size n_col+1 */ + double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */ + SuiteSparse_long stats [COLAMD_STATS], /* output stats and error codes */ + void * (*allocate) (size_t, size_t), + /* pointer to calloc (ANSI C) or */ + /* mxCalloc (for MATLAB mexFunction) */ + void (*release) (void *) + /* pointer to free (ANSI C) or */ + /* mxFree (for MATLAB mexFunction) */ +) ; + +void colamd_report +( + int stats [COLAMD_STATS] +) ; + +void colamd_l_report +( + SuiteSparse_long stats [COLAMD_STATS] +) ; + +void symamd_report +( + int stats [COLAMD_STATS] +) ; + +void symamd_l_report +( + SuiteSparse_long stats [COLAMD_STATS] +) ; + +#ifdef __cplusplus +} +#endif + +#endif /* COLAMD_H */ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/klu.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/klu.h new file mode 100644 index 0000000..2da483b --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/SuiteSparse/include/klu.h @@ -0,0 +1,832 @@ +/* ========================================================================== */ +/* === klu include file ===================================================== */ +/* ========================================================================== */ + +/* Include file for user programs that call klu_* routines */ + +#ifndef _KLU_H +#define _KLU_H + +/* make it easy for C++ programs to include KLU */ +#ifdef __cplusplus +extern "C" { +#endif + +#include "amd.h" +#include "colamd.h" +#include "btf.h" + +/* -------------------------------------------------------------------------- */ +/* Symbolic object - contains the pre-ordering computed by klu_analyze */ +/* -------------------------------------------------------------------------- */ + +typedef struct +{ + /* A (P,Q) is in upper block triangular form. The kth block goes from + * row/col index R [k] to R [k+1]-1. The estimated number of nonzeros + * in the L factor of the kth block is Lnz [k]. + */ + + /* only computed if the AMD ordering is chosen: */ + double symmetry ; /* symmetry of largest block */ + double est_flops ; /* est. factorization flop count */ + double lnz, unz ; /* estimated nz in L and U, including diagonals */ + double *Lnz ; /* size n, but only Lnz [0..nblocks-1] is used */ + + /* computed for all orderings: */ + int + n, /* input matrix A is n-by-n */ + nz, /* # entries in input matrix */ + *P, /* size n */ + *Q, /* size n */ + *R, /* size n+1, but only R [0..nblocks] is used */ + nzoff, /* nz in off-diagonal blocks */ + nblocks, /* number of blocks */ + maxblock, /* size of largest block */ + ordering, /* ordering used (AMD, COLAMD, or GIVEN) */ + do_btf ; /* whether or not BTF preordering was requested */ + + /* only computed if BTF preordering requested */ + int structural_rank ; /* 0 to n-1 if the matrix is structurally rank + * deficient. -1 if not computed. n if the matrix has + * full structural rank */ + +} klu_symbolic ; + +typedef struct /* 64-bit version (otherwise same as above) */ +{ + double symmetry, est_flops, lnz, unz ; + double *Lnz ; + SuiteSparse_long n, nz, *P, *Q, *R, nzoff, nblocks, maxblock, ordering, + do_btf, structural_rank ; + +} klu_l_symbolic ; + +/* -------------------------------------------------------------------------- */ +/* Numeric object - contains the factors computed by klu_factor */ +/* -------------------------------------------------------------------------- */ + +typedef struct +{ + /* LU factors of each block, the pivot row permutation, and the + * entries in the off-diagonal blocks */ + + int n ; /* A is n-by-n */ + int nblocks ; /* number of diagonal blocks */ + int lnz ; /* actual nz in L, including diagonal */ + int unz ; /* actual nz in U, including diagonal */ + int max_lnz_block ; /* max actual nz in L in any one block, incl. diag */ + int max_unz_block ; /* max actual nz in U in any one block, incl. diag */ + int *Pnum ; /* size n. final pivot permutation */ + int *Pinv ; /* size n. inverse of final pivot permutation */ + + /* LU factors of each block */ + int *Lip ; /* size n. pointers into LUbx[block] for L */ + int *Uip ; /* size n. pointers into LUbx[block] for U */ + int *Llen ; /* size n. Llen [k] = # of entries in kth column of L */ + int *Ulen ; /* size n. Ulen [k] = # of entries in kth column of U */ + void **LUbx ; /* L and U indices and entries (excl. diagonal of U) */ + size_t *LUsize ; /* size of each LUbx [block], in sizeof (Unit) */ + void *Udiag ; /* diagonal of U */ + + /* scale factors; can be NULL if no scaling */ + double *Rs ; /* size n. Rs [i] is scale factor for row i */ + + /* permanent workspace for factorization and solve */ + size_t worksize ; /* size (in bytes) of Work */ + void *Work ; /* workspace */ + void *Xwork ; /* alias into Numeric->Work */ + int *Iwork ; /* alias into Numeric->Work */ + + /* off-diagonal entries in a conventional compressed-column sparse matrix */ + int *Offp ; /* size n+1, column pointers */ + int *Offi ; /* size nzoff, row indices */ + void *Offx ; /* size nzoff, numerical values */ + int nzoff ; + +} klu_numeric ; + +typedef struct /* 64-bit version (otherwise same as above) */ +{ + SuiteSparse_long n, nblocks, lnz, unz, max_lnz_block, max_unz_block, *Pnum, + *Pinv, *Lip, *Uip, *Llen, *Ulen ; + void **LUbx ; + size_t *LUsize ; + void *Udiag ; + double *Rs ; + size_t worksize ; + void *Work, *Xwork ; + SuiteSparse_long *Iwork ; + SuiteSparse_long *Offp, *Offi ; + void *Offx ; + SuiteSparse_long nzoff ; + +} klu_l_numeric ; + +/* -------------------------------------------------------------------------- */ +/* KLU control parameters and statistics */ +/* -------------------------------------------------------------------------- */ + +/* Common->status values */ +#define KLU_OK 0 +#define KLU_SINGULAR (1) /* status > 0 is a warning, not an error */ +#define KLU_OUT_OF_MEMORY (-2) +#define KLU_INVALID (-3) +#define KLU_TOO_LARGE (-4) /* integer overflow has occured */ + +typedef struct klu_common_struct +{ + + /* ---------------------------------------------------------------------- */ + /* parameters */ + /* ---------------------------------------------------------------------- */ + + double tol ; /* pivot tolerance for diagonal preference */ + double memgrow ; /* realloc memory growth size for LU factors */ + double initmem_amd ; /* init. memory size with AMD: c*nnz(L) + n */ + double initmem ; /* init. memory size: c*nnz(A) + n */ + double maxwork ; /* maxwork for BTF, <= 0 if no limit */ + + int btf ; /* use BTF pre-ordering, or not */ + int ordering ; /* 0: AMD, 1: COLAMD, 2: user P and Q, + * 3: user function */ + int scale ; /* row scaling: -1: none (and no error check), + * 0: none, 1: sum, 2: max */ + + /* pointer to user ordering function */ + int (*user_order) (int, int *, int *, int *, struct klu_common_struct *) ; + + /* pointer to user data, passed unchanged as the last parameter to the + * user ordering function (optional, the user function need not use this + * information). */ + void *user_data ; + + int halt_if_singular ; /* how to handle a singular matrix: + * FALSE: keep going. Return a Numeric object with a zero U(k,k). A + * divide-by-zero may occur when computing L(:,k). The Numeric object + * can be passed to klu_solve (a divide-by-zero will occur). It can + * also be safely passed to klu_refactor. + * TRUE: stop quickly. klu_factor will free the partially-constructed + * Numeric object. klu_refactor will not free it, but will leave the + * numerical values only partially defined. This is the default. */ + + /* ---------------------------------------------------------------------- */ + /* statistics */ + /* ---------------------------------------------------------------------- */ + + int status ; /* KLU_OK if OK, < 0 if error */ + int nrealloc ; /* # of reallocations of L and U */ + + int structural_rank ; /* 0 to n-1 if the matrix is structurally rank + * deficient (as determined by maxtrans). -1 if not computed. n if the + * matrix has full structural rank. This is computed by klu_analyze + * if a BTF preordering is requested. */ + + int numerical_rank ; /* First k for which a zero U(k,k) was found, + * if the matrix was singular (in the range 0 to n-1). n if the matrix + * has full rank. This is not a true rank-estimation. It just reports + * where the first zero pivot was found. -1 if not computed. + * Computed by klu_factor and klu_refactor. */ + + int singular_col ; /* n if the matrix is not singular. If in the + * range 0 to n-1, this is the column index of the original matrix A that + * corresponds to the column of U that contains a zero diagonal entry. + * -1 if not computed. Computed by klu_factor and klu_refactor. */ + + int noffdiag ; /* # of off-diagonal pivots, -1 if not computed */ + + double flops ; /* actual factorization flop count, from klu_flops */ + double rcond ; /* crude reciprocal condition est., from klu_rcond */ + double condest ; /* accurate condition est., from klu_condest */ + double rgrowth ; /* reciprocal pivot rgrowth, from klu_rgrowth */ + double work ; /* actual work done in BTF, in klu_analyze */ + + size_t memusage ; /* current memory usage, in bytes */ + size_t mempeak ; /* peak memory usage, in bytes */ + +} klu_common ; + +typedef struct klu_l_common_struct /* 64-bit version (otherwise same as above)*/ +{ + + double tol, memgrow, initmem_amd, initmem, maxwork ; + SuiteSparse_long btf, ordering, scale ; + SuiteSparse_long (*user_order) (SuiteSparse_long, SuiteSparse_long *, + SuiteSparse_long *, SuiteSparse_long *, + struct klu_l_common_struct *) ; + void *user_data ; + SuiteSparse_long halt_if_singular ; + SuiteSparse_long status, nrealloc, structural_rank, numerical_rank, + singular_col, noffdiag ; + double flops, rcond, condest, rgrowth, work ; + size_t memusage, mempeak ; + +} klu_l_common ; + +/* -------------------------------------------------------------------------- */ +/* klu_defaults: sets default control parameters */ +/* -------------------------------------------------------------------------- */ + +int klu_defaults +( + klu_common *Common +) ; + +SuiteSparse_long klu_l_defaults (klu_l_common *Common) ; + +/* -------------------------------------------------------------------------- */ +/* klu_analyze: orders and analyzes a matrix */ +/* -------------------------------------------------------------------------- */ + +/* Order the matrix with BTF (or not), then order each block with AMD, COLAMD, + * a natural ordering, or with a user-provided ordering function */ + +klu_symbolic *klu_analyze +( + /* inputs, not modified */ + int n, /* A is n-by-n */ + int Ap [ ], /* size n+1, column pointers */ + int Ai [ ], /* size nz, row indices */ + klu_common *Common +) ; + +klu_l_symbolic *klu_l_analyze (SuiteSparse_long, SuiteSparse_long *, + SuiteSparse_long *, klu_l_common *Common) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_analyze_given: analyzes a matrix using given P and Q */ +/* -------------------------------------------------------------------------- */ + +/* Order the matrix with BTF (or not), then use natural or given ordering + * P and Q on the blocks. P and Q are interpretted as identity + * if NULL. */ + +klu_symbolic *klu_analyze_given +( + /* inputs, not modified */ + int n, /* A is n-by-n */ + int Ap [ ], /* size n+1, column pointers */ + int Ai [ ], /* size nz, row indices */ + int P [ ], /* size n, user's row permutation (may be NULL) */ + int Q [ ], /* size n, user's column permutation (may be NULL) */ + klu_common *Common +) ; + +klu_l_symbolic *klu_l_analyze_given (SuiteSparse_long, SuiteSparse_long *, + SuiteSparse_long *, SuiteSparse_long *, SuiteSparse_long *, + klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_factor: factors a matrix using the klu_analyze results */ +/* -------------------------------------------------------------------------- */ + +klu_numeric *klu_factor /* returns KLU_OK if OK, < 0 if error */ +( + /* inputs, not modified */ + int Ap [ ], /* size n+1, column pointers */ + int Ai [ ], /* size nz, row indices */ + double Ax [ ], /* size nz, numerical values */ + klu_symbolic *Symbolic, + klu_common *Common +) ; + +klu_numeric *klu_z_factor /* returns KLU_OK if OK, < 0 if error */ +( + /* inputs, not modified */ + int Ap [ ], /* size n+1, column pointers */ + int Ai [ ], /* size nz, row indices */ + double Ax [ ], /* size 2*nz, numerical values (real,imag pairs) */ + klu_symbolic *Symbolic, + klu_common *Common +) ; + +/* long / real version */ +klu_l_numeric *klu_l_factor (SuiteSparse_long *, SuiteSparse_long *, double *, + klu_l_symbolic *, klu_l_common *) ; + +/* long / complex version */ +klu_l_numeric *klu_zl_factor (SuiteSparse_long *, SuiteSparse_long *, double *, + klu_l_symbolic *, klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_solve: solves Ax=b using the Symbolic and Numeric objects */ +/* -------------------------------------------------------------------------- */ + +int klu_solve +( + /* inputs, not modified */ + klu_symbolic *Symbolic, + klu_numeric *Numeric, + int ldim, /* leading dimension of B */ + int nrhs, /* number of right-hand-sides */ + + /* right-hand-side on input, overwritten with solution to Ax=b on output */ + double B [ ], /* size ldim*nrhs */ + klu_common *Common +) ; + +int klu_z_solve +( + /* inputs, not modified */ + klu_symbolic *Symbolic, + klu_numeric *Numeric, + int ldim, /* leading dimension of B */ + int nrhs, /* number of right-hand-sides */ + + /* right-hand-side on input, overwritten with solution to Ax=b on output */ + double B [ ], /* size 2*ldim*nrhs */ + klu_common *Common +) ; + +SuiteSparse_long klu_l_solve (klu_l_symbolic *, klu_l_numeric *, + SuiteSparse_long, SuiteSparse_long, double *, klu_l_common *) ; + +SuiteSparse_long klu_zl_solve (klu_l_symbolic *, klu_l_numeric *, + SuiteSparse_long, SuiteSparse_long, double *, klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_tsolve: solves A'x=b using the Symbolic and Numeric objects */ +/* -------------------------------------------------------------------------- */ + +int klu_tsolve +( + /* inputs, not modified */ + klu_symbolic *Symbolic, + klu_numeric *Numeric, + int ldim, /* leading dimension of B */ + int nrhs, /* number of right-hand-sides */ + + /* right-hand-side on input, overwritten with solution to Ax=b on output */ + double B [ ], /* size ldim*nrhs */ + klu_common *Common +) ; + +int klu_z_tsolve +( + /* inputs, not modified */ + klu_symbolic *Symbolic, + klu_numeric *Numeric, + int ldim, /* leading dimension of B */ + int nrhs, /* number of right-hand-sides */ + + /* right-hand-side on input, overwritten with solution to Ax=b on output */ + double B [ ], /* size 2*ldim*nrhs */ + int conj_solve, /* TRUE: conjugate solve, FALSE: solve A.'x=b */ + klu_common *Common + +) ; + +SuiteSparse_long klu_l_tsolve (klu_l_symbolic *, klu_l_numeric *, + SuiteSparse_long, SuiteSparse_long, double *, klu_l_common *) ; + +SuiteSparse_long klu_zl_tsolve (klu_l_symbolic *, klu_l_numeric *, + SuiteSparse_long, SuiteSparse_long, double *, SuiteSparse_long, + klu_l_common * ) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_refactor: refactorizes matrix with same ordering as klu_factor */ +/* -------------------------------------------------------------------------- */ + +int klu_refactor /* return TRUE if successful, FALSE otherwise */ +( + /* inputs, not modified */ + int Ap [ ], /* size n+1, column pointers */ + int Ai [ ], /* size nz, row indices */ + double Ax [ ], /* size nz, numerical values */ + klu_symbolic *Symbolic, + /* input, and numerical values modified on output */ + klu_numeric *Numeric, + klu_common *Common +) ; + +int klu_z_refactor /* return TRUE if successful, FALSE otherwise */ +( + /* inputs, not modified */ + int Ap [ ], /* size n+1, column pointers */ + int Ai [ ], /* size nz, row indices */ + double Ax [ ], /* size 2*nz, numerical values */ + klu_symbolic *Symbolic, + /* input, and numerical values modified on output */ + klu_numeric *Numeric, + klu_common *Common +) ; + +SuiteSparse_long klu_l_refactor (SuiteSparse_long *, SuiteSparse_long *, + double *, klu_l_symbolic *, klu_l_numeric *, klu_l_common *) ; + +SuiteSparse_long klu_zl_refactor (SuiteSparse_long *, SuiteSparse_long *, + double *, klu_l_symbolic *, klu_l_numeric *, klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_free_symbolic: destroys the Symbolic object */ +/* -------------------------------------------------------------------------- */ + +int klu_free_symbolic +( + klu_symbolic **Symbolic, + klu_common *Common +) ; + +SuiteSparse_long klu_l_free_symbolic (klu_l_symbolic **, klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_free_numeric: destroys the Numeric object */ +/* -------------------------------------------------------------------------- */ + +/* Note that klu_free_numeric and klu_z_free_numeric are identical; each can + * free both kinds of Numeric objects (real and complex) */ + +int klu_free_numeric +( + klu_numeric **Numeric, + klu_common *Common +) ; + +int klu_z_free_numeric +( + klu_numeric **Numeric, + klu_common *Common +) ; + +SuiteSparse_long klu_l_free_numeric (klu_l_numeric **, klu_l_common *) ; +SuiteSparse_long klu_zl_free_numeric (klu_l_numeric **, klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_sort: sorts the columns of the LU factorization */ +/* -------------------------------------------------------------------------- */ + +/* this is not needed except for the MATLAB interface */ + +int klu_sort +( + /* inputs, not modified */ + klu_symbolic *Symbolic, + /* input/output */ + klu_numeric *Numeric, + klu_common *Common +) ; + +int klu_z_sort +( + /* inputs, not modified */ + klu_symbolic *Symbolic, + /* input/output */ + klu_numeric *Numeric, + klu_common *Common +) ; + +SuiteSparse_long klu_l_sort (klu_l_symbolic *, klu_l_numeric *, + klu_l_common *) ; +SuiteSparse_long klu_zl_sort (klu_l_symbolic *, klu_l_numeric *, + klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_flops: determines # of flops performed in numeric factorzation */ +/* -------------------------------------------------------------------------- */ + +int klu_flops +( + /* inputs, not modified */ + klu_symbolic *Symbolic, + klu_numeric *Numeric, + /* input/output */ + klu_common *Common +) ; + +int klu_z_flops +( + /* inputs, not modified */ + klu_symbolic *Symbolic, + klu_numeric *Numeric, + /* input/output */ + klu_common *Common +) ; + +SuiteSparse_long klu_l_flops (klu_l_symbolic *, klu_l_numeric *, + klu_l_common *) ; +SuiteSparse_long klu_zl_flops (klu_l_symbolic *, klu_l_numeric *, + klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_rgrowth : compute the reciprocal pivot growth */ +/* -------------------------------------------------------------------------- */ + +/* Pivot growth is computed after the input matrix is permuted, scaled, and + * off-diagonal entries pruned. This is because the LU factorization of each + * block takes as input the scaled diagonal blocks of the BTF form. The + * reciprocal pivot growth in column j of an LU factorization of a matrix C + * is the largest entry in C divided by the largest entry in U; then the overall + * reciprocal pivot growth is the smallest such value for all columns j. Note + * that the off-diagonal entries are not scaled, since they do not take part in + * the LU factorization of the diagonal blocks. + * + * In MATLAB notation: + * + * rgrowth = min (max (abs ((R \ A(p,q)) - F)) ./ max (abs (U))) */ + +int klu_rgrowth +( + int Ap [ ], + int Ai [ ], + double Ax [ ], + klu_symbolic *Symbolic, + klu_numeric *Numeric, + klu_common *Common /* Common->rgrowth = reciprocal pivot growth */ +) ; + +int klu_z_rgrowth +( + int Ap [ ], + int Ai [ ], + double Ax [ ], + klu_symbolic *Symbolic, + klu_numeric *Numeric, + klu_common *Common /* Common->rgrowth = reciprocal pivot growth */ +) ; + +SuiteSparse_long klu_l_rgrowth (SuiteSparse_long *, SuiteSparse_long *, + double *, klu_l_symbolic *, klu_l_numeric *, klu_l_common *) ; + +SuiteSparse_long klu_zl_rgrowth (SuiteSparse_long *, SuiteSparse_long *, + double *, klu_l_symbolic *, klu_l_numeric *, klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_condest */ +/* -------------------------------------------------------------------------- */ + +/* Computes a reasonably accurate estimate of the 1-norm condition number, using + * Hager's method, as modified by Higham and Tisseur (same method as used in + * MATLAB's condest */ + +int klu_condest +( + int Ap [ ], /* size n+1, column pointers, not modified */ + double Ax [ ], /* size nz = Ap[n], numerical values, not modified*/ + klu_symbolic *Symbolic, /* symbolic analysis, not modified */ + klu_numeric *Numeric, /* numeric factorization, not modified */ + klu_common *Common /* result returned in Common->condest */ +) ; + +int klu_z_condest +( + int Ap [ ], + double Ax [ ], /* size 2*nz */ + klu_symbolic *Symbolic, + klu_numeric *Numeric, + klu_common *Common /* result returned in Common->condest */ +) ; + +SuiteSparse_long klu_l_condest (SuiteSparse_long *, double *, klu_l_symbolic *, + klu_l_numeric *, klu_l_common *) ; + +SuiteSparse_long klu_zl_condest (SuiteSparse_long *, double *, klu_l_symbolic *, + klu_l_numeric *, klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_rcond: compute min(abs(diag(U))) / max(abs(diag(U))) */ +/* -------------------------------------------------------------------------- */ + +int klu_rcond +( + klu_symbolic *Symbolic, /* input, not modified */ + klu_numeric *Numeric, /* input, not modified */ + klu_common *Common /* result in Common->rcond */ +) ; + +int klu_z_rcond +( + klu_symbolic *Symbolic, /* input, not modified */ + klu_numeric *Numeric, /* input, not modified */ + klu_common *Common /* result in Common->rcond */ +) ; + +SuiteSparse_long klu_l_rcond (klu_l_symbolic *, klu_l_numeric *, + klu_l_common *) ; + +SuiteSparse_long klu_zl_rcond (klu_l_symbolic *, klu_l_numeric *, + klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_scale */ +/* -------------------------------------------------------------------------- */ + +int klu_scale /* return TRUE if successful, FALSE otherwise */ +( + /* inputs, not modified */ + int scale, /* <0: none, no error check; 0: none, 1: sum, 2: max */ + int n, + int Ap [ ], /* size n+1, column pointers */ + int Ai [ ], /* size nz, row indices */ + double Ax [ ], + /* outputs, not defined on input */ + double Rs [ ], + /* workspace, not defined on input or output */ + int W [ ], /* size n, can be NULL */ + klu_common *Common +) ; + +int klu_z_scale /* return TRUE if successful, FALSE otherwise */ +( + /* inputs, not modified */ + int scale, /* <0: none, no error check; 0: none, 1: sum, 2: max */ + int n, + int Ap [ ], /* size n+1, column pointers */ + int Ai [ ], /* size nz, row indices */ + double Ax [ ], + /* outputs, not defined on input */ + double Rs [ ], + /* workspace, not defined on input or output */ + int W [ ], /* size n, can be NULL */ + klu_common *Common +) ; + +SuiteSparse_long klu_l_scale (SuiteSparse_long, SuiteSparse_long, + SuiteSparse_long *, SuiteSparse_long *, double *, + double *, SuiteSparse_long *, klu_l_common *) ; + +SuiteSparse_long klu_zl_scale (SuiteSparse_long, SuiteSparse_long, + SuiteSparse_long *, SuiteSparse_long *, double *, + double *, SuiteSparse_long *, klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* klu_extract */ +/* -------------------------------------------------------------------------- */ + +int klu_extract /* returns TRUE if successful, FALSE otherwise */ +( + /* inputs: */ + klu_numeric *Numeric, + klu_symbolic *Symbolic, + + /* outputs, either allocated on input, or ignored otherwise */ + + /* L */ + int *Lp, /* size n+1 */ + int *Li, /* size Numeric->lnz */ + double *Lx, /* size Numeric->lnz */ + + /* U */ + int *Up, /* size n+1 */ + int *Ui, /* size Numeric->unz */ + double *Ux, /* size Numeric->unz */ + + /* F */ + int *Fp, /* size n+1 */ + int *Fi, /* size Numeric->nzoff */ + double *Fx, /* size Numeric->nzoff */ + + /* P, row permutation */ + int *P, /* size n */ + + /* Q, column permutation */ + int *Q, /* size n */ + + /* Rs, scale factors */ + double *Rs, /* size n */ + + /* R, block boundaries */ + int *R, /* size Symbolic->nblocks+1 (nblocks is at most n) */ + + klu_common *Common +) ; + + +int klu_z_extract /* returns TRUE if successful, FALSE otherwise */ +( + /* inputs: */ + klu_numeric *Numeric, + klu_symbolic *Symbolic, + + /* outputs, all of which must be allocated on input */ + + /* L */ + int *Lp, /* size n+1 */ + int *Li, /* size nnz(L) */ + double *Lx, /* size nnz(L) */ + double *Lz, /* size nnz(L) for the complex case, ignored if real */ + + /* U */ + int *Up, /* size n+1 */ + int *Ui, /* size nnz(U) */ + double *Ux, /* size nnz(U) */ + double *Uz, /* size nnz(U) for the complex case, ignored if real */ + + /* F */ + int *Fp, /* size n+1 */ + int *Fi, /* size nnz(F) */ + double *Fx, /* size nnz(F) */ + double *Fz, /* size nnz(F) for the complex case, ignored if real */ + + /* P, row permutation */ + int *P, /* size n */ + + /* Q, column permutation */ + int *Q, /* size n */ + + /* Rs, scale factors */ + double *Rs, /* size n */ + + /* R, block boundaries */ + int *R, /* size Symbolic->nblocks+1 (nblocks is at most n) */ + + klu_common *Common +) ; + +SuiteSparse_long klu_l_extract (klu_l_numeric *, klu_l_symbolic *, + SuiteSparse_long *, SuiteSparse_long *, double *, + SuiteSparse_long *, SuiteSparse_long *, double *, + SuiteSparse_long *, SuiteSparse_long *, double *, + SuiteSparse_long *, SuiteSparse_long *, double *, + SuiteSparse_long *, klu_l_common *) ; + +SuiteSparse_long klu_zl_extract (klu_l_numeric *, klu_l_symbolic *, + SuiteSparse_long *, SuiteSparse_long *, double *, double *, + SuiteSparse_long *, SuiteSparse_long *, double *, double *, + SuiteSparse_long *, SuiteSparse_long *, double *, double *, + SuiteSparse_long *, SuiteSparse_long *, double *, + SuiteSparse_long *, klu_l_common *) ; + + +/* -------------------------------------------------------------------------- */ +/* KLU memory management routines */ +/* -------------------------------------------------------------------------- */ + +void *klu_malloc /* returns pointer to the newly malloc'd block */ +( + /* ---- input ---- */ + size_t n, /* number of items */ + size_t size, /* size of each item */ + /* --------------- */ + klu_common *Common +) ; + +void *klu_free /* always returns NULL */ +( + /* ---- in/out --- */ + void *p, /* block of memory to free */ + size_t n, /* number of items */ + size_t size, /* size of each item */ + /* --------------- */ + klu_common *Common +) ; + +void *klu_realloc /* returns pointer to reallocated block */ +( + /* ---- input ---- */ + size_t nnew, /* requested # of items in reallocated block */ + size_t nold, /* current size of block, in # of items */ + size_t size, /* size of each item */ + /* ---- in/out --- */ + void *p, /* block of memory to realloc */ + /* --------------- */ + klu_common *Common +) ; + +void *klu_l_malloc (size_t, size_t, klu_l_common *) ; +void *klu_l_free (void *, size_t, size_t, klu_l_common *) ; +void *klu_l_realloc (size_t, size_t, size_t, void *, klu_l_common *) ; + + +/* ========================================================================== */ +/* === KLU version ========================================================== */ +/* ========================================================================== */ + +/* All versions of KLU include these definitions. + * As an example, to test if the version you are using is 1.2 or later: + * + * if (KLU_VERSION >= KLU_VERSION_CODE (1,2)) ... + * + * This also works during compile-time: + * + * #if (KLU >= KLU_VERSION_CODE (1,2)) + * printf ("This is version 1.2 or later\n") ; + * #else + * printf ("This is an early version\n") ; + * #endif + */ + +#define KLU_DATE "May 4, 2016" +#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_VERSION KLU_VERSION_CODE(KLU_MAIN_VERSION,KLU_SUB_VERSION) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode.h new file mode 100644 index 0000000..00a10fe --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode.h @@ -0,0 +1,134 @@ +/* ----------------------------------------------------------------- + * Programmer(s): 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 header file for the main ARKode infrastructure. + * ----------------------------------------------------------------- + * ARKode is used to numerically solve the ordinary initial value + * problems using one-step methods. Users do not call ARKode + * infrastructure routines directly; they instead interact with + * one of the time stepping modules built on top of ARKode. + * These time step modules define their supported problem types, + * solver options, etc. + * + * This file serves to define constants and provide function + * prototypes for use across ARKode-based time integration + * modules. + * -----------------------------------------------------------------*/ + +#ifndef _ARKODE_H +#define _ARKODE_H + +#include <stdio.h> +#include <sundials/sundials_nvector.h> +#include <arkode/arkode_butcher.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* ----------------- + * ARKode Constants + * ----------------- */ + +/* itask */ +#define ARK_NORMAL 1 +#define ARK_ONE_STEP 2 + +/* 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 + +/* ------------------------------ + * User-Supplied Function Types + * ------------------------------ */ + +typedef int (*ARKRhsFn)(realtype t, N_Vector y, + N_Vector ydot, void *user_data); + +typedef int (*ARKRootFn)(realtype t, N_Vector y, + realtype *gout, void *user_data); + +typedef int (*ARKEwtFn)(N_Vector y, N_Vector ewt, void *user_data); + +typedef int (*ARKRwtFn)(N_Vector y, N_Vector rwt, void *user_data); + +typedef void (*ARKErrHandlerFn)(int error_code, const char *module, + const char *function, char *msg, + void *user_data); + +typedef int (*ARKAdaptFn)(N_Vector y, realtype t, realtype h1, + realtype h2, realtype h3, + realtype e1, realtype e2, + realtype e3, int q, int p, + realtype *hnew, void *user_data); + +typedef int (*ARKExpStabFn)(N_Vector y, realtype t, + realtype *hstab, void *user_data); + +typedef int (*ARKVecResizeFn)(N_Vector y, N_Vector ytemplate, + void *user_data); + +typedef int (*ARKPostProcessStepFn)(realtype t, N_Vector y, + void *user_data); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_arkstep.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_arkstep.h new file mode 100644 index 0000000..e622b01 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_arkstep.h @@ -0,0 +1,368 @@ +/* ----------------------------------------------------------------- + * Programmer(s): 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 header file for the ARKode ARKStep module. + * -----------------------------------------------------------------*/ + +#ifndef _ARKSTEP_H +#define _ARKSTEP_H + +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_linearsolver.h> +#include <sundials/sundials_nonlinearsolver.h> +#include <arkode/arkode.h> +#include <arkode/arkode_ls.h> +#include <arkode/arkode_butcher_erk.h> +#include <arkode/arkode_butcher_dirk.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* ----------------- + * ARKStep Constants + * ----------------- */ + +/* Default Butcher tables for each method/order */ + +/* explicit */ +#define DEFAULT_ERK_2 HEUN_EULER_2_1_2 +#define DEFAULT_ERK_3 BOGACKI_SHAMPINE_4_2_3 +#define DEFAULT_ERK_4 ZONNEVELD_5_3_4 +#define DEFAULT_ERK_5 CASH_KARP_6_4_5 +#define DEFAULT_ERK_6 VERNER_8_5_6 +#define DEFAULT_ERK_8 FEHLBERG_13_7_8 + +/* implicit */ +#define DEFAULT_DIRK_2 SDIRK_2_1_2 +#define DEFAULT_DIRK_3 ARK324L2SA_DIRK_4_2_3 +#define DEFAULT_DIRK_4 SDIRK_5_3_4 +#define DEFAULT_DIRK_5 ARK548L2SA_DIRK_8_4_5 + +/* ImEx */ +#define DEFAULT_ARK_ETABLE_3 ARK324L2SA_ERK_4_2_3 +#define DEFAULT_ARK_ETABLE_4 ARK436L2SA_ERK_6_3_4 +#define DEFAULT_ARK_ETABLE_5 ARK548L2SA_ERK_8_4_5 +#define DEFAULT_ARK_ITABLE_3 ARK324L2SA_DIRK_4_2_3 +#define DEFAULT_ARK_ITABLE_4 ARK436L2SA_DIRK_6_3_4 +#define DEFAULT_ARK_ITABLE_5 ARK548L2SA_DIRK_8_4_5 + + +/* ------------------- + * Exported Functions + * ------------------- */ + +/* Create, Resize, and Reinitialization functions */ +SUNDIALS_EXPORT void* ARKStepCreate(ARKRhsFn fe, ARKRhsFn fi, + realtype t0, N_Vector y0); + +SUNDIALS_EXPORT int ARKStepResize(void *arkode_mem, N_Vector ynew, + realtype hscale, realtype t0, + ARKVecResizeFn resize, + void *resize_data); + +SUNDIALS_EXPORT int ARKStepReInit(void* arkode_mem, ARKRhsFn fe, + ARKRhsFn fi, realtype t0, N_Vector y0); + +/* Tolerance input functions */ +SUNDIALS_EXPORT int ARKStepSStolerances(void *arkode_mem, + realtype reltol, + realtype abstol); +SUNDIALS_EXPORT int ARKStepSVtolerances(void *arkode_mem, + realtype reltol, + N_Vector abstol); +SUNDIALS_EXPORT int ARKStepWFtolerances(void *arkode_mem, + ARKEwtFn efun); + +/* Resudal tolerance input functions */ +SUNDIALS_EXPORT int ARKStepResStolerance(void *arkode_mem, + realtype rabstol); +SUNDIALS_EXPORT int ARKStepResVtolerance(void *arkode_mem, + N_Vector rabstol); +SUNDIALS_EXPORT int ARKStepResFtolerance(void *arkode_mem, + ARKRwtFn rfun); + + +/* Linear solver set functions */ +SUNDIALS_EXPORT int ARKStepSetLinearSolver(void *arkode_mem, + SUNLinearSolver LS, + SUNMatrix A); +SUNDIALS_EXPORT int ARKStepSetMassLinearSolver(void *arkode_mem, + SUNLinearSolver LS, + SUNMatrix M, + booleantype time_dep); + +/* Rootfinding initialization */ +SUNDIALS_EXPORT int ARKStepRootInit(void *arkode_mem, int nrtfn, + ARKRootFn g); + +/* Optional input functions -- must be called AFTER ARKStepCreate */ +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 ARKStepSetDenseOrder(void *arkode_mem, int dord); +SUNDIALS_EXPORT int ARKStepSetNonlinearSolver(void *arkode_mem, + SUNNonlinearSolver NLS); +SUNDIALS_EXPORT int ARKStepSetLinear(void *arkode_mem, int timedepend); +SUNDIALS_EXPORT int ARKStepSetNonlinear(void *arkode_mem); +SUNDIALS_EXPORT int ARKStepSetExplicit(void *arkode_mem); +SUNDIALS_EXPORT int ARKStepSetImplicit(void *arkode_mem); +SUNDIALS_EXPORT int ARKStepSetImEx(void *arkode_mem); +SUNDIALS_EXPORT int ARKStepSetTables(void *arkode_mem, int q, int p, + ARKodeButcherTable Bi, + ARKodeButcherTable Be); +SUNDIALS_EXPORT int ARKStepSetTableNum(void *arkode_mem, + int itable, int etable); +SUNDIALS_EXPORT int ARKStepSetCFLFraction(void *arkode_mem, + realtype cfl_frac); +SUNDIALS_EXPORT int ARKStepSetSafetyFactor(void *arkode_mem, + realtype safety); +SUNDIALS_EXPORT int ARKStepSetErrorBias(void *arkode_mem, + realtype bias); +SUNDIALS_EXPORT int ARKStepSetMaxGrowth(void *arkode_mem, + realtype mx_growth); +SUNDIALS_EXPORT int ARKStepSetFixedStepBounds(void *arkode_mem, + realtype lb, realtype ub); +SUNDIALS_EXPORT int ARKStepSetAdaptivityMethod(void *arkode_mem, + int imethod, + int idefault, int pq, + realtype *adapt_params); +SUNDIALS_EXPORT int ARKStepSetAdaptivityFn(void *arkode_mem, + ARKAdaptFn hfun, + void *h_data); +SUNDIALS_EXPORT int ARKStepSetMaxFirstGrowth(void *arkode_mem, + realtype etamx1); +SUNDIALS_EXPORT int ARKStepSetMaxEFailGrowth(void *arkode_mem, + realtype etamxf); +SUNDIALS_EXPORT int ARKStepSetSmallNumEFails(void *arkode_mem, + int small_nef); +SUNDIALS_EXPORT int ARKStepSetMaxCFailGrowth(void *arkode_mem, + realtype etacf); +SUNDIALS_EXPORT int ARKStepSetNonlinCRDown(void *arkode_mem, + realtype crdown); +SUNDIALS_EXPORT int ARKStepSetNonlinRDiv(void *arkode_mem, + realtype rdiv); +SUNDIALS_EXPORT int ARKStepSetDeltaGammaMax(void *arkode_mem, + realtype dgmax); +SUNDIALS_EXPORT int ARKStepSetMaxStepsBetweenLSet(void *arkode_mem, + int msbp); +SUNDIALS_EXPORT int ARKStepSetPredictorMethod(void *arkode_mem, + int method); +SUNDIALS_EXPORT int ARKStepSetStabilityFn(void *arkode_mem, + ARKExpStabFn EStab, + void *estab_data); +SUNDIALS_EXPORT int ARKStepSetMaxErrTestFails(void *arkode_mem, + int maxnef); +SUNDIALS_EXPORT int ARKStepSetMaxNonlinIters(void *arkode_mem, + int maxcor); +SUNDIALS_EXPORT int ARKStepSetMaxConvFails(void *arkode_mem, + int maxncf); +SUNDIALS_EXPORT int ARKStepSetNonlinConvCoef(void *arkode_mem, + realtype nlscoef); +SUNDIALS_EXPORT int ARKStepSetMaxNumSteps(void *arkode_mem, + long int mxsteps); +SUNDIALS_EXPORT int ARKStepSetMaxHnilWarns(void *arkode_mem, + int mxhnil); +SUNDIALS_EXPORT int ARKStepSetInitStep(void *arkode_mem, + realtype hin); +SUNDIALS_EXPORT int ARKStepSetMinStep(void *arkode_mem, + realtype hmin); +SUNDIALS_EXPORT int ARKStepSetMaxStep(void *arkode_mem, + realtype hmax); +SUNDIALS_EXPORT int ARKStepSetStopTime(void *arkode_mem, + realtype tstop); +SUNDIALS_EXPORT int ARKStepSetFixedStep(void *arkode_mem, + realtype hfixed); + +SUNDIALS_EXPORT int ARKStepSetRootDirection(void *arkode_mem, + int *rootdir); +SUNDIALS_EXPORT int ARKStepSetNoInactiveRootWarn(void *arkode_mem); + +SUNDIALS_EXPORT int ARKStepSetErrHandlerFn(void *arkode_mem, + ARKErrHandlerFn ehfun, + void *eh_data); +SUNDIALS_EXPORT int ARKStepSetErrFile(void *arkode_mem, + FILE *errfp); +SUNDIALS_EXPORT int ARKStepSetUserData(void *arkode_mem, + void *user_data); +SUNDIALS_EXPORT int ARKStepSetDiagnostics(void *arkode_mem, + FILE *diagfp); + +SUNDIALS_EXPORT int ARKStepSetPostprocessStepFn(void *arkode_mem, + ARKPostProcessStepFn ProcessStep); + +/* Linear solver interface optional input functions -- must be called + AFTER ARKStepSetLinearSolver and/or ARKStepSetMassLinearSolver */ +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 ARKStepSetEpsLin(void *arkode_mem, realtype eplifac); +SUNDIALS_EXPORT int ARKStepSetMassEpsLin(void *arkode_mem, realtype eplifac); +SUNDIALS_EXPORT int ARKStepSetPreconditioner(void *arkode_mem, + ARKLsPrecSetupFn psetup, + ARKLsPrecSolveFn psolve); +SUNDIALS_EXPORT int ARKStepSetMassPreconditioner(void *arkode_mem, + ARKLsMassPrecSetupFn psetup, + ARKLsMassPrecSolveFn psolve); +SUNDIALS_EXPORT int ARKStepSetJacTimes(void *arkode_mem, + ARKLsJacTimesSetupFn jtsetup, + ARKLsJacTimesVecFn jtimes); +SUNDIALS_EXPORT int ARKStepSetMassTimes(void *arkode_mem, + ARKLsMassTimesSetupFn msetup, + ARKLsMassTimesVecFn mtimes, + void *mtimes_data); + +/* Integrate the ODE over an interval in t */ +SUNDIALS_EXPORT int ARKStepEvolve(void *arkode_mem, realtype tout, + N_Vector yout, realtype *tret, + int itask); + +/* Computes the kth derivative of the y function at time t */ +SUNDIALS_EXPORT int ARKStepGetDky(void *arkode_mem, realtype t, + int k, N_Vector dky); + +/* Optional output functions */ +SUNDIALS_EXPORT int ARKStepGetNumExpSteps(void *arkode_mem, + long int *expsteps); +SUNDIALS_EXPORT int ARKStepGetNumAccSteps(void *arkode_mem, + long int *accsteps); +SUNDIALS_EXPORT int ARKStepGetNumStepAttempts(void *arkode_mem, + long int *step_attempts); +SUNDIALS_EXPORT int ARKStepGetNumRhsEvals(void *arkode_mem, + long int *nfe_evals, + long int *nfi_evals); +SUNDIALS_EXPORT int ARKStepGetNumLinSolvSetups(void *arkode_mem, + long int *nlinsetups); +SUNDIALS_EXPORT int ARKStepGetNumErrTestFails(void *arkode_mem, + long int *netfails); +SUNDIALS_EXPORT int ARKStepGetCurrentButcherTables(void *arkode_mem, + ARKodeButcherTable *Bi, + ARKodeButcherTable *Be); +SUNDIALS_EXPORT int ARKStepGetEstLocalErrors(void *arkode_mem, + N_Vector ele); +SUNDIALS_EXPORT int ARKStepGetWorkSpace(void *arkode_mem, + long int *lenrw, + long int *leniw); +SUNDIALS_EXPORT int ARKStepGetNumSteps(void *arkode_mem, + long int *nsteps); +SUNDIALS_EXPORT int ARKStepGetActualInitStep(void *arkode_mem, + realtype *hinused); +SUNDIALS_EXPORT int ARKStepGetLastStep(void *arkode_mem, + realtype *hlast); +SUNDIALS_EXPORT int ARKStepGetCurrentStep(void *arkode_mem, + realtype *hcur); +SUNDIALS_EXPORT int ARKStepGetCurrentTime(void *arkode_mem, + realtype *tcur); +SUNDIALS_EXPORT int ARKStepGetTolScaleFactor(void *arkode_mem, + realtype *tolsfac); +SUNDIALS_EXPORT int ARKStepGetErrWeights(void *arkode_mem, + N_Vector eweight); +SUNDIALS_EXPORT int ARKStepGetResWeights(void *arkode_mem, + N_Vector rweight); +SUNDIALS_EXPORT int ARKStepGetNumGEvals(void *arkode_mem, + long int *ngevals); +SUNDIALS_EXPORT int ARKStepGetRootInfo(void *arkode_mem, + int *rootsfound); +SUNDIALS_EXPORT char *ARKStepGetReturnFlagName(long int flag); + +SUNDIALS_EXPORT int ARKStepWriteParameters(void *arkode_mem, FILE *fp); + +SUNDIALS_EXPORT int ARKStepWriteButcher(void *arkode_mem, FILE *fp); + + +/* Grouped optional output functions */ +SUNDIALS_EXPORT int ARKStepGetTimestepperStats(void *arkode_mem, + long int *expsteps, + long int *accsteps, + long int *step_attempts, + long int *nfe_evals, + long int *nfi_evals, + long int *nlinsetups, + long int *netfails); +SUNDIALS_EXPORT int ARKStepGetStepStats(void *arkode_mem, + long int *nsteps, + realtype *hinused, + realtype *hlast, + realtype *hcur, + realtype *tcur); + +/* Nonlinear solver optional output functions */ +SUNDIALS_EXPORT int ARKStepGetNumNonlinSolvIters(void *arkode_mem, + long int *nniters); +SUNDIALS_EXPORT int ARKStepGetNumNonlinSolvConvFails(void *arkode_mem, + long int *nncfails); +SUNDIALS_EXPORT int ARKStepGetNonlinSolvStats(void *arkode_mem, + long int *nniters, + long int *nncfails); + +/* Linear solver optional output functions */ +SUNDIALS_EXPORT int ARKStepGetLinWorkSpace(void *arkode_mem, + long int *lenrwLS, + long int *leniwLS); +SUNDIALS_EXPORT int ARKStepGetNumJacEvals(void *arkode_mem, + long int *njevals); +SUNDIALS_EXPORT int ARKStepGetNumPrecEvals(void *arkode_mem, + long int *npevals); +SUNDIALS_EXPORT int ARKStepGetNumPrecSolves(void *arkode_mem, + long int *npsolves); +SUNDIALS_EXPORT int ARKStepGetNumLinIters(void *arkode_mem, + long int *nliters); +SUNDIALS_EXPORT int ARKStepGetNumLinConvFails(void *arkode_mem, + long int *nlcfails); +SUNDIALS_EXPORT int ARKStepGetNumJTSetupEvals(void *arkode_mem, + long int *njtsetups); +SUNDIALS_EXPORT int ARKStepGetNumJtimesEvals(void *arkode_mem, + long int *njvevals); +SUNDIALS_EXPORT int ARKStepGetNumLinRhsEvals(void *arkode_mem, + long int *nfevalsLS); +SUNDIALS_EXPORT int ARKStepGetLastLinFlag(void *arkode_mem, + long int *flag); + +SUNDIALS_EXPORT int ARKStepGetMassWorkSpace(void *arkode_mem, + long int *lenrwMLS, + long int *leniwMLS); +SUNDIALS_EXPORT int ARKStepGetNumMassSetups(void *arkode_mem, + long int *nmsetups); +SUNDIALS_EXPORT int ARKStepGetNumMassMult(void *arkode_mem, + long int *nmvevals); +SUNDIALS_EXPORT int ARKStepGetNumMassSolves(void *arkode_mem, + long int *nmsolves); +SUNDIALS_EXPORT int ARKStepGetNumMassPrecEvals(void *arkode_mem, + long int *nmpevals); +SUNDIALS_EXPORT int ARKStepGetNumMassPrecSolves(void *arkode_mem, + long int *nmpsolves); +SUNDIALS_EXPORT int ARKStepGetNumMassIters(void *arkode_mem, + long int *nmiters); +SUNDIALS_EXPORT int ARKStepGetNumMassConvFails(void *arkode_mem, + long int *nmcfails); +SUNDIALS_EXPORT int ARKStepGetNumMTSetups(void *arkode_mem, + long int *nmtsetups); +SUNDIALS_EXPORT int ARKStepGetLastMassFlag(void *arkode_mem, + long int *flag); + +SUNDIALS_EXPORT char *ARKStepGetLinReturnFlagName(long int flag); + + +/* Free function */ +SUNDIALS_EXPORT void ARKStepFree(void **arkode_mem); + +/* Output the ARKStep memory structure (useful when debugging) */ +SUNDIALS_EXPORT void ARKStepPrintMem(void* arkode_mem, FILE* outfile); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_bandpre.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_bandpre.h new file mode 100644 index 0000000..ebcb38c --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_bandpre.h @@ -0,0 +1,46 @@ +/* ----------------------------------------------------------------- + * Programmer(s): 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 header file for the ARKBANDPRE module, which provides + * a banded difference quotient Jacobian-based preconditioner. + * -----------------------------------------------------------------*/ + +#ifndef _ARKBANDPRE_H +#define _ARKBANDPRE_H + +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/* BandPrec inititialization function */ + +SUNDIALS_EXPORT int ARKBandPrecInit(void *arkode_mem, sunindextype N, + sunindextype mu, sunindextype ml); + +/* Optional output functions */ + +SUNDIALS_EXPORT int ARKBandPrecGetWorkSpace(void *arkode_mem, + long int *lenrwLS, + long int *leniwLS); +SUNDIALS_EXPORT int ARKBandPrecGetNumRhsEvals(void *arkode_mem, + long int *nfevalsBP); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_bbdpre.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_bbdpre.h new file mode 100644 index 0000000..1594cf6 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_bbdpre.h @@ -0,0 +1,67 @@ +/* ----------------------------------------------------------------- + * Programmer(s): 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 header file for the ARKBBDPRE module, for a + * band-block-diagonal preconditioner, i.e. a block-diagonal + * matrix with banded blocks. + * -----------------------------------------------------------------*/ + +#ifndef _ARKBBDPRE_H +#define _ARKBBDPRE_H + +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/* User-supplied function Types */ + +typedef int (*ARKLocalFn)(sunindextype Nlocal, realtype t, + N_Vector y, N_Vector g, void *user_data); + +typedef int (*ARKCommFn)(sunindextype Nlocal, realtype t, + N_Vector y, void *user_data); + +/* Exported Functions */ + +SUNDIALS_EXPORT int ARKBBDPrecInit(void *arkode_mem, + sunindextype Nlocal, + sunindextype mudq, + sunindextype mldq, + sunindextype mukeep, + sunindextype mlkeep, + realtype dqrely, + ARKLocalFn gloc, + ARKCommFn cfn); + +SUNDIALS_EXPORT int ARKBBDPrecReInit(void *arkode_mem, + sunindextype mudq, + sunindextype mldq, + realtype dqrely); + +/* Optional output functions */ + +SUNDIALS_EXPORT int ARKBBDPrecGetWorkSpace(void *arkode_mem, + long int *lenrwBBDP, + long int *leniwBBDP); + +SUNDIALS_EXPORT int ARKBBDPrecGetNumGfnEvals(void *arkode_mem, + long int *ngevalsBBDP); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_butcher.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_butcher.h new file mode 100644 index 0000000..d4432e9 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_butcher.h @@ -0,0 +1,72 @@ +/* ----------------------------------------------------------------- + * Programmer(s): 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 header file for ARKode Butcher table structures. + * -----------------------------------------------------------------*/ + +#ifndef _ARKODE_BUTCHER_H +#define _ARKODE_BUTCHER_H + +#include <sundials/sundials_types.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*--------------------------------------------------------------- + Types : struct ARKodeButcherTableMem, ARKodeButcherTable + ---------------------------------------------------------------*/ +typedef struct ARKodeButcherTableMem { + + int q; /* method order of accuracy */ + int p; /* embedding order of accuracy */ + int stages; /* number of stages */ + realtype **A; /* Butcher table coefficients */ + realtype *c; /* canopy node coefficients */ + realtype *b; /* root node coefficients */ + realtype *d; /* embedding coefficients */ + +} *ARKodeButcherTable; + + +/* Utility routines to allocate/free/output Butcher table structures */ +SUNDIALS_EXPORT ARKodeButcherTable ARKodeButcherTable_Alloc(int stages, + booleantype embedded); +SUNDIALS_EXPORT ARKodeButcherTable ARKodeButcherTable_Create(int s, int q, + int p, + realtype *c, + realtype *A, + realtype *b, + realtype *d); +SUNDIALS_EXPORT ARKodeButcherTable ARKodeButcherTable_Copy(ARKodeButcherTable B); +SUNDIALS_EXPORT void ARKodeButcherTable_Space(ARKodeButcherTable B, + sunindextype *liw, + sunindextype *lrw); +SUNDIALS_EXPORT void ARKodeButcherTable_Free(ARKodeButcherTable B); +SUNDIALS_EXPORT void ARKodeButcherTable_Write(ARKodeButcherTable B, + FILE *outfile); + +SUNDIALS_EXPORT int ARKodeButcherTable_CheckOrder(ARKodeButcherTable B, int *q, + int *p, FILE *outfile); +SUNDIALS_EXPORT int ARKodeButcherTable_CheckARKOrder(ARKodeButcherTable B1, + ARKodeButcherTable B2, + int *q, int *p, + FILE *outfile); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_butcher_dirk.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_butcher_dirk.h new file mode 100644 index 0000000..8b907ce --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_butcher_dirk.h @@ -0,0 +1,55 @@ +/* ----------------------------------------------------------------- + * Programmer(s): 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 header file for ARKode's built-in DIRK Butcher tables. + * -----------------------------------------------------------------*/ + +#ifndef _ARKODE_DIRK_TABLES_H +#define _ARKODE_DIRK_TABLES_H + +#include <arkode/arkode_butcher.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/* Butcher table accessor IDs + ERK: 0 - 99 + DIRK: 100 - 199 */ +#define SDIRK_2_1_2 100 +#define BILLINGTON_3_3_2 101 +#define TRBDF2_3_3_2 102 +#define KVAERNO_4_2_3 103 +#define ARK324L2SA_DIRK_4_2_3 104 +#define CASH_5_2_4 105 +#define CASH_5_3_4 106 +#define SDIRK_5_3_4 107 +#define KVAERNO_5_3_4 108 +#define ARK436L2SA_DIRK_6_3_4 109 +#define KVAERNO_7_4_5 110 +#define ARK548L2SA_DIRK_8_4_5 111 + +/* Utility #defines to ensure valid input IDs for DIRK tables */ +#define MIN_DIRK_NUM 100 +#define MAX_DIRK_NUM 111 + +/* Accessor routine to load built-in DIRK table */ +SUNDIALS_EXPORT ARKodeButcherTable ARKodeButcherTable_LoadDIRK(int imethod); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_butcher_erk.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_butcher_erk.h new file mode 100644 index 0000000..d4f4dee --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_butcher_erk.h @@ -0,0 +1,56 @@ +/* ----------------------------------------------------------------- + * Programmer(s): 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 header file for ARKode's built-in ERK Butcher tables. + * -----------------------------------------------------------------*/ + +#ifndef _ARKODE_ERK_TABLES_H +#define _ARKODE_ERK_TABLES_H + +#include <arkode/arkode_butcher.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/* Butcher table accessor IDs + ERK: 0 - 99 + DIRK: 100 - 199 */ +#define HEUN_EULER_2_1_2 0 +#define BOGACKI_SHAMPINE_4_2_3 1 +#define ARK324L2SA_ERK_4_2_3 2 +#define ZONNEVELD_5_3_4 3 +#define ARK436L2SA_ERK_6_3_4 4 +#define SAYFY_ABURUB_6_3_4 5 +#define CASH_KARP_6_4_5 6 +#define FEHLBERG_6_4_5 7 +#define DORMAND_PRINCE_7_4_5 8 +#define ARK548L2SA_ERK_8_4_5 9 +#define VERNER_8_5_6 10 +#define FEHLBERG_13_7_8 11 +#define KNOTH_WOLKE_3_3 12 + +/* Utility #defines to ensure valid input IDs for ERK tables */ +#define MIN_ERK_NUM 0 +#define MAX_ERK_NUM 12 + +/* Accessor routine to load built-in ERK table */ +SUNDIALS_EXPORT ARKodeButcherTable ARKodeButcherTable_LoadERK(int imethod); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_erkstep.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_erkstep.h new file mode 100644 index 0000000..f339d74 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_erkstep.h @@ -0,0 +1,218 @@ +/* ----------------------------------------------------------------- + * Programmer(s): 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 header file for the ARKode ERKStep module. + * -----------------------------------------------------------------*/ + +#ifndef _ERKSTEP_H +#define _ERKSTEP_H + +#include <sundials/sundials_nvector.h> +#include <arkode/arkode.h> +#include <arkode/arkode_butcher_erk.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* ----------------- + * ERKStep Constants + * ----------------- */ + +/* Default Butcher tables for each order */ + +#define DEFAULT_ERK_2 HEUN_EULER_2_1_2 +#define DEFAULT_ERK_3 BOGACKI_SHAMPINE_4_2_3 +#define DEFAULT_ERK_4 ZONNEVELD_5_3_4 +#define DEFAULT_ERK_5 CASH_KARP_6_4_5 +#define DEFAULT_ERK_6 VERNER_8_5_6 +#define DEFAULT_ERK_8 FEHLBERG_13_7_8 + + +/* ------------------- + * Exported Functions + * ------------------- */ + +/* Create, Resize, and Reinitialization functions */ +SUNDIALS_EXPORT void* ERKStepCreate(ARKRhsFn f, realtype t0, + N_Vector y0); + +SUNDIALS_EXPORT int ERKStepResize(void *arkode_mem, N_Vector ynew, + realtype hscale, realtype t0, + ARKVecResizeFn resize, + void *resize_data); + +SUNDIALS_EXPORT int ERKStepReInit(void* arkode_mem, ARKRhsFn f, + realtype t0, N_Vector y0); + +/* Tolerance input functions */ +SUNDIALS_EXPORT int ERKStepSStolerances(void *arkode_mem, + realtype reltol, + realtype abstol); +SUNDIALS_EXPORT int ERKStepSVtolerances(void *arkode_mem, + realtype reltol, + N_Vector abstol); +SUNDIALS_EXPORT int ERKStepWFtolerances(void *arkode_mem, + ARKEwtFn efun); + +/* Rootfinding initialization */ +SUNDIALS_EXPORT int ERKStepRootInit(void *arkode_mem, int nrtfn, + ARKRootFn g); + +/* 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 ERKStepSetDenseOrder(void *arkode_mem, int dord); +SUNDIALS_EXPORT int ERKStepSetTable(void *arkode_mem, + ARKodeButcherTable B); +SUNDIALS_EXPORT int ERKStepSetTableNum(void *arkode_mem, int itable); +SUNDIALS_EXPORT int ERKStepSetCFLFraction(void *arkode_mem, + realtype cfl_frac); +SUNDIALS_EXPORT int ERKStepSetSafetyFactor(void *arkode_mem, + realtype safety); +SUNDIALS_EXPORT int ERKStepSetErrorBias(void *arkode_mem, + realtype bias); +SUNDIALS_EXPORT int ERKStepSetMaxGrowth(void *arkode_mem, + realtype mx_growth); +SUNDIALS_EXPORT int ERKStepSetFixedStepBounds(void *arkode_mem, + realtype lb, realtype ub); +SUNDIALS_EXPORT int ERKStepSetAdaptivityMethod(void *arkode_mem, + int imethod, + int idefault, int pq, + realtype *adapt_params); +SUNDIALS_EXPORT int ERKStepSetAdaptivityFn(void *arkode_mem, + ARKAdaptFn hfun, + void *h_data); +SUNDIALS_EXPORT int ERKStepSetMaxFirstGrowth(void *arkode_mem, + realtype etamx1); +SUNDIALS_EXPORT int ERKStepSetMaxEFailGrowth(void *arkode_mem, + realtype etamxf); +SUNDIALS_EXPORT int ERKStepSetSmallNumEFails(void *arkode_mem, + int small_nef); +SUNDIALS_EXPORT int ERKStepSetStabilityFn(void *arkode_mem, + ARKExpStabFn EStab, + void *estab_data); +SUNDIALS_EXPORT int ERKStepSetMaxErrTestFails(void *arkode_mem, + int maxnef); +SUNDIALS_EXPORT int ERKStepSetMaxNumSteps(void *arkode_mem, + long int mxsteps); +SUNDIALS_EXPORT int ERKStepSetMaxHnilWarns(void *arkode_mem, + int mxhnil); +SUNDIALS_EXPORT int ERKStepSetInitStep(void *arkode_mem, + realtype hin); +SUNDIALS_EXPORT int ERKStepSetMinStep(void *arkode_mem, + realtype hmin); +SUNDIALS_EXPORT int ERKStepSetMaxStep(void *arkode_mem, + realtype hmax); +SUNDIALS_EXPORT int ERKStepSetStopTime(void *arkode_mem, + realtype tstop); +SUNDIALS_EXPORT int ERKStepSetFixedStep(void *arkode_mem, + realtype hfixed); + +SUNDIALS_EXPORT int ERKStepSetRootDirection(void *arkode_mem, + int *rootdir); +SUNDIALS_EXPORT int ERKStepSetNoInactiveRootWarn(void *arkode_mem); + +SUNDIALS_EXPORT int ERKStepSetErrHandlerFn(void *arkode_mem, + ARKErrHandlerFn ehfun, + void *eh_data); +SUNDIALS_EXPORT int ERKStepSetErrFile(void *arkode_mem, + FILE *errfp); +SUNDIALS_EXPORT int ERKStepSetUserData(void *arkode_mem, + void *user_data); +SUNDIALS_EXPORT int ERKStepSetDiagnostics(void *arkode_mem, + FILE *diagfp); + +SUNDIALS_EXPORT int ERKStepSetPostprocessStepFn(void *arkode_mem, + ARKPostProcessStepFn ProcessStep); + + +/* Integrate the ODE over an interval in t */ +SUNDIALS_EXPORT int ERKStepEvolve(void *arkode_mem, realtype tout, + N_Vector yout, realtype *tret, + int itask); + +/* Computes the kth derivative of the y function at time t */ +SUNDIALS_EXPORT int ERKStepGetDky(void *arkode_mem, realtype t, + int k, N_Vector dky); + +/* Optional output functions */ +SUNDIALS_EXPORT int ERKStepGetNumExpSteps(void *arkode_mem, + long int *expsteps); +SUNDIALS_EXPORT int ERKStepGetNumAccSteps(void *arkode_mem, + long int *accsteps); +SUNDIALS_EXPORT int ERKStepGetNumStepAttempts(void *arkode_mem, + long int *step_attempts); +SUNDIALS_EXPORT int ERKStepGetNumRhsEvals(void *arkode_mem, + long int *nfevals); +SUNDIALS_EXPORT int ERKStepGetNumErrTestFails(void *arkode_mem, + long int *netfails); +SUNDIALS_EXPORT int ERKStepGetCurrentButcherTable(void *arkode_mem, + ARKodeButcherTable *B); +SUNDIALS_EXPORT int ERKStepGetEstLocalErrors(void *arkode_mem, + N_Vector ele); +SUNDIALS_EXPORT int ERKStepGetWorkSpace(void *arkode_mem, + long int *lenrw, + long int *leniw); +SUNDIALS_EXPORT int ERKStepGetNumSteps(void *arkode_mem, + long int *nsteps); +SUNDIALS_EXPORT int ERKStepGetActualInitStep(void *arkode_mem, + realtype *hinused); +SUNDIALS_EXPORT int ERKStepGetLastStep(void *arkode_mem, + realtype *hlast); +SUNDIALS_EXPORT int ERKStepGetCurrentStep(void *arkode_mem, + realtype *hcur); +SUNDIALS_EXPORT int ERKStepGetCurrentTime(void *arkode_mem, + realtype *tcur); +SUNDIALS_EXPORT int ERKStepGetTolScaleFactor(void *arkode_mem, + realtype *tolsfac); +SUNDIALS_EXPORT int ERKStepGetErrWeights(void *arkode_mem, + N_Vector eweight); +SUNDIALS_EXPORT int ERKStepGetNumGEvals(void *arkode_mem, + long int *ngevals); +SUNDIALS_EXPORT int ERKStepGetRootInfo(void *arkode_mem, + int *rootsfound); +SUNDIALS_EXPORT char *ERKStepGetReturnFlagName(long int flag); + +SUNDIALS_EXPORT int ERKStepWriteParameters(void *arkode_mem, FILE *fp); + +SUNDIALS_EXPORT int ERKStepWriteButcher(void *arkode_mem, FILE *fp); + + +/* Grouped optional output functions */ +SUNDIALS_EXPORT int ERKStepGetTimestepperStats(void *arkode_mem, + long int *expsteps, + long int *accsteps, + long int *step_attempts, + long int *nfevals, + long int *netfails); +SUNDIALS_EXPORT int ERKStepGetStepStats(void *arkode_mem, + long int *nsteps, + realtype *hinused, + realtype *hlast, + realtype *hcur, + realtype *tcur); + + +/* Free function */ +SUNDIALS_EXPORT void ERKStepFree(void **arkode_mem); + +/* Output the ERKStep memory structure (useful when debugging) */ +SUNDIALS_EXPORT void ERKStepPrintMem(void* arkode_mem, FILE* outfile); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_ls.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_ls.h new file mode 100644 index 0000000..8cbac5c --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_ls.h @@ -0,0 +1,97 @@ +/* ---------------------------------------------------------------- + * Programmer(s): 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 header file for ARKode's linear solver interface. + * ----------------------------------------------------------------*/ + +#ifndef _ARKLS_H +#define _ARKLS_H + +#include <sundials/sundials_direct.h> +#include <sundials/sundials_iterative.h> +#include <sundials/sundials_linearsolver.h> +#include <sundials/sundials_matrix.h> +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*================================================================= + ARKLS Constants + =================================================================*/ + +#define ARKLS_SUCCESS 0 +#define ARKLS_MEM_NULL -1 +#define ARKLS_LMEM_NULL -2 +#define ARKLS_ILL_INPUT -3 +#define ARKLS_MEM_FAIL -4 +#define ARKLS_PMEM_NULL -5 +#define ARKLS_MASSMEM_NULL -6 +#define ARKLS_JACFUNC_UNRECVR -7 +#define ARKLS_JACFUNC_RECVR -8 +#define ARKLS_MASSFUNC_UNRECVR -9 +#define ARKLS_MASSFUNC_RECVR -10 +#define ARKLS_SUNMAT_FAIL -11 +#define ARKLS_SUNLS_FAIL -12 + + +/*================================================================= + ARKLS user-supplied function prototypes + =================================================================*/ + +typedef int (*ARKLsJacFn)(realtype t, N_Vector y, N_Vector fy, + SUNMatrix Jac, void *user_data, + N_Vector tmp1, N_Vector tmp2, N_Vector tmp3); + +typedef int (*ARKLsMassFn)(realtype t, SUNMatrix M, void *user_data, + N_Vector tmp1, N_Vector tmp2, N_Vector tmp3); + +typedef int (*ARKLsPrecSetupFn)(realtype t, N_Vector y, + N_Vector fy, booleantype jok, + booleantype *jcurPtr, + realtype gamma, void *user_data); + +typedef int (*ARKLsPrecSolveFn)(realtype t, N_Vector y, + N_Vector fy, N_Vector r, + N_Vector z, realtype gamma, + realtype delta, int lr, + void *user_data); + +typedef int (*ARKLsJacTimesSetupFn)(realtype t, N_Vector y, + N_Vector fy, void *user_data); + +typedef int (*ARKLsJacTimesVecFn)(N_Vector v, N_Vector Jv, + realtype t, N_Vector y, + N_Vector fy, void *user_data, + N_Vector tmp); + +typedef int (*ARKLsMassTimesSetupFn)(realtype t, void *mtimes_data); + + +typedef int (*ARKLsMassTimesVecFn)(N_Vector v, N_Vector Mv, + realtype t, void *mtimes_data); + +typedef int (*ARKLsMassPrecSetupFn)(realtype t, void *user_data); + +typedef int (*ARKLsMassPrecSolveFn)(realtype t, N_Vector r, + N_Vector z, realtype delta, + int lr, void *user_data); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_mristep.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_mristep.h new file mode 100644 index 0000000..fde2242 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/arkode/arkode_mristep.h @@ -0,0 +1,139 @@ +/* ----------------------------------------------------------------- + * 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 is the header file for the ARKode MRIStep module. + * -----------------------------------------------------------------*/ + +#ifndef _MRISTEP_H +#define _MRISTEP_H + +#include <sundials/sundials_nvector.h> +#include <arkode/arkode.h> +#include <arkode/arkode_butcher_erk.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* ----------------- + * MRIStep Constants + * ----------------- */ + +/* Default Butcher tables for each order */ + +#define DEFAULT_MRI_STABLE_3 KNOTH_WOLKE_3_3 +#define DEFAULT_MRI_FTABLE_3 KNOTH_WOLKE_3_3 + + +/* ------------------- + * Exported Functions + * ------------------- */ + +/* Create, Resize, and Reinitialization functions */ +SUNDIALS_EXPORT void* MRIStepCreate(ARKRhsFn fs, ARKRhsFn ff, + realtype t0, N_Vector y0); + +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); + +/* Rootfinding initialization */ +SUNDIALS_EXPORT int MRIStepRootInit(void *arkode_mem, int nrtfn, + ARKRootFn g); + +/* Optional input functions -- must be called AFTER MRIStepCreate */ +SUNDIALS_EXPORT int MRIStepSetDefaults(void* arkode_mem); +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 MRIStepSetMaxNumSteps(void *arkode_mem, + long int mxsteps); +SUNDIALS_EXPORT int MRIStepSetMaxHnilWarns(void *arkode_mem, + int mxhnil); +SUNDIALS_EXPORT int MRIStepSetStopTime(void *arkode_mem, + realtype tstop); +SUNDIALS_EXPORT int MRIStepSetFixedStep(void *arkode_mem, + realtype hsfixed, + realtype hffixed); +SUNDIALS_EXPORT int MRIStepSetRootDirection(void *arkode_mem, + int *rootdir); +SUNDIALS_EXPORT int MRIStepSetNoInactiveRootWarn(void *arkode_mem); +SUNDIALS_EXPORT int MRIStepSetErrHandlerFn(void *arkode_mem, + ARKErrHandlerFn ehfun, + void *eh_data); +SUNDIALS_EXPORT int MRIStepSetErrFile(void *arkode_mem, + FILE *errfp); +SUNDIALS_EXPORT int MRIStepSetUserData(void *arkode_mem, + void *user_data); +SUNDIALS_EXPORT int MRIStepSetDiagnostics(void *arkode_mem, + FILE *diagfp); +SUNDIALS_EXPORT int MRIStepSetPostprocessStepFn(void *arkode_mem, + ARKPostProcessStepFn ProcessStep); + + +/* Integrate the ODE over an interval in t */ +SUNDIALS_EXPORT int MRIStepEvolve(void *arkode_mem, realtype tout, + N_Vector yout, realtype *tret, + int itask); + +/* Computes the kth derivative of the y function at time t */ +SUNDIALS_EXPORT int MRIStepGetDky(void *arkode_mem, realtype t, + int k, N_Vector dky); + +/* Optional output functions */ +SUNDIALS_EXPORT int MRIStepGetNumRhsEvals(void *arkode_mem, + long int *nfs_evals, + long int *nff_evals); +SUNDIALS_EXPORT int MRIStepGetCurrentButcherTables(void *arkode_mem, + ARKodeButcherTable *Bs, + ARKodeButcherTable *Bf); +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); +SUNDIALS_EXPORT int MRIStepGetLastStep(void *arkode_mem, + realtype *hlast); +SUNDIALS_EXPORT int MRIStepGetCurrentTime(void *arkode_mem, + realtype *tcur); +SUNDIALS_EXPORT int MRIStepGetNumGEvals(void *arkode_mem, + long int *ngevals); +SUNDIALS_EXPORT int MRIStepGetRootInfo(void *arkode_mem, + int *rootsfound); +SUNDIALS_EXPORT int MRIStepGetLastInnerStepFlag(void *arkode_mem, int *flag); + +SUNDIALS_EXPORT char *MRIStepGetReturnFlagName(long int flag); + +SUNDIALS_EXPORT int MRIStepWriteParameters(void *arkode_mem, FILE *fp); + +SUNDIALS_EXPORT int MRIStepWriteButcher(void *arkode_mem, FILE *fp); + +/* Free function */ +SUNDIALS_EXPORT void MRIStepFree(void **arkode_mem); + +/* Output the MRIStep memory structure (useful when debugging) */ +SUNDIALS_EXPORT void MRIStepPrintMem(void* arkode_mem, FILE* outfile); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode.h new file mode 100644 index 0000000..48f7c82 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode.h @@ -0,0 +1,194 @@ +/* ----------------------------------------------------------------- + * 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 + * 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 main CVODE integrator. + * -----------------------------------------------------------------*/ + +#ifndef _CVODE_H +#define _CVODE_H + +#include <stdio.h> +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_nonlinearsolver.h> +#include <cvode/cvode_ls.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* ----------------- + * CVODE Constants + * ----------------- */ + +/* lmm */ +#define CV_ADAMS 1 +#define CV_BDF 2 + +/* itask */ +#define CV_NORMAL 1 +#define CV_ONE_STEP 2 + + +/* return values */ + +#define CV_SUCCESS 0 +#define CV_TSTOP_RETURN 1 +#define CV_ROOT_RETURN 2 + +#define CV_WARNING 99 + +#define CV_TOO_MUCH_WORK -1 +#define CV_TOO_MUCH_ACC -2 +#define CV_ERR_FAILURE -3 +#define CV_CONV_FAILURE -4 + +#define CV_LINIT_FAIL -5 +#define CV_LSETUP_FAIL -6 +#define CV_LSOLVE_FAIL -7 +#define CV_RHSFUNC_FAIL -8 +#define CV_FIRST_RHSFUNC_ERR -9 +#define CV_REPTD_RHSFUNC_ERR -10 +#define CV_UNREC_RHSFUNC_ERR -11 +#define CV_RTFUNC_FAIL -12 +#define CV_NLS_INIT_FAIL -13 +#define CV_NLS_SETUP_FAIL -14 +#define CV_CONSTR_FAIL -15 + +#define CV_MEM_FAIL -20 +#define CV_MEM_NULL -21 +#define CV_ILL_INPUT -22 +#define CV_NO_MALLOC -23 +#define CV_BAD_K -24 +#define CV_BAD_T -25 +#define CV_BAD_DKY -26 +#define CV_TOO_CLOSE -27 +#define CV_VECTOROP_ERR -28 + +/* ------------------------------ + * User-Supplied Function Types + * ------------------------------ */ + +typedef int (*CVRhsFn)(realtype t, N_Vector y, + N_Vector ydot, void *user_data); + +typedef int (*CVRootFn)(realtype t, N_Vector y, realtype *gout, + void *user_data); + +typedef int (*CVEwtFn)(N_Vector y, N_Vector ewt, void *user_data); + +typedef void (*CVErrHandlerFn)(int error_code, + const char *module, const char *function, + char *msg, void *user_data); + +/* ------------------- + * Exported Functions + * ------------------- */ + +/* Initialization functions */ +SUNDIALS_EXPORT void *CVodeCreate(int lmm); + +SUNDIALS_EXPORT int CVodeInit(void *cvode_mem, CVRhsFn f, realtype t0, + N_Vector y0); +SUNDIALS_EXPORT int CVodeReInit(void *cvode_mem, realtype t0, N_Vector y0); + +/* Tolerance input functions */ +SUNDIALS_EXPORT int CVodeSStolerances(void *cvode_mem, realtype reltol, + realtype abstol); +SUNDIALS_EXPORT int CVodeSVtolerances(void *cvode_mem, realtype reltol, + N_Vector abstol); +SUNDIALS_EXPORT int CVodeWFtolerances(void *cvode_mem, CVEwtFn efun); + +/* Optional input functions */ +SUNDIALS_EXPORT int CVodeSetErrHandlerFn(void *cvode_mem, CVErrHandlerFn ehfun, + void *eh_data); +SUNDIALS_EXPORT int CVodeSetErrFile(void *cvode_mem, FILE *errfp); +SUNDIALS_EXPORT int CVodeSetUserData(void *cvode_mem, void *user_data); +SUNDIALS_EXPORT int CVodeSetMaxOrd(void *cvode_mem, int maxord); +SUNDIALS_EXPORT int CVodeSetMaxNumSteps(void *cvode_mem, long int mxsteps); +SUNDIALS_EXPORT int CVodeSetMaxHnilWarns(void *cvode_mem, int mxhnil); +SUNDIALS_EXPORT int CVodeSetStabLimDet(void *cvode_mem, booleantype stldet); +SUNDIALS_EXPORT int CVodeSetInitStep(void *cvode_mem, realtype hin); +SUNDIALS_EXPORT int CVodeSetMinStep(void *cvode_mem, realtype hmin); +SUNDIALS_EXPORT int CVodeSetMaxStep(void *cvode_mem, realtype hmax); +SUNDIALS_EXPORT int CVodeSetStopTime(void *cvode_mem, realtype tstop); +SUNDIALS_EXPORT int CVodeSetMaxErrTestFails(void *cvode_mem, int maxnef); +SUNDIALS_EXPORT int CVodeSetMaxNonlinIters(void *cvode_mem, int maxcor); +SUNDIALS_EXPORT int CVodeSetMaxConvFails(void *cvode_mem, int maxncf); +SUNDIALS_EXPORT int CVodeSetNonlinConvCoef(void *cvode_mem, realtype nlscoef); +SUNDIALS_EXPORT int CVodeSetConstraints(void *cvode_mem, N_Vector constraints); + +SUNDIALS_EXPORT int CVodeSetNonlinearSolver(void *cvode_mem, + SUNNonlinearSolver NLS); + +/* Rootfinding initialization function */ +SUNDIALS_EXPORT int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g); + +/* Rootfinding optional input functions */ +SUNDIALS_EXPORT int CVodeSetRootDirection(void *cvode_mem, int *rootdir); +SUNDIALS_EXPORT int CVodeSetNoInactiveRootWarn(void *cvode_mem); + +/* Solver function */ +SUNDIALS_EXPORT int CVode(void *cvode_mem, realtype tout, N_Vector yout, + realtype *tret, int itask); + +/* Dense output function */ +SUNDIALS_EXPORT int CVodeGetDky(void *cvode_mem, realtype t, int k, + N_Vector dky); + +/* Optional output functions */ +SUNDIALS_EXPORT int CVodeGetWorkSpace(void *cvode_mem, long int *lenrw, + long int *leniw); +SUNDIALS_EXPORT int CVodeGetNumSteps(void *cvode_mem, long int *nsteps); +SUNDIALS_EXPORT int CVodeGetNumRhsEvals(void *cvode_mem, long int *nfevals); +SUNDIALS_EXPORT int CVodeGetNumLinSolvSetups(void *cvode_mem, + long int *nlinsetups); +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 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 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); +SUNDIALS_EXPORT int CVodeGetEstLocalErrors(void *cvode_mem, N_Vector ele); +SUNDIALS_EXPORT int CVodeGetNumGEvals(void *cvode_mem, long int *ngevals); +SUNDIALS_EXPORT int CVodeGetRootInfo(void *cvode_mem, int *rootsfound); +SUNDIALS_EXPORT 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); +SUNDIALS_EXPORT int CVodeGetNumNonlinSolvIters(void *cvode_mem, + long int *nniters); +SUNDIALS_EXPORT int CVodeGetNumNonlinSolvConvFails(void *cvode_mem, + long int *nncfails); +SUNDIALS_EXPORT int CVodeGetNonlinSolvStats(void *cvode_mem, long int *nniters, + long int *nncfails); +SUNDIALS_EXPORT char *CVodeGetReturnFlagName(long int flag); + +/* Free function */ +SUNDIALS_EXPORT void CVodeFree(void **cvode_mem); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_bandpre.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_bandpre.h new file mode 100644 index 0000000..a75b0ab --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_bandpre.h @@ -0,0 +1,48 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 CVBANDPRE module, which provides + * a banded difference quotient Jacobian-based preconditioner. + * -----------------------------------------------------------------*/ + + +#ifndef _CVBANDPRE_H +#define _CVBANDPRE_H + +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/* BandPrec inititialization function */ + +SUNDIALS_EXPORT int CVBandPrecInit(void *cvode_mem, sunindextype N, + sunindextype mu, sunindextype ml); + +/* Optional output functions */ + +SUNDIALS_EXPORT int CVBandPrecGetWorkSpace(void *cvode_mem, + long int *lenrwLS, + long int *leniwLS); +SUNDIALS_EXPORT int CVBandPrecGetNumRhsEvals(void *cvode_mem, + long int *nfevalsBP); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_bbdpre.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_bbdpre.h new file mode 100644 index 0000000..7d60618 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_bbdpre.h @@ -0,0 +1,65 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * Michael Wittman, 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 CVBBDPRE module, for a + * band-block-diagonal preconditioner, i.e. a block-diagonal + * matrix with banded blocks. + * -----------------------------------------------------------------*/ + +#ifndef _CVBBDPRE_H +#define _CVBBDPRE_H + +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/* User-supplied function Types */ + +typedef int (*CVLocalFn)(sunindextype Nlocal, realtype t, + N_Vector y, N_Vector g, void *user_data); + +typedef int (*CVCommFn)(sunindextype Nlocal, realtype t, + N_Vector y, void *user_data); + +/* Exported Functions */ + +SUNDIALS_EXPORT int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, + sunindextype mudq, sunindextype mldq, + sunindextype mukeep, sunindextype mlkeep, + realtype dqrely, CVLocalFn gloc, CVCommFn cfn); + +SUNDIALS_EXPORT int CVBBDPrecReInit(void *cvode_mem, + sunindextype mudq, sunindextype mldq, + realtype dqrely); + + +/* Optional output functions */ + +SUNDIALS_EXPORT int CVBBDPrecGetWorkSpace(void *cvode_mem, + long int *lenrwBBDP, + long int *leniwBBDP); + +SUNDIALS_EXPORT int CVBBDPrecGetNumGfnEvals(void *cvode_mem, + long int *ngevalsBBDP); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_diag.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_diag.h new file mode 100644 index 0000000..2575e84 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_diag.h @@ -0,0 +1,60 @@ +/* --------------------------------------------------------------------- + * 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 CVODE diagonal linear solver, CVDIAG. + * ---------------------------------------------------------------------*/ + +#ifndef _CVDIAG_H +#define _CVDIAG_H + +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* --------------------- + * CVDIAG return values + * --------------------- */ + +#define CVDIAG_SUCCESS 0 +#define CVDIAG_MEM_NULL -1 +#define CVDIAG_LMEM_NULL -2 +#define CVDIAG_ILL_INPUT -3 +#define CVDIAG_MEM_FAIL -4 + +/* Additional last_flag values */ + +#define CVDIAG_INV_FAIL -5 +#define CVDIAG_RHSFUNC_UNRECVR -6 +#define CVDIAG_RHSFUNC_RECVR -7 + +/* CVDiag initialization function */ + +SUNDIALS_EXPORT int CVDiag(void *cvode_mem); + +/* Optional output functions */ + +SUNDIALS_EXPORT int CVDiagGetWorkSpace(void *cvode_mem, long int *lenrwLS, + long int *leniwLS); +SUNDIALS_EXPORT int CVDiagGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS); +SUNDIALS_EXPORT int CVDiagGetLastFlag(void *cvode_mem, long int *flag); +SUNDIALS_EXPORT char *CVDiagGetReturnFlagName(long int flag); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_direct.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_direct.h new file mode 100644 index 0000000..95aa8e1 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_direct.h @@ -0,0 +1,60 @@ +/* ----------------------------------------------------------------- + * Programmer(s): 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 + * ----------------------------------------------------------------- + * Header 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. + * -----------------------------------------------------------------*/ + +#ifndef _CVDLS_H +#define _CVDLS_H + +#include <cvode/cvode_ls.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*================================================================= + Function Types (typedefs for equivalent types in cvode_ls.h) + =================================================================*/ + +typedef CVLsJacFn CVDlsJacFn; + +/*=================================================================== + Exported Functions (wrappers for equivalent routines in cvode_ls.h) + ===================================================================*/ + +int CVDlsSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, + SUNMatrix A); + +int CVDlsSetJacFn(void *cvode_mem, CVDlsJacFn jac); + +int CVDlsGetWorkSpace(void *cvode_mem, long int *lenrwLS, + long int *leniwLS); + +int CVDlsGetNumJacEvals(void *cvode_mem, long int *njevals); + +int CVDlsGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS); + +int CVDlsGetLastFlag(void *cvode_mem, long int *flag); + +char *CVDlsGetReturnFlagName(long int flag); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_ls.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_ls.h new file mode 100644 index 0000000..94d1d78 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_ls.h @@ -0,0 +1,129 @@ +/* ---------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 CVODE's linear solver interface. + * ----------------------------------------------------------------*/ + +#ifndef _CVLS_H +#define _CVLS_H + +#include <sundials/sundials_direct.h> +#include <sundials/sundials_iterative.h> +#include <sundials/sundials_linearsolver.h> +#include <sundials/sundials_matrix.h> +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*================================================================= + CVLS Constants + =================================================================*/ + +#define CVLS_SUCCESS 0 +#define CVLS_MEM_NULL -1 +#define CVLS_LMEM_NULL -2 +#define CVLS_ILL_INPUT -3 +#define CVLS_MEM_FAIL -4 +#define CVLS_PMEM_NULL -5 +#define CVLS_JACFUNC_UNRECVR -6 +#define CVLS_JACFUNC_RECVR -7 +#define CVLS_SUNMAT_FAIL -8 +#define CVLS_SUNLS_FAIL -9 + + +/*================================================================= + CVLS user-supplied function prototypes + =================================================================*/ + +typedef int (*CVLsJacFn)(realtype t, N_Vector y, N_Vector fy, + SUNMatrix Jac, void *user_data, + N_Vector tmp1, N_Vector tmp2, N_Vector tmp3); + +typedef int (*CVLsPrecSetupFn)(realtype t, N_Vector y, N_Vector fy, + booleantype jok, booleantype *jcurPtr, + realtype gamma, void *user_data); + +typedef int (*CVLsPrecSolveFn)(realtype t, N_Vector y, N_Vector fy, + N_Vector r, N_Vector z, realtype gamma, + realtype delta, int lr, void *user_data); + +typedef int (*CVLsJacTimesSetupFn)(realtype t, N_Vector y, + N_Vector fy, void *user_data); + +typedef int (*CVLsJacTimesVecFn)(N_Vector v, N_Vector Jv, realtype t, + N_Vector y, N_Vector fy, + void *user_data, N_Vector tmp); + + +/*================================================================= + CVLS Exported functions + =================================================================*/ + +SUNDIALS_EXPORT int CVodeSetLinearSolver(void *cvode_mem, + SUNLinearSolver LS, + SUNMatrix A); + + +/*----------------------------------------------------------------- + Optional inputs to the CVLS linear solver interface + -----------------------------------------------------------------*/ + +SUNDIALS_EXPORT int CVodeSetJacFn(void *cvode_mem, CVLsJacFn jac); +SUNDIALS_EXPORT int CVodeSetMaxStepsBetweenJac(void *cvode_mem, + long int msbj); +SUNDIALS_EXPORT int CVodeSetEpsLin(void *cvode_mem, realtype eplifac); +SUNDIALS_EXPORT int CVodeSetPreconditioner(void *cvode_mem, + CVLsPrecSetupFn pset, + CVLsPrecSolveFn psolve); +SUNDIALS_EXPORT int CVodeSetJacTimes(void *cvode_mem, + CVLsJacTimesSetupFn jtsetup, + CVLsJacTimesVecFn jtimes); + +/*----------------------------------------------------------------- + Optional outputs from the CVLS linear solver interface + -----------------------------------------------------------------*/ + +SUNDIALS_EXPORT int CVodeGetLinWorkSpace(void *cvode_mem, + long int *lenrwLS, + long int *leniwLS); +SUNDIALS_EXPORT int CVodeGetNumJacEvals(void *cvode_mem, + long int *njevals); +SUNDIALS_EXPORT int CVodeGetNumPrecEvals(void *cvode_mem, + long int *npevals); +SUNDIALS_EXPORT int CVodeGetNumPrecSolves(void *cvode_mem, + long int *npsolves); +SUNDIALS_EXPORT int CVodeGetNumLinIters(void *cvode_mem, + long int *nliters); +SUNDIALS_EXPORT int CVodeGetNumLinConvFails(void *cvode_mem, + long int *nlcfails); +SUNDIALS_EXPORT int CVodeGetNumJTSetupEvals(void *cvode_mem, + long int *njtsetups); +SUNDIALS_EXPORT int CVodeGetNumJtimesEvals(void *cvode_mem, + long int *njvevals); +SUNDIALS_EXPORT int CVodeGetNumLinRhsEvals(void *cvode_mem, + long int *nfevalsLS); +SUNDIALS_EXPORT int CVodeGetLastLinFlag(void *cvode_mem, + long int *flag); +SUNDIALS_EXPORT char *CVodeGetLinReturnFlagName(long int flag); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_spils.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_spils.h new file mode 100644 index 0000000..0d4e044 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvode/cvode_spils.h @@ -0,0 +1,78 @@ +/* ----------------------------------------------------------------- + * Programmer(s): 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 + * ----------------------------------------------------------------- + * Header file for the deprecated Scaled, Preconditioned Iterative + * Linear Solver interface in CVODE; these routines now just wrap + * the updated CVODE generic linear solver interface in cvode_ls.h. + * -----------------------------------------------------------------*/ + +#ifndef _CVSPILS_H +#define _CVSPILS_H + +#include <cvode/cvode_ls.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*=============================================================== + Function Types (typedefs for equivalent types in cvode_ls.h) + ===============================================================*/ + +typedef CVLsPrecSetupFn CVSpilsPrecSetupFn; +typedef CVLsPrecSolveFn CVSpilsPrecSolveFn; +typedef CVLsJacTimesSetupFn CVSpilsJacTimesSetupFn; +typedef CVLsJacTimesVecFn CVSpilsJacTimesVecFn; + +/*==================================================================== + Exported Functions (wrappers for equivalent routines in cvode_ls.h) + ====================================================================*/ + +int CVSpilsSetLinearSolver(void *cvode_mem, SUNLinearSolver LS); + +int CVSpilsSetEpsLin(void *cvode_mem, realtype eplifac); + +int CVSpilsSetPreconditioner(void *cvode_mem, CVSpilsPrecSetupFn pset, + CVSpilsPrecSolveFn psolve); + +int CVSpilsSetJacTimes(void *cvode_mem, CVSpilsJacTimesSetupFn jtsetup, + CVSpilsJacTimesVecFn jtimes); + +int CVSpilsGetWorkSpace(void *cvode_mem, long int *lenrwLS, + long int *leniwLS); + +int CVSpilsGetNumPrecEvals(void *cvode_mem, long int *npevals); + +int CVSpilsGetNumPrecSolves(void *cvode_mem, long int *npsolves); + +int CVSpilsGetNumLinIters(void *cvode_mem, long int *nliters); + +int CVSpilsGetNumConvFails(void *cvode_mem, long int *nlcfails); + +int CVSpilsGetNumJTSetupEvals(void *cvode_mem, long int *njtsetups); + +int CVSpilsGetNumJtimesEvals(void *cvode_mem, long int *njvevals); + +int CVSpilsGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS); + +int CVSpilsGetLastFlag(void *cvode_mem, long int *flag); + +char *CVSpilsGetReturnFlagName(long int flag); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes.h new file mode 100644 index 0000000..194fb08 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes.h @@ -0,0 +1,573 @@ +/* ----------------------------------------------------------------- + * Programmer(s): 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 main CVODES integrator. + * -----------------------------------------------------------------*/ + +#ifndef _CVODES_H +#define _CVODES_H + +#include <stdio.h> +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_nonlinearsolver.h> +#include <cvodes/cvodes_ls.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* ----------------- + * CVODES Constants + * ----------------- */ + +/* lmm */ +#define CV_ADAMS 1 +#define CV_BDF 2 + +/* itask */ +#define CV_NORMAL 1 +#define CV_ONE_STEP 2 + +/* ism */ +#define CV_SIMULTANEOUS 1 +#define CV_STAGGERED 2 +#define CV_STAGGERED1 3 + +/* DQtype */ +#define CV_CENTERED 1 +#define CV_FORWARD 2 + +/* interp */ +#define CV_HERMITE 1 +#define CV_POLYNOMIAL 2 + +/* return values */ + +#define CV_SUCCESS 0 +#define CV_TSTOP_RETURN 1 +#define CV_ROOT_RETURN 2 + +#define CV_WARNING 99 + +#define CV_TOO_MUCH_WORK -1 +#define CV_TOO_MUCH_ACC -2 +#define CV_ERR_FAILURE -3 +#define CV_CONV_FAILURE -4 + +#define CV_LINIT_FAIL -5 +#define CV_LSETUP_FAIL -6 +#define CV_LSOLVE_FAIL -7 +#define CV_RHSFUNC_FAIL -8 +#define CV_FIRST_RHSFUNC_ERR -9 +#define CV_REPTD_RHSFUNC_ERR -10 +#define CV_UNREC_RHSFUNC_ERR -11 +#define CV_RTFUNC_FAIL -12 +#define CV_NLS_INIT_FAIL -13 +#define CV_NLS_SETUP_FAIL -14 +#define CV_CONSTR_FAIL -15 + +#define CV_MEM_FAIL -20 +#define CV_MEM_NULL -21 +#define CV_ILL_INPUT -22 +#define CV_NO_MALLOC -23 +#define CV_BAD_K -24 +#define CV_BAD_T -25 +#define CV_BAD_DKY -26 +#define CV_TOO_CLOSE -27 +#define CV_VECTOROP_ERR -28 + +#define CV_NO_QUAD -30 +#define CV_QRHSFUNC_FAIL -31 +#define CV_FIRST_QRHSFUNC_ERR -32 +#define CV_REPTD_QRHSFUNC_ERR -33 +#define CV_UNREC_QRHSFUNC_ERR -34 + +#define CV_NO_SENS -40 +#define CV_SRHSFUNC_FAIL -41 +#define CV_FIRST_SRHSFUNC_ERR -42 +#define CV_REPTD_SRHSFUNC_ERR -43 +#define CV_UNREC_SRHSFUNC_ERR -44 + +#define CV_BAD_IS -45 + +#define CV_NO_QUADSENS -50 +#define CV_QSRHSFUNC_FAIL -51 +#define CV_FIRST_QSRHSFUNC_ERR -52 +#define CV_REPTD_QSRHSFUNC_ERR -53 +#define CV_UNREC_QSRHSFUNC_ERR -54 + +/* adjoint return values */ + +#define CV_NO_ADJ -101 +#define CV_NO_FWD -102 +#define CV_NO_BCK -103 +#define CV_BAD_TB0 -104 +#define CV_REIFWD_FAIL -105 +#define CV_FWD_FAIL -106 +#define CV_GETY_BADT -107 + +/* ------------------------------ + * User-Supplied Function Types + * ------------------------------ */ + +typedef int (*CVRhsFn)(realtype t, N_Vector y, + N_Vector ydot, void *user_data); + +typedef int (*CVRootFn)(realtype t, N_Vector y, realtype *gout, + void *user_data); + +typedef int (*CVEwtFn)(N_Vector y, N_Vector ewt, void *user_data); + +typedef void (*CVErrHandlerFn)(int error_code, + const char *module, const char *function, + char *msg, void *user_data); + +typedef int (*CVQuadRhsFn)(realtype t, N_Vector y, + N_Vector yQdot, void *user_data); + +typedef int (*CVSensRhsFn)(int Ns, realtype t, + N_Vector y, N_Vector ydot, + N_Vector *yS, N_Vector *ySdot, + void *user_data, + N_Vector tmp1, N_Vector tmp2); + +typedef int (*CVSensRhs1Fn)(int Ns, realtype t, + N_Vector y, N_Vector ydot, + int iS, N_Vector yS, N_Vector ySdot, + void *user_data, + N_Vector tmp1, N_Vector tmp2); + +typedef int (*CVQuadSensRhsFn)(int Ns, realtype t, + N_Vector y, N_Vector *yS, + N_Vector yQdot, N_Vector *yQSdot, + void *user_data, + N_Vector tmp, N_Vector tmpQ); + +typedef int (*CVRhsFnB)(realtype t, N_Vector y, N_Vector yB, N_Vector yBdot, + void *user_dataB); + +typedef int (*CVRhsFnBS)(realtype t, N_Vector y, N_Vector *yS, + N_Vector yB, N_Vector yBdot, void *user_dataB); + + +typedef int (*CVQuadRhsFnB)(realtype t, N_Vector y, N_Vector yB, N_Vector qBdot, + void *user_dataB); + +typedef int (*CVQuadRhsFnBS)(realtype t, N_Vector y, N_Vector *yS, + N_Vector yB, N_Vector qBdot, void *user_dataB); + + +/* --------------------------------------- + * Exported Functions -- Forward Problems + * --------------------------------------- */ + +/* Initialization functions */ +SUNDIALS_EXPORT void *CVodeCreate(int lmm); + +SUNDIALS_EXPORT int CVodeInit(void *cvode_mem, CVRhsFn f, realtype t0, + N_Vector y0); +SUNDIALS_EXPORT int CVodeReInit(void *cvode_mem, realtype t0, N_Vector y0); + +/* Tolerance input functions */ +SUNDIALS_EXPORT int CVodeSStolerances(void *cvode_mem, realtype reltol, + realtype abstol); +SUNDIALS_EXPORT int CVodeSVtolerances(void *cvode_mem, realtype reltol, + N_Vector abstol); +SUNDIALS_EXPORT int CVodeWFtolerances(void *cvode_mem, CVEwtFn efun); + +/* Optional input functions */ +SUNDIALS_EXPORT int CVodeSetErrHandlerFn(void *cvode_mem, CVErrHandlerFn ehfun, + void *eh_data); +SUNDIALS_EXPORT int CVodeSetErrFile(void *cvode_mem, FILE *errfp); +SUNDIALS_EXPORT int CVodeSetUserData(void *cvode_mem, void *user_data); +SUNDIALS_EXPORT int CVodeSetMaxOrd(void *cvode_mem, int maxord); +SUNDIALS_EXPORT int CVodeSetMaxNumSteps(void *cvode_mem, long int mxsteps); +SUNDIALS_EXPORT int CVodeSetMaxHnilWarns(void *cvode_mem, int mxhnil); +SUNDIALS_EXPORT int CVodeSetStabLimDet(void *cvode_mem, booleantype stldet); +SUNDIALS_EXPORT int CVodeSetInitStep(void *cvode_mem, realtype hin); +SUNDIALS_EXPORT int CVodeSetMinStep(void *cvode_mem, realtype hmin); +SUNDIALS_EXPORT int CVodeSetMaxStep(void *cvode_mem, realtype hmax); +SUNDIALS_EXPORT int CVodeSetStopTime(void *cvode_mem, realtype tstop); +SUNDIALS_EXPORT int CVodeSetMaxErrTestFails(void *cvode_mem, int maxnef); +SUNDIALS_EXPORT int CVodeSetMaxNonlinIters(void *cvode_mem, int maxcor); +SUNDIALS_EXPORT int CVodeSetMaxConvFails(void *cvode_mem, int maxncf); +SUNDIALS_EXPORT int CVodeSetNonlinConvCoef(void *cvode_mem, realtype nlscoef); +SUNDIALS_EXPORT int CVodeSetConstraints(void *cvode_mem, N_Vector constraints); + +SUNDIALS_EXPORT int CVodeSetNonlinearSolver(void *cvode_mem, + SUNNonlinearSolver NLS); + +/* Rootfinding initialization function */ +SUNDIALS_EXPORT int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g); + +/* Rootfinding optional input functions */ +SUNDIALS_EXPORT int CVodeSetRootDirection(void *cvode_mem, int *rootdir); +SUNDIALS_EXPORT int CVodeSetNoInactiveRootWarn(void *cvode_mem); + +/* Solver function */ +SUNDIALS_EXPORT int CVode(void *cvode_mem, realtype tout, N_Vector yout, + realtype *tret, int itask); + +/* Dense output function */ +SUNDIALS_EXPORT int CVodeGetDky(void *cvode_mem, realtype t, int k, + N_Vector dky); + +/* Optional output functions */ +SUNDIALS_EXPORT int CVodeGetWorkSpace(void *cvode_mem, long int *lenrw, + long int *leniw); +SUNDIALS_EXPORT int CVodeGetNumSteps(void *cvode_mem, long int *nsteps); +SUNDIALS_EXPORT int CVodeGetNumRhsEvals(void *cvode_mem, long int *nfevals); +SUNDIALS_EXPORT int CVodeGetNumLinSolvSetups(void *cvode_mem, + long int *nlinsetups); +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 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 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); +SUNDIALS_EXPORT int CVodeGetEstLocalErrors(void *cvode_mem, N_Vector ele); +SUNDIALS_EXPORT int CVodeGetNumGEvals(void *cvode_mem, long int *ngevals); +SUNDIALS_EXPORT int CVodeGetRootInfo(void *cvode_mem, int *rootsfound); +SUNDIALS_EXPORT 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); +SUNDIALS_EXPORT int CVodeGetNumNonlinSolvIters(void *cvode_mem, + long int *nniters); +SUNDIALS_EXPORT int CVodeGetNumNonlinSolvConvFails(void *cvode_mem, + long int *nncfails); +SUNDIALS_EXPORT int CVodeGetNonlinSolvStats(void *cvode_mem, long int *nniters, + long int *nncfails); +SUNDIALS_EXPORT char *CVodeGetReturnFlagName(long int flag); + +/* Free function */ +SUNDIALS_EXPORT void CVodeFree(void **cvode_mem); + + +/* --------------------------------- + * Exported Functions -- Quadrature + * --------------------------------- */ + +/* Initialization functions */ +SUNDIALS_EXPORT int CVodeQuadInit(void *cvode_mem, CVQuadRhsFn fQ, + N_Vector yQ0); +SUNDIALS_EXPORT int CVodeQuadReInit(void *cvode_mem, N_Vector yQ0); + +/* Tolerance input functions */ +SUNDIALS_EXPORT int CVodeQuadSStolerances(void *cvode_mem, realtype reltolQ, + realtype abstolQ); +SUNDIALS_EXPORT int CVodeQuadSVtolerances(void *cvode_mem, realtype reltolQ, + N_Vector abstolQ); + +/* Optional input specification functions */ +SUNDIALS_EXPORT int CVodeSetQuadErrCon(void *cvode_mem, booleantype errconQ); + +/* Extraction and Dense Output Functions for Forward Problems */ +SUNDIALS_EXPORT int CVodeGetQuad(void *cvode_mem, realtype *tret, + N_Vector yQout); +SUNDIALS_EXPORT int CVodeGetQuadDky(void *cvode_mem, realtype t, int k, + N_Vector dky); + +/* Optional output specification functions */ +SUNDIALS_EXPORT int CVodeGetQuadNumRhsEvals(void *cvode_mem, + long int *nfQevals); +SUNDIALS_EXPORT int CVodeGetQuadNumErrTestFails(void *cvode_mem, + long int *nQetfails); +SUNDIALS_EXPORT int CVodeGetQuadErrWeights(void *cvode_mem, N_Vector eQweight); +SUNDIALS_EXPORT int CVodeGetQuadStats(void *cvode_mem, long int *nfQevals, + long int *nQetfails); + +/* Free function */ +SUNDIALS_EXPORT void CVodeQuadFree(void *cvode_mem); + + +/* ------------------------------------ + * Exported Functions -- Sensitivities + * ------------------------------------ */ + +/* Initialization functions */ +SUNDIALS_EXPORT int CVodeSensInit(void *cvode_mem, int Ns, int ism, + CVSensRhsFn fS, N_Vector *yS0); +SUNDIALS_EXPORT int CVodeSensInit1(void *cvode_mem, int Ns, int ism, + CVSensRhs1Fn fS1, N_Vector *yS0); +SUNDIALS_EXPORT int CVodeSensReInit(void *cvode_mem, int ism, N_Vector *yS0); + +/* Tolerance input functions */ +SUNDIALS_EXPORT int CVodeSensSStolerances(void *cvode_mem, realtype reltolS, + realtype *abstolS); +SUNDIALS_EXPORT int CVodeSensSVtolerances(void *cvode_mem, realtype reltolS, + N_Vector *abstolS); +SUNDIALS_EXPORT int CVodeSensEEtolerances(void *cvode_mem); + +/* Optional input specification functions */ +SUNDIALS_EXPORT int CVodeSetSensDQMethod(void *cvode_mem, int DQtype, + realtype DQrhomax); +SUNDIALS_EXPORT int CVodeSetSensErrCon(void *cvode_mem, booleantype errconS); +SUNDIALS_EXPORT int CVodeSetSensMaxNonlinIters(void *cvode_mem, int maxcorS); +SUNDIALS_EXPORT int CVodeSetSensParams(void *cvode_mem, realtype *p, + realtype *pbar, int *plist); + +/* Integrator nonlinear solver specification functions */ +SUNDIALS_EXPORT int CVodeSetNonlinearSolverSensSim(void *cvode_mem, + SUNNonlinearSolver NLS); +SUNDIALS_EXPORT int CVodeSetNonlinearSolverSensStg(void *cvode_mem, + SUNNonlinearSolver NLS); +SUNDIALS_EXPORT int CVodeSetNonlinearSolverSensStg1(void *cvode_mem, + SUNNonlinearSolver NLS); + +/* Enable/disable sensitivities */ +SUNDIALS_EXPORT int CVodeSensToggleOff(void *cvode_mem); + +/* Extraction and dense output functions */ +SUNDIALS_EXPORT int CVodeGetSens(void *cvode_mem, realtype *tret, + N_Vector *ySout); +SUNDIALS_EXPORT int CVodeGetSens1(void *cvode_mem, realtype *tret, int is, + N_Vector ySout); + +SUNDIALS_EXPORT int CVodeGetSensDky(void *cvode_mem, realtype t, int k, + N_Vector *dkyA); +SUNDIALS_EXPORT int CVodeGetSensDky1(void *cvode_mem, realtype t, int k, int is, + N_Vector dky); + +/* Optional output specification functions */ +SUNDIALS_EXPORT int CVodeGetSensNumRhsEvals(void *cvode_mem, + long int *nfSevals); +SUNDIALS_EXPORT int CVodeGetNumRhsEvalsSens(void *cvode_mem, + long int *nfevalsS); +SUNDIALS_EXPORT int CVodeGetSensNumErrTestFails(void *cvode_mem, + long int *nSetfails); +SUNDIALS_EXPORT int CVodeGetSensNumLinSolvSetups(void *cvode_mem, + long int *nlinsetupsS); +SUNDIALS_EXPORT int CVodeGetSensErrWeights(void *cvode_mem, N_Vector *eSweight); +SUNDIALS_EXPORT int CVodeGetSensStats(void *cvode_mem, long int *nfSevals, + long int *nfevalsS, long int *nSetfails, + long int *nlinsetupsS); +SUNDIALS_EXPORT int CVodeGetSensNumNonlinSolvIters(void *cvode_mem, + long int *nSniters); +SUNDIALS_EXPORT int CVodeGetSensNumNonlinSolvConvFails(void *cvode_mem, + long int *nSncfails); +SUNDIALS_EXPORT int CVodeGetStgrSensNumNonlinSolvIters(void *cvode_mem, + long int *nSTGR1niters); +SUNDIALS_EXPORT int CVodeGetStgrSensNumNonlinSolvConvFails(void *cvode_mem, + long int *nSTGR1ncfails); +SUNDIALS_EXPORT int CVodeGetSensNonlinSolvStats(void *cvode_mem, + long int *nSniters, + long int *nSncfails); + +/* Free function */ +SUNDIALS_EXPORT void CVodeSensFree(void *cvode_mem); + + +/* ------------------------------------------------------- + * Exported Functions -- Sensitivity dependent quadrature + * ------------------------------------------------------- */ + +/* Initialization functions */ +SUNDIALS_EXPORT int CVodeQuadSensInit(void *cvode_mem, CVQuadSensRhsFn fQS, + N_Vector *yQS0); +SUNDIALS_EXPORT int CVodeQuadSensReInit(void *cvode_mem, N_Vector *yQS0); + +/* Tolerance input functions */ +SUNDIALS_EXPORT int CVodeQuadSensSStolerances(void *cvode_mem, + realtype reltolQS, + realtype *abstolQS); +SUNDIALS_EXPORT int CVodeQuadSensSVtolerances(void *cvode_mem, + realtype reltolQS, + N_Vector *abstolQS); +SUNDIALS_EXPORT int CVodeQuadSensEEtolerances(void *cvode_mem); + +/* Optional input specification functions */ +SUNDIALS_EXPORT int CVodeSetQuadSensErrCon(void *cvode_mem, + booleantype errconQS); + +/* Extraction and dense output functions */ +SUNDIALS_EXPORT int CVodeGetQuadSens(void *cvode_mem, realtype *tret, + N_Vector *yQSout); +SUNDIALS_EXPORT int CVodeGetQuadSens1(void *cvode_mem, realtype *tret, int is, + N_Vector yQSout); + +SUNDIALS_EXPORT int CVodeGetQuadSensDky(void *cvode_mem, realtype t, int k, + N_Vector *dkyQS_all); +SUNDIALS_EXPORT int CVodeGetQuadSensDky1(void *cvode_mem, realtype t, int k, + int is, N_Vector dkyQS); + +/* Optional output specification functions */ +SUNDIALS_EXPORT int CVodeGetQuadSensNumRhsEvals(void *cvode_mem, + long int *nfQSevals); +SUNDIALS_EXPORT int CVodeGetQuadSensNumErrTestFails(void *cvode_mem, + long int *nQSetfails); +SUNDIALS_EXPORT int CVodeGetQuadSensErrWeights(void *cvode_mem, + N_Vector *eQSweight); +SUNDIALS_EXPORT int CVodeGetQuadSensStats(void *cvode_mem, + long int *nfQSevals, + long int *nQSetfails); + +/* Free function */ +SUNDIALS_EXPORT void CVodeQuadSensFree(void *cvode_mem); + + +/* ---------------------------------------- + * Exported Functions -- Backward Problems + * ---------------------------------------- */ + +/* Initialization functions */ + +SUNDIALS_EXPORT int CVodeAdjInit(void *cvode_mem, long int steps, int interp); + +SUNDIALS_EXPORT int CVodeAdjReInit(void *cvode_mem); + +SUNDIALS_EXPORT void CVodeAdjFree(void *cvode_mem); + +/* Backward Problem Setup Functions */ + +SUNDIALS_EXPORT int CVodeCreateB(void *cvode_mem, int lmmB, int *which); + +SUNDIALS_EXPORT int CVodeInitB(void *cvode_mem, int which, + CVRhsFnB fB, + realtype tB0, N_Vector yB0); +SUNDIALS_EXPORT int CVodeInitBS(void *cvode_mem, int which, + CVRhsFnBS fBs, + realtype tB0, N_Vector yB0); +SUNDIALS_EXPORT int CVodeReInitB(void *cvode_mem, int which, + realtype tB0, N_Vector yB0); + +SUNDIALS_EXPORT int CVodeSStolerancesB(void *cvode_mem, int which, + realtype reltolB, realtype abstolB); +SUNDIALS_EXPORT int CVodeSVtolerancesB(void *cvode_mem, int which, + realtype reltolB, N_Vector abstolB); + +SUNDIALS_EXPORT int CVodeQuadInitB(void *cvode_mem, int which, + CVQuadRhsFnB fQB, N_Vector yQB0); +SUNDIALS_EXPORT int CVodeQuadInitBS(void *cvode_mem, int which, + CVQuadRhsFnBS fQBs, N_Vector yQB0); +SUNDIALS_EXPORT int CVodeQuadReInitB(void *cvode_mem, int which, N_Vector yQB0); + +SUNDIALS_EXPORT int CVodeQuadSStolerancesB(void *cvode_mem, int which, + realtype reltolQB, + realtype abstolQB); +SUNDIALS_EXPORT int CVodeQuadSVtolerancesB(void *cvode_mem, int which, + realtype reltolQB, + N_Vector abstolQB); + +/* Solver Function For Forward Problems */ + +SUNDIALS_EXPORT int CVodeF(void *cvode_mem, realtype tout, N_Vector yout, + realtype *tret, int itask, int *ncheckPtr); + + +/* Solver Function For Backward Problems */ + +SUNDIALS_EXPORT int CVodeB(void *cvode_mem, realtype tBout, int itaskB); + +/* Optional Input Functions For Adjoint Problems */ + +SUNDIALS_EXPORT int CVodeSetAdjNoSensi(void *cvode_mem); + +SUNDIALS_EXPORT int CVodeSetUserDataB(void *cvode_mem, int which, + void *user_dataB); +SUNDIALS_EXPORT int CVodeSetMaxOrdB(void *cvode_mem, int which, int maxordB); +SUNDIALS_EXPORT int CVodeSetMaxNumStepsB(void *cvode_mem, int which, + long int mxstepsB); +SUNDIALS_EXPORT int CVodeSetStabLimDetB(void *cvode_mem, int which, + booleantype stldetB); +SUNDIALS_EXPORT int CVodeSetInitStepB(void *cvode_mem, int which, + realtype hinB); +SUNDIALS_EXPORT int CVodeSetMinStepB(void *cvode_mem, int which, + realtype hminB); +SUNDIALS_EXPORT int CVodeSetMaxStepB(void *cvode_mem, int which, + realtype hmaxB); +SUNDIALS_EXPORT int CVodeSetConstraintsB(void *cvode_mem, int which, + N_Vector constraintsB); +SUNDIALS_EXPORT int CVodeSetQuadErrConB(void *cvode_mem, int which, + booleantype errconQB); + +SUNDIALS_EXPORT int CVodeSetNonlinearSolverB(void *cvode_mem, int which, + SUNNonlinearSolver NLS); + +/* Extraction And Dense Output Functions For Backward Problems */ + +SUNDIALS_EXPORT int CVodeGetB(void *cvode_mem, int which, + realtype *tBret, N_Vector yB); +SUNDIALS_EXPORT int CVodeGetQuadB(void *cvode_mem, int which, + realtype *tBret, N_Vector qB); + +/* Optional Output Functions For Backward Problems */ + +SUNDIALS_EXPORT void *CVodeGetAdjCVodeBmem(void *cvode_mem, int which); + +SUNDIALS_EXPORT int CVodeGetAdjY(void *cvode_mem, realtype t, N_Vector y); + +typedef struct { + void *my_addr; + void *next_addr; + realtype t0; + realtype t1; + long int nstep; + int order; + realtype step; +} CVadjCheckPointRec; + +SUNDIALS_EXPORT int CVodeGetAdjCheckPointsInfo(void *cvode_mem, + CVadjCheckPointRec *ckpnt); + + +/* Undocumented Optional Output Functions For Backward Problems */ + +/* ----------------------------------------------------------------- + * CVodeGetAdjDataPointHermite + * ----------------------------------------------------------------- + * Returns the 2 vectors stored for cubic Hermite interpolation + * at the data point 'which'. The user must allocate space for + * y and yd. Returns CV_MEM_NULL if cvode_mem is NULL, + * CV_ILL_INPUT if the interpolation type previously specified + * is not CV_HERMITE, or CV_SUCCESS otherwise. + * ----------------------------------------------------------------- + * CVodeGetAdjDataPointPolynomial + * ----------------------------------------------------------------- + * Returns the vector stored for polynomial interpolation + * at the data point 'which'. The user must allocate space for + * y. Returns CV_MEM_NULL if cvode_mem is NULL, CV_ILL_INPUT if + * the interpolation type previously specified is not + * CV_POLYNOMIAL, or CV_SUCCESS otherwise. + * ----------------------------------------------------------------- */ + +SUNDIALS_EXPORT int CVodeGetAdjDataPointHermite(void *cvode_mem, int which, + realtype *t, N_Vector y, + N_Vector yd); + +SUNDIALS_EXPORT int CVodeGetAdjDataPointPolynomial(void *cvode_mem, int which, + realtype *t, int *order, + N_Vector y); + +/* ----------------------------------------------------------------- + * CVodeGetAdjCurrentCheckPoint + * Returns the address of the 'active' check point. + * ----------------------------------------------------------------- */ + +SUNDIALS_EXPORT int CVodeGetAdjCurrentCheckPoint(void *cvode_mem, void **addr); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_bandpre.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_bandpre.h new file mode 100644 index 0000000..aec8709 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_bandpre.h @@ -0,0 +1,60 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 CVBANDPRE module, which provides + * a banded difference quotient Jacobian-based preconditioner. + * -----------------------------------------------------------------*/ + +#ifndef _CVSBANDPRE_H +#define _CVSBANDPRE_H + +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*----------------- + FORWARD PROBLEMS + -----------------*/ + +/* BandPrec inititialization function */ + +SUNDIALS_EXPORT int CVBandPrecInit(void *cvode_mem, sunindextype N, + sunindextype mu, sunindextype ml); + +/* Optional output functions */ + +SUNDIALS_EXPORT int CVBandPrecGetWorkSpace(void *cvode_mem, + long int *lenrwLS, + long int *leniwLS); +SUNDIALS_EXPORT int CVBandPrecGetNumRhsEvals(void *cvode_mem, + long int *nfevalsBP); + + +/*------------------ + BACKWARD PROBLEMS + ------------------*/ + +SUNDIALS_EXPORT int CVBandPrecInitB(void *cvode_mem, int which, + sunindextype nB, sunindextype muB, + sunindextype mlB); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_bbdpre.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_bbdpre.h new file mode 100644 index 0000000..13dea8d --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_bbdpre.h @@ -0,0 +1,93 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 CVBBDPRE module, for a + * band-block-diagonal preconditioner, i.e. a block-diagonal + * matrix with banded blocks. + * -----------------------------------------------------------------*/ + +#ifndef _CVSBBDPRE_H +#define _CVSBBDPRE_H + +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*----------------- + FORWARD PROBLEMS + -----------------*/ + +/* User-supplied function Types */ + +typedef int (*CVLocalFn)(sunindextype Nlocal, realtype t, + N_Vector y, N_Vector g, void *user_data); + +typedef int (*CVCommFn)(sunindextype Nlocal, realtype t, + N_Vector y, void *user_data); + +/* Exported Functions */ + +SUNDIALS_EXPORT int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, + sunindextype mudq, sunindextype mldq, + sunindextype mukeep, sunindextype mlkeep, + realtype dqrely, CVLocalFn gloc, CVCommFn cfn); + +SUNDIALS_EXPORT int CVBBDPrecReInit(void *cvode_mem, + sunindextype mudq, sunindextype mldq, + realtype dqrely); + + +/* Optional output functions */ + +SUNDIALS_EXPORT int CVBBDPrecGetWorkSpace(void *cvode_mem, + long int *lenrwBBDP, + long int *leniwBBDP); + +SUNDIALS_EXPORT int CVBBDPrecGetNumGfnEvals(void *cvode_mem, + long int *ngevalsBBDP); + + +/*------------------ + BACKWARD PROBLEMS + ------------------*/ + +/* User-Supplied Function Types */ + +typedef int (*CVLocalFnB)(sunindextype NlocalB, realtype t, + N_Vector y, N_Vector yB, N_Vector gB, void *user_dataB); + +typedef int (*CVCommFnB)(sunindextype NlocalB, realtype t, + N_Vector y, N_Vector yB, void *user_dataB); + + +/* Exported Functions */ + +SUNDIALS_EXPORT int CVBBDPrecInitB(void *cvode_mem, int which, sunindextype NlocalB, + sunindextype mudqB, sunindextype mldqB, + sunindextype mukeepB, sunindextype mlkeepB, + realtype dqrelyB, CVLocalFnB glocB, CVCommFnB cfnB); + +SUNDIALS_EXPORT int CVBBDPrecReInitB(void *cvode_mem, int which, + sunindextype mudqB, sunindextype mldqB, + realtype dqrelyB); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_diag.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_diag.h new file mode 100644 index 0000000..b98e341 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_diag.h @@ -0,0 +1,73 @@ +/* --------------------------------------------------------------------- + * Programmer(s): 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 CVODE diagonal linear solver, CVDIAG. + * ---------------------------------------------------------------------*/ + +#ifndef _CVSDIAG_H +#define _CVSDIAG_H + +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* --------------------- + * CVDIAG return values + * --------------------- */ + +#define CVDIAG_SUCCESS 0 +#define CVDIAG_MEM_NULL -1 +#define CVDIAG_LMEM_NULL -2 +#define CVDIAG_ILL_INPUT -3 +#define CVDIAG_MEM_FAIL -4 + +/* Additional last_flag values */ + +#define CVDIAG_INV_FAIL -5 +#define CVDIAG_RHSFUNC_UNRECVR -6 +#define CVDIAG_RHSFUNC_RECVR -7 + +/* Return values for adjoint module */ + +#define CVDIAG_NO_ADJ -101 + +/* ----------------- + * Forward Problems + * ----------------- */ + +/* CVDiag initialization function */ + +SUNDIALS_EXPORT int CVDiag(void *cvode_mem); + +/* Optional output functions */ + +SUNDIALS_EXPORT int CVDiagGetWorkSpace(void *cvode_mem, long int *lenrwLS, + long int *leniwLS); +SUNDIALS_EXPORT int CVDiagGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS); +SUNDIALS_EXPORT int CVDiagGetLastFlag(void *cvode_mem, long int *flag); +SUNDIALS_EXPORT char *CVDiagGetReturnFlagName(long int flag); + +/* ------------------------------------- + * Backward Problems - Function CVDiagB + * ------------------------------------- */ + +SUNDIALS_EXPORT int CVDiagB(void *cvode_mem, int which); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_direct.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_direct.h new file mode 100644 index 0000000..cef57b0 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_direct.h @@ -0,0 +1,69 @@ +/* ----------------------------------------------------------------- + * Programmer(s): 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 + * ----------------------------------------------------------------- + * 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. + * -----------------------------------------------------------------*/ + +#ifndef _CVSDLS_H +#define _CVSDLS_H + +#include <cvodes/cvodes_ls.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*================================================================= + Function Types (typedefs for equivalent types in cvodes_ls.h) + =================================================================*/ + +typedef CVLsJacFn CVDlsJacFn; +typedef CVLsJacFnB CVDlsJacFnB; +typedef CVLsJacFnBS CVDlsJacFnBS; + +/*==================================================================== + Exported Functions (wrappers for equivalent routines in cvodes_ls.h) + ====================================================================*/ + +int CVDlsSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, + SUNMatrix A); + +int CVDlsSetJacFn(void *cvode_mem, CVDlsJacFn jac); + +int CVDlsGetWorkSpace(void *cvode_mem, long int *lenrwLS, + long int *leniwLS); + +int CVDlsGetNumJacEvals(void *cvode_mem, long int *njevals); + +int CVDlsGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS); + +int CVDlsGetLastFlag(void *cvode_mem, long int *flag); + +char *CVDlsGetReturnFlagName(long int flag); + +int CVDlsSetLinearSolverB(void *cvode_mem, int which, + SUNLinearSolver LS, SUNMatrix A); + +int CVDlsSetJacFnB(void *cvode_mem, int which, CVDlsJacFnB jacB); + +int CVDlsSetJacFnBS(void *cvode_mem, int which, CVDlsJacFnBS jacBS); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_ls.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_ls.h new file mode 100644 index 0000000..fb8e9f0 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_ls.h @@ -0,0 +1,234 @@ +/* ---------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 CVODES' linear solver interface. + * ----------------------------------------------------------------*/ + +#ifndef _CVSLS_H +#define _CVSLS_H + +#include <sundials/sundials_direct.h> +#include <sundials/sundials_iterative.h> +#include <sundials/sundials_linearsolver.h> +#include <sundials/sundials_matrix.h> +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*================================================================= + CVLS Constants + =================================================================*/ + +#define CVLS_SUCCESS 0 +#define CVLS_MEM_NULL -1 +#define CVLS_LMEM_NULL -2 +#define CVLS_ILL_INPUT -3 +#define CVLS_MEM_FAIL -4 +#define CVLS_PMEM_NULL -5 +#define CVLS_JACFUNC_UNRECVR -6 +#define CVLS_JACFUNC_RECVR -7 +#define CVLS_SUNMAT_FAIL -8 +#define CVLS_SUNLS_FAIL -9 + +/* Return values for the adjoint module */ + +#define CVLS_NO_ADJ -101 +#define CVLS_LMEMB_NULL -102 + + +/*================================================================= + Forward problems + =================================================================*/ + +/*================================================================= + CVLS user-supplied function prototypes + =================================================================*/ + +typedef int (*CVLsJacFn)(realtype t, N_Vector y, N_Vector fy, + SUNMatrix Jac, void *user_data, + N_Vector tmp1, N_Vector tmp2, N_Vector tmp3); + +typedef int (*CVLsPrecSetupFn)(realtype t, N_Vector y, N_Vector fy, + booleantype jok, booleantype *jcurPtr, + realtype gamma, void *user_data); + +typedef int (*CVLsPrecSolveFn)(realtype t, N_Vector y, N_Vector fy, + N_Vector r, N_Vector z, realtype gamma, + realtype delta, int lr, void *user_data); + +typedef int (*CVLsJacTimesSetupFn)(realtype t, N_Vector y, + N_Vector fy, void *user_data); + +typedef int (*CVLsJacTimesVecFn)(N_Vector v, N_Vector Jv, realtype t, + N_Vector y, N_Vector fy, + void *user_data, N_Vector tmp); + + +/*================================================================= + CVLS Exported functions + =================================================================*/ + +SUNDIALS_EXPORT int CVodeSetLinearSolver(void *cvode_mem, + SUNLinearSolver LS, + SUNMatrix A); + + +/*----------------------------------------------------------------- + Optional inputs to the CVLS linear solver interface + -----------------------------------------------------------------*/ + +SUNDIALS_EXPORT int CVodeSetJacFn(void *cvode_mem, CVLsJacFn jac); +SUNDIALS_EXPORT int CVodeSetMaxStepsBetweenJac(void *cvode_mem, + long int msbj); +SUNDIALS_EXPORT int CVodeSetEpsLin(void *cvode_mem, realtype eplifac); +SUNDIALS_EXPORT int CVodeSetPreconditioner(void *cvode_mem, + CVLsPrecSetupFn pset, + CVLsPrecSolveFn psolve); +SUNDIALS_EXPORT int CVodeSetJacTimes(void *cvode_mem, + CVLsJacTimesSetupFn jtsetup, + CVLsJacTimesVecFn jtimes); + +/*----------------------------------------------------------------- + Optional outputs from the CVLS linear solver interface + -----------------------------------------------------------------*/ + +SUNDIALS_EXPORT int CVodeGetLinWorkSpace(void *cvode_mem, + long int *lenrwLS, + long int *leniwLS); +SUNDIALS_EXPORT int CVodeGetNumJacEvals(void *cvode_mem, + long int *njevals); +SUNDIALS_EXPORT int CVodeGetNumPrecEvals(void *cvode_mem, + long int *npevals); +SUNDIALS_EXPORT int CVodeGetNumPrecSolves(void *cvode_mem, + long int *npsolves); +SUNDIALS_EXPORT int CVodeGetNumLinIters(void *cvode_mem, + long int *nliters); +SUNDIALS_EXPORT int CVodeGetNumLinConvFails(void *cvode_mem, + long int *nlcfails); +SUNDIALS_EXPORT int CVodeGetNumJTSetupEvals(void *cvode_mem, + long int *njtsetups); +SUNDIALS_EXPORT int CVodeGetNumJtimesEvals(void *cvode_mem, + long int *njvevals); +SUNDIALS_EXPORT int CVodeGetNumLinRhsEvals(void *cvode_mem, + long int *nfevalsLS); +SUNDIALS_EXPORT int CVodeGetLastLinFlag(void *cvode_mem, + long int *flag); +SUNDIALS_EXPORT char *CVodeGetLinReturnFlagName(long int flag); + + +/*================================================================= + Backward problems + =================================================================*/ + +/*================================================================= + CVLS user-supplied function prototypes + =================================================================*/ + +typedef int (*CVLsJacFnB)(realtype t, N_Vector y, N_Vector yB, + N_Vector fyB, SUNMatrix JB, + void *user_dataB, N_Vector tmp1B, + N_Vector tmp2B, N_Vector tmp3B); + +typedef int (*CVLsJacFnBS)(realtype t, N_Vector y, N_Vector *yS, + N_Vector yB, N_Vector fyB, SUNMatrix JB, + void *user_dataB, N_Vector tmp1B, + N_Vector tmp2B, N_Vector tmp3B); + +typedef int (*CVLsPrecSetupFnB)(realtype t, N_Vector y, N_Vector yB, + N_Vector fyB, booleantype jokB, + booleantype *jcurPtrB, + realtype gammaB, void *user_dataB); + +typedef int (*CVLsPrecSetupFnBS)(realtype t, N_Vector y, + N_Vector *yS, N_Vector yB, + N_Vector fyB, booleantype jokB, + booleantype *jcurPtrB, + realtype gammaB, void *user_dataB); + +typedef int (*CVLsPrecSolveFnB)(realtype t, N_Vector y, N_Vector yB, + N_Vector fyB, N_Vector rB, + N_Vector zB, realtype gammaB, + realtype deltaB, int lrB, + void *user_dataB); + +typedef int (*CVLsPrecSolveFnBS)(realtype t, N_Vector y, N_Vector *yS, + N_Vector yB, N_Vector fyB, + N_Vector rB, N_Vector zB, + realtype gammaB, realtype deltaB, + int lrB, void *user_dataB); + +typedef int (*CVLsJacTimesSetupFnB)(realtype t, N_Vector y, N_Vector yB, + N_Vector fyB, void *jac_dataB); + +typedef int (*CVLsJacTimesSetupFnBS)(realtype t, N_Vector y, + N_Vector *yS, N_Vector yB, + N_Vector fyB, void *jac_dataB); + +typedef int (*CVLsJacTimesVecFnB)(N_Vector vB, N_Vector JvB, realtype t, + N_Vector y, N_Vector yB, N_Vector fyB, + void *jac_dataB, N_Vector tmpB); + +typedef int (*CVLsJacTimesVecFnBS)(N_Vector vB, N_Vector JvB, + realtype t, N_Vector y, N_Vector *yS, + N_Vector yB, N_Vector fyB, + void *jac_dataB, N_Vector tmpB); + + +/*================================================================= + CVLS Exported functions + =================================================================*/ + +SUNDIALS_EXPORT int CVodeSetLinearSolverB(void *cvode_mem, + int which, + SUNLinearSolver LS, + SUNMatrix A); + +/*----------------------------------------------------------------- + Each CVodeSet***B or CVodeSet***BS function below links the + main CVODES integrator with the corresponding CVSLS + optional input function for the backward integration. + The 'which' argument is the int returned by CVodeCreateB. + -----------------------------------------------------------------*/ + +SUNDIALS_EXPORT int CVodeSetJacFnB(void *cvode_mem, int which, + CVLsJacFnB jacB); +SUNDIALS_EXPORT int CVodeSetJacFnBS(void *cvode_mem, int which, + CVLsJacFnBS jacBS); + +SUNDIALS_EXPORT int CVodeSetEpsLinB(void *cvode_mem, int which, + realtype eplifacB); + +SUNDIALS_EXPORT int CVodeSetPreconditionerB(void *cvode_mem, int which, + CVLsPrecSetupFnB psetB, + CVLsPrecSolveFnB psolveB); +SUNDIALS_EXPORT int CVodeSetPreconditionerBS(void *cvode_mem, int which, + CVLsPrecSetupFnBS psetBS, + CVLsPrecSolveFnBS psolveBS); + +SUNDIALS_EXPORT int CVodeSetJacTimesB(void *cvode_mem, int which, + CVLsJacTimesSetupFnB jtsetupB, + CVLsJacTimesVecFnB jtimesB); +SUNDIALS_EXPORT int CVodeSetJacTimesBS(void *cvode_mem, int which, + CVLsJacTimesSetupFnBS jtsetupBS, + CVLsJacTimesVecFnBS jtimesBS); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_spils.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_spils.h new file mode 100644 index 0000000..da3bc71 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/cvodes/cvodes_spils.h @@ -0,0 +1,107 @@ +/* ----------------------------------------------------------------- + * Programmer(s): 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 + * ----------------------------------------------------------------- + * Header file for the deprecated Scaled, Preconditioned Iterative + * Linear Solver interface in CVODES; these routines now just wrap + * the updated CVODES generic linear solver interface in cvodes_ls.h. + * -----------------------------------------------------------------*/ + +#ifndef _CVSSPILS_H +#define _CVSSPILS_H + +#include <cvodes/cvodes_ls.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*=============================================================== + Function Types (typedefs for equivalent types in cvodes_ls.h) + ===============================================================*/ + +typedef CVLsPrecSetupFn CVSpilsPrecSetupFn; +typedef CVLsPrecSolveFn CVSpilsPrecSolveFn; +typedef CVLsJacTimesSetupFn CVSpilsJacTimesSetupFn; +typedef CVLsJacTimesVecFn CVSpilsJacTimesVecFn; +typedef CVLsPrecSetupFnB CVSpilsPrecSetupFnB; +typedef CVLsPrecSetupFnBS CVSpilsPrecSetupFnBS; +typedef CVLsPrecSolveFnB CVSpilsPrecSolveFnB; +typedef CVLsPrecSolveFnBS CVSpilsPrecSolveFnBS; +typedef CVLsJacTimesSetupFnB CVSpilsJacTimesSetupFnB; +typedef CVLsJacTimesSetupFnBS CVSpilsJacTimesSetupFnBS; +typedef CVLsJacTimesVecFnB CVSpilsJacTimesVecFnB; +typedef CVLsJacTimesVecFnBS CVSpilsJacTimesVecFnBS; + +/*==================================================================== + Exported Functions (wrappers for equivalent routines in cvodes_ls.h) + ====================================================================*/ + +int CVSpilsSetLinearSolver(void *cvode_mem, SUNLinearSolver LS); + +int CVSpilsSetEpsLin(void *cvode_mem, realtype eplifac); + +int CVSpilsSetPreconditioner(void *cvode_mem, CVSpilsPrecSetupFn pset, + CVSpilsPrecSolveFn psolve); + +int CVSpilsSetJacTimes(void *cvode_mem, CVSpilsJacTimesSetupFn jtsetup, + CVSpilsJacTimesVecFn jtimes); + +int CVSpilsGetWorkSpace(void *cvode_mem, long int *lenrwLS, + long int *leniwLS); + +int CVSpilsGetNumPrecEvals(void *cvode_mem, long int *npevals); + +int CVSpilsGetNumPrecSolves(void *cvode_mem, long int *npsolves); + +int CVSpilsGetNumLinIters(void *cvode_mem, long int *nliters); + +int CVSpilsGetNumConvFails(void *cvode_mem, long int *nlcfails); + +int CVSpilsGetNumJTSetupEvals(void *cvode_mem, long int *njtsetups); + +int CVSpilsGetNumJtimesEvals(void *cvode_mem, long int *njvevals); + +int CVSpilsGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS); + +int CVSpilsGetLastFlag(void *cvode_mem, long int *flag); + +char *CVSpilsGetReturnFlagName(long int flag); + +int CVSpilsSetLinearSolverB(void *cvode_mem, int which, + SUNLinearSolver LS); + +int CVSpilsSetEpsLinB(void *cvode_mem, int which, realtype eplifacB); + +int CVSpilsSetPreconditionerB(void *cvode_mem, int which, + CVSpilsPrecSetupFnB psetB, + CVSpilsPrecSolveFnB psolveB); + +int CVSpilsSetPreconditionerBS(void *cvode_mem, int which, + CVSpilsPrecSetupFnBS psetBS, + CVSpilsPrecSolveFnBS psolveBS); + +int CVSpilsSetJacTimesB(void *cvode_mem, int which, + CVSpilsJacTimesSetupFnB jtsetupB, + CVSpilsJacTimesVecFnB jtimesB); + +int CVSpilsSetJacTimesBS(void *cvode_mem, int which, + CVSpilsJacTimesSetupFnBS jtsetupBS, + CVSpilsJacTimesVecFnBS jtimesBS); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/ida/ida.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/ida/ida.h new file mode 100644 index 0000000..bdfa9ef --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/ida/ida.h @@ -0,0 +1,207 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Allan G. Taylor, Alan C. Hindmarsh, Radu Serban, + * 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 main IDA solver. + * -----------------------------------------------------------------*/ + +#ifndef _IDA_H +#define _IDA_H + +#include <stdio.h> +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_nonlinearsolver.h> +#include <ida/ida_ls.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* ----------------- + * IDA Constants + * ----------------- */ + +/* itask */ +#define IDA_NORMAL 1 +#define IDA_ONE_STEP 2 + +/* icopt */ +#define IDA_YA_YDP_INIT 1 +#define IDA_Y_INIT 2 + +/* return values */ + +#define IDA_SUCCESS 0 +#define IDA_TSTOP_RETURN 1 +#define IDA_ROOT_RETURN 2 + +#define IDA_WARNING 99 + +#define IDA_TOO_MUCH_WORK -1 +#define IDA_TOO_MUCH_ACC -2 +#define IDA_ERR_FAIL -3 +#define IDA_CONV_FAIL -4 + +#define IDA_LINIT_FAIL -5 +#define IDA_LSETUP_FAIL -6 +#define IDA_LSOLVE_FAIL -7 +#define IDA_RES_FAIL -8 +#define IDA_REP_RES_ERR -9 +#define IDA_RTFUNC_FAIL -10 +#define IDA_CONSTR_FAIL -11 + +#define IDA_FIRST_RES_FAIL -12 +#define IDA_LINESEARCH_FAIL -13 +#define IDA_NO_RECOVERY -14 +#define IDA_NLS_INIT_FAIL -15 +#define IDA_NLS_SETUP_FAIL -16 + +#define IDA_MEM_NULL -20 +#define IDA_MEM_FAIL -21 +#define IDA_ILL_INPUT -22 +#define IDA_NO_MALLOC -23 +#define IDA_BAD_EWT -24 +#define IDA_BAD_K -25 +#define IDA_BAD_T -26 +#define IDA_BAD_DKY -27 +#define IDA_VECTOROP_ERR -28 + +#define IDA_UNRECOGNIZED_ERROR -99 + + +/* ------------------------------ + * User-Supplied Function Types + * ------------------------------ */ + +typedef int (*IDAResFn)(realtype tt, N_Vector yy, N_Vector yp, + N_Vector rr, void *user_data); + +typedef int (*IDARootFn)(realtype t, N_Vector y, N_Vector yp, + realtype *gout, void *user_data); + +typedef int (*IDAEwtFn)(N_Vector y, N_Vector ewt, void *user_data); + +typedef void (*IDAErrHandlerFn)(int error_code, + const char *module, const char *function, + char *msg, void *user_data); + +/* ------------------- + * Exported Functions + * ------------------- */ + +/* Initialization functions */ +SUNDIALS_EXPORT void *IDACreate(void); + +SUNDIALS_EXPORT int IDAInit(void *ida_mem, IDAResFn res, realtype t0, + N_Vector yy0, N_Vector yp0); +SUNDIALS_EXPORT int IDAReInit(void *ida_mem, realtype t0, N_Vector yy0, + N_Vector yp0); + +/* Tolerance input functions */ +SUNDIALS_EXPORT int IDASStolerances(void *ida_mem, realtype reltol, + realtype abstol); +SUNDIALS_EXPORT int IDASVtolerances(void *ida_mem, realtype reltol, + N_Vector abstol); +SUNDIALS_EXPORT int IDAWFtolerances(void *ida_mem, IDAEwtFn efun); + +/* Initial condition calculation function */ +SUNDIALS_EXPORT int IDACalcIC(void *ida_mem, int icopt, realtype tout1); + +/* Initial condition calculation optional input functions */ +SUNDIALS_EXPORT int IDASetNonlinConvCoefIC(void *ida_mem, realtype epiccon); +SUNDIALS_EXPORT int IDASetMaxNumStepsIC(void *ida_mem, int maxnh); +SUNDIALS_EXPORT int IDASetMaxNumJacsIC(void *ida_mem, int maxnj); +SUNDIALS_EXPORT int IDASetMaxNumItersIC(void *ida_mem, int maxnit); +SUNDIALS_EXPORT int IDASetLineSearchOffIC(void *ida_mem, booleantype lsoff); +SUNDIALS_EXPORT int IDASetStepToleranceIC(void *ida_mem, realtype steptol); +SUNDIALS_EXPORT int IDASetMaxBacksIC(void *ida_mem, int maxbacks); + +/* Optional input functions */ +SUNDIALS_EXPORT int IDASetErrHandlerFn(void *ida_mem, IDAErrHandlerFn ehfun, + void *eh_data); +SUNDIALS_EXPORT int IDASetErrFile(void *ida_mem, FILE *errfp); +SUNDIALS_EXPORT int IDASetUserData(void *ida_mem, void *user_data); +SUNDIALS_EXPORT int IDASetMaxOrd(void *ida_mem, int maxord); +SUNDIALS_EXPORT int IDASetMaxNumSteps(void *ida_mem, long int mxsteps); +SUNDIALS_EXPORT int IDASetInitStep(void *ida_mem, realtype hin); +SUNDIALS_EXPORT int IDASetMaxStep(void *ida_mem, realtype hmax); +SUNDIALS_EXPORT int IDASetStopTime(void *ida_mem, realtype tstop); +SUNDIALS_EXPORT int IDASetNonlinConvCoef(void *ida_mem, realtype epcon); +SUNDIALS_EXPORT int IDASetMaxErrTestFails(void *ida_mem, int maxnef); +SUNDIALS_EXPORT int IDASetMaxNonlinIters(void *ida_mem, int maxcor); +SUNDIALS_EXPORT int IDASetMaxConvFails(void *ida_mem, int maxncf); +SUNDIALS_EXPORT int IDASetSuppressAlg(void *ida_mem, booleantype suppressalg); +SUNDIALS_EXPORT int IDASetId(void *ida_mem, N_Vector id); +SUNDIALS_EXPORT int IDASetConstraints(void *ida_mem, N_Vector constraints); + +SUNDIALS_EXPORT int IDASetNonlinearSolver(void *ida_mem, + SUNNonlinearSolver NLS); + +/* Rootfinding initialization function */ +SUNDIALS_EXPORT int IDARootInit(void *ida_mem, int nrtfn, IDARootFn g); + +/* Rootfinding optional input functions */ +SUNDIALS_EXPORT int IDASetRootDirection(void *ida_mem, int *rootdir); +SUNDIALS_EXPORT int IDASetNoInactiveRootWarn(void *ida_mem); + +/* Solver function */ +SUNDIALS_EXPORT int IDASolve(void *ida_mem, realtype tout, realtype *tret, + N_Vector yret, N_Vector ypret, int itask); + +/* Dense output function */ +SUNDIALS_EXPORT int IDAGetDky(void *ida_mem, realtype t, int k, N_Vector dky); + +/* Optional output functions */ +SUNDIALS_EXPORT int IDAGetWorkSpace(void *ida_mem, long int *lenrw, + long int *leniw); +SUNDIALS_EXPORT int IDAGetNumSteps(void *ida_mem, long int *nsteps); +SUNDIALS_EXPORT int IDAGetNumResEvals(void *ida_mem, long int *nrevals); +SUNDIALS_EXPORT int IDAGetNumLinSolvSetups(void *ida_mem, long int *nlinsetups); +SUNDIALS_EXPORT int IDAGetNumErrTestFails(void *ida_mem, long int *netfails); +SUNDIALS_EXPORT int IDAGetNumBacktrackOps(void *ida_mem, long int *nbacktr); +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 IDAGetActualInitStep(void *ida_mem, realtype *hinused); +SUNDIALS_EXPORT int IDAGetLastStep(void *ida_mem, realtype *hlast); +SUNDIALS_EXPORT int IDAGetCurrentStep(void *ida_mem, realtype *hcur); +SUNDIALS_EXPORT int IDAGetCurrentTime(void *ida_mem, realtype *tcur); +SUNDIALS_EXPORT int IDAGetTolScaleFactor(void *ida_mem, realtype *tolsfact); +SUNDIALS_EXPORT int IDAGetErrWeights(void *ida_mem, N_Vector eweight); +SUNDIALS_EXPORT int IDAGetEstLocalErrors(void *ida_mem, N_Vector ele); +SUNDIALS_EXPORT int IDAGetNumGEvals(void *ida_mem, long int *ngevals); +SUNDIALS_EXPORT int IDAGetRootInfo(void *ida_mem, int *rootsfound); +SUNDIALS_EXPORT int IDAGetIntegratorStats(void *ida_mem, long int *nsteps, + long int *nrevals, + long int *nlinsetups, + long int *netfails, + int *qlast, int *qcur, + realtype *hinused, realtype *hlast, + realtype *hcur, realtype *tcur); +SUNDIALS_EXPORT int IDAGetNumNonlinSolvIters(void *ida_mem, long int *nniters); +SUNDIALS_EXPORT int IDAGetNumNonlinSolvConvFails(void *ida_mem, + long int *nncfails); +SUNDIALS_EXPORT int IDAGetNonlinSolvStats(void *ida_mem, long int *nniters, + long int *nncfails); +SUNDIALS_EXPORT char *IDAGetReturnFlagName(long int flag); + +/* Free function */ +SUNDIALS_EXPORT void IDAFree(void **ida_mem); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/ida/ida_bbdpre.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/ida/ida_bbdpre.h new file mode 100644 index 0000000..0c99d1c --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/ida/ida_bbdpre.h @@ -0,0 +1,65 @@ +/* ----------------------------------------------------------------- + * 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 + * 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 IDABBDPRE module, for a + * band-block-diagonal preconditioner, i.e. a block-diagonal + * matrix with banded blocks. + * -----------------------------------------------------------------*/ + +#ifndef _IDABBDPRE_H +#define _IDABBDPRE_H + +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/* User-supplied function Types */ + +typedef int (*IDABBDLocalFn)(sunindextype Nlocal, realtype tt, + N_Vector yy, N_Vector yp, N_Vector gval, + void *user_data); + +typedef int (*IDABBDCommFn)(sunindextype Nlocal, realtype tt, + N_Vector yy, N_Vector yp, void *user_data); + +/* Exported Functions */ + +SUNDIALS_EXPORT int IDABBDPrecInit(void *ida_mem, sunindextype Nlocal, + sunindextype mudq, sunindextype mldq, + sunindextype mukeep, sunindextype mlkeep, + realtype dq_rel_yy, + IDABBDLocalFn Gres, IDABBDCommFn Gcomm); + +SUNDIALS_EXPORT int IDABBDPrecReInit(void *ida_mem, + sunindextype mudq, sunindextype mldq, + realtype dq_rel_yy); + +/* Optional output functions */ + +SUNDIALS_EXPORT int IDABBDPrecGetWorkSpace(void *ida_mem, + long int *lenrwBBDP, + long int *leniwBBDP); + +SUNDIALS_EXPORT int IDABBDPrecGetNumGfnEvals(void *ida_mem, + long int *ngevalsBBDP); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/ida/ida_direct.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/ida/ida_direct.h new file mode 100644 index 0000000..2545583 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/ida/ida_direct.h @@ -0,0 +1,61 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 + * ----------------------------------------------------------------- + * Header file for the deprecated direct linear solver interface in + * IDA; these routines now just wrap the updated IDA generic + * linear solver interface in ida_ls.h. + * -----------------------------------------------------------------*/ + +#ifndef _IDADLS_H +#define _IDADLS_H + +#include <ida/ida_ls.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*================================================================= + Function Types (typedefs for equivalent types in ida_ls.h) + =================================================================*/ + +typedef IDALsJacFn IDADlsJacFn; + +/*=================================================================== + Exported Functions (wrappers for equivalent routines in ida_ls.h) + ===================================================================*/ + +int IDADlsSetLinearSolver(void *ida_mem, SUNLinearSolver LS, + SUNMatrix A); + +int IDADlsSetJacFn(void *ida_mem, IDADlsJacFn jac); + +int IDADlsGetWorkSpace(void *ida_mem, long int *lenrwLS, + long int *leniwLS); + +int IDADlsGetNumJacEvals(void *ida_mem, long int *njevals); + +int IDADlsGetNumResEvals(void *ida_mem, long int *nrevalsLS); + +int IDADlsGetLastFlag(void *ida_mem, long int *flag); + +char *IDADlsGetReturnFlagName(long int flag); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/ida/ida_ls.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/ida/ida_ls.h new file mode 100644 index 0000000..3255b2d --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/ida/ida_ls.h @@ -0,0 +1,135 @@ +/* ---------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * Alan Hindmarsh, Radu Serban 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 IDA's linear solver interface. + * ----------------------------------------------------------------*/ + +#ifndef _IDALS_H +#define _IDALS_H + +#include <sundials/sundials_direct.h> +#include <sundials/sundials_iterative.h> +#include <sundials/sundials_linearsolver.h> +#include <sundials/sundials_matrix.h> +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*================================================================= + IDALS Constants + =================================================================*/ + +#define IDALS_SUCCESS 0 +#define IDALS_MEM_NULL -1 +#define IDALS_LMEM_NULL -2 +#define IDALS_ILL_INPUT -3 +#define IDALS_MEM_FAIL -4 +#define IDALS_PMEM_NULL -5 +#define IDALS_JACFUNC_UNRECVR -6 +#define IDALS_JACFUNC_RECVR -7 +#define IDALS_SUNMAT_FAIL -8 +#define IDALS_SUNLS_FAIL -9 + + +/*================================================================= + IDALS user-supplied function prototypes + =================================================================*/ + +typedef int (*IDALsJacFn)(realtype t, realtype c_j, N_Vector y, + N_Vector yp, N_Vector r, SUNMatrix Jac, + void *user_data, N_Vector tmp1, + N_Vector tmp2, N_Vector tmp3); + +typedef int (*IDALsPrecSetupFn)(realtype tt, N_Vector yy, + N_Vector yp, N_Vector rr, + realtype c_j, void *user_data); + +typedef int (*IDALsPrecSolveFn)(realtype tt, N_Vector yy, + N_Vector yp, N_Vector rr, + N_Vector rvec, N_Vector zvec, + realtype c_j, realtype delta, + void *user_data); + +typedef int (*IDALsJacTimesSetupFn)(realtype tt, N_Vector yy, + N_Vector yp, N_Vector rr, + realtype c_j, void *user_data); + +typedef int (*IDALsJacTimesVecFn)(realtype tt, N_Vector yy, + N_Vector yp, N_Vector rr, + N_Vector v, N_Vector Jv, + realtype c_j, void *user_data, + N_Vector tmp1, N_Vector tmp2); + + +/*================================================================= + IDALS Exported functions + =================================================================*/ + +SUNDIALS_EXPORT int IDASetLinearSolver(void *ida_mem, + SUNLinearSolver LS, + SUNMatrix A); + + +/*----------------------------------------------------------------- + Optional inputs to the IDALS linear solver interface + -----------------------------------------------------------------*/ + +SUNDIALS_EXPORT int IDASetJacFn(void *ida_mem, IDALsJacFn jac); +SUNDIALS_EXPORT int IDASetPreconditioner(void *ida_mem, + IDALsPrecSetupFn pset, + IDALsPrecSolveFn psolve); +SUNDIALS_EXPORT int IDASetJacTimes(void *ida_mem, + IDALsJacTimesSetupFn jtsetup, + IDALsJacTimesVecFn jtimes); +SUNDIALS_EXPORT int IDASetEpsLin(void *ida_mem, realtype eplifac); +SUNDIALS_EXPORT int IDASetIncrementFactor(void *ida_mem, + realtype dqincfac); + +/*----------------------------------------------------------------- + Optional outputs from the IDALS linear solver interface + -----------------------------------------------------------------*/ + +SUNDIALS_EXPORT int IDAGetLinWorkSpace(void *ida_mem, + long int *lenrwLS, + long int *leniwLS); +SUNDIALS_EXPORT int IDAGetNumJacEvals(void *ida_mem, + long int *njevals); +SUNDIALS_EXPORT int IDAGetNumPrecEvals(void *ida_mem, + long int *npevals); +SUNDIALS_EXPORT int IDAGetNumPrecSolves(void *ida_mem, + long int *npsolves); +SUNDIALS_EXPORT int IDAGetNumLinIters(void *ida_mem, + long int *nliters); +SUNDIALS_EXPORT int IDAGetNumLinConvFails(void *ida_mem, + long int *nlcfails); +SUNDIALS_EXPORT int IDAGetNumJTSetupEvals(void *ida_mem, + long int *njtsetups); +SUNDIALS_EXPORT int IDAGetNumJtimesEvals(void *ida_mem, + long int *njvevals); +SUNDIALS_EXPORT int IDAGetNumLinResEvals(void *ida_mem, + long int *nrevalsLS); +SUNDIALS_EXPORT int IDAGetLastLinFlag(void *ida_mem, + long int *flag); +SUNDIALS_EXPORT char *IDAGetLinReturnFlagName(long int flag); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/ida/ida_spils.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/ida/ida_spils.h new file mode 100644 index 0000000..2ec98da --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/ida/ida_spils.h @@ -0,0 +1,80 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * Alan Hindmarsh, Radu Serban 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 + * ----------------------------------------------------------------- + * Header file for the deprecated Scaled, Preconditioned Iterative + * Linear Solver interface in IDA; these routines now just wrap + * the updated IDA generic linear solver interface in ida_ls.h. + * -----------------------------------------------------------------*/ + +#ifndef _IDASPILS_H +#define _IDASPILS_H + +#include <ida/ida_ls.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*=============================================================== + Function Types (typedefs for equivalent types in ida_ls.h) + ===============================================================*/ + +typedef IDALsPrecSetupFn IDASpilsPrecSetupFn; +typedef IDALsPrecSolveFn IDASpilsPrecSolveFn; +typedef IDALsJacTimesSetupFn IDASpilsJacTimesSetupFn; +typedef IDALsJacTimesVecFn IDASpilsJacTimesVecFn; + +/*==================================================================== + Exported Functions (wrappers for equivalent routines in ida_ls.h) + ====================================================================*/ + +int IDASpilsSetLinearSolver(void *ida_mem, SUNLinearSolver LS); + +int IDASpilsSetPreconditioner(void *ida_mem, IDASpilsPrecSetupFn pset, + IDASpilsPrecSolveFn psolve); + +int IDASpilsSetJacTimes(void *ida_mem, IDASpilsJacTimesSetupFn jtsetup, + IDASpilsJacTimesVecFn jtimes); + +int IDASpilsSetEpsLin(void *ida_mem, realtype eplifac); + +int IDASpilsSetIncrementFactor(void *ida_mem, realtype dqincfac); + +int IDASpilsGetWorkSpace(void *ida_mem, long int *lenrwLS, long int *leniwLS); + +int IDASpilsGetNumPrecEvals(void *ida_mem, long int *npevals); + +int IDASpilsGetNumPrecSolves(void *ida_mem, long int *npsolves); + +int IDASpilsGetNumLinIters(void *ida_mem, long int *nliters); + +int IDASpilsGetNumConvFails(void *ida_mem, long int *nlcfails); + +int IDASpilsGetNumJTSetupEvals(void *ida_mem, long int *njtsetups); + +int IDASpilsGetNumJtimesEvals(void *ida_mem, long int *njvevals); + +int IDASpilsGetNumResEvals(void *ida_mem, long int *nrevalsLS); + +int IDASpilsGetLastFlag(void *ida_mem, long int *flag); + +char *IDASpilsGetReturnFlagName(long int flag); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/idas/idas.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/idas/idas.h new file mode 100644 index 0000000..af33c8d --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/idas/idas.h @@ -0,0 +1,581 @@ +/* ----------------------------------------------------------------- + * Programmer(s): 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 main IDAS solver. + * -----------------------------------------------------------------*/ + +#ifndef _IDAS_H +#define _IDAS_H + +#include <stdio.h> +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_nonlinearsolver.h> +#include <idas/idas_ls.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* ----------------- + * IDAS Constants + * ----------------- */ + +/* itask */ +#define IDA_NORMAL 1 +#define IDA_ONE_STEP 2 + +/* icopt */ +#define IDA_YA_YDP_INIT 1 +#define IDA_Y_INIT 2 + +/* ism */ +#define IDA_SIMULTANEOUS 1 +#define IDA_STAGGERED 2 + +/* DQtype */ +#define IDA_CENTERED 1 +#define IDA_FORWARD 2 + +/* interp */ +#define IDA_HERMITE 1 +#define IDA_POLYNOMIAL 2 + +/* return values */ + +#define IDA_SUCCESS 0 +#define IDA_TSTOP_RETURN 1 +#define IDA_ROOT_RETURN 2 + +#define IDA_WARNING 99 + +#define IDA_TOO_MUCH_WORK -1 +#define IDA_TOO_MUCH_ACC -2 +#define IDA_ERR_FAIL -3 +#define IDA_CONV_FAIL -4 + +#define IDA_LINIT_FAIL -5 +#define IDA_LSETUP_FAIL -6 +#define IDA_LSOLVE_FAIL -7 +#define IDA_RES_FAIL -8 +#define IDA_REP_RES_ERR -9 +#define IDA_RTFUNC_FAIL -10 +#define IDA_CONSTR_FAIL -11 + +#define IDA_FIRST_RES_FAIL -12 +#define IDA_LINESEARCH_FAIL -13 +#define IDA_NO_RECOVERY -14 +#define IDA_NLS_INIT_FAIL -15 +#define IDA_NLS_SETUP_FAIL -16 + +#define IDA_MEM_NULL -20 +#define IDA_MEM_FAIL -21 +#define IDA_ILL_INPUT -22 +#define IDA_NO_MALLOC -23 +#define IDA_BAD_EWT -24 +#define IDA_BAD_K -25 +#define IDA_BAD_T -26 +#define IDA_BAD_DKY -27 +#define IDA_VECTOROP_ERR -28 + +#define IDA_NO_QUAD -30 +#define IDA_QRHS_FAIL -31 +#define IDA_FIRST_QRHS_ERR -32 +#define IDA_REP_QRHS_ERR -33 + +#define IDA_NO_SENS -40 +#define IDA_SRES_FAIL -41 +#define IDA_REP_SRES_ERR -42 +#define IDA_BAD_IS -43 + +#define IDA_NO_QUADSENS -50 +#define IDA_QSRHS_FAIL -51 +#define IDA_FIRST_QSRHS_ERR -52 +#define IDA_REP_QSRHS_ERR -53 + +#define IDA_UNRECOGNIZED_ERROR -99 + +/* adjoint return values */ + +#define IDA_NO_ADJ -101 +#define IDA_NO_FWD -102 +#define IDA_NO_BCK -103 +#define IDA_BAD_TB0 -104 +#define IDA_REIFWD_FAIL -105 +#define IDA_FWD_FAIL -106 +#define IDA_GETY_BADT -107 + +/* ------------------------------ + * User-Supplied Function Types + * ------------------------------ */ + +typedef int (*IDAResFn)(realtype tt, N_Vector yy, N_Vector yp, + N_Vector rr, void *user_data); + +typedef int (*IDARootFn)(realtype t, N_Vector y, N_Vector yp, + realtype *gout, void *user_data); + +typedef int (*IDAEwtFn)(N_Vector y, N_Vector ewt, void *user_data); + +typedef void (*IDAErrHandlerFn)(int error_code, + const char *module, const char *function, + char *msg, void *user_data); + +typedef int (*IDAQuadRhsFn)(realtype tres, N_Vector yy, N_Vector yp, + N_Vector rrQ, void *user_data); + +typedef int (*IDASensResFn)(int Ns, realtype t, + N_Vector yy, N_Vector yp, N_Vector resval, + N_Vector *yyS, N_Vector *ypS, + N_Vector *resvalS, void *user_data, + N_Vector tmp1, N_Vector tmp2, N_Vector tmp3); + +typedef int (*IDAQuadSensRhsFn)(int Ns, realtype t, + N_Vector yy, N_Vector yp, + N_Vector *yyS, N_Vector *ypS, + N_Vector rrQ, N_Vector *rhsvalQS, + void *user_data, + N_Vector yytmp, N_Vector yptmp, N_Vector tmpQS); + +typedef int (*IDAResFnB)(realtype tt, + N_Vector yy, N_Vector yp, + N_Vector yyB, N_Vector ypB, + N_Vector rrB, void *user_dataB); + +typedef int (*IDAResFnBS)(realtype t, + N_Vector yy, N_Vector yp, + N_Vector *yyS, N_Vector *ypS, + N_Vector yyB, N_Vector ypB, + N_Vector rrBS, void *user_dataB); + +typedef int (*IDAQuadRhsFnB)(realtype tt, + N_Vector yy, N_Vector yp, + N_Vector yyB, N_Vector ypB, + N_Vector rhsvalBQ, void *user_dataB); + +typedef int (*IDAQuadRhsFnBS)(realtype t, + N_Vector yy, N_Vector yp, + N_Vector *yyS, N_Vector *ypS, + N_Vector yyB, N_Vector ypB, + N_Vector rhsvalBQS, void *user_dataB); + + +/* --------------------------------------- + * Exported Functions -- Forward Problems + * --------------------------------------- */ + +/* Initialization functions */ +SUNDIALS_EXPORT void *IDACreate(void); + +SUNDIALS_EXPORT int IDAInit(void *ida_mem, IDAResFn res, realtype t0, + N_Vector yy0, N_Vector yp0); +SUNDIALS_EXPORT int IDAReInit(void *ida_mem, realtype t0, N_Vector yy0, + N_Vector yp0); + +/* Tolerance input functions */ +SUNDIALS_EXPORT int IDASStolerances(void *ida_mem, realtype reltol, + realtype abstol); +SUNDIALS_EXPORT int IDASVtolerances(void *ida_mem, realtype reltol, + N_Vector abstol); +SUNDIALS_EXPORT int IDAWFtolerances(void *ida_mem, IDAEwtFn efun); + +/* Initial condition calculation function */ +SUNDIALS_EXPORT int IDACalcIC(void *ida_mem, int icopt, realtype tout1); + +/* Initial condition calculation optional input functions */ +SUNDIALS_EXPORT int IDASetNonlinConvCoefIC(void *ida_mem, realtype epiccon); +SUNDIALS_EXPORT int IDASetMaxNumStepsIC(void *ida_mem, int maxnh); +SUNDIALS_EXPORT int IDASetMaxNumJacsIC(void *ida_mem, int maxnj); +SUNDIALS_EXPORT int IDASetMaxNumItersIC(void *ida_mem, int maxnit); +SUNDIALS_EXPORT int IDASetLineSearchOffIC(void *ida_mem, booleantype lsoff); +SUNDIALS_EXPORT int IDASetStepToleranceIC(void *ida_mem, realtype steptol); +SUNDIALS_EXPORT int IDASetMaxBacksIC(void *ida_mem, int maxbacks); + +/* Optional input functions */ +SUNDIALS_EXPORT int IDASetErrHandlerFn(void *ida_mem, IDAErrHandlerFn ehfun, + void *eh_data); +SUNDIALS_EXPORT int IDASetErrFile(void *ida_mem, FILE *errfp); +SUNDIALS_EXPORT int IDASetUserData(void *ida_mem, void *user_data); +SUNDIALS_EXPORT int IDASetMaxOrd(void *ida_mem, int maxord); +SUNDIALS_EXPORT int IDASetMaxNumSteps(void *ida_mem, long int mxsteps); +SUNDIALS_EXPORT int IDASetInitStep(void *ida_mem, realtype hin); +SUNDIALS_EXPORT int IDASetMaxStep(void *ida_mem, realtype hmax); +SUNDIALS_EXPORT int IDASetStopTime(void *ida_mem, realtype tstop); +SUNDIALS_EXPORT int IDASetNonlinConvCoef(void *ida_mem, realtype epcon); +SUNDIALS_EXPORT int IDASetMaxErrTestFails(void *ida_mem, int maxnef); +SUNDIALS_EXPORT int IDASetMaxNonlinIters(void *ida_mem, int maxcor); +SUNDIALS_EXPORT int IDASetMaxConvFails(void *ida_mem, int maxncf); +SUNDIALS_EXPORT int IDASetSuppressAlg(void *ida_mem, booleantype suppressalg); +SUNDIALS_EXPORT int IDASetId(void *ida_mem, N_Vector id); +SUNDIALS_EXPORT int IDASetConstraints(void *ida_mem, N_Vector constraints); + +SUNDIALS_EXPORT int IDASetNonlinearSolver(void *ida_mem, + SUNNonlinearSolver NLS); + +/* Rootfinding initialization function */ +SUNDIALS_EXPORT int IDARootInit(void *ida_mem, int nrtfn, IDARootFn g); + +/* Rootfinding optional input functions */ +SUNDIALS_EXPORT int IDASetRootDirection(void *ida_mem, int *rootdir); +SUNDIALS_EXPORT int IDASetNoInactiveRootWarn(void *ida_mem); + +/* Solver function */ +SUNDIALS_EXPORT int IDASolve(void *ida_mem, realtype tout, realtype *tret, + N_Vector yret, N_Vector ypret, int itask); + +/* Dense output function */ +SUNDIALS_EXPORT int IDAGetDky(void *ida_mem, realtype t, int k, N_Vector dky); + +/* Optional output functions */ +SUNDIALS_EXPORT int IDAGetWorkSpace(void *ida_mem, long int *lenrw, + long int *leniw); +SUNDIALS_EXPORT int IDAGetNumSteps(void *ida_mem, long int *nsteps); +SUNDIALS_EXPORT int IDAGetNumResEvals(void *ida_mem, long int *nrevals); +SUNDIALS_EXPORT int IDAGetNumLinSolvSetups(void *ida_mem, long int *nlinsetups); +SUNDIALS_EXPORT int IDAGetNumErrTestFails(void *ida_mem, long int *netfails); +SUNDIALS_EXPORT int IDAGetNumBacktrackOps(void *ida_mem, long int *nbacktr); +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 IDAGetActualInitStep(void *ida_mem, realtype *hinused); +SUNDIALS_EXPORT int IDAGetLastStep(void *ida_mem, realtype *hlast); +SUNDIALS_EXPORT int IDAGetCurrentStep(void *ida_mem, realtype *hcur); +SUNDIALS_EXPORT int IDAGetCurrentTime(void *ida_mem, realtype *tcur); +SUNDIALS_EXPORT int IDAGetTolScaleFactor(void *ida_mem, realtype *tolsfact); +SUNDIALS_EXPORT int IDAGetErrWeights(void *ida_mem, N_Vector eweight); +SUNDIALS_EXPORT int IDAGetEstLocalErrors(void *ida_mem, N_Vector ele); +SUNDIALS_EXPORT int IDAGetNumGEvals(void *ida_mem, long int *ngevals); +SUNDIALS_EXPORT int IDAGetRootInfo(void *ida_mem, int *rootsfound); +SUNDIALS_EXPORT int IDAGetIntegratorStats(void *ida_mem, long int *nsteps, + long int *nrevals, + long int *nlinsetups, + long int *netfails, + int *qlast, int *qcur, + realtype *hinused, realtype *hlast, + realtype *hcur, realtype *tcur); +SUNDIALS_EXPORT int IDAGetNumNonlinSolvIters(void *ida_mem, long int *nniters); +SUNDIALS_EXPORT int IDAGetNumNonlinSolvConvFails(void *ida_mem, + long int *nncfails); +SUNDIALS_EXPORT int IDAGetNonlinSolvStats(void *ida_mem, long int *nniters, + long int *nncfails); +SUNDIALS_EXPORT char *IDAGetReturnFlagName(long int flag); + +/* Free function */ +SUNDIALS_EXPORT void IDAFree(void **ida_mem); + + +/* --------------------------------- + * Exported Functions -- Quadrature + * --------------------------------- */ + +/* Initialization functions */ +SUNDIALS_EXPORT int IDAQuadInit(void *ida_mem, IDAQuadRhsFn rhsQ, N_Vector yQ0); +SUNDIALS_EXPORT int IDAQuadReInit(void *ida_mem, N_Vector yQ0); + +/* Tolerance input functions */ +SUNDIALS_EXPORT int IDAQuadSStolerances(void *ida_mem, realtype reltolQ, + realtype abstolQ); +SUNDIALS_EXPORT int IDAQuadSVtolerances(void *ida_mem, realtype reltolQ, + N_Vector abstolQ); + +/* Optional input specification functions */ +SUNDIALS_EXPORT int IDASetQuadErrCon(void *ida_mem, booleantype errconQ); + +/* Extraction and dense output functions */ +SUNDIALS_EXPORT int IDAGetQuad(void *ida_mem, realtype *t, N_Vector yQout); +SUNDIALS_EXPORT int IDAGetQuadDky(void *ida_mem, realtype t, int k, + N_Vector dky); + +/* Optional output specification functions */ +SUNDIALS_EXPORT int IDAGetQuadNumRhsEvals(void *ida_mem, long int *nrhsQevals); +SUNDIALS_EXPORT int IDAGetQuadNumErrTestFails(void *ida_mem, + long int *nQetfails); +SUNDIALS_EXPORT int IDAGetQuadErrWeights(void *ida_mem, N_Vector eQweight); +SUNDIALS_EXPORT int IDAGetQuadStats(void *ida_mem, long int *nrhsQevals, + long int *nQetfails); + +/* Free function */ +SUNDIALS_EXPORT void IDAQuadFree(void *ida_mem); + + +/* ------------------------------------ + * Exported Functions -- Sensitivities + * ------------------------------------ */ + +/* Initialization functions */ +SUNDIALS_EXPORT int IDASensInit(void *ida_mem, int Ns, int ism, + IDASensResFn resS, N_Vector *yS0, + N_Vector *ypS0); +SUNDIALS_EXPORT int IDASensReInit(void *ida_mem, int ism, N_Vector *yS0, + N_Vector *ypS0); + +/* Tolerance input functions */ +SUNDIALS_EXPORT int IDASensSStolerances(void *ida_mem, realtype reltolS, + realtype *abstolS); +SUNDIALS_EXPORT int IDASensSVtolerances(void *ida_mem, realtype reltolS, + N_Vector *abstolS); +SUNDIALS_EXPORT int IDASensEEtolerances(void *ida_mem); + +/* Initial condition calculation function */ +SUNDIALS_EXPORT int IDAGetSensConsistentIC(void *ida_mem, N_Vector *yyS0, + N_Vector *ypS0); + +/* Optional input specification functions */ +SUNDIALS_EXPORT int IDASetSensDQMethod(void *ida_mem, int DQtype, + realtype DQrhomax); +SUNDIALS_EXPORT int IDASetSensErrCon(void *ida_mem, booleantype errconS); +SUNDIALS_EXPORT int IDASetSensMaxNonlinIters(void *ida_mem, int maxcorS); +SUNDIALS_EXPORT int IDASetSensParams(void *ida_mem, realtype *p, realtype *pbar, + int *plist); + +/* Integrator nonlinear solver specification functions */ +SUNDIALS_EXPORT int IDASetNonlinearSolverSensSim(void *ida_mem, + SUNNonlinearSolver NLS); +SUNDIALS_EXPORT int IDASetNonlinearSolverSensStg(void *ida_mem, + SUNNonlinearSolver NLS); + +/* Enable/disable sensitivities */ +SUNDIALS_EXPORT int IDASensToggleOff(void *ida_mem); + +/* Extraction and dense output functions */ +SUNDIALS_EXPORT int IDAGetSens(void *ida_mem, realtype *tret, N_Vector *yySout); +SUNDIALS_EXPORT int IDAGetSens1(void *ida_mem, realtype *tret, int is, + N_Vector yySret); + +SUNDIALS_EXPORT int IDAGetSensDky(void *ida_mem, realtype t, int k, + N_Vector *dkyS); +SUNDIALS_EXPORT int IDAGetSensDky1(void *ida_mem, realtype t, int k, int is, + N_Vector dkyS); + +/* Optional output specification functions */ +SUNDIALS_EXPORT int IDAGetSensNumResEvals(void *ida_mem, long int *nresSevals); +SUNDIALS_EXPORT int IDAGetNumResEvalsSens(void *ida_mem, long int *nresevalsS); +SUNDIALS_EXPORT int IDAGetSensNumErrTestFails(void *ida_mem, + long int *nSetfails); +SUNDIALS_EXPORT int IDAGetSensNumLinSolvSetups(void *ida_mem, + long int *nlinsetupsS); +SUNDIALS_EXPORT int IDAGetSensErrWeights(void *ida_mem, N_Vector_S eSweight); +SUNDIALS_EXPORT int IDAGetSensStats(void *ida_mem, long int *nresSevals, + long int *nresevalsS, long int *nSetfails, + long int *nlinsetupsS); +SUNDIALS_EXPORT int IDAGetSensNumNonlinSolvIters(void *ida_mem, + long int *nSniters); +SUNDIALS_EXPORT int IDAGetSensNumNonlinSolvConvFails(void *ida_mem, + long int *nSncfails); +SUNDIALS_EXPORT int IDAGetSensNonlinSolvStats(void *ida_mem, + long int *nSniters, + long int *nSncfails); + +/* Free function */ +SUNDIALS_EXPORT void IDASensFree(void *ida_mem); + + +/* ------------------------------------------------------- + * Exported Functions -- Sensitivity dependent quadrature + * ------------------------------------------------------- */ + +/* Initialization functions */ +SUNDIALS_EXPORT int IDAQuadSensInit(void *ida_mem, IDAQuadSensRhsFn resQS, + N_Vector *yQS0); +SUNDIALS_EXPORT int IDAQuadSensReInit(void *ida_mem, N_Vector *yQS0); + +/* Tolerance input functions */ +SUNDIALS_EXPORT int IDAQuadSensSStolerances(void *ida_mem, realtype reltolQS, + realtype *abstolQS); +SUNDIALS_EXPORT int IDAQuadSensSVtolerances(void *ida_mem, realtype reltolQS, + N_Vector *abstolQS); +SUNDIALS_EXPORT int IDAQuadSensEEtolerances(void *ida_mem); + +/* Optional input specification functions */ +SUNDIALS_EXPORT int IDASetQuadSensErrCon(void *ida_mem, booleantype errconQS); + +/* Extraction and dense output functions */ +SUNDIALS_EXPORT int IDAGetQuadSens(void *ida_mem, realtype *tret, + N_Vector *yyQSout); +SUNDIALS_EXPORT int IDAGetQuadSens1(void *ida_mem, realtype *tret, int is, + N_Vector yyQSret); +SUNDIALS_EXPORT int IDAGetQuadSensDky(void *ida_mem, realtype t, int k, + N_Vector *dkyQS); +SUNDIALS_EXPORT int IDAGetQuadSensDky1(void *ida_mem, realtype t, int k, int is, + N_Vector dkyQS); + +/* Optional output specification functions */ +SUNDIALS_EXPORT int IDAGetQuadSensNumRhsEvals(void *ida_mem, + long int *nrhsQSevals); +SUNDIALS_EXPORT int IDAGetQuadSensNumErrTestFails(void *ida_mem, + long int *nQSetfails); +SUNDIALS_EXPORT int IDAGetQuadSensErrWeights(void *ida_mem, + N_Vector *eQSweight); +SUNDIALS_EXPORT int IDAGetQuadSensStats(void *ida_mem, + long int *nrhsQSevals, + long int *nQSetfails); + +/* Free function */ +SUNDIALS_EXPORT void IDAQuadSensFree(void* ida_mem); + + +/* ---------------------------------------- + * Exported Functions -- Backward Problems + * ---------------------------------------- */ + +/* Initialization functions */ + +SUNDIALS_EXPORT int IDAAdjInit(void *ida_mem, long int steps, int interp); + +SUNDIALS_EXPORT int IDAAdjReInit(void *ida_mem); + +SUNDIALS_EXPORT void IDAAdjFree(void *ida_mem); + +/* Backward Problem Setup Functions */ + +SUNDIALS_EXPORT int IDACreateB(void *ida_mem, int *which); + +SUNDIALS_EXPORT int IDAInitB(void *ida_mem, int which, IDAResFnB resB, + realtype tB0, N_Vector yyB0, N_Vector ypB0); + +SUNDIALS_EXPORT int IDAInitBS(void *ida_mem, int which, IDAResFnBS resS, + realtype tB0, N_Vector yyB0, N_Vector ypB0); + +SUNDIALS_EXPORT int IDAReInitB(void *ida_mem, int which, + realtype tB0, N_Vector yyB0, N_Vector ypB0); + +SUNDIALS_EXPORT int IDASStolerancesB(void *ida_mem, int which, + realtype relTolB, realtype absTolB); +SUNDIALS_EXPORT int IDASVtolerancesB(void *ida_mem, int which, + realtype relTolB, N_Vector absTolB); + +SUNDIALS_EXPORT int IDAQuadInitB(void *ida_mem, int which, + IDAQuadRhsFnB rhsQB, N_Vector yQB0); + +SUNDIALS_EXPORT int IDAQuadInitBS(void *ida_mem, int which, + IDAQuadRhsFnBS rhsQS, N_Vector yQB0); + +SUNDIALS_EXPORT int IDAQuadReInitB(void *ida_mem, int which, N_Vector yQB0); + +SUNDIALS_EXPORT int IDAQuadSStolerancesB(void *ida_mem, int which, + realtype reltolQB, realtype abstolQB); +SUNDIALS_EXPORT int IDAQuadSVtolerancesB(void *ida_mem, int which, + realtype reltolQB, N_Vector abstolQB); + +/* Consistent IC calculation functions */ + +SUNDIALS_EXPORT int IDACalcICB (void *ida_mem, int which, realtype tout1, + N_Vector yy0, N_Vector yp0); + +SUNDIALS_EXPORT int IDACalcICBS(void *ida_mem, int which, realtype tout1, + N_Vector yy0, N_Vector yp0, + N_Vector *yyS0, N_Vector *ypS0); + +/* Solver Function For Forward Problems */ + +SUNDIALS_EXPORT int IDASolveF(void *ida_mem, realtype tout, + realtype *tret, + N_Vector yret, N_Vector ypret, + int itask, int *ncheckPtr); + +/* Solver Function For Backward Problems */ + +SUNDIALS_EXPORT int IDASolveB(void *ida_mem, realtype tBout, int itaskB); + +/* Optional Input Functions For Adjoint Problems */ + +SUNDIALS_EXPORT int IDAAdjSetNoSensi(void *ida_mem); + +SUNDIALS_EXPORT int IDASetUserDataB(void *ida_mem, int which, void *user_dataB); +SUNDIALS_EXPORT int IDASetMaxOrdB(void *ida_mem, int which, int maxordB); +SUNDIALS_EXPORT int IDASetMaxNumStepsB(void *ida_mem, int which, + long int mxstepsB); +SUNDIALS_EXPORT int IDASetInitStepB(void *ida_mem, int which, realtype hinB); +SUNDIALS_EXPORT int IDASetMaxStepB(void *ida_mem, int which, realtype hmaxB); +SUNDIALS_EXPORT int IDASetSuppressAlgB(void *ida_mem, int which, + booleantype suppressalgB); +SUNDIALS_EXPORT int IDASetIdB(void *ida_mem, int which, N_Vector idB); +SUNDIALS_EXPORT int IDASetConstraintsB(void *ida_mem, int which, + N_Vector constraintsB); +SUNDIALS_EXPORT int IDASetQuadErrConB(void *ida_mem, int which, int errconQB); + +SUNDIALS_EXPORT int IDASetNonlinearSolverB(void *ida_mem, int which, + SUNNonlinearSolver NLS); + +/* Extraction And Dense Output Functions For Backward Problems */ + +SUNDIALS_EXPORT int IDAGetB(void* ida_mem, int which, realtype *tret, + N_Vector yy, N_Vector yp); +SUNDIALS_EXPORT int IDAGetQuadB(void *ida_mem, int which, + realtype *tret, N_Vector qB); + +/* Optional Output Functions For Backward Problems */ + +SUNDIALS_EXPORT void *IDAGetAdjIDABmem(void *ida_mem, int which); + +SUNDIALS_EXPORT int IDAGetConsistentICB(void *ida_mem, int which, + N_Vector yyB0, N_Vector ypB0); + +SUNDIALS_EXPORT int IDAGetAdjY(void *ida_mem, realtype t, + N_Vector yy, N_Vector yp); + +typedef struct { + void *my_addr; + void *next_addr; + realtype t0; + realtype t1; + long int nstep; + int order; + realtype step; +} IDAadjCheckPointRec; + +SUNDIALS_EXPORT int IDAGetAdjCheckPointsInfo(void *ida_mem, + IDAadjCheckPointRec *ckpnt); + + +/* Undocumented Optional Output Functions For Backward Problems */ + +/* ----------------------------------------------------------------- + * IDAGetAdjDataPointHermite + * ----------------------------------------------------------------- + * Returns the 2 vectors stored for cubic Hermite interpolation + * at the data point 'which'. The user must allocate space for + * yy and yd. Returns IDA_MEM_NULL if ida_mem is NULL, + * IDA_ILL_INPUT if the interpolation type previously specified + * is not IDA_HERMITE, or IDA_SUCCESS otherwise. + * ----------------------------------------------------------------- + * IDAGetAdjDataPointPolynomial + * ----------------------------------------------------------------- + * Returns the vector stored for polynomial interpolation + * at the data point 'which'. The user must allocate space for + * y. Returns IDA_MEM_NULL if ida_mem is NULL, IDA_ILL_INPUT if + * the interpolation type previously specified is not + * IDA_POLYNOMIAL, or IDA_SUCCESS otherwise. + * ----------------------------------------------------------------- */ + +SUNDIALS_EXPORT int IDAGetAdjDataPointHermite(void *ida_mem, int which, + realtype *t, N_Vector yy, + N_Vector yd); + +SUNDIALS_EXPORT int IDAGetAdjDataPointPolynomial(void *ida_mem, int which, + realtype *t, int *order, + N_Vector y); + +/* ----------------------------------------------------------------- + * IDAGetAdjCurrentCheckPoint + * Returns the address of the 'active' check point. + * ----------------------------------------------------------------- */ + +SUNDIALS_EXPORT int IDAGetAdjCurrentCheckPoint(void *ida_mem, void **addr); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/idas/idas_bbdpre.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/idas/idas_bbdpre.h new file mode 100644 index 0000000..3e956c0 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/idas/idas_bbdpre.h @@ -0,0 +1,96 @@ +/* ----------------------------------------------------------------- + * 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 + * 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 IDABBDPRE module, for a + * band-block-diagonal preconditioner, i.e. a block-diagonal + * matrix with banded blocks. + * -----------------------------------------------------------------*/ + +#ifndef _IDASBBDPRE_H +#define _IDASBBDPRE_H + +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*----------------- + FORWARD PROBLEMS + -----------------*/ + +/* User-supplied function Types */ + +typedef int (*IDABBDLocalFn)(sunindextype Nlocal, realtype tt, + N_Vector yy, N_Vector yp, N_Vector gval, + void *user_data); + +typedef int (*IDABBDCommFn)(sunindextype Nlocal, realtype tt, + N_Vector yy, N_Vector yp, void *user_data); + +/* Exported Functions */ + +SUNDIALS_EXPORT int IDABBDPrecInit(void *ida_mem, sunindextype Nlocal, + sunindextype mudq, sunindextype mldq, + sunindextype mukeep, sunindextype mlkeep, + realtype dq_rel_yy, + IDABBDLocalFn Gres, IDABBDCommFn Gcomm); + +SUNDIALS_EXPORT int IDABBDPrecReInit(void *ida_mem, + sunindextype mudq, sunindextype mldq, + realtype dq_rel_yy); + +/* Optional output functions */ + +SUNDIALS_EXPORT int IDABBDPrecGetWorkSpace(void *ida_mem, + long int *lenrwBBDP, + long int *leniwBBDP); + +SUNDIALS_EXPORT int IDABBDPrecGetNumGfnEvals(void *ida_mem, + long int *ngevalsBBDP); + + +/*------------------ + BACKWARD PROBLEMS + ------------------*/ + +/* User-Supplied Function Types */ + +typedef int (*IDABBDLocalFnB)(sunindextype NlocalB, realtype tt, + N_Vector yy, N_Vector yp, + N_Vector yyB, N_Vector ypB, + N_Vector gvalB, void *user_dataB); + +typedef int (*IDABBDCommFnB)(sunindextype NlocalB, realtype tt, + N_Vector yy, N_Vector yp, + N_Vector yyB, N_Vector ypB, void *user_dataB); + +/* Exported Functions */ + +SUNDIALS_EXPORT int IDABBDPrecInitB(void *ida_mem, int which, sunindextype NlocalB, + sunindextype mudqB, sunindextype mldqB, + sunindextype mukeepB, sunindextype mlkeepB, + realtype dq_rel_yyB, + IDABBDLocalFnB GresB, IDABBDCommFnB GcommB); + +SUNDIALS_EXPORT int IDABBDPrecReInitB(void *ida_mem, int which, + sunindextype mudqB, sunindextype mldqB, + realtype dq_rel_yyB); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/idas/idas_direct.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/idas/idas_direct.h new file mode 100644 index 0000000..74df9ed --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/idas/idas_direct.h @@ -0,0 +1,70 @@ +/* ----------------------------------------------------------------- + * Programmer(s): 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 + * ----------------------------------------------------------------- + * Header file for the deprecated direct linear solver interface in + * IDA; these routines now just wrap the updated IDA generic + * linear solver interface in idas_ls.h. + * -----------------------------------------------------------------*/ + +#ifndef _IDADLS_H +#define _IDADLS_H + +#include <idas/idas_ls.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*================================================================= + Function Types (typedefs for equivalent types in ida_ls.h) + =================================================================*/ + +typedef IDALsJacFn IDADlsJacFn; +typedef IDALsJacFnB IDADlsJacFnB; +typedef IDALsJacFnBS IDADlsJacFnBS; + +/*=================================================================== + Exported Functions (wrappers for equivalent routines in idas_ls.h) + ===================================================================*/ + +int IDADlsSetLinearSolver(void *ida_mem, SUNLinearSolver LS, + SUNMatrix A); + +int IDADlsSetJacFn(void *ida_mem, IDADlsJacFn jac); + +int IDADlsGetWorkSpace(void *ida_mem, long int *lenrwLS, + long int *leniwLS); + +int IDADlsGetNumJacEvals(void *ida_mem, long int *njevals); + +int IDADlsGetNumResEvals(void *ida_mem, long int *nrevalsLS); + +int IDADlsGetLastFlag(void *ida_mem, long int *flag); + +char *IDADlsGetReturnFlagName(long int flag); + +int IDADlsSetLinearSolverB(void *ida_mem, int which, + SUNLinearSolver LS, SUNMatrix A); + +int IDADlsSetJacFnB(void *ida_mem, int which, IDADlsJacFnB jacB); + +int IDADlsSetJacFnBS(void *ida_mem, int which, IDADlsJacFnBS jacBS); + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/idas/idas_ls.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/idas/idas_ls.h new file mode 100644 index 0000000..eed5c19 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/idas/idas_ls.h @@ -0,0 +1,255 @@ +/* ---------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 IDAS' linear solver interface. + * ----------------------------------------------------------------*/ + +#ifndef _IDASLS_H +#define _IDASLS_H + +#include <sundials/sundials_direct.h> +#include <sundials/sundials_iterative.h> +#include <sundials/sundials_linearsolver.h> +#include <sundials/sundials_matrix.h> +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*================================================================= + IDALS Constants + =================================================================*/ + +#define IDALS_SUCCESS 0 +#define IDALS_MEM_NULL -1 +#define IDALS_LMEM_NULL -2 +#define IDALS_ILL_INPUT -3 +#define IDALS_MEM_FAIL -4 +#define IDALS_PMEM_NULL -5 +#define IDALS_JACFUNC_UNRECVR -6 +#define IDALS_JACFUNC_RECVR -7 +#define IDALS_SUNMAT_FAIL -8 +#define IDALS_SUNLS_FAIL -9 + +/* Return values for the adjoint module */ +#define IDALS_NO_ADJ -101 +#define IDALS_LMEMB_NULL -102 + + +/*================================================================= + Forward problems + =================================================================*/ + +/*================================================================= + IDALS user-supplied function prototypes + =================================================================*/ + +typedef int (*IDALsJacFn)(realtype t, realtype c_j, N_Vector y, + N_Vector yp, N_Vector r, SUNMatrix Jac, + void *user_data, N_Vector tmp1, + N_Vector tmp2, N_Vector tmp3); + +typedef int (*IDALsPrecSetupFn)(realtype tt, N_Vector yy, + N_Vector yp, N_Vector rr, + realtype c_j, void *user_data); + +typedef int (*IDALsPrecSolveFn)(realtype tt, N_Vector yy, + N_Vector yp, N_Vector rr, + N_Vector rvec, N_Vector zvec, + realtype c_j, realtype delta, + void *user_data); + +typedef int (*IDALsJacTimesSetupFn)(realtype tt, N_Vector yy, + N_Vector yp, N_Vector rr, + realtype c_j, void *user_data); + +typedef int (*IDALsJacTimesVecFn)(realtype tt, N_Vector yy, + N_Vector yp, N_Vector rr, + N_Vector v, N_Vector Jv, + realtype c_j, void *user_data, + N_Vector tmp1, N_Vector tmp2); + + +/*================================================================= + IDALS Exported functions + =================================================================*/ + +SUNDIALS_EXPORT int IDASetLinearSolver(void *ida_mem, + SUNLinearSolver LS, + SUNMatrix A); + + +/*----------------------------------------------------------------- + Optional inputs to the IDALS linear solver interface + -----------------------------------------------------------------*/ + +SUNDIALS_EXPORT int IDASetJacFn(void *ida_mem, IDALsJacFn jac); +SUNDIALS_EXPORT int IDASetPreconditioner(void *ida_mem, + IDALsPrecSetupFn pset, + IDALsPrecSolveFn psolve); +SUNDIALS_EXPORT int IDASetJacTimes(void *ida_mem, + IDALsJacTimesSetupFn jtsetup, + IDALsJacTimesVecFn jtimes); +SUNDIALS_EXPORT int IDASetEpsLin(void *ida_mem, realtype eplifac); +SUNDIALS_EXPORT int IDASetIncrementFactor(void *ida_mem, + realtype dqincfac); + +/*----------------------------------------------------------------- + Optional outputs from the IDALS linear solver interface + -----------------------------------------------------------------*/ + +SUNDIALS_EXPORT int IDAGetLinWorkSpace(void *ida_mem, + long int *lenrwLS, + long int *leniwLS); +SUNDIALS_EXPORT int IDAGetNumJacEvals(void *ida_mem, + long int *njevals); +SUNDIALS_EXPORT int IDAGetNumPrecEvals(void *ida_mem, + long int *npevals); +SUNDIALS_EXPORT int IDAGetNumPrecSolves(void *ida_mem, + long int *npsolves); +SUNDIALS_EXPORT int IDAGetNumLinIters(void *ida_mem, + long int *nliters); +SUNDIALS_EXPORT int IDAGetNumLinConvFails(void *ida_mem, + long int *nlcfails); +SUNDIALS_EXPORT int IDAGetNumJTSetupEvals(void *ida_mem, + long int *njtsetups); +SUNDIALS_EXPORT int IDAGetNumJtimesEvals(void *ida_mem, + long int *njvevals); +SUNDIALS_EXPORT int IDAGetNumLinResEvals(void *ida_mem, + long int *nrevalsLS); +SUNDIALS_EXPORT int IDAGetLastLinFlag(void *ida_mem, + long int *flag); +SUNDIALS_EXPORT char *IDAGetLinReturnFlagName(long int flag); + + +/*================================================================= + Backward problems + =================================================================*/ + +/*================================================================= + IDALS user-supplied function prototypes + =================================================================*/ + +typedef int (*IDALsJacFnB)(realtype tt, realtype c_jB, N_Vector yy, + N_Vector yp, N_Vector yyB, N_Vector ypB, + N_Vector rrB, SUNMatrix JacB, + void *user_dataB, N_Vector tmp1B, + N_Vector tmp2B, N_Vector tmp3B); + +typedef int (*IDALsJacFnBS)(realtype tt, realtype c_jB, N_Vector yy, + N_Vector yp, N_Vector *yS, N_Vector *ypS, + N_Vector yyB, N_Vector ypB, N_Vector rrB, + SUNMatrix JacB, void *user_dataB, + N_Vector tmp1B, N_Vector tmp2B, + N_Vector tmp3B); + +typedef int (*IDALsPrecSetupFnB)(realtype tt, N_Vector yy, + N_Vector yp, N_Vector yyB, + N_Vector ypB, N_Vector rrB, + realtype c_jB, void *user_dataB); + +typedef int (*IDALsPrecSetupFnBS)(realtype tt, N_Vector yy, + N_Vector yp, N_Vector *yyS, + N_Vector *ypS, N_Vector yyB, + N_Vector ypB, N_Vector rrB, + realtype c_jB, void *user_dataB); + +typedef int (*IDALsPrecSolveFnB)(realtype tt, N_Vector yy, + N_Vector yp, N_Vector yyB, + N_Vector ypB, N_Vector rrB, + N_Vector rvecB, N_Vector zvecB, + realtype c_jB, realtype deltaB, + void *user_dataB); + +typedef int (*IDALsPrecSolveFnBS)(realtype tt, N_Vector yy, + N_Vector yp, N_Vector *yyS, + N_Vector *ypS, N_Vector yyB, + N_Vector ypB, N_Vector rrB, + N_Vector rvecB, N_Vector zvecB, + realtype c_jB, realtype deltaB, + void *user_dataB); + +typedef int (*IDALsJacTimesSetupFnB)(realtype t, N_Vector yy, + N_Vector yp, N_Vector yyB, + N_Vector ypB, N_Vector rrB, + realtype c_jB, void *user_dataB); + +typedef int (*IDALsJacTimesSetupFnBS)(realtype t, N_Vector yy, + N_Vector yp, N_Vector *yyS, + N_Vector *ypS, N_Vector yyB, + N_Vector ypB, N_Vector rrB, + realtype c_jB, void *user_dataB); + +typedef int (*IDALsJacTimesVecFnB)(realtype t, N_Vector yy, + N_Vector yp, N_Vector yyB, + N_Vector ypB, N_Vector rrB, + N_Vector vB, N_Vector JvB, + realtype c_jB, void *user_dataB, + N_Vector tmp1B, N_Vector tmp2B); + +typedef int (*IDALsJacTimesVecFnBS)(realtype t, N_Vector yy, + N_Vector yp, N_Vector *yyS, + N_Vector *ypS, N_Vector yyB, + N_Vector ypB, N_Vector rrB, + N_Vector vB, N_Vector JvB, + realtype c_jB, void *user_dataB, + N_Vector tmp1B, N_Vector tmp2B); + + +/*================================================================= + IDALS Exported functions + =================================================================*/ + +SUNDIALS_EXPORT int IDASetLinearSolverB(void *ida_mem, + int which, + SUNLinearSolver LS, + SUNMatrix A); + +/*----------------------------------------------------------------- + Each IDASet***B or IDASet***BS function below links the + main IDAS integrator with the corresponding IDALS + optional input function for the backward integration. + The 'which' argument is the int returned by IDACreateB. + -----------------------------------------------------------------*/ + +SUNDIALS_EXPORT int IDASetJacFnB(void *ida_mem, int which, + IDALsJacFnB jacB); +SUNDIALS_EXPORT int IDASetJacFnBS(void *ida_mem, int which, + IDALsJacFnBS jacBS); + +SUNDIALS_EXPORT int IDASetEpsLinB(void *ida_mem, int which, + realtype eplifacB); +SUNDIALS_EXPORT int IDASetIncrementFactorB(void *ida_mem, int which, + realtype dqincfacB); +SUNDIALS_EXPORT int IDASetPreconditionerB(void *ida_mem, int which, + IDALsPrecSetupFnB psetB, + IDALsPrecSolveFnB psolveB); +SUNDIALS_EXPORT int IDASetPreconditionerBS(void *ida_mem, int which, + IDALsPrecSetupFnBS psetBS, + IDALsPrecSolveFnBS psolveBS); +SUNDIALS_EXPORT int IDASetJacTimesB(void *ida_mem, int which, + IDALsJacTimesSetupFnB jtsetupB, + IDALsJacTimesVecFnB jtimesB); +SUNDIALS_EXPORT int IDASetJacTimesBS(void *ida_mem, int which, + IDALsJacTimesSetupFnBS jtsetupBS, + IDALsJacTimesVecFnBS jtimesBS); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/idas/idas_spils.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/idas/idas_spils.h new file mode 100644 index 0000000..e7ef52e --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/idas/idas_spils.h @@ -0,0 +1,111 @@ +/* ----------------------------------------------------------------- + * Programmer(s): 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 + * ----------------------------------------------------------------- + * Header file for the deprecated Scaled, Preconditioned Iterative + * Linear Solver interface in IDAS; these routines now just wrap + * the updated IDA generic linear solver interface in idas_ls.h. + * -----------------------------------------------------------------*/ + +#ifndef _IDASSPILS_H +#define _IDASSPILS_H + +#include <idas/idas_ls.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*=============================================================== + Function Types (typedefs for equivalent types in idas_ls.h) + ===============================================================*/ + +typedef IDALsPrecSetupFn IDASpilsPrecSetupFn; +typedef IDALsPrecSolveFn IDASpilsPrecSolveFn; +typedef IDALsJacTimesSetupFn IDASpilsJacTimesSetupFn; +typedef IDALsJacTimesVecFn IDASpilsJacTimesVecFn; +typedef IDALsPrecSetupFnB IDASpilsPrecSetupFnB; +typedef IDALsPrecSetupFnBS IDASpilsPrecSetupFnBS; +typedef IDALsPrecSolveFnB IDASpilsPrecSolveFnB; +typedef IDALsPrecSolveFnBS IDASpilsPrecSolveFnBS; +typedef IDALsJacTimesSetupFnB IDASpilsJacTimesSetupFnB; +typedef IDALsJacTimesSetupFnBS IDASpilsJacTimesSetupFnBS; +typedef IDALsJacTimesVecFnB IDASpilsJacTimesVecFnB; +typedef IDALsJacTimesVecFnBS IDASpilsJacTimesVecFnBS; + +/*==================================================================== + Exported Functions (wrappers for equivalent routines in idas_ls.h) + ====================================================================*/ + +int IDASpilsSetLinearSolver(void *ida_mem, SUNLinearSolver LS); + +int IDASpilsSetPreconditioner(void *ida_mem, IDASpilsPrecSetupFn pset, + IDASpilsPrecSolveFn psolve); + +int IDASpilsSetJacTimes(void *ida_mem, IDASpilsJacTimesSetupFn jtsetup, + IDASpilsJacTimesVecFn jtimes); + +int IDASpilsSetEpsLin(void *ida_mem, realtype eplifac); + +int IDASpilsSetIncrementFactor(void *ida_mem, realtype dqincfac); + +int IDASpilsGetWorkSpace(void *ida_mem, long int *lenrwLS, long int *leniwLS); + +int IDASpilsGetNumPrecEvals(void *ida_mem, long int *npevals); + +int IDASpilsGetNumPrecSolves(void *ida_mem, long int *npsolves); + +int IDASpilsGetNumLinIters(void *ida_mem, long int *nliters); + +int IDASpilsGetNumConvFails(void *ida_mem, long int *nlcfails); + +int IDASpilsGetNumJTSetupEvals(void *ida_mem, long int *njtsetups); + +int IDASpilsGetNumJtimesEvals(void *ida_mem, long int *njvevals); + +int IDASpilsGetNumResEvals(void *ida_mem, long int *nrevalsLS); + +int IDASpilsGetLastFlag(void *ida_mem, long int *flag); + +char *IDASpilsGetReturnFlagName(long int flag); + +int IDASpilsSetLinearSolverB(void *ida_mem, int which, + SUNLinearSolver LS); + +int IDASpilsSetEpsLinB(void *ida_mem, int which, realtype eplifacB); + +int IDASpilsSetIncrementFactorB(void *ida_mem, int which, + realtype dqincfacB); + +int IDASpilsSetPreconditionerB(void *ida_mem, int which, + IDASpilsPrecSetupFnB psetB, + IDASpilsPrecSolveFnB psolveB); + +int IDASpilsSetPreconditionerBS(void *ida_mem, int which, + IDASpilsPrecSetupFnBS psetBS, + IDASpilsPrecSolveFnBS psolveBS); + +int IDASpilsSetJacTimesB(void *ida_mem, int which, + IDASpilsJacTimesSetupFnB jtsetupB, + IDASpilsJacTimesVecFnB jtimesB); + +int IDASpilsSetJacTimesBS(void *ida_mem, int which, + IDASpilsJacTimesSetupFnBS jtsetupBS, + IDASpilsJacTimesVecFnBS jtimesBS); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/kinsol/kinsol.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/kinsol/kinsol.h new file mode 100644 index 0000000..fa8a372 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/kinsol/kinsol.h @@ -0,0 +1,149 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Allan Taylor, Alan Hindmarsh, Radu Serban, 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 main KINSOL solver. + * -----------------------------------------------------------------*/ + +#ifndef _KINSOL_H +#define _KINSOL_H + +#include <stdio.h> +#include <sundials/sundials_nvector.h> +#include <kinsol/kinsol_ls.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* ----------------- + * KINSOL Constants + * ----------------- */ + +/* return values */ + +#define KIN_SUCCESS 0 +#define KIN_INITIAL_GUESS_OK 1 +#define KIN_STEP_LT_STPTOL 2 + +#define KIN_WARNING 99 + +#define KIN_MEM_NULL -1 +#define KIN_ILL_INPUT -2 +#define KIN_NO_MALLOC -3 +#define KIN_MEM_FAIL -4 +#define KIN_LINESEARCH_NONCONV -5 +#define KIN_MAXITER_REACHED -6 +#define KIN_MXNEWT_5X_EXCEEDED -7 +#define KIN_LINESEARCH_BCFAIL -8 +#define KIN_LINSOLV_NO_RECOVERY -9 +#define KIN_LINIT_FAIL -10 +#define KIN_LSETUP_FAIL -11 +#define KIN_LSOLVE_FAIL -12 + +#define KIN_SYSFUNC_FAIL -13 +#define KIN_FIRST_SYSFUNC_ERR -14 +#define KIN_REPTD_SYSFUNC_ERR -15 + +#define KIN_VECTOROP_ERR -16 + +/* Enumeration for eta choice */ +#define KIN_ETACHOICE1 1 +#define KIN_ETACHOICE2 2 +#define KIN_ETACONSTANT 3 + +/* Enumeration for global strategy */ +#define KIN_NONE 0 +#define KIN_LINESEARCH 1 +#define KIN_PICARD 2 +#define KIN_FP 3 + +/* ------------------------------ + * User-Supplied Function Types + * ------------------------------ */ + +typedef int (*KINSysFn)(N_Vector uu, N_Vector fval, void *user_data ); + +typedef void (*KINErrHandlerFn)(int error_code, + const char *module, const char *function, + char *msg, void *user_data); + +typedef void (*KINInfoHandlerFn)(const char *module, const char *function, + char *msg, void *user_data); + +/* ------------------- + * Exported Functions + * ------------------- */ + +/* Creation function */ +SUNDIALS_EXPORT void *KINCreate(void); + +/* Initialization function */ +SUNDIALS_EXPORT int KINInit(void *kinmem, KINSysFn func, N_Vector tmpl); + +/* Solver function */ +SUNDIALS_EXPORT int KINSol(void *kinmem, N_Vector uu, int strategy, + N_Vector u_scale, N_Vector f_scale); + +/* Optional input functions */ +SUNDIALS_EXPORT int KINSetErrHandlerFn(void *kinmem, KINErrHandlerFn ehfun, + void *eh_data); +SUNDIALS_EXPORT int KINSetErrFile(void *kinmem, FILE *errfp); +SUNDIALS_EXPORT int KINSetInfoHandlerFn(void *kinmem, KINInfoHandlerFn ihfun, + void *ih_data); +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 KINSetNumMaxIters(void *kinmem, long int mxiter); +SUNDIALS_EXPORT int KINSetNoInitSetup(void *kinmem, booleantype noInitSetup); +SUNDIALS_EXPORT int KINSetNoResMon(void *kinmem, booleantype noNNIResMon); +SUNDIALS_EXPORT int KINSetMaxSetupCalls(void *kinmem, long int msbset); +SUNDIALS_EXPORT int KINSetMaxSubSetupCalls(void *kinmem, long int msbsetsub); +SUNDIALS_EXPORT int KINSetEtaForm(void *kinmem, int etachoice); +SUNDIALS_EXPORT int KINSetEtaConstValue(void *kinmem, realtype eta); +SUNDIALS_EXPORT int KINSetEtaParams(void *kinmem, realtype egamma, + realtype ealpha); +SUNDIALS_EXPORT int KINSetResMonParams(void *kinmem, realtype omegamin, + realtype omegamax); +SUNDIALS_EXPORT int KINSetResMonConstValue(void *kinmem, realtype omegaconst); +SUNDIALS_EXPORT int KINSetNoMinEps(void *kinmem, booleantype noMinEps); +SUNDIALS_EXPORT int KINSetMaxNewtonStep(void *kinmem, realtype mxnewtstep); +SUNDIALS_EXPORT int KINSetMaxBetaFails(void *kinmem, long int mxnbcf); +SUNDIALS_EXPORT int KINSetRelErrFunc(void *kinmem, realtype relfunc); +SUNDIALS_EXPORT int KINSetFuncNormTol(void *kinmem, realtype fnormtol); +SUNDIALS_EXPORT int KINSetScaledStepTol(void *kinmem, realtype scsteptol); +SUNDIALS_EXPORT int KINSetConstraints(void *kinmem, N_Vector constraints); +SUNDIALS_EXPORT int KINSetSysFunc(void *kinmem, KINSysFn func); + + +/* Optional output functions */ +SUNDIALS_EXPORT int KINGetWorkSpace(void *kinmem, long int *lenrw, + long int *leniw); +SUNDIALS_EXPORT int KINGetNumNonlinSolvIters(void *kinmem, long int *nniters); +SUNDIALS_EXPORT int KINGetNumFuncEvals(void *kinmem, long int *nfevals); +SUNDIALS_EXPORT int KINGetNumBetaCondFails(void *kinmem, long int *nbcfails); +SUNDIALS_EXPORT int KINGetNumBacktrackOps(void *kinmem, long int *nbacktr); +SUNDIALS_EXPORT int KINGetFuncNorm(void *kinmem, realtype *fnorm); +SUNDIALS_EXPORT int KINGetStepLength(void *kinmem, realtype *steplength); +SUNDIALS_EXPORT char *KINGetReturnFlagName(long int flag); + +/* Free function */ +SUNDIALS_EXPORT void KINFree(void **kinmem); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/kinsol/kinsol_bbdpre.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/kinsol/kinsol_bbdpre.h new file mode 100644 index 0000000..bbc6910 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/kinsol/kinsol_bbdpre.h @@ -0,0 +1,66 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * Alan Hindmarsh, Radu Serban, 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 KINBBDPRE module, for a + * band-block-diagonal preconditioner, i.e. a block-diagonal + * matrix with banded blocks. + * -----------------------------------------------------------------*/ + +#ifndef _KINBBDPRE_H +#define _KINBBDPRE_H + +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* KINBBDPRE return values */ + +#define KINBBDPRE_SUCCESS 0 +#define KINBBDPRE_PDATA_NULL -11 +#define KINBBDPRE_FUNC_UNRECVR -12 + +/* User-supplied function Types */ + +typedef int (*KINBBDCommFn)(sunindextype Nlocal, N_Vector u, + void *user_data); + +typedef int (*KINBBDLocalFn)(sunindextype Nlocal, N_Vector uu, + N_Vector gval, void *user_data); + +/* Exported Functions */ + +SUNDIALS_EXPORT int KINBBDPrecInit(void *kinmem, sunindextype Nlocal, + sunindextype mudq, sunindextype mldq, + sunindextype mukeep, sunindextype mlkeep, + realtype dq_rel_uu, + KINBBDLocalFn gloc, KINBBDCommFn gcomm); + +/* Optional output functions */ + +SUNDIALS_EXPORT int KINBBDPrecGetWorkSpace(void *kinmem, + long int *lenrwBBDP, + long int *leniwBBDP); + +SUNDIALS_EXPORT int KINBBDPrecGetNumGfnEvals(void *kinmem, + long int *ngevalsBBDP); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/kinsol/kinsol_direct.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/kinsol/kinsol_direct.h new file mode 100644 index 0000000..c7e1ce7 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/kinsol/kinsol_direct.h @@ -0,0 +1,59 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 + * ----------------------------------------------------------------- + * Header file for the deprecated direct linear solver interface in + * KINSOL; these routines now just wrap the updated KINSOL generic + * linear solver interface in kinsol_ls.h. + * -----------------------------------------------------------------*/ + +#ifndef _KINDLS_H +#define _KINDLS_H + +#include <kinsol/kinsol_ls.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*================================================================= + Function Types (typedefs for equivalent types in kinsol_ls.h) + =================================================================*/ + +typedef KINLsJacFn KINDlsJacFn; + +/*=================================================================== + Exported Functions (wrappers for equivalent routines in kinsol_ls.h) + ===================================================================*/ + +int KINDlsSetLinearSolver(void *kinmem, SUNLinearSolver LS, SUNMatrix A); + +int KINDlsSetJacFn(void *kinmem, KINDlsJacFn jac); + +int KINDlsGetWorkSpace(void *kinmem, long int *lenrw, long int *leniw); + +int KINDlsGetNumJacEvals(void *kinmem, long int *njevals); + +int KINDlsGetNumFuncEvals(void *kinmem, long int *nfevals); + +int KINDlsGetLastFlag(void *kinmem, long int *flag); + +char *KINDlsGetReturnFlagName(long int flag); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/kinsol/kinsol_ls.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/kinsol/kinsol_ls.h new file mode 100644 index 0000000..27a8ea4 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/kinsol/kinsol_ls.h @@ -0,0 +1,119 @@ +/* ---------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * Scott Cohen, Alan Hindmarsh, Radu Serban, 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 KINSOL's linear solver interface. + * ----------------------------------------------------------------*/ + +#ifndef _KINLS_H +#define _KINLS_H + +#include <sundials/sundials_direct.h> +#include <sundials/sundials_iterative.h> +#include <sundials/sundials_linearsolver.h> +#include <sundials/sundials_matrix.h> +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*================================================================== + KINLS Constants + ==================================================================*/ + +#define KINLS_SUCCESS 0 + +#define KINLS_MEM_NULL -1 +#define KINLS_LMEM_NULL -2 +#define KINLS_ILL_INPUT -3 +#define KINLS_MEM_FAIL -4 +#define KINLS_PMEM_NULL -5 +#define KINLS_JACFUNC_ERR -6 +#define KINLS_SUNMAT_FAIL -7 +#define KINLS_SUNLS_FAIL -8 + + +/*=============================================================== + KINLS user-supplied function prototypes + ===============================================================*/ + +typedef int (*KINLsJacFn)(N_Vector u, N_Vector fu, SUNMatrix J, + void *user_data, N_Vector tmp1, N_Vector tmp2); + +typedef int (*KINLsPrecSetupFn)(N_Vector uu, N_Vector uscale, + N_Vector fval, N_Vector fscale, + void *user_data); + +typedef int (*KINLsPrecSolveFn)(N_Vector uu, N_Vector uscale, + N_Vector fval, N_Vector fscale, + N_Vector vv, void *user_data); + +typedef int (*KINLsJacTimesVecFn)(N_Vector v, N_Vector Jv, N_Vector uu, + booleantype *new_uu, void *J_data); + + +/*================================================================== + KINLS Exported functions + ==================================================================*/ + +SUNDIALS_EXPORT int KINSetLinearSolver(void *kinmem, SUNLinearSolver LS, + SUNMatrix A); + + +/*----------------------------------------------------------------- + Optional inputs to the KINLS linear solver interface + -----------------------------------------------------------------*/ + +SUNDIALS_EXPORT int KINSetJacFn(void *kinmem, KINLsJacFn jac); +SUNDIALS_EXPORT int KINSetPreconditioner(void *kinmem, + KINLsPrecSetupFn psetup, + KINLsPrecSolveFn psolve); +SUNDIALS_EXPORT int KINSetJacTimesVecFn(void *kinmem, + KINLsJacTimesVecFn jtv); + +/*----------------------------------------------------------------- + Optional outputs from the KINLS linear solver interface + -----------------------------------------------------------------*/ + +SUNDIALS_EXPORT int KINGetLinWorkSpace(void *kinmem, + long int *lenrwLS, + long int *leniwLS); +SUNDIALS_EXPORT int KINGetNumJacEvals(void *kinmem, + long int *njevals); +SUNDIALS_EXPORT int KINGetNumLinFuncEvals(void *kinmem, + long int *nfevals); +SUNDIALS_EXPORT int KINGetNumPrecEvals(void *kinmem, + long int *npevals); +SUNDIALS_EXPORT int KINGetNumPrecSolves(void *kinmem, + long int *npsolves); +SUNDIALS_EXPORT int KINGetNumLinIters(void *kinmem, + long int *nliters); +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); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/kinsol/kinsol_spils.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/kinsol/kinsol_spils.h new file mode 100644 index 0000000..a20731d --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/kinsol/kinsol_spils.h @@ -0,0 +1,73 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * Scott Cohen, Alan Hindmarsh, Radu Serban, + * 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 + * ----------------------------------------------------------------- + * Header file for the deprecated Scaled Preconditioned Iterative + * Linear Solver interface in KINSOL; these routines now just wrap + * the updated KINSOL generic linear solver interface in kinsol_ls.h. + * -----------------------------------------------------------------*/ + +#ifndef _KINSPILS_H +#define _KINSPILS_H + +#include <kinsol/kinsol_ls.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*=============================================================== + Function Types (typedefs for equivalent types in kinsol_ls.h) + ===============================================================*/ + +typedef KINLsPrecSetupFn KINSpilsPrecSetupFn; +typedef KINLsPrecSolveFn KINSpilsPrecSolveFn; +typedef KINLsJacTimesVecFn KINSpilsJacTimesVecFn; + +/*==================================================================== + Exported Functions (wrappers for equivalent routines in kinsol_ls.h) + ====================================================================*/ + +int KINSpilsSetLinearSolver(void *kinmem, SUNLinearSolver LS); + +int KINSpilsSetPreconditioner(void *kinmem, KINSpilsPrecSetupFn psetup, + KINSpilsPrecSolveFn psolve); + +int KINSpilsSetJacTimesVecFn(void *kinmem, KINSpilsJacTimesVecFn jtv); + +int KINSpilsGetWorkSpace(void *kinmem, long int *lenrwLS, long int *leniwLS); + +int KINSpilsGetNumPrecEvals(void *kinmem, long int *npevals); + +int KINSpilsGetNumPrecSolves(void *kinmem, long int *npsolves); + +int KINSpilsGetNumLinIters(void *kinmem, long int *nliters); + +int KINSpilsGetNumConvFails(void *kinmem, long int *nlcfails); + +int KINSpilsGetNumJtimesEvals(void *kinmem, long int *njvevals); + +int KINSpilsGetNumFuncEvals(void *kinmem, long int *nfevals); + +int KINSpilsGetLastFlag(void *kinmem, long int *flag); + +char *KINSpilsGetReturnFlagName(long int flag); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_cuda.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_cuda.h new file mode 100644 index 0000000..c78989c --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_cuda.h @@ -0,0 +1,180 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Slaven Peles and 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 is the header file for the 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 <stdio.h> +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_config.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* + * ----------------------------------------------------------------- + * 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_cuda + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT N_Vector N_VNew_Cuda(sunindextype length); + +SUNDIALS_EXPORT N_Vector N_VNewManaged_Cuda(sunindextype length); + +SUNDIALS_EXPORT N_Vector N_VNewEmpty_Cuda(); + +SUNDIALS_EXPORT N_Vector N_VMake_Cuda(sunindextype length, + realtype *h_vdata, + realtype *d_vdata); + +SUNDIALS_EXPORT N_Vector N_VMakeManaged_Cuda(sunindextype length, + realtype *vdata); + +SUNDIALS_EXPORT sunindextype N_VGetLength_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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_mpicuda.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_mpicuda.h new file mode 100644 index 0000000..b51b8e6 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_mpicuda.h @@ -0,0 +1,194 @@ +/* ----------------------------------------------------------------- + * 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 <mpi.h> +#include <stdio.h> + +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_config.h> + +#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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_mpiraja.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_mpiraja.h new file mode 100644 index 0000000..4915ea1 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_mpiraja.h @@ -0,0 +1,180 @@ +/* ----------------------------------------------------------------- + * 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 <mpi.h> +#include <stdio.h> + +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_config.h> + +#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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_openmp.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_openmp.h new file mode 100644 index 0000000..00d2c8a --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_openmp.h @@ -0,0 +1,197 @@ +/* ----------------------------------------------------------------- + * 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 + * @ 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 OpenMP 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 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_OpenMP(a,x,b,y,y); + * + * (which stores the result of the operation a*x+b*y in y) + * is legal. + * -----------------------------------------------------------------*/ + +#ifndef _NVECTOR_OPENMP_H +#define _NVECTOR_OPENMP_H + +#include <stdio.h> +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* + * ----------------------------------------------------------------- + * OpenMP implementation of N_Vector + * ----------------------------------------------------------------- + */ + +struct _N_VectorContent_OpenMP { + sunindextype length; /* vector length */ + booleantype own_data; /* data ownership flag */ + realtype *data; /* data array */ + int num_threads; /* number of OpenMP threads */ +}; + +typedef struct _N_VectorContent_OpenMP *N_VectorContent_OpenMP; + +/* + * ----------------------------------------------------------------- + * Macros NV_CONTENT_OMP, NV_DATA_OMP, NV_OWN_DATA_OMP, + * NV_LENGTH_OMP, and NV_Ith_OMP + * ----------------------------------------------------------------- + */ + +#define NV_CONTENT_OMP(v) ( (N_VectorContent_OpenMP)(v->content) ) + +#define NV_LENGTH_OMP(v) ( NV_CONTENT_OMP(v)->length ) + +#define NV_NUM_THREADS_OMP(v) ( NV_CONTENT_OMP(v)->num_threads ) + +#define NV_OWN_DATA_OMP(v) ( NV_CONTENT_OMP(v)->own_data ) + +#define NV_DATA_OMP(v) ( NV_CONTENT_OMP(v)->data ) + +#define NV_Ith_OMP(v,i) ( NV_DATA_OMP(v)[i] ) + +/* + * ----------------------------------------------------------------- + * Functions exported by nvector_openmp + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT N_Vector N_VNew_OpenMP(sunindextype vec_length, int num_threads); + +SUNDIALS_EXPORT N_Vector N_VNewEmpty_OpenMP(sunindextype vec_length, int num_threads); + +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_VCloneVectorArrayEmpty_OpenMP(int count, N_Vector w); + +SUNDIALS_EXPORT void N_VDestroyVectorArray_OpenMP(N_Vector *vs, int count); + +SUNDIALS_EXPORT sunindextype N_VGetLength_OpenMP(N_Vector v); + +SUNDIALS_EXPORT void N_VPrint_OpenMP(N_Vector v); + +SUNDIALS_EXPORT void N_VPrintFile_OpenMP(N_Vector v, FILE *outfile); + + +SUNDIALS_EXPORT N_Vector_ID N_VGetVectorID_OpenMP(N_Vector v); +SUNDIALS_EXPORT N_Vector N_VCloneEmpty_OpenMP(N_Vector w); +SUNDIALS_EXPORT N_Vector N_VClone_OpenMP(N_Vector w); +SUNDIALS_EXPORT void N_VDestroy_OpenMP(N_Vector v); +SUNDIALS_EXPORT void N_VSpace_OpenMP(N_Vector v, sunindextype *lrw, sunindextype *liw); +SUNDIALS_EXPORT realtype *N_VGetArrayPointer_OpenMP(N_Vector v); +SUNDIALS_EXPORT void N_VSetArrayPointer_OpenMP(realtype *v_data, N_Vector v); + +/* standard vector operations */ +SUNDIALS_EXPORT void N_VLinearSum_OpenMP(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VConst_OpenMP(realtype c, N_Vector z); +SUNDIALS_EXPORT void N_VProd_OpenMP(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VDiv_OpenMP(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VScale_OpenMP(realtype c, N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAbs_OpenMP(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VInv_OpenMP(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAddConst_OpenMP(N_Vector x, realtype b, N_Vector z); +SUNDIALS_EXPORT realtype N_VDotProd_OpenMP(N_Vector x, N_Vector y); +SUNDIALS_EXPORT realtype N_VMaxNorm_OpenMP(N_Vector x); +SUNDIALS_EXPORT realtype N_VWrmsNorm_OpenMP(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWrmsNormMask_OpenMP(N_Vector x, N_Vector w, N_Vector id); +SUNDIALS_EXPORT realtype N_VMin_OpenMP(N_Vector x); +SUNDIALS_EXPORT realtype N_VWL2Norm_OpenMP(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VL1Norm_OpenMP(N_Vector x); +SUNDIALS_EXPORT void N_VCompare_OpenMP(realtype c, N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VInvTest_OpenMP(N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VConstrMask_OpenMP(N_Vector c, N_Vector x, N_Vector m); +SUNDIALS_EXPORT realtype N_VMinQuotient_OpenMP(N_Vector num, N_Vector denom); + +/* fused vector operations */ +SUNDIALS_EXPORT int N_VLinearCombination_OpenMP(int nvec, realtype* c, + N_Vector* V, N_Vector z); +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); + +/* vector array operations */ +SUNDIALS_EXPORT int N_VLinearSumVectorArray_OpenMP(int nvec, + realtype a, N_Vector* X, + realtype b, N_Vector* Y, + N_Vector* Z); +SUNDIALS_EXPORT int N_VScaleVectorArray_OpenMP(int nvec, realtype* c, + N_Vector* X, N_Vector* Z); +SUNDIALS_EXPORT int N_VConstVectorArray_OpenMP(int nvecs, realtype c, + N_Vector* Z); +SUNDIALS_EXPORT int N_VWrmsNormVectorArray_OpenMP(int nvecs, N_Vector* X, + N_Vector* W, realtype* nrm); +SUNDIALS_EXPORT int N_VWrmsNormMaskVectorArray_OpenMP(int nvecs, N_Vector* X, + N_Vector* W, N_Vector id, + realtype* nrm); +SUNDIALS_EXPORT int N_VScaleAddMultiVectorArray_OpenMP(int nvec, int nsum, + realtype* a, + N_Vector* X, + N_Vector** Y, + N_Vector** Z); +SUNDIALS_EXPORT int N_VLinearCombinationVectorArray_OpenMP(int nvec, int nsum, + realtype* c, + N_Vector** X, + N_Vector* Z); + +/* + * ----------------------------------------------------------------- + * Enable / disable fused vector operations + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT int N_VEnableFusedOps_OpenMP(N_Vector v, booleantype tf); + +SUNDIALS_EXPORT int N_VEnableLinearCombination_OpenMP(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleAddMulti_OpenMP(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableDotProdMulti_OpenMP(N_Vector v, booleantype tf); + +SUNDIALS_EXPORT int N_VEnableLinearSumVectorArray_OpenMP(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleVectorArray_OpenMP(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableConstVectorArray_OpenMP(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableWrmsNormVectorArray_OpenMP(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableWrmsNormMaskVectorArray_OpenMP(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleAddMultiVectorArray_OpenMP(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableLinearCombinationVectorArray_OpenMP(N_Vector v, booleantype tf); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_openmpdev.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_openmpdev.h new file mode 100644 index 0000000..250b57c --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_openmpdev.h @@ -0,0 +1,201 @@ +/* ------------------------------------------------------------------- + * Programmer(s): David J. Gardner and Shelby Lockhart @ LLNL + * ------------------------------------------------------------------- + * 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 + * 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 OpenMP 4.5+ 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 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_OpenMPDEV(a,x,b,y,y); + * + * (which stores the result of the operation a*x+b*y in y) + * is legal. + * -----------------------------------------------------------------*/ + +#ifndef _NVECTOR_OPENMP_H +#define _NVECTOR_OPENMP_H + +#include <stdio.h> +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* + * ----------------------------------------------------------------- + * OpenMPDEV implementation of N_Vector + * ----------------------------------------------------------------- + */ + +struct _N_VectorContent_OpenMPDEV { + sunindextype length; /* vector length */ + booleantype own_data; /* data ownership flag */ + realtype *host_data; /* host data array */ + realtype *dev_data; /* device data array */ +}; + +typedef struct _N_VectorContent_OpenMPDEV *N_VectorContent_OpenMPDEV; + +/* + * ----------------------------------------------------------------- + * Macros NV_CONTENT_OMPDEV, NV_DATA_HOST_OMPDEV, NV_OWN_DATA_OMPDEV, + * NV_LENGTH_OMPDEV, and NV_Ith_OMPDEV + * ----------------------------------------------------------------- + */ + +#define NV_CONTENT_OMPDEV(v) ( (N_VectorContent_OpenMPDEV)(v->content) ) + +#define NV_LENGTH_OMPDEV(v) ( NV_CONTENT_OMPDEV(v)->length ) + +#define NV_OWN_DATA_OMPDEV(v) ( NV_CONTENT_OMPDEV(v)->own_data ) + +#define NV_DATA_HOST_OMPDEV(v) ( NV_CONTENT_OMPDEV(v)->host_data ) + +#define NV_DATA_DEV_OMPDEV(v) ( NV_CONTENT_OMPDEV(v)->dev_data ) + +/* + * ----------------------------------------------------------------- + * Functions exported by nvector_openmpdev + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT N_Vector N_VNew_OpenMPDEV(sunindextype vec_length); + +SUNDIALS_EXPORT N_Vector N_VNewEmpty_OpenMPDEV(sunindextype vec_length); + +SUNDIALS_EXPORT N_Vector N_VMake_OpenMPDEV(sunindextype vec_length, + realtype *h_data, + realtype *v_data); + +SUNDIALS_EXPORT N_Vector *N_VCloneVectorArray_OpenMPDEV(int count, N_Vector w); + +SUNDIALS_EXPORT N_Vector *N_VCloneVectorArrayEmpty_OpenMPDEV(int count, N_Vector w); + +SUNDIALS_EXPORT void N_VDestroyVectorArray_OpenMPDEV(N_Vector *vs, int count); + +SUNDIALS_EXPORT sunindextype N_VGetLength_OpenMPDEV(N_Vector v); + +SUNDIALS_EXPORT realtype *N_VGetHostArrayPointer_OpenMPDEV(N_Vector v); + +SUNDIALS_EXPORT realtype *N_VGetDeviceArrayPointer_OpenMPDEV(N_Vector v); + +SUNDIALS_EXPORT void N_VPrint_OpenMPDEV(N_Vector v); + +SUNDIALS_EXPORT void N_VPrintFile_OpenMPDEV(N_Vector v, FILE *outfile); + +SUNDIALS_EXPORT void N_VCopyToDevice_OpenMPDEV(N_Vector v); + +SUNDIALS_EXPORT void N_VCopyFromDevice_OpenMPDEV(N_Vector v); + +SUNDIALS_EXPORT N_Vector_ID N_VGetVectorID_OpenMPDEV(N_Vector v); +SUNDIALS_EXPORT N_Vector N_VCloneEmpty_OpenMPDEV(N_Vector w); +SUNDIALS_EXPORT N_Vector N_VClone_OpenMPDEV(N_Vector w); +SUNDIALS_EXPORT void N_VDestroy_OpenMPDEV(N_Vector v); +SUNDIALS_EXPORT void N_VSpace_OpenMPDEV(N_Vector v, sunindextype *lrw, sunindextype *liw); + +/* standard vector operations */ +SUNDIALS_EXPORT void N_VLinearSum_OpenMPDEV(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VConst_OpenMPDEV(realtype c, N_Vector z); +SUNDIALS_EXPORT void N_VProd_OpenMPDEV(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VDiv_OpenMPDEV(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VScale_OpenMPDEV(realtype c, N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAbs_OpenMPDEV(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VInv_OpenMPDEV(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAddConst_OpenMPDEV(N_Vector x, realtype b, N_Vector z); +SUNDIALS_EXPORT realtype N_VDotProd_OpenMPDEV(N_Vector x, N_Vector y); +SUNDIALS_EXPORT realtype N_VMaxNorm_OpenMPDEV(N_Vector x); +SUNDIALS_EXPORT realtype N_VWrmsNorm_OpenMPDEV(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWrmsNormMask_OpenMPDEV(N_Vector x, N_Vector w, N_Vector id); +SUNDIALS_EXPORT realtype N_VMin_OpenMPDEV(N_Vector x); +SUNDIALS_EXPORT realtype N_VWL2Norm_OpenMPDEV(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VL1Norm_OpenMPDEV(N_Vector x); +SUNDIALS_EXPORT void N_VCompare_OpenMPDEV(realtype c, N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VInvTest_OpenMPDEV(N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VConstrMask_OpenMPDEV(N_Vector c, N_Vector x, N_Vector m); +SUNDIALS_EXPORT realtype N_VMinQuotient_OpenMPDEV(N_Vector num, N_Vector denom); + +/* fused vector operations */ +SUNDIALS_EXPORT int N_VLinearCombination_OpenMPDEV(int nvec, realtype* c, + N_Vector* V, N_Vector z); +SUNDIALS_EXPORT int N_VScaleAddMulti_OpenMPDEV(int nvec, realtype* a, N_Vector x, + N_Vector* Y, N_Vector* Z); +SUNDIALS_EXPORT int N_VDotProdMulti_OpenMPDEV(int nvec, N_Vector x, + N_Vector *Y, realtype* dotprods); + +/* vector array operations */ +SUNDIALS_EXPORT int N_VLinearSumVectorArray_OpenMPDEV(int nvec, + realtype a, N_Vector* X, + realtype b, N_Vector* Y, + N_Vector* Z); +SUNDIALS_EXPORT int N_VScaleVectorArray_OpenMPDEV(int nvec, realtype* c, + N_Vector* X, N_Vector* Z); +SUNDIALS_EXPORT int N_VConstVectorArray_OpenMPDEV(int nvecs, realtype c, + N_Vector* Z); +SUNDIALS_EXPORT int N_VWrmsNormVectorArray_OpenMPDEV(int nvecs, N_Vector* X, + N_Vector* W, realtype* nrm); +SUNDIALS_EXPORT int N_VWrmsNormMaskVectorArray_OpenMPDEV(int nvecs, N_Vector* X, + N_Vector* W, N_Vector id, + realtype* nrm); +SUNDIALS_EXPORT int N_VScaleAddMultiVectorArray_OpenMPDEV(int nvec, int nsum, + realtype* a, + N_Vector* X, + N_Vector** Y, + N_Vector** Z); +SUNDIALS_EXPORT int N_VLinearCombinationVectorArray_OpenMPDEV(int nvec, int nsum, + realtype* c, + N_Vector** X, + N_Vector* Z); + +/* + * ----------------------------------------------------------------- + * Enable / disable fused vector operations + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT int N_VEnableFusedOps_OpenMPDEV(N_Vector v, booleantype tf); + +SUNDIALS_EXPORT int N_VEnableLinearCombination_OpenMPDEV(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleAddMulti_OpenMPDEV(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableDotProdMulti_OpenMPDEV(N_Vector v, booleantype tf); + +SUNDIALS_EXPORT int N_VEnableLinearSumVectorArray_OpenMPDEV(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleVectorArray_OpenMPDEV(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableConstVectorArray_OpenMPDEV(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableWrmsNormVectorArray_OpenMPDEV(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableWrmsNormMaskVectorArray_OpenMPDEV(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleAddMultiVectorArray_OpenMPDEV(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableLinearCombinationVectorArray_OpenMPDEV(N_Vector v, booleantype tf); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_parallel.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_parallel.h new file mode 100644 index 0000000..eaa87a8 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_parallel.h @@ -0,0 +1,206 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Scott D. Cohen, Alan C. Hindmarsh, Radu Serban, + * 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 main header file for the MPI-enabled 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 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_Parallel(a,x,b,y,y); + * + * (which stores the result of the operation a*x+b*y in y) + * is legal. + * -----------------------------------------------------------------*/ + +#ifndef _NVECTOR_PARALLEL_H +#define _NVECTOR_PARALLEL_H + +#include <stdio.h> +#include <mpi.h> +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_mpi_types.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* + * ----------------------------------------------------------------- + * Parallel implementation of N_Vector + * ----------------------------------------------------------------- + */ + +struct _N_VectorContent_Parallel { + sunindextype local_length; /* local vector length */ + sunindextype global_length; /* global vector length */ + booleantype own_data; /* ownership of data */ + realtype *data; /* local data array */ + MPI_Comm comm; /* pointer to MPI communicator */ +}; + +typedef struct _N_VectorContent_Parallel *N_VectorContent_Parallel; + +/* + * ----------------------------------------------------------------- + * Macros NV_CONTENT_P, NV_DATA_P, NV_OWN_DATA_P, + * NV_LOCLENGTH_P, NV_GLOBLENGTH_P,NV_COMM_P, and NV_Ith_P + * ----------------------------------------------------------------- + */ + +#define NV_CONTENT_P(v) ( (N_VectorContent_Parallel)(v->content) ) + +#define NV_LOCLENGTH_P(v) ( NV_CONTENT_P(v)->local_length ) + +#define NV_GLOBLENGTH_P(v) ( NV_CONTENT_P(v)->global_length ) + +#define NV_OWN_DATA_P(v) ( NV_CONTENT_P(v)->own_data ) + +#define NV_DATA_P(v) ( NV_CONTENT_P(v)->data ) + +#define NV_COMM_P(v) ( NV_CONTENT_P(v)->comm ) + +#define NV_Ith_P(v,i) ( NV_DATA_P(v)[i] ) + +/* + * ----------------------------------------------------------------- + * Functions exported by nvector_parallel + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT N_Vector N_VNew_Parallel(MPI_Comm comm, + sunindextype local_length, + sunindextype global_length); + +SUNDIALS_EXPORT N_Vector N_VNewEmpty_Parallel(MPI_Comm comm, + sunindextype local_length, + sunindextype global_length); + +SUNDIALS_EXPORT N_Vector N_VMake_Parallel(MPI_Comm comm, + sunindextype local_length, + sunindextype global_length, + realtype *v_data); + +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 void N_VDestroyVectorArray_Parallel(N_Vector *vs, int count); + +SUNDIALS_EXPORT sunindextype N_VGetLength_Parallel(N_Vector v); + +SUNDIALS_EXPORT sunindextype N_VGetLocalLength_Parallel(N_Vector v); + +SUNDIALS_EXPORT void N_VPrint_Parallel(N_Vector v); + +SUNDIALS_EXPORT void N_VPrintFile_Parallel(N_Vector v, FILE *outfile); + +SUNDIALS_EXPORT N_Vector_ID N_VGetVectorID_Parallel(N_Vector v); +SUNDIALS_EXPORT N_Vector N_VCloneEmpty_Parallel(N_Vector w); +SUNDIALS_EXPORT N_Vector N_VClone_Parallel(N_Vector w); +SUNDIALS_EXPORT void N_VDestroy_Parallel(N_Vector v); +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); + +/* standard vector operations */ +SUNDIALS_EXPORT void N_VLinearSum_Parallel(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VConst_Parallel(realtype c, N_Vector z); +SUNDIALS_EXPORT void N_VProd_Parallel(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VDiv_Parallel(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VScale_Parallel(realtype c, N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAbs_Parallel(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VInv_Parallel(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAddConst_Parallel(N_Vector x, realtype b, N_Vector z); +SUNDIALS_EXPORT realtype N_VDotProd_Parallel(N_Vector x, N_Vector y); +SUNDIALS_EXPORT realtype N_VMaxNorm_Parallel(N_Vector x); +SUNDIALS_EXPORT realtype N_VWrmsNorm_Parallel(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWrmsNormMask_Parallel(N_Vector x, N_Vector w, N_Vector id); +SUNDIALS_EXPORT realtype N_VMin_Parallel(N_Vector x); +SUNDIALS_EXPORT realtype N_VWL2Norm_Parallel(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VL1Norm_Parallel(N_Vector x); +SUNDIALS_EXPORT void N_VCompare_Parallel(realtype c, N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VInvTest_Parallel(N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VConstrMask_Parallel(N_Vector c, N_Vector x, N_Vector m); +SUNDIALS_EXPORT realtype N_VMinQuotient_Parallel(N_Vector num, N_Vector denom); + +/* fused vector operations */ +SUNDIALS_EXPORT int N_VLinearCombination_Parallel(int nvec, realtype* c, N_Vector* V, + N_Vector z); +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); + +/* vector array operations */ +SUNDIALS_EXPORT int N_VLinearSumVectorArray_Parallel(int nvec, + realtype a, N_Vector* X, + realtype b, N_Vector* Y, + N_Vector* Z); +SUNDIALS_EXPORT int N_VScaleVectorArray_Parallel(int nvec, realtype* c, + N_Vector* X, N_Vector* Z); +SUNDIALS_EXPORT int N_VConstVectorArray_Parallel(int nvecs, realtype c, + N_Vector* Z); +SUNDIALS_EXPORT int N_VWrmsNormVectorArray_Parallel(int nvecs, N_Vector* X, + N_Vector* W, realtype* nrm); +SUNDIALS_EXPORT int N_VWrmsNormMaskVectorArray_Parallel(int nvec, N_Vector* X, + N_Vector* W, N_Vector id, + realtype* nrm); +SUNDIALS_EXPORT int N_VScaleAddMultiVectorArray_Parallel(int nvec, int nsum, + realtype* a, + N_Vector* X, + N_Vector** Y, + N_Vector** Z); +SUNDIALS_EXPORT int N_VLinearCombinationVectorArray_Parallel(int nvec, int nsum, + realtype* c, + N_Vector** X, + N_Vector* Z); + +/* + * ----------------------------------------------------------------- + * Enable / disable fused vector operations + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT int N_VEnableFusedOps_Parallel(N_Vector v, booleantype tf); + +SUNDIALS_EXPORT int N_VEnableLinearCombination_Parallel(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleAddMulti_Parallel(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableDotProdMulti_Parallel(N_Vector v, booleantype tf); + +SUNDIALS_EXPORT int N_VEnableLinearSumVectorArray_Parallel(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleVectorArray_Parallel(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableConstVectorArray_Parallel(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableWrmsNormVectorArray_Parallel(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableWrmsNormMaskVectorArray_Parallel(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleAddMultiVectorArray_Parallel(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableLinearCombinationVectorArray_Parallel(N_Vector v, booleantype tf); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_parhyp.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_parhyp.h new file mode 100644 index 0000000..992a991 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_parhyp.h @@ -0,0 +1,183 @@ +/* ----------------------------------------------------------------- + * 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 + * 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 ParHyp 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 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_ParHyp(a,x,b,y,y); + * + * (which stores the result of the operation a*x+b*y in y) + * is legal. + * -----------------------------------------------------------------*/ + +#ifndef _NVECTOR_PARHYP_H +#define _NVECTOR_PARHYP_H + +#include <stdio.h> +#include <mpi.h> +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_mpi_types.h> + +/* hypre header files */ +#include <_hypre_parcsr_mv.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* + * ----------------------------------------------------------------- + * ParHyp implementation of N_Vector + * ----------------------------------------------------------------- + */ + +struct _N_VectorContent_ParHyp { + sunindextype local_length; /* local vector length */ + sunindextype global_length; /* global vector length */ + booleantype own_parvector; /* ownership of HYPRE vector */ + MPI_Comm comm; /* pointer to MPI communicator */ + + HYPRE_ParVector x; /* the actual HYPRE_ParVector object */ +}; + +typedef struct _N_VectorContent_ParHyp *N_VectorContent_ParHyp; + + +/* + * ----------------------------------------------------------------- + * Functions exported by nvector_parhyp + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT N_Vector N_VNewEmpty_ParHyp(MPI_Comm comm, + sunindextype local_length, + sunindextype global_length); + +SUNDIALS_EXPORT N_Vector N_VMake_ParHyp(HYPRE_ParVector x); + +SUNDIALS_EXPORT N_Vector *N_VCloneVectorArray_ParHyp(int count, N_Vector w); + +SUNDIALS_EXPORT N_Vector *N_VCloneVectorArrayEmpty_ParHyp(int count, N_Vector w); + +SUNDIALS_EXPORT void N_VDestroyVectorArray_ParHyp(N_Vector *vs, int count); + +SUNDIALS_EXPORT HYPRE_ParVector N_VGetVector_ParHyp(N_Vector v); + +SUNDIALS_EXPORT void N_VPrint_ParHyp(N_Vector v); + +SUNDIALS_EXPORT void N_VPrintFile_ParHyp(N_Vector v, FILE *outfile); + +SUNDIALS_EXPORT N_Vector_ID N_VGetVectorID_ParHyp(N_Vector v); +SUNDIALS_EXPORT N_Vector N_VCloneEmpty_ParHyp(N_Vector w); +SUNDIALS_EXPORT N_Vector N_VClone_ParHyp(N_Vector w); +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); + +/* standard vector operations */ +SUNDIALS_EXPORT void N_VLinearSum_ParHyp(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VConst_ParHyp(realtype c, N_Vector z); +SUNDIALS_EXPORT void N_VProd_ParHyp(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VDiv_ParHyp(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VScale_ParHyp(realtype c, N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAbs_ParHyp(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VInv_ParHyp(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAddConst_ParHyp(N_Vector x, realtype b, N_Vector z); +SUNDIALS_EXPORT realtype N_VDotProd_ParHyp(N_Vector x, N_Vector y); +SUNDIALS_EXPORT realtype N_VMaxNorm_ParHyp(N_Vector x); +SUNDIALS_EXPORT realtype N_VWrmsNorm_ParHyp(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWrmsNormMask_ParHyp(N_Vector x, N_Vector w, N_Vector id); +SUNDIALS_EXPORT realtype N_VMin_ParHyp(N_Vector x); +SUNDIALS_EXPORT realtype N_VWL2Norm_ParHyp(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VL1Norm_ParHyp(N_Vector x); +SUNDIALS_EXPORT void N_VCompare_ParHyp(realtype c, N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VInvTest_ParHyp(N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VConstrMask_ParHyp(N_Vector c, N_Vector x, N_Vector m); +SUNDIALS_EXPORT realtype N_VMinQuotient_ParHyp(N_Vector num, N_Vector denom); + +/* fused vector operations */ +SUNDIALS_EXPORT int N_VLinearCombination_ParHyp(int nvec, realtype* c, + N_Vector* X, N_Vector z); +SUNDIALS_EXPORT int N_VScaleAddMulti_ParHyp(int nvec, realtype* a, N_Vector x, + N_Vector* Y, N_Vector* Z); +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, + realtype a, N_Vector* X, + realtype b, N_Vector* Y, + N_Vector* Z); +SUNDIALS_EXPORT int N_VScaleVectorArray_ParHyp(int nvec, realtype* c, + N_Vector* X, N_Vector* Z); +SUNDIALS_EXPORT int N_VConstVectorArray_ParHyp(int nvecs, realtype c, + N_Vector* Z); +SUNDIALS_EXPORT int N_VWrmsNormVectorArray_ParHyp(int nvecs, N_Vector* X, + N_Vector* W, realtype* nrm); +SUNDIALS_EXPORT int N_VWrmsNormMaskVectorArray_ParHyp(int nvec, N_Vector* X, + N_Vector* W, N_Vector id, + realtype* nrm); +SUNDIALS_EXPORT int N_VScaleAddMultiVectorArray_ParHyp(int nvec, int nsum, + realtype* a, + N_Vector* X, + N_Vector** Y, + N_Vector** Z); +SUNDIALS_EXPORT int N_VLinearCombinationVectorArray_ParHyp(int nvec, int nsum, + realtype* c, + N_Vector** X, + N_Vector* Z); + +/* + * ----------------------------------------------------------------- + * Enable / disable fused vector operations + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT int N_VEnableFusedOps_ParHyp(N_Vector v, booleantype tf); + +SUNDIALS_EXPORT int N_VEnableLinearCombination_ParHyp(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleAddMulti_ParHyp(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableDotProdMulti_ParHyp(N_Vector v, booleantype tf); + +SUNDIALS_EXPORT int N_VEnableLinearSumVectorArray_ParHyp(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleVectorArray_ParHyp(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableConstVectorArray_ParHyp(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableWrmsNormVectorArray_ParHyp(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableWrmsNormMaskVectorArray_ParHyp(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleAddMultiVectorArray_ParHyp(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableLinearCombinationVectorArray_ParHyp(N_Vector v, booleantype tf); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_petsc.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_petsc.h new file mode 100644 index 0000000..8f7e11a --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_petsc.h @@ -0,0 +1,175 @@ +/* ----------------------------------------------------------------- + * 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 the main header file for the PETSc vector wrapper + * for NVECTOR module. + * + * 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 + * build 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_Petsc(a,x,b,y,y); + * + * (which stores the result of the operation a*x+b*y in y) + * is legal. + * -----------------------------------------------------------------*/ + +#ifndef _NVECTOR_PETSC_H +#define _NVECTOR_PETSC_H + +#include <mpi.h> +#include <petscvec.h> +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_mpi_types.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* + * ----------------------------------------------------------------- + * PETSc implementation of N_Vector + * ----------------------------------------------------------------- + */ + +struct _N_VectorContent_Petsc { + sunindextype local_length; /* copy of local vector length */ + sunindextype global_length; /* copy of global vector length */ + booleantype own_data; /* ownership of data */ + Vec pvec; /* the PETSc Vec object */ + MPI_Comm comm; /* copy of MPI communicator */ +}; + +typedef struct _N_VectorContent_Petsc *N_VectorContent_Petsc; + +/* + * ----------------------------------------------------------------- + * Functions exported by nvector_petsc + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT N_Vector N_VNewEmpty_Petsc(MPI_Comm comm, + sunindextype local_length, + sunindextype global_length); + +SUNDIALS_EXPORT N_Vector N_VMake_Petsc(Vec v); + +SUNDIALS_EXPORT realtype *N_VGetArrayPointer_Petsc(N_Vector v); + +SUNDIALS_EXPORT N_Vector *N_VCloneVectorArray_Petsc(int count, N_Vector w); + +SUNDIALS_EXPORT N_Vector *N_VCloneVectorArrayEmpty_Petsc(int count, N_Vector w); + +SUNDIALS_EXPORT void N_VDestroyVectorArray_Petsc(N_Vector *vs, int count); + +SUNDIALS_EXPORT Vec N_VGetVector_Petsc(N_Vector v); + +SUNDIALS_EXPORT void N_VPrint_Petsc(N_Vector v); + +SUNDIALS_EXPORT void N_VPrintFile_Petsc(N_Vector v, const char fname[]); + +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); + +/* standard vector operations */ +SUNDIALS_EXPORT void N_VLinearSum_Petsc(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VConst_Petsc(realtype c, N_Vector z); +SUNDIALS_EXPORT void N_VProd_Petsc(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VDiv_Petsc(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VScale_Petsc(realtype c, N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAbs_Petsc(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VInv_Petsc(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAddConst_Petsc(N_Vector x, realtype b, N_Vector z); +SUNDIALS_EXPORT realtype N_VDotProd_Petsc(N_Vector x, N_Vector y); +SUNDIALS_EXPORT realtype N_VMaxNorm_Petsc(N_Vector x); +SUNDIALS_EXPORT realtype N_VWrmsNorm_Petsc(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWrmsNormMask_Petsc(N_Vector x, N_Vector w, N_Vector id); +SUNDIALS_EXPORT realtype N_VMin_Petsc(N_Vector x); +SUNDIALS_EXPORT realtype N_VWL2Norm_Petsc(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VL1Norm_Petsc(N_Vector x); +SUNDIALS_EXPORT void N_VCompare_Petsc(realtype c, N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VInvTest_Petsc(N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VConstrMask_Petsc(N_Vector c, N_Vector x, N_Vector m); +SUNDIALS_EXPORT realtype N_VMinQuotient_Petsc(N_Vector num, N_Vector denom); + +/* fused vector operations */ +SUNDIALS_EXPORT int N_VLinearCombination_Petsc(int nvec, realtype* c, + N_Vector* X, N_Vector z); +SUNDIALS_EXPORT int N_VScaleAddMulti_Petsc(int nvec, realtype* a, N_Vector x, + N_Vector* Y, N_Vector* Z); +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, + realtype a, N_Vector* X, + realtype b, N_Vector* Y, + N_Vector* Z); +SUNDIALS_EXPORT int N_VScaleVectorArray_Petsc(int nvec, realtype* c, + N_Vector* X, N_Vector* Z); +SUNDIALS_EXPORT int N_VConstVectorArray_Petsc(int nvecs, realtype c, + N_Vector* Z); +SUNDIALS_EXPORT int N_VWrmsNormVectorArray_Petsc(int nvecs, N_Vector* X, + N_Vector* W, realtype* nrm); +SUNDIALS_EXPORT int N_VWrmsNormMaskVectorArray_Petsc(int nvec, N_Vector* X, + N_Vector* W, N_Vector id, + realtype* nrm); +SUNDIALS_EXPORT int N_VScaleAddMultiVectorArray_Petsc(int nvec, int nsum, + realtype* a, + N_Vector* X, + N_Vector** Y, + N_Vector** Z); +SUNDIALS_EXPORT int N_VLinearCombinationVectorArray_Petsc(int nvec, int nsum, + realtype* c, + N_Vector** X, + N_Vector* Z); + +/* + * ----------------------------------------------------------------- + * Enable / disable fused vector operations + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT int N_VEnableFusedOps_Petsc(N_Vector v, booleantype tf); + +SUNDIALS_EXPORT int N_VEnableLinearCombination_Petsc(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleAddMulti_Petsc(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableDotProdMulti_Petsc(N_Vector v, booleantype tf); + +SUNDIALS_EXPORT int N_VEnableLinearSumVectorArray_Petsc(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleVectorArray_Petsc(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableConstVectorArray_Petsc(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableWrmsNormVectorArray_Petsc(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableWrmsNormMaskVectorArray_Petsc(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleAddMultiVectorArray_Petsc(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableLinearCombinationVectorArray_Petsc(N_Vector v, booleantype tf); + +#ifdef __cplusplus +} +#endif + +#endif /* _NVECTOR_PETSC_H */ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_pthreads.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_pthreads.h new file mode 100644 index 0000000..0fc029f --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_pthreads.h @@ -0,0 +1,231 @@ +/* ----------------------------------------------------------------- + * 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 + * @ 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 POSIX Threads (Pthreads) + * implementation of the NVECTOR module using LOCAL data structs + * to share data between threads. + * + * 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_Pthreads(a,x,b,y,y); + * + * (which stores the result of the operation a*x+b*y in y) + * is legal. + * -----------------------------------------------------------------*/ + +#ifndef _NVECTOR_PTHREADS_H +#define _NVECTOR_PTHREADS_H + +#include <stdio.h> +#include <pthread.h> +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* + * ----------------------------------------------------------------- + * Pthreads implementation of N_Vector + * ----------------------------------------------------------------- + */ + +struct _N_VectorContent_Pthreads { + sunindextype length; /* vector length */ + booleantype own_data; /* data ownership flag */ + realtype *data; /* data array */ + int num_threads; /* number of POSIX threads */ +}; + +typedef struct _N_VectorContent_Pthreads *N_VectorContent_Pthreads; + +/* Structure to hold parallelization information for each thread when + calling "companion" functions to compute vector operations. The + start and end vector (loop) indices are unique to each thread, the + realtype variables are the same for each thread, and the mutex + variable is used to lock variables in reductions. */ + +struct _Pthreads_Data{ + sunindextype start; /* starting index for loop */ + sunindextype end; /* ending index for loop */ + realtype c1, c2; /* scalar values */ + realtype *v1, *v2, *v3; /* vector data */ + realtype *global_val; /* shared global variable */ + pthread_mutex_t *global_mutex; /* lock for shared variable */ + + int nvec; /* number of vectors in fused op */ + int nsum; /* number of sums in fused op */ + + realtype* cvals; /* scalar values in fused op */ + + N_Vector x1; /* vector array in fused op */ + N_Vector x2; /* vector array in fused op */ + N_Vector x3; /* vector array in fused op */ + + N_Vector* Y1; /* vector array in fused op */ + N_Vector* Y2; /* vector array in fused op */ + N_Vector* Y3; /* vector array in fused op */ + + N_Vector** ZZ1; /* array of vector arrays in fused op */ + N_Vector** ZZ2; /* array of vector arrays in fused op */ +}; + +typedef struct _Pthreads_Data Pthreads_Data; + +/* + * ----------------------------------------------------------------- + * Macros NV_CONTENT_PT, NV_DATA_PT, NV_OWN_DATA_PT, + * NV_LENGTH_PT, and NV_Ith_PT + * ----------------------------------------------------------------- + */ + +#define NV_CONTENT_PT(v) ( (N_VectorContent_Pthreads)(v->content) ) + +#define NV_LENGTH_PT(v) ( NV_CONTENT_PT(v)->length ) + +#define NV_NUM_THREADS_PT(v) ( NV_CONTENT_PT(v)->num_threads ) + +#define NV_OWN_DATA_PT(v) ( NV_CONTENT_PT(v)->own_data ) + +#define NV_DATA_PT(v) ( NV_CONTENT_PT(v)->data ) + +#define NV_Ith_PT(v,i) ( NV_DATA_PT(v)[i] ) + +/* + * ----------------------------------------------------------------- + * Functions exported by nvector_Pthreads + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT N_Vector N_VNew_Pthreads(sunindextype vec_length, int n_threads); + +SUNDIALS_EXPORT N_Vector N_VNewEmpty_Pthreads(sunindextype vec_length, int n_threads); + +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_VCloneVectorArrayEmpty_Pthreads(int count, N_Vector w); + +SUNDIALS_EXPORT void N_VDestroyVectorArray_Pthreads(N_Vector *vs, int count); + +SUNDIALS_EXPORT sunindextype N_VGetLength_Pthreads(N_Vector v); + +SUNDIALS_EXPORT void N_VPrint_Pthreads(N_Vector v); + +SUNDIALS_EXPORT void N_VPrintFile_Pthreads(N_Vector v, FILE *outfile); + +SUNDIALS_EXPORT N_Vector_ID N_VGetVectorID_Pthreads(N_Vector v); +SUNDIALS_EXPORT N_Vector N_VCloneEmpty_Pthreads(N_Vector w); +SUNDIALS_EXPORT N_Vector N_VClone_Pthreads(N_Vector w); +SUNDIALS_EXPORT void N_VDestroy_Pthreads(N_Vector v); +SUNDIALS_EXPORT void N_VSpace_Pthreads(N_Vector v, sunindextype *lrw, sunindextype *liw); +SUNDIALS_EXPORT realtype *N_VGetArrayPointer_Pthreads(N_Vector v); +SUNDIALS_EXPORT void N_VSetArrayPointer_Pthreads(realtype *v_data, N_Vector v); + +/* standard vector operations */ +SUNDIALS_EXPORT void N_VLinearSum_Pthreads(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VConst_Pthreads(realtype c, N_Vector z); +SUNDIALS_EXPORT void N_VProd_Pthreads(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VDiv_Pthreads(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VScale_Pthreads(realtype c, N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAbs_Pthreads(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VInv_Pthreads(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAddConst_Pthreads(N_Vector x, realtype b, N_Vector z); +SUNDIALS_EXPORT realtype N_VDotProd_Pthreads(N_Vector x, N_Vector y); +SUNDIALS_EXPORT realtype N_VMaxNorm_Pthreads(N_Vector x); +SUNDIALS_EXPORT realtype N_VWrmsNorm_Pthreads(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWrmsNormMask_Pthreads(N_Vector x, N_Vector w, N_Vector id); +SUNDIALS_EXPORT realtype N_VMin_Pthreads(N_Vector x); +SUNDIALS_EXPORT realtype N_VWL2Norm_Pthreads(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VL1Norm_Pthreads(N_Vector x); +SUNDIALS_EXPORT void N_VCompare_Pthreads(realtype c, N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VInvTest_Pthreads(N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VConstrMask_Pthreads(N_Vector c, N_Vector x, N_Vector m); +SUNDIALS_EXPORT realtype N_VMinQuotient_Pthreads(N_Vector num, N_Vector denom); + +/* fused vector operations */ +SUNDIALS_EXPORT int N_VLinearCombination_Pthreads(int nvec, realtype* c, + N_Vector* X, N_Vector z); +SUNDIALS_EXPORT int N_VScaleAddMulti_Pthreads(int nvec, realtype* a, N_Vector x, + N_Vector* Y, N_Vector* Z); +SUNDIALS_EXPORT int N_VDotProdMulti_Pthreads(int nvec, N_Vector x, N_Vector* Y, + realtype* dotprods); + +/* vector array operations */ +SUNDIALS_EXPORT int N_VLinearSumVectorArray_Pthreads(int nvec, + realtype a, N_Vector* X, + realtype b, N_Vector* Y, + N_Vector* Z); +SUNDIALS_EXPORT int N_VScaleVectorArray_Pthreads(int nvec, realtype* c, + N_Vector* X, N_Vector* Z); +SUNDIALS_EXPORT int N_VConstVectorArray_Pthreads(int nvec, realtype c, + N_Vector* Z); +SUNDIALS_EXPORT int N_VWrmsNormVectorArray_Pthreads(int nvec, N_Vector* X, + N_Vector* W, realtype* nrm); +SUNDIALS_EXPORT int N_VWrmsNormMaskVectorArray_Pthreads(int nvec, N_Vector* X, + N_Vector* W, N_Vector id, + realtype* nrm); +SUNDIALS_EXPORT int N_VScaleAddMultiVectorArray_Pthreads(int nvec, int nsum, + realtype* a, + N_Vector* X, + N_Vector** Y, + N_Vector** Z); +SUNDIALS_EXPORT int N_VLinearCombinationVectorArray_Pthreads(int nvec, int nsum, + realtype* c, + N_Vector** X, + N_Vector* Z); + +/* + * ----------------------------------------------------------------- + * Enable / disable fused vector operations + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT int N_VEnableFusedOps_Pthreads(N_Vector v, booleantype tf); + +SUNDIALS_EXPORT int N_VEnableLinearCombination_Pthreads(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleAddMulti_Pthreads(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableDotProdMulti_Pthreads(N_Vector v, booleantype tf); + +SUNDIALS_EXPORT int N_VEnableLinearSumVectorArray_Pthreads(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleVectorArray_Pthreads(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableConstVectorArray_Pthreads(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableWrmsNormVectorArray_Pthreads(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableWrmsNormMaskVectorArray_Pthreads(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleAddMultiVectorArray_Pthreads(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableLinearCombinationVectorArray_Pthreads(N_Vector v, booleantype tf); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_raja.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_raja.h new file mode 100644 index 0000000..22d8e4d --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_raja.h @@ -0,0 +1,162 @@ +/* ----------------------------------------------------------------- + * 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 the header file for the RAJA 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 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 <stdio.h> +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_config.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* + * ----------------------------------------------------------------- + * 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_raja + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT N_Vector N_VNew_Raja(sunindextype 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 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_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_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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_serial.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_serial.h new file mode 100644 index 0000000..10bcffc --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_serial.h @@ -0,0 +1,188 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Scott D. Cohen, Alan C. Hindmarsh, Radu Serban, + * 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 serial 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 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_Serial(a,x,b,y,y); + * + * (which stores the result of the operation a*x+b*y in y) + * is legal. + * -----------------------------------------------------------------*/ + +#ifndef _NVECTOR_SERIAL_H +#define _NVECTOR_SERIAL_H + +#include <stdio.h> +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* + * ----------------------------------------------------------------- + * SERIAL implementation of N_Vector + * ----------------------------------------------------------------- + */ + +struct _N_VectorContent_Serial { + sunindextype length; /* vector length */ + booleantype own_data; /* data ownership flag */ + realtype *data; /* data array */ +}; + +typedef struct _N_VectorContent_Serial *N_VectorContent_Serial; + +/* + * ----------------------------------------------------------------- + * Macros NV_CONTENT_S, NV_DATA_S, NV_OWN_DATA_S, + * NV_LENGTH_S, and NV_Ith_S + * ----------------------------------------------------------------- + */ + +#define NV_CONTENT_S(v) ( (N_VectorContent_Serial)(v->content) ) + +#define NV_LENGTH_S(v) ( NV_CONTENT_S(v)->length ) + +#define NV_OWN_DATA_S(v) ( NV_CONTENT_S(v)->own_data ) + +#define NV_DATA_S(v) ( NV_CONTENT_S(v)->data ) + +#define NV_Ith_S(v,i) ( NV_DATA_S(v)[i] ) + +/* + * ----------------------------------------------------------------- + * Functions exported by nvector_serial + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT N_Vector N_VNew_Serial(sunindextype vec_length); + +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_VCloneVectorArrayEmpty_Serial(int count, N_Vector w); + +SUNDIALS_EXPORT void N_VDestroyVectorArray_Serial(N_Vector *vs, int count); + +SUNDIALS_EXPORT sunindextype N_VGetLength_Serial(N_Vector v); + +SUNDIALS_EXPORT void N_VPrint_Serial(N_Vector v); + +SUNDIALS_EXPORT void N_VPrintFile_Serial(N_Vector v, FILE *outfile); + +SUNDIALS_EXPORT N_Vector_ID N_VGetVectorID_Serial(N_Vector v); +SUNDIALS_EXPORT N_Vector N_VCloneEmpty_Serial(N_Vector w); +SUNDIALS_EXPORT N_Vector N_VClone_Serial(N_Vector w); +SUNDIALS_EXPORT void N_VDestroy_Serial(N_Vector v); +SUNDIALS_EXPORT void N_VSpace_Serial(N_Vector v, sunindextype *lrw, sunindextype *liw); +SUNDIALS_EXPORT realtype *N_VGetArrayPointer_Serial(N_Vector v); +SUNDIALS_EXPORT void N_VSetArrayPointer_Serial(realtype *v_data, N_Vector v); + +/* standard vector operations */ +SUNDIALS_EXPORT void N_VLinearSum_Serial(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VConst_Serial(realtype c, N_Vector z); +SUNDIALS_EXPORT void N_VProd_Serial(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VDiv_Serial(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VScale_Serial(realtype c, N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAbs_Serial(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VInv_Serial(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAddConst_Serial(N_Vector x, realtype b, N_Vector z); +SUNDIALS_EXPORT realtype N_VDotProd_Serial(N_Vector x, N_Vector y); +SUNDIALS_EXPORT realtype N_VMaxNorm_Serial(N_Vector x); +SUNDIALS_EXPORT realtype N_VWrmsNorm_Serial(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWrmsNormMask_Serial(N_Vector x, N_Vector w, N_Vector id); +SUNDIALS_EXPORT realtype N_VMin_Serial(N_Vector x); +SUNDIALS_EXPORT realtype N_VWL2Norm_Serial(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VL1Norm_Serial(N_Vector x); +SUNDIALS_EXPORT void N_VCompare_Serial(realtype c, N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VInvTest_Serial(N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VConstrMask_Serial(N_Vector c, N_Vector x, N_Vector m); +SUNDIALS_EXPORT realtype N_VMinQuotient_Serial(N_Vector num, N_Vector denom); + +/* fused vector operations */ +SUNDIALS_EXPORT int N_VLinearCombination_Serial(int nvec, realtype* c, N_Vector* V, + N_Vector z); +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); + +/* vector array operations */ +SUNDIALS_EXPORT int N_VLinearSumVectorArray_Serial(int nvec, + realtype a, N_Vector* X, + realtype b, N_Vector* Y, + N_Vector* Z); +SUNDIALS_EXPORT int N_VScaleVectorArray_Serial(int nvec, realtype* c, + N_Vector* X, N_Vector* Z); +SUNDIALS_EXPORT int N_VConstVectorArray_Serial(int nvecs, realtype c, + N_Vector* Z); +SUNDIALS_EXPORT int N_VWrmsNormVectorArray_Serial(int nvecs, N_Vector* X, + N_Vector* W, realtype* nrm); +SUNDIALS_EXPORT int N_VWrmsNormMaskVectorArray_Serial(int nvecs, N_Vector* X, + N_Vector* W, N_Vector id, + realtype* nrm); +SUNDIALS_EXPORT int N_VScaleAddMultiVectorArray_Serial(int nvec, int nsum, + realtype* a, + N_Vector* X, + N_Vector** Y, + N_Vector** Z); +SUNDIALS_EXPORT int N_VLinearCombinationVectorArray_Serial(int nvec, int nsum, + realtype* c, + N_Vector** X, + N_Vector* Z); + +/* + * ----------------------------------------------------------------- + * Enable / disable fused vector operations + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT int N_VEnableFusedOps_Serial(N_Vector v, booleantype tf); + +SUNDIALS_EXPORT int N_VEnableLinearCombination_Serial(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleAddMulti_Serial(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableDotProdMulti_Serial(N_Vector v, booleantype tf); + +SUNDIALS_EXPORT int N_VEnableLinearSumVectorArray_Serial(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleVectorArray_Serial(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableConstVectorArray_Serial(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableWrmsNormVectorArray_Serial(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableWrmsNormMaskVectorArray_Serial(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableScaleAddMultiVectorArray_Serial(N_Vector v, booleantype tf); +SUNDIALS_EXPORT int N_VEnableLinearCombinationVectorArray_Serial(N_Vector v, booleantype tf); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_trilinos.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_trilinos.h new file mode 100644 index 0000000..9ffcdc3 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/nvector/nvector_trilinos.h @@ -0,0 +1,125 @@ +/* ----------------------------------------------------------------- + * 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 the main header file for the Trilinos vector wrapper + * for NVECTOR module. + * + * Part I contains declarations specific to the Trilinos vector wrapper + * implementation. + * + * Part II contains the prototype for the constructor + * N_VMake_Trilinos as well as Trilinos-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 + * build 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_Trilinos(a,x,b,y,y); + * + * (which stores the result of the operation a*x+b*y in y) + * is legal. + * -----------------------------------------------------------------*/ + +#ifndef _NVECTOR_TRILINOS_H +#define _NVECTOR_TRILINOS_H + +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/* + * ----------------------------------------------------------------- + * PART I: N_Vector interface to Trilinos vector + * ----------------------------------------------------------------- + */ + +/* + * Dummy _N_VectorContent_Trilinos structure is used for + * interfacing C with C++ code + */ + +struct _N_VectorContent_Trilinos {}; + +typedef struct _N_VectorContent_Trilinos *N_VectorContent_Trilinos; + +/* + * ----------------------------------------------------------------- + * PART II: functions exported by nvector_Trilinos + * + * CONSTRUCTORS: + * N_VNewEmpty_Trilinos + * ----------------------------------------------------------------- + */ + + +/* + * ----------------------------------------------------------------- + * Function : N_VNewEmpty_Trilinos + * ----------------------------------------------------------------- + * This function creates a new N_Vector wrapper for a Trilinos + * vector. + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT N_Vector N_VNewEmpty_Trilinos(); + +/* + * ----------------------------------------------------------------- + * Trilinos implementations of the vector operations + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT N_Vector_ID N_VGetVectorID_Trilinos(N_Vector v); +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_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); +SUNDIALS_EXPORT void N_VDiv_Trilinos(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VScale_Trilinos(realtype c, N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAbs_Trilinos(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VInv_Trilinos(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAddConst_Trilinos(N_Vector x, realtype b, N_Vector z); +SUNDIALS_EXPORT realtype N_VDotProd_Trilinos(N_Vector x, N_Vector y); +SUNDIALS_EXPORT realtype N_VMaxNorm_Trilinos(N_Vector x); +SUNDIALS_EXPORT realtype N_VWrmsNorm_Trilinos(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWrmsNormMask_Trilinos(N_Vector x, N_Vector w, N_Vector id); +SUNDIALS_EXPORT realtype N_VMin_Trilinos(N_Vector x); +SUNDIALS_EXPORT realtype N_VWL2Norm_Trilinos(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VL1Norm_Trilinos(N_Vector x); +SUNDIALS_EXPORT void N_VCompare_Trilinos(realtype c, N_Vector x, N_Vector z); +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); + +#ifdef __cplusplus +} +#endif + +#endif /* _NVECTOR_TRILINOS_H */ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_band.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_band.h new file mode 100644 index 0000000..c549d29 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_band.h @@ -0,0 +1,181 @@ +/* ----------------------------------------------------------------- + * Programmer(s): 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 a generic BAND linear solver + * package, based on the DlsMat type defined in sundials_direct.h. + * + * There are two sets of band solver routines listed in + * this file: one set uses type DlsMat defined below and the + * other set uses the type realtype ** for band matrix arguments. + * Routines that work with the type DlsMat begin with "Band". + * Routines that work with realtype ** begin with "band". + * -----------------------------------------------------------------*/ + +#ifndef _SUNDIALS_BAND_H +#define _SUNDIALS_BAND_H + +#include <sundials/sundials_direct.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* + * ----------------------------------------------------------------- + * Function : BandGBTRF + * ----------------------------------------------------------------- + * Usage : ier = BandGBTRF(A, p); + * if (ier != 0) ... A is singular + * ----------------------------------------------------------------- + * BandGBTRF performs the LU factorization of the N by N band + * matrix A. This is done using standard Gaussian elimination + * with partial pivoting. + * + * A successful LU factorization leaves the "matrix" A and the + * pivot array p with the following information: + * + * (1) p[k] contains the row number of the pivot element chosen + * at the beginning of elimination step k, k=0, 1, ..., N-1. + * + * (2) If the unique LU factorization of A is given by PA = LU, + * where P is a permutation matrix, L is a lower triangular + * matrix with all 1's on the diagonal, and U is an upper + * triangular matrix, then the upper triangular part of A + * (including its diagonal) contains U and the strictly lower + * triangular part of A contains the multipliers, I-L. + * + * BandGBTRF returns 0 if successful. Otherwise it encountered + * a zero diagonal element during the factorization. In this case + * it returns the column index (numbered from one) at which + * it encountered the zero. + * + * Important Note: A must be allocated to accommodate the increase + * in upper bandwidth that occurs during factorization. If + * mathematically, A is a band matrix with upper bandwidth mu and + * lower bandwidth ml, then the upper triangular factor U can + * have upper bandwidth as big as smu = MIN(n-1,mu+ml). The lower + * triangular factor L has lower bandwidth ml. Allocate A with + * call A = BandAllocMat(N,mu,ml,smu), where mu, ml, and smu are + * as defined above. The user does not have to zero the "extra" + * storage allocated for the purpose of factorization. This will + * handled by the BandGBTRF routine. + * + * BandGBTRF is only a wrapper around bandGBTRF. All work is done + * in bandGBTRF, which works directly on the data in the DlsMat A + * (i.e. in the field A->cols). + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT sunindextype BandGBTRF(DlsMat A, sunindextype *p); +SUNDIALS_EXPORT sunindextype bandGBTRF(realtype **a, sunindextype n, + sunindextype mu, sunindextype ml, + sunindextype smu, sunindextype *p); + +/* + * ----------------------------------------------------------------- + * Function : BandGBTRS + * ----------------------------------------------------------------- + * Usage : BandGBTRS(A, p, b); + * ----------------------------------------------------------------- + * BandGBTRS solves the N-dimensional system A x = b using + * the LU factorization in A and the pivot information in p + * computed in BandGBTRF. The solution x is returned in b. This + * routine cannot fail if the corresponding call to BandGBTRF + * did not fail. + * + * BandGBTRS is only a wrapper around bandGBTRS which does all the + * work directly on the data in the DlsMat A (i.e. in A->cols). + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT void BandGBTRS(DlsMat A, sunindextype *p, realtype *b); +SUNDIALS_EXPORT void bandGBTRS(realtype **a, sunindextype n, sunindextype smu, + sunindextype ml, sunindextype *p, realtype *b); + +/* + * ----------------------------------------------------------------- + * Function : BandCopy + * ----------------------------------------------------------------- + * Usage : BandCopy(A, B, copymu, copyml); + * ----------------------------------------------------------------- + * BandCopy copies the submatrix with upper and lower bandwidths + * copymu, copyml of the N by N band matrix A into the N by N + * band matrix B. + * + * BandCopy is a wrapper around bandCopy which accesses the data + * in the DlsMat A and DlsMat B (i.e. the fields cols). + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT void BandCopy(DlsMat A, DlsMat B, sunindextype copymu, + sunindextype copyml); +SUNDIALS_EXPORT void bandCopy(realtype **a, realtype **b, sunindextype n, + sunindextype a_smu, sunindextype b_smu, + sunindextype copymu, sunindextype copyml); + +/* + * ----------------------------------------------------------------- + * Function: BandScale + * ----------------------------------------------------------------- + * Usage : BandScale(c, A); + * ----------------------------------------------------------------- + * A(i,j) <- c*A(i,j), j-(A->mu) <= i <= j+(A->ml). + * + * BandScale is a wrapper around bandScale which performs the actual + * scaling by accessing the data in the DlsMat A (i.e. the field + * A->cols). + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT void BandScale(realtype c, DlsMat A); +SUNDIALS_EXPORT void bandScale(realtype c, realtype **a, sunindextype n, + sunindextype mu, sunindextype ml, + sunindextype smu); + +/* + * ----------------------------------------------------------------- + * Function: bandAddIdentity + * ----------------------------------------------------------------- + * bandAddIdentity adds the identity matrix to the n-by-n matrix + * stored in the realtype** arrays. + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT void bandAddIdentity(realtype **a, sunindextype n, + sunindextype smu); + + +/* + * ----------------------------------------------------------------- + * Function: BandMatvec + * ----------------------------------------------------------------- + * BandMatvec computes the matrix-vector product y = A*x, where A + * is an M-by-N band matrix, x is a vector of length N, and y is a + * vector of length M. No error checking is performed on the length + * of the arrays x and y. Only y is modified in this routine. + * + * BandMatvec is a wrapper around bandMatvec which performs the + * actual product by accessing the data in the DlsMat A. + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT void BandMatvec(DlsMat A, realtype *x, realtype *y); +SUNDIALS_EXPORT void bandMatvec(realtype **a, realtype *x, realtype *y, + sunindextype n, sunindextype mu, + sunindextype ml, sunindextype smu); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_config.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_config.h new file mode 100644 index 0000000..21a3540 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_config.h @@ -0,0 +1,118 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Aaron Collier and Radu Serban @ LLNL + * ----------------------------------------------------------------- + * 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 + * ----------------------------------------------------------------- + * SUNDIALS configuration header file + * -----------------------------------------------------------------*/ + +/* Define SUNDIALS version numbers */ +#define SUNDIALS_VERSION "4.0.2" +#define SUNDIALS_VERSION_MAJOR 4 +#define SUNDIALS_VERSION_MINOR 0 +#define SUNDIALS_VERSION_PATCH 2 +#define SUNDIALS_VERSION_LABEL "" + +/* FCMIX: Define Fortran name-mangling macro for C identifiers. + * Depending on the inferred scheme, one of the following six + * macros will be defined: + * #define SUNDIALS_F77_FUNC(name,NAME) name + * #define SUNDIALS_F77_FUNC(name,NAME) name ## _ + * #define SUNDIALS_F77_FUNC(name,NAME) name ## __ + * #define SUNDIALS_F77_FUNC(name,NAME) NAME + * #define SUNDIALS_F77_FUNC(name,NAME) NAME ## _ + * #define SUNDIALS_F77_FUNC(name,NAME) NAME ## __ + */ + + +/* FCMIX: Define Fortran name-mangling macro for C identifiers + * which contain underscores. + */ + + +/* Define precision of SUNDIALS data type 'realtype' + * Depending on the precision level, one of the following + * three macros will be defined: + * #define SUNDIALS_SINGLE_PRECISION 1 + * #define SUNDIALS_DOUBLE_PRECISION 1 + * #define SUNDIALS_EXTENDED_PRECISION 1 + */ +#define SUNDIALS_DOUBLE_PRECISION 1 + +/* Define type of vector indices in SUNDIALS 'sunindextype'. + * Depending on user choice of index type, one of the following + * two macros will be defined: + * #define SUNDIALS_INT64_T 1 + * #define SUNDIALS_INT32_T 1 + */ +#define SUNDIALS_INT64_T 1 + +/* Define the type of vector indices in SUNDIALS 'sunindextype'. + * The macro will be defined with a type of the appropriate size. + */ +#define SUNDIALS_INDEX_TYPE int64_t + +/* Use generic math functions + * If it was decided that generic math functions can be used, then + * #define SUNDIALS_USE_GENERIC_MATH + */ +#define SUNDIALS_USE_GENERIC_MATH + +/* Use POSIX timers if available. + * #define SUNDIALS_HAVE_POSIX_TIMERS + */ +#define SUNDIALS_HAVE_POSIX_TIMERS + +/* Blas/Lapack available + * If working libraries for Blas/lapack support were found, then + * #define SUNDIALS_BLAS_LAPACK + */ +/* #undef SUNDIALS_BLAS_LAPACK */ + +/* SUPERLUMT available + * If working libraries for SUPERLUMT support were found, then + * #define SUNDIALS_SUPERLUMT + */ +/* #undef SUNDIALS_SUPERLUMT */ +/* #undef SUNDIALS_SUPERLUMT_THREAD_TYPE */ + +/* KLU available + * If working libraries for KLU support were found, then + * #define SUNDIALS_KLU + */ +#define SUNDIALS_KLU + +/* Set if SUNDIALS is built with MPI support. + * + */ + + +/* FNVECTOR: Allow user to specify different MPI communicator + * If it was found that the MPI implementation supports MPI_Comm_f2c, then + * #define SUNDIALS_MPI_COMM_F2C 1 + * otherwise + * #define SUNDIALS_MPI_COMM_F2C 0 + */ +#define SUNDIALS_MPI_COMM_F2C 0 + +/* Mark SUNDIALS API functions for export/import + * When building shared SUNDIALS libraries under Windows, use + * #define SUNDIALS_EXPORT __declspec(dllexport) + * When linking to shared SUNDIALS libraries under Windows, use + * #define SUNDIALS_EXPORT __declspec(dllimport) + * In all other cases (other platforms or static libraries under + * Windows), the SUNDIALS_EXPORT macro is empty + */ +#define SUNDIALS_EXPORT diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_dense.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_dense.h new file mode 100644 index 0000000..7dee165 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_dense.h @@ -0,0 +1,212 @@ +/* ----------------------------------------------------------------- + * Programmer: 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 a generic package of DENSE matrix + * operations, based on the DlsMat type defined in sundials_direct.h. + * + * There are two sets of dense solver routines listed in + * this file: one set uses type DlsMat defined below and the + * other set uses the type realtype ** for dense matrix arguments. + * Routines that work with the type DlsMat begin with "Dense". + * Routines that work with realtype** begin with "dense". + * -----------------------------------------------------------------*/ + +#ifndef _SUNDIALS_DENSE_H +#define _SUNDIALS_DENSE_H + +#include <sundials/sundials_direct.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* + * ----------------------------------------------------------------- + * Functions: DenseGETRF and DenseGETRS + * ----------------------------------------------------------------- + * DenseGETRF performs the LU factorization of the M by N dense + * matrix A. This is done using standard Gaussian elimination + * with partial (row) pivoting. Note that this applies only + * to matrices with M >= N and full column rank. + * + * A successful LU factorization leaves the matrix A and the + * pivot array p with the following information: + * + * (1) p[k] contains the row number of the pivot element chosen + * at the beginning of elimination step k, k=0, 1, ..., N-1. + * + * (2) If the unique LU factorization of A is given by PA = LU, + * where P is a permutation matrix, L is a lower trapezoidal + * matrix with all 1's on the diagonal, and U is an upper + * triangular matrix, then the upper triangular part of A + * (including its diagonal) contains U and the strictly lower + * trapezoidal part of A contains the multipliers, I-L. + * + * For square matrices (M = N), L is unit lower triangular. + * + * DenseGETRF returns 0 if successful. Otherwise it encountered + * a zero diagonal element during the factorization. In this case + * it returns the column index (numbered from one) at which + * it encountered the zero. + * + * DenseGETRS solves the N-dimensional system A x = b using + * the LU factorization in A and the pivot information in p + * computed in DenseGETRF. The solution x is returned in b. This + * routine cannot fail if the corresponding call to DenseGETRF + * did not fail. + * DenseGETRS does NOT check for a square matrix! + * + * ----------------------------------------------------------------- + * DenseGETRF and DenseGETRS are simply wrappers around denseGETRF + * and denseGETRS, respectively, which perform all the work by + * directly accessing the data in the DlsMat A (i.e. in A->cols). + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT sunindextype DenseGETRF(DlsMat A, sunindextype *p); +SUNDIALS_EXPORT void DenseGETRS(DlsMat A, sunindextype *p, realtype *b); + +SUNDIALS_EXPORT sunindextype denseGETRF(realtype **a, sunindextype m, + sunindextype n, sunindextype *p); +SUNDIALS_EXPORT void denseGETRS(realtype **a, sunindextype n, sunindextype *p, + realtype *b); + +/* + * ----------------------------------------------------------------- + * Functions : DensePOTRF and DensePOTRS + * ----------------------------------------------------------------- + * DensePOTRF computes the Cholesky factorization of a real symmetric + * positive definite matrix A. + * ----------------------------------------------------------------- + * DensePOTRS solves a system of linear equations A*X = B with a + * symmetric positive definite matrix A using the Cholesky factorization + * A = L*L**T computed by DensePOTRF. + * + * ----------------------------------------------------------------- + * DensePOTRF and DensePOTRS are simply wrappers around densePOTRF + * and densePOTRS, respectively, which perform all the work by + * directly accessing the data in the DlsMat A (i.e. the field cols) + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT sunindextype DensePOTRF(DlsMat A); +SUNDIALS_EXPORT void DensePOTRS(DlsMat A, realtype *b); + +SUNDIALS_EXPORT sunindextype densePOTRF(realtype **a, sunindextype m); +SUNDIALS_EXPORT void densePOTRS(realtype **a, sunindextype m, realtype *b); + +/* + * ----------------------------------------------------------------- + * Functions : DenseGEQRF and DenseORMQR + * ----------------------------------------------------------------- + * DenseGEQRF computes a QR factorization of a real M-by-N matrix A: + * A = Q * R (with M>= N). + * + * DenseGEQRF requires a temporary work vector wrk of length M. + * ----------------------------------------------------------------- + * DenseORMQR computes the product w = Q * v where Q is a real + * orthogonal matrix defined as the product of k elementary reflectors + * + * Q = H(1) H(2) . . . H(k) + * + * as returned by DenseGEQRF. Q is an M-by-N matrix, v is a vector + * of length N and w is a vector of length M (with M >= N). + * + * DenseORMQR requires a temporary work vector wrk of length M. + * + * ----------------------------------------------------------------- + * DenseGEQRF and DenseORMQR are simply wrappers around denseGEQRF + * and denseORMQR, respectively, which perform all the work by + * directly accessing the data in the DlsMat A (i.e. the field cols) + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT int DenseGEQRF(DlsMat A, realtype *beta, realtype *wrk); +SUNDIALS_EXPORT int DenseORMQR(DlsMat A, realtype *beta, realtype *vn, + realtype *vm, realtype *wrk); + +SUNDIALS_EXPORT int denseGEQRF(realtype **a, sunindextype m, sunindextype n, + realtype *beta, realtype *wrk); +SUNDIALS_EXPORT int denseORMQR(realtype **a, sunindextype m, sunindextype n, + realtype *beta, realtype *v, realtype *w, + realtype *wrk); + +/* + * ----------------------------------------------------------------- + * Function : DenseCopy + * ----------------------------------------------------------------- + * DenseCopy copies the contents of the M-by-N matrix A into the + * M-by-N matrix B. + * + * DenseCopy is a wrapper around denseCopy which accesses the data + * in the DlsMat A and DlsMat B (i.e. the fields cols) + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT void DenseCopy(DlsMat A, DlsMat B); +SUNDIALS_EXPORT void denseCopy(realtype **a, realtype **b, sunindextype m, + sunindextype n); + +/* + * ----------------------------------------------------------------- + * Function: DenseScale + * ----------------------------------------------------------------- + * DenseScale scales the elements of the M-by-N matrix A by the + * constant c and stores the result back in A. + * + * DenseScale is a wrapper around denseScale which performs the actual + * scaling by accessing the data in the DlsMat A (i.e. in A->cols). + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT void DenseScale(realtype c, DlsMat A); +SUNDIALS_EXPORT void denseScale(realtype c, realtype **a, sunindextype m, + sunindextype n); + + +/* + * ----------------------------------------------------------------- + * Function: denseAddIdentity + * ----------------------------------------------------------------- + * denseAddIdentity adds the identity matrix to the n-by-n matrix + * stored in a realtype** array. + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT void denseAddIdentity(realtype **a, sunindextype n); + + +/* + * ----------------------------------------------------------------- + * Function: DenseMatvec + * ----------------------------------------------------------------- + * DenseMatvec computes the matrix-vector product y = A*x, where A + * is an M-by-N matrix, x is a vector of length N, and y is a vector + * of length M. No error checking is performed on the length of the + * arrays x and y. Only y is modified in this routine. + * + * DenseMatvec is a wrapper around denseMatvec which performs the + * actual product by accessing the data in the DlsMat A. + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT void DenseMatvec(DlsMat A, realtype *x, realtype *y); +SUNDIALS_EXPORT void denseMatvec(realtype **a, realtype *x, realtype *y, + sunindextype m, sunindextype n); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_direct.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_direct.h new file mode 100644 index 0000000..da4be77 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_direct.h @@ -0,0 +1,339 @@ +/* ----------------------------------------------------------------- + * Programmer: 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 header file contains definitions and declarations for use by + * generic direct linear solvers for Ax = b. It defines types for + * dense and banded matrices and corresponding accessor macros. + * -----------------------------------------------------------------*/ + +#ifndef _SUNDIALS_DIRECT_H +#define _SUNDIALS_DIRECT_H + +#include <stdio.h> +#include <sundials/sundials_types.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* + * ================================================================= + * C O N S T A N T S + * ================================================================= + */ + +/* + * SUNDIALS_DENSE: dense matrix + * SUNDIALS_BAND: banded matrix + */ + +#define SUNDIALS_DENSE 1 +#define SUNDIALS_BAND 2 + +/* + * ================================================================== + * Type definitions + * ================================================================== + */ + +/* + * ----------------------------------------------------------------- + * Type : DlsMat + * ----------------------------------------------------------------- + * The type DlsMat is defined to be a pointer to a structure + * with various sizes, a data field, and an array of pointers to + * the columns which defines a dense or band matrix for use in + * direct linear solvers. The M and N fields indicates the number + * of rows and columns, respectively. The data field is a one + * dimensional array used for component storage. The cols field + * stores the pointers in data for the beginning of each column. + * ----------------------------------------------------------------- + * For DENSE matrices, the relevant fields in DlsMat are: + * type = SUNDIALS_DENSE + * M - number of rows + * N - number of columns + * ldim - leading dimension (ldim >= M) + * data - pointer to a contiguous block of realtype variables + * ldata - length of the data array =ldim*N + * cols - array of pointers. cols[j] points to the first element + * of the j-th column of the matrix in the array data. + * + * The elements of a dense matrix are stored columnwise (i.e. columns + * are stored one on top of the other in memory). + * If A is of type DlsMat, then the (i,j)th element of A (with + * 0 <= i < M and 0 <= j < N) is given by (A->data)[j*n+i]. + * + * The DENSE_COL and DENSE_ELEM macros below allow a user to access + * efficiently individual matrix elements without writing out explicit + * data structure references and without knowing too much about the + * underlying element storage. The only storage assumption needed is + * that elements are stored columnwise and that a pointer to the + * jth column of elements can be obtained via the DENSE_COL macro. + * ----------------------------------------------------------------- + * For BAND matrices, the relevant fields in DlsMat are: + * type = SUNDIALS_BAND + * M - number of rows + * N - number of columns + * mu - upper bandwidth, 0 <= mu <= min(M,N) + * ml - lower bandwidth, 0 <= ml <= min(M,N) + * s_mu - storage upper bandwidth, mu <= s_mu <= N-1. + * The dgbtrf routine writes the LU factors into the storage + * for A. The upper triangular factor U, however, may have + * an upper bandwidth as big as MIN(N-1,mu+ml) because of + * partial pivoting. The s_mu field holds the upper + * bandwidth allocated for A. + * ldim - leading dimension (ldim >= s_mu) + * data - pointer to a contiguous block of realtype variables + * ldata - length of the data array =ldim*(s_mu+ml+1) + * cols - array of pointers. cols[j] points to the first element + * of the j-th column of the matrix in the array data. + * + * The BAND_COL, BAND_COL_ELEM, and BAND_ELEM macros below allow a + * user to access individual matrix elements without writing out + * explicit data structure references and without knowing too much + * about the underlying element storage. The only storage assumption + * needed is that elements are stored columnwise and that a pointer + * into the jth column of elements can be obtained via the BAND_COL + * macro. The BAND_COL_ELEM macro selects an element from a column + * which has already been isolated via BAND_COL. The macro + * BAND_COL_ELEM allows the user to avoid the translation + * from the matrix location (i,j) to the index in the array returned + * by BAND_COL at which the (i,j)th element is stored. + * ----------------------------------------------------------------- + */ + +typedef struct _DlsMat { + int type; + sunindextype M; + sunindextype N; + sunindextype ldim; + sunindextype mu; + sunindextype ml; + sunindextype s_mu; + realtype *data; + sunindextype ldata; + realtype **cols; +} *DlsMat; + +/* + * ================================================================== + * Data accessor macros + * ================================================================== + */ + +/* + * ----------------------------------------------------------------- + * DENSE_COL and DENSE_ELEM + * ----------------------------------------------------------------- + * + * DENSE_COL(A,j) references the jth column of the M-by-N dense + * matrix A, 0 <= j < N. The type of the expression DENSE_COL(A,j) + * is (realtype *). After the assignment col_j = DENSE_COL(A,j), + * col_j may be treated as an array indexed from 0 to M-1. + * The (i,j)-th element of A is thus referenced by col_j[i]. + * + * DENSE_ELEM(A,i,j) references the (i,j)th element of the dense + * M-by-N matrix A, 0 <= i < M ; 0 <= j < N. + * + * ----------------------------------------------------------------- + */ + +#define DENSE_COL(A,j) ((A->cols)[j]) +#define DENSE_ELEM(A,i,j) ((A->cols)[j][i]) + +/* + * ----------------------------------------------------------------- + * BAND_COL, BAND_COL_ELEM, and BAND_ELEM + * ----------------------------------------------------------------- + * + * BAND_COL(A,j) references the diagonal element of the jth column + * of the N by N band matrix A, 0 <= j <= N-1. The type of the + * expression BAND_COL(A,j) is realtype *. The pointer returned by + * the call BAND_COL(A,j) can be treated as an array which is + * indexed from -(A->mu) to (A->ml). + * + * BAND_COL_ELEM references the (i,j)th entry of the band matrix A + * when used in conjunction with BAND_COL. The index (i,j) should + * satisfy j-(A->mu) <= i <= j+(A->ml). + * + * BAND_ELEM(A,i,j) references the (i,j)th element of the M-by-N + * band matrix A, where 0 <= i,j <= N-1. The location (i,j) should + * further satisfy j-(A->mu) <= i <= j+(A->ml). + * + * ----------------------------------------------------------------- + */ + +#define BAND_COL(A,j) (((A->cols)[j])+(A->s_mu)) +#define BAND_COL_ELEM(col_j,i,j) (col_j[(i)-(j)]) +#define BAND_ELEM(A,i,j) ((A->cols)[j][(i)-(j)+(A->s_mu)]) + +/* + * ================================================================== + * Exported function prototypes (functions working on dlsMat) + * ================================================================== + */ + +/* + * ----------------------------------------------------------------- + * Function: NewDenseMat + * ----------------------------------------------------------------- + * NewDenseMat allocates memory for an M-by-N dense matrix and + * returns the storage allocated (type DlsMat). NewDenseMat + * returns NULL if the request for matrix storage cannot be + * satisfied. See the above documentation for the type DlsMat + * for matrix storage details. + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT DlsMat NewDenseMat(sunindextype M, sunindextype N); + +/* + * ----------------------------------------------------------------- + * Function: NewBandMat + * ----------------------------------------------------------------- + * NewBandMat allocates memory for an M-by-N band matrix + * with upper bandwidth mu, lower bandwidth ml, and storage upper + * bandwidth smu. Pass smu as follows depending on whether A will + * be LU factored: + * + * (1) Pass smu = mu if A will not be factored. + * + * (2) Pass smu = MIN(N-1,mu+ml) if A will be factored. + * + * NewBandMat returns the storage allocated (type DlsMat) or + * NULL if the request for matrix storage cannot be satisfied. + * See the documentation for the type DlsMat for matrix storage + * details. + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT DlsMat NewBandMat(sunindextype N, sunindextype mu, + sunindextype ml, sunindextype smu); + +/* + * ----------------------------------------------------------------- + * Functions: DestroyMat + * ----------------------------------------------------------------- + * DestroyMat frees the memory allocated by NewDenseMat or NewBandMat + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT void DestroyMat(DlsMat A); + +/* + * ----------------------------------------------------------------- + * Function: NewIntArray + * ----------------------------------------------------------------- + * NewIntArray allocates memory an array of N int's and returns + * the pointer to the memory it allocates. If the request for + * memory storage cannot be satisfied, it returns NULL. + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT int *NewIntArray(int N); + +/* + * ----------------------------------------------------------------- + * Function: NewIndexArray + * ----------------------------------------------------------------- + * NewIndexArray allocates memory an array of N sunindextype's and + * returns the pointer to the memory it allocates. If the request + * for memory storage cannot be satisfied, it returns NULL. + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT sunindextype *NewIndexArray(sunindextype N); + +/* + * ----------------------------------------------------------------- + * Function: NewRealArray + * ----------------------------------------------------------------- + * NewRealArray allocates memory an array of N realtype and returns + * the pointer to the memory it allocates. If the request for + * memory storage cannot be satisfied, it returns NULL. + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT realtype *NewRealArray(sunindextype N); + +/* + * ----------------------------------------------------------------- + * Function: DestroyArray + * ----------------------------------------------------------------- + * DestroyArray frees memory allocated by NewIntArray, NewIndexArray, + * or NewRealArray. + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT void DestroyArray(void *p); + +/* + * ----------------------------------------------------------------- + * Function : AddIdentity + * ----------------------------------------------------------------- + * AddIdentity adds 1.0 to the main diagonal (A_ii, i=0,1,...,N-1) of + * the M-by-N matrix A (M>= N) and stores the result back in A. + * AddIdentity is typically used with square matrices. + * AddIdentity does not check for M >= N and therefore a segmentation + * fault will occur if M < N! + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT void AddIdentity(DlsMat A); + +/* + * ----------------------------------------------------------------- + * Function : SetToZero + * ----------------------------------------------------------------- + * SetToZero sets all the elements of the M-by-N matrix A to 0.0. + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT void SetToZero(DlsMat A); + +/* + * ----------------------------------------------------------------- + * Functions: PrintMat + * ----------------------------------------------------------------- + * This function prints the M-by-N (dense or band) matrix A to + * outfile as it would normally appear on paper. + * It is intended as debugging tools with small values of M and N. + * The elements are printed using the %g/%lg/%Lg option. + * A blank line is printed before and after the matrix. + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT void PrintMat(DlsMat A, FILE *outfile); + + +/* + * ================================================================== + * Exported function prototypes (functions working on realtype**) + * ================================================================== + */ + +SUNDIALS_EXPORT realtype **newDenseMat(sunindextype m, sunindextype n); +SUNDIALS_EXPORT realtype **newBandMat(sunindextype n, sunindextype smu, + sunindextype ml); +SUNDIALS_EXPORT void destroyMat(realtype **a); +SUNDIALS_EXPORT int *newIntArray(int n); +SUNDIALS_EXPORT sunindextype *newIndexArray(sunindextype n); +SUNDIALS_EXPORT realtype *newRealArray(sunindextype m); +SUNDIALS_EXPORT void destroyArray(void *v); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_fnvector.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_fnvector.h new file mode 100644 index 0000000..a1946f0 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_fnvector.h @@ -0,0 +1,42 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Radu Serban 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 file (companion of nvector.h) contains definitions + * needed for the initialization of vector operations in Fortran. + * -----------------------------------------------------------------*/ + + +#ifndef _FNVECTOR_H +#define _FNVECTOR_H + +#ifndef _SUNDIALS_CONFIG_H +#define _SUNDIALS_CONFIG_H +#include <sundials/sundials_config.h> +#endif + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* SUNDIALS solver IDs */ + +#define FCMIX_CVODE 1 +#define FCMIX_IDA 2 +#define FCMIX_KINSOL 3 +#define FCMIX_ARKODE 4 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_iterative.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_iterative.h new file mode 100644 index 0000000..8d5ab4d --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_iterative.h @@ -0,0 +1,263 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Scott D. Cohen and Alan C. Hindmarsh @ 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 declarations intended for use by + * generic iterative solvers of Ax = b. The enumeration gives + * symbolic names for the type of preconditioning to be used. + * The function type declarations give the prototypes for the + * functions to be called within an iterative linear solver, that + * are responsible for + * multiplying A by a given vector v (ATimesFn), + * setting up a preconditioner P (PSetupFn), and + * solving the preconditioner equation Pz = r (PSolveFn). + * -----------------------------------------------------------------*/ + +#ifndef _ITERATIVE_H +#define _ITERATIVE_H + +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/* + * ----------------------------------------------------------------- + * enum : types of preconditioning + * ----------------------------------------------------------------- + * PREC_NONE : The iterative linear solver should not use + * preconditioning. + * + * PREC_LEFT : The iterative linear solver uses preconditioning on + * the left only. + * + * PREC_RIGHT : The iterative linear solver uses preconditioning on + * the right only. + * + * PREC_BOTH : The iterative linear solver uses preconditioning on + * both the left and the right. + * ----------------------------------------------------------------- + */ + +enum { PREC_NONE, PREC_LEFT, PREC_RIGHT, PREC_BOTH }; + +/* + * ----------------------------------------------------------------- + * enum : types of Gram-Schmidt routines + * ----------------------------------------------------------------- + * MODIFIED_GS : The iterative solver uses the modified + * Gram-Schmidt routine ModifiedGS listed in this + * file. + * + * CLASSICAL_GS : The iterative solver uses the classical + * Gram-Schmidt routine ClassicalGS listed in this + * file. + * ----------------------------------------------------------------- + */ + +enum { MODIFIED_GS = 1, CLASSICAL_GS = 2 }; + +/* + * ----------------------------------------------------------------- + * Type: ATimesFn + * ----------------------------------------------------------------- + * An ATimesFn multiplies Av and stores the result in z. The + * caller is responsible for allocating memory for the z vector. + * The parameter A_data is a pointer to any information about A + * which the function needs in order to do its job. The vector v + * is unchanged. An ATimesFn returns 0 if successful and a + * non-zero value if unsuccessful. + * ----------------------------------------------------------------- + */ + +typedef int (*ATimesFn)(void *A_data, N_Vector v, N_Vector z); + +/* + * ----------------------------------------------------------------- + * Type: PSetupFn + * ----------------------------------------------------------------- + * A PSetupFn is an integrator-supplied routine that accesses data + * stored in the integrator memory structure (P_data), and calls + * the user-supplied, integrator-specific preconditioner setup + * routine. + * ----------------------------------------------------------------- + */ + +typedef int (*PSetupFn)(void *P_data); + +/* + * ----------------------------------------------------------------- + * Type: PSolveFn + * ----------------------------------------------------------------- + * A PSolveFn solves the preconditioner equation Pz = r for the + * vector z. The caller is responsible for allocating memory for + * the z vector. The parameter P_data is a pointer to any + * information about P which the function needs in order to do + * its job. The parameter lr is input, and indicates whether P + * is to be taken as the left preconditioner or the right + * preconditioner: lr = 1 for left and lr = 2 for right. + * If preconditioning is on one side only, lr can be ignored. + * If the preconditioner is iterative, then it should strive to + * solve the preconditioner equation so that + * || Pz - r ||_wrms < tol + * where the weight vector for the WRMS norm may be accessed from + * the main integrator memory structure. + * The vector r should not be modified by the PSolveFn. + * A PSolveFn returns 0 if successful and a non-zero value if + * unsuccessful. On a failure, a negative return value indicates + * an unrecoverable condition, while a positive value indicates + * a recoverable one, in which the calling routine may reattempt + * the solution after updating preconditioner data. + * ----------------------------------------------------------------- + */ + +typedef int (*PSolveFn)(void *P_data, N_Vector r, N_Vector z, + realtype tol, int lr); + +/* + * ----------------------------------------------------------------- + * Function: ModifiedGS + * ----------------------------------------------------------------- + * ModifiedGS performs a modified Gram-Schmidt orthogonalization + * of the N_Vector v[k] against the p unit N_Vectors at + * v[k-1], v[k-2], ..., v[k-p]. + * + * v is an array of (k+1) N_Vectors v[i], i=0, 1, ..., k. + * v[k-1], v[k-2], ..., v[k-p] are assumed to have L2-norm + * equal to 1. + * + * h is the output k by k Hessenberg matrix of inner products. + * This matrix must be allocated row-wise so that the (i,j)th + * entry is h[i][j]. The inner products (v[i],v[k]), + * i=i0, i0+1, ..., k-1, are stored at h[i][k-1]. Here + * i0=SUNMAX(0,k-p). + * + * k is the index of the vector in the v array that needs to be + * orthogonalized against previous vectors in the v array. + * + * p is the number of previous vectors in the v array against + * which v[k] is to be orthogonalized. + * + * new_vk_norm is a pointer to memory allocated by the caller to + * hold the Euclidean norm of the orthogonalized vector v[k]. + * + * If (k-p) < 0, then ModifiedGS uses p=k. The orthogonalized + * v[k] is NOT normalized and is stored over the old v[k]. Once + * the orthogonalization has been performed, the Euclidean norm + * of v[k] is stored in (*new_vk_norm). + * + * ModifiedGS returns 0 to indicate success. It cannot fail. + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT int ModifiedGS(N_Vector *v, realtype **h, int k, int p, + realtype *new_vk_norm); + +/* + * ----------------------------------------------------------------- + * Function: ClassicalGS + * ----------------------------------------------------------------- + * ClassicalGS performs a classical Gram-Schmidt + * orthogonalization of the N_Vector v[k] against the p unit + * N_Vectors at v[k-1], v[k-2], ..., v[k-p]. The parameters v, h, + * k, p, and new_vk_norm are as described in the documentation + * for ModifiedGS. + * + * stemp is a length k+1 array of realtype which can be used as + * workspace by the ClassicalGS routine. + * + * vtemp is an N_Vector array of k+1 vectors which can be used as + * workspace by the ClassicalGS routine. + * + * ClassicalGS returns 0 to indicate success. + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT int ClassicalGS(N_Vector *v, realtype **h, int k, int p, + realtype *new_vk_norm, realtype *stemp, + N_Vector *vtemp); + +/* + * ----------------------------------------------------------------- + * Function: QRfact + * ----------------------------------------------------------------- + * QRfact performs a QR factorization of the Hessenberg matrix H. + * + * n is the problem size; the matrix H is (n+1) by n. + * + * h is the (n+1) by n Hessenberg matrix H to be factored. It is + * stored row-wise. + * + * q is an array of length 2*n containing the Givens rotations + * computed by this function. A Givens rotation has the form: + * | c -s | + * | s c |. + * The components of the Givens rotations are stored in q as + * (c, s, c, s, ..., c, s). + * + * job is a control flag. If job==0, then a new QR factorization + * is performed. If job!=0, then it is assumed that the first + * n-1 columns of h have already been factored and only the last + * column needs to be updated. + * + * QRfact returns 0 if successful. If a zero is encountered on + * the diagonal of the triangular factor R, then QRfact returns + * the equation number of the zero entry, where the equations are + * numbered from 1, not 0. If QRsol is subsequently called in + * this situation, it will return an error because it could not + * divide by the zero diagonal entry. + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT int QRfact(int n, realtype **h, realtype *q, int job); + +/* + * ----------------------------------------------------------------- + * Function: QRsol + * ----------------------------------------------------------------- + * QRsol solves the linear least squares problem + * + * min (b - H*x, b - H*x), x in R^n, + * + * where H is a Hessenberg matrix, and b is in R^(n+1). + * It uses the QR factors of H computed by QRfact. + * + * n is the problem size; the matrix H is (n+1) by n. + * + * h is a matrix (computed by QRfact) containing the upper + * triangular factor R of the original Hessenberg matrix H. + * + * q is an array of length 2*n (computed by QRfact) containing + * the Givens rotations used to factor H. + * + * b is the (n+1)-vector appearing in the least squares problem + * above. + * + * On return, b contains the solution x of the least squares + * problem, if QRsol was successful. + * + * QRsol returns a 0 if successful. Otherwise, a zero was + * encountered on the diagonal of the triangular factor R. + * In this case, QRsol returns the equation number (numbered + * from 1, not 0) of the zero entry. + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT int QRsol(int n, realtype **h, realtype *q, realtype *b); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_klu_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_klu_impl.h new file mode 100644 index 0000000..fecca9a --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_klu_impl.h @@ -0,0 +1,57 @@ +/* + * ----------------------------------------------------------------- + * $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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_lapack.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_lapack.h new file mode 100644 index 0000000..886fecb --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_lapack.h @@ -0,0 +1,209 @@ +/* + * ----------------------------------------------------------------- + * $Revision$ + * $Date$ + * ----------------------------------------------------------------- + * Programmer: Radu Serban @ LLNL + * Daniel 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 header file for a generic package of direct matrix + * operations for use with BLAS/LAPACK. + * ----------------------------------------------------------------- + */ + +#ifndef _SUNDIALS_LAPACK_H +#define _SUNDIALS_LAPACK_H + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* + * ================================================================== + * Blas and Lapack functions + * ================================================================== + */ + +#if defined(SUNDIALS_F77_FUNC) + +#define dcopy_f77 SUNDIALS_F77_FUNC(dcopy, DCOPY) +#define dscal_f77 SUNDIALS_F77_FUNC(dscal, DSCAL) +#define dgemv_f77 SUNDIALS_F77_FUNC(dgemv, DGEMV) +#define dtrsv_f77 SUNDIALS_F77_FUNC(dtrsv, DTRSV) +#define dsyrk_f77 SUNDIALS_F77_FUNC(dsyrk, DSKYR) + +#define dgbtrf_f77 SUNDIALS_F77_FUNC(dgbtrf, DGBTRF) +#define dgbtrs_f77 SUNDIALS_F77_FUNC(dgbtrs, DGBTRS) +#define dgetrf_f77 SUNDIALS_F77_FUNC(dgetrf, DGETRF) +#define dgetrs_f77 SUNDIALS_F77_FUNC(dgetrs, DGETRS) +#define dgeqp3_f77 SUNDIALS_F77_FUNC(dgeqp3, DGEQP3) +#define dgeqrf_f77 SUNDIALS_F77_FUNC(dgeqrf, DGEQRF) +#define dormqr_f77 SUNDIALS_F77_FUNC(dormqr, DORMQR) +#define dpotrf_f77 SUNDIALS_F77_FUNC(dpotrf, DPOTRF) +#define dpotrs_f77 SUNDIALS_F77_FUNC(dpotrs, DPOTRS) + +#define scopy_f77 SUNDIALS_F77_FUNC(scopy, SCOPY) +#define sscal_f77 SUNDIALS_F77_FUNC(sscal, SSCAL) +#define sgemv_f77 SUNDIALS_F77_FUNC(sgemv, SGEMV) +#define strsv_f77 SUNDIALS_F77_FUNC(strsv, STRSV) +#define ssyrk_f77 SUNDIALS_F77_FUNC(ssyrk, SSKYR) + +#define sgbtrf_f77 SUNDIALS_F77_FUNC(sgbtrf, SGBTRF) +#define sgbtrs_f77 SUNDIALS_F77_FUNC(sgbtrs, SGBTRS) +#define sgetrf_f77 SUNDIALS_F77_FUNC(sgetrf, SGETRF) +#define sgetrs_f77 SUNDIALS_F77_FUNC(sgetrs, SGETRS) +#define sgeqp3_f77 SUNDIALS_F77_FUNC(sgeqp3, SGEQP3) +#define sgeqrf_f77 SUNDIALS_F77_FUNC(sgeqrf, SGEQRF) +#define sormqr_f77 SUNDIALS_F77_FUNC(sormqr, SORMQR) +#define spotrf_f77 SUNDIALS_F77_FUNC(spotrf, SPOTRF) +#define spotrs_f77 SUNDIALS_F77_FUNC(spotrs, SPOTRS) + +#else + +#define dcopy_f77 dcopy_ +#define dscal_f77 dscal_ +#define dgemv_f77 dgemv_ +#define dtrsv_f77 dtrsv_ +#define dsyrk_f77 dsyrk_ + +#define dgbtrf_f77 dgbtrf_ +#define dgbtrs_f77 dgbtrs_ +#define dgeqp3_f77 dgeqp3_ +#define dgeqrf_f77 dgeqrf_ +#define dgetrf_f77 dgetrf_ +#define dgetrs_f77 dgetrs_ +#define dormqr_f77 dormqr_ +#define dpotrf_f77 dpotrf_ +#define dpotrs_f77 dpotrs_ + +#define scopy_f77 scopy_ +#define sscal_f77 sscal_ +#define sgemv_f77 sgemv_ +#define strsv_f77 strsv_ +#define ssyrk_f77 ssyrk_ + +#define sgbtrf_f77 sgbtrf_ +#define sgbtrs_f77 sgbtrs_ +#define sgeqp3_f77 sgeqp3_ +#define sgeqrf_f77 sgeqrf_ +#define sgetrf_f77 sgetrf_ +#define sgetrs_f77 sgetrs_ +#define sormqr_f77 sormqr_ +#define spotrf_f77 spotrf_ +#define spotrs_f77 spotrs_ + +#endif + +/* 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 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); + +/* 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 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 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 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); + +/* 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 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); + +/* 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 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 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 dgeqrf_f77(const int *m, const int *n, double *a, const int *lda, double *tau, double *work, + const int *lwork, int *info); + +extern void dgetrf_f77(const int *m, const int *n, double *a, int *lda, int *ipiv, int *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 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 dpotrf_f77(const char *uplo, const int *n, double *a, int *lda, int *info, int len_uplo); + +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 sgbtrf_f77(const int *m, const int *n, const int *kl, const int *ku, + float *ab, int *ldab, int *ipiv, int *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 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 sgeqrf_f77(const int *m, const int *n, float *a, const int *lda, float *tau, float *work, + const int *lwork, int *info); + +extern void sgetrf_f77(const int *m, const int *n, float *a, int *lda, int *ipiv, int *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 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 spotrf_f77(const char *uplo, const int *n, float *a, int *lda, int *info, int len_uplo); + +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); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_linearsolver.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_linearsolver.h new file mode 100644 index 0000000..3d29097 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_linearsolver.h @@ -0,0 +1,180 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * David Gardner, Carol Woodward, 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 the header file for a generic linear solver package. + * It defines the SUNLinearSolver structure (_generic_SUNLinearSolver) + * which contains the following fields: + * - an implementation-dependent 'content' field which contains + * any internal data required by the solver + * - an 'ops' filed which contains a structure listing operations + * acting on/by such solvers + * + * We consider both direct linear solvers and iterative linear solvers + * as available implementations of this package. Furthermore, iterative + * linear solvers can either use a matrix or be matrix-free. As a + * result of these different solver characteristics, some of the + * routines are applicable only to some types of linear solver. + * ----------------------------------------------------------------- + * This header file contains: + * - enumeration constants for all SUNDIALS-defined linear solver + * types, as well as a generic type for user-supplied linear + * solver types, + * - type declarations for the _generic_SUNLinearSolver and + * _generic_SUNLinearSolver_Ops structures, as well as references + * to pointers to such structures (SUNLinearSolver), + * - prototypes for the linear solver functions which operate + * on/by SUNLinearSolver objects, and + * - return codes for SUNLinearSolver objects. + * ----------------------------------------------------------------- + * At a minimum, a particular implementation of a SUNLinearSolver must + * do the following: + * - specify the 'content' field of SUNLinearSolver, + * - implement the operations on/by those SUNLinearSolver objects, + * - provide a constructor routine for new SUNLinearSolver objects + * + * Additionally, a SUNLinearSolver implementation may provide the + * following: + * - "Set" routines to control solver-specific parameters/options + * - "Get" routines to access solver-specific performance metrics + * -----------------------------------------------------------------*/ + +#ifndef _SUNLINEARSOLVER_H +#define _SUNLINEARSOLVER_H + +#include <sundials/sundials_types.h> +#include <sundials/sundials_iterative.h> +#include <sundials/sundials_matrix.h> +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/* ----------------------------------------------------------------- + * Implemented SUNLinearSolver types: + * ----------------------------------------------------------------- */ + +typedef enum { + SUNLINEARSOLVER_DIRECT, + SUNLINEARSOLVER_ITERATIVE, + SUNLINEARSOLVER_MATRIX_ITERATIVE +} SUNLinearSolver_Type; + + +/* ----------------------------------------------------------------- + * Generic definition of SUNLinearSolver + * ----------------------------------------------------------------- */ + +/* Forward reference for pointer to SUNLinearSolver_Ops object */ +typedef struct _generic_SUNLinearSolver_Ops *SUNLinearSolver_Ops; + +/* Forward reference for pointer to SUNLinearSolver object */ +typedef struct _generic_SUNLinearSolver *SUNLinearSolver; + +/* Structure containing function pointers to linear solver operations */ +struct _generic_SUNLinearSolver_Ops { + SUNLinearSolver_Type (*gettype)(SUNLinearSolver); + int (*setatimes)(SUNLinearSolver, void*, ATimesFn); + int (*setpreconditioner)(SUNLinearSolver, void*, + PSetupFn, PSolveFn); + int (*setscalingvectors)(SUNLinearSolver, + N_Vector, N_Vector); + int (*initialize)(SUNLinearSolver); + int (*setup)(SUNLinearSolver, SUNMatrix); + int (*solve)(SUNLinearSolver, SUNMatrix, N_Vector, + N_Vector, realtype); + int (*numiters)(SUNLinearSolver); + realtype (*resnorm)(SUNLinearSolver); + long int (*lastflag)(SUNLinearSolver); + int (*space)(SUNLinearSolver, long int*, long int*); + N_Vector (*resid)(SUNLinearSolver); + int (*free)(SUNLinearSolver); +}; + +/* A linear solver is a structure with an implementation-dependent + 'content' field, and a pointer to a structure of linear solver + operations corresponding to that implementation. */ +struct _generic_SUNLinearSolver { + void *content; + struct _generic_SUNLinearSolver_Ops *ops; +}; + + +/* ----------------------------------------------------------------- + * Functions exported by SUNLinearSolver module + * ----------------------------------------------------------------- */ + +SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType(SUNLinearSolver S); + +SUNDIALS_EXPORT int SUNLinSolSetATimes(SUNLinearSolver S, void* A_data, + ATimesFn ATimes); + +SUNDIALS_EXPORT int SUNLinSolSetPreconditioner(SUNLinearSolver S, void* P_data, + PSetupFn Pset, PSolveFn Psol); + +SUNDIALS_EXPORT int SUNLinSolSetScalingVectors(SUNLinearSolver S, N_Vector s1, + N_Vector s2); + +SUNDIALS_EXPORT int SUNLinSolInitialize(SUNLinearSolver S); + +SUNDIALS_EXPORT int SUNLinSolSetup(SUNLinearSolver S, SUNMatrix A); + +SUNDIALS_EXPORT int SUNLinSolSolve(SUNLinearSolver S, SUNMatrix A, N_Vector x, + N_Vector b, realtype tol); + +SUNDIALS_EXPORT int SUNLinSolNumIters(SUNLinearSolver S); + +SUNDIALS_EXPORT realtype SUNLinSolResNorm(SUNLinearSolver S); + +SUNDIALS_EXPORT N_Vector SUNLinSolResid(SUNLinearSolver S); + +SUNDIALS_EXPORT long int SUNLinSolLastFlag(SUNLinearSolver S); + +SUNDIALS_EXPORT int SUNLinSolSpace(SUNLinearSolver S, long int *lenrwLS, + long int *leniwLS); + +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 */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_math.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_math.h new file mode 100644 index 0000000..ab25391 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_math.h @@ -0,0 +1,168 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Scott D. Cohen, Alan C. Hindmarsh 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 a simple C-language math library. The + * routines listed here work with the type realtype as defined in + * the header file sundials_types.h. + * ----------------------------------------------------------------- + */ + +#ifndef _SUNDIALSMATH_H +#define _SUNDIALSMATH_H + +#include <math.h> + +#include <sundials/sundials_types.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* + * ----------------------------------------------------------------- + * Macros + * ----------------------------------------------------------------- + * MIN(A,B) returns the minimum of A and B + * + * MAX(A,B) returns the maximum of A and B + * + * SQR(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 + * ----------------------------------------------------------------- + */ + +#ifndef SUNMIN +#define SUNMIN(A, B) ((A) < (B) ? (A) : (B)) +#endif + +#ifndef SUNMAX +#define SUNMAX(A, B) ((A) > (B) ? (A) : (B)) +#endif + +#ifndef SUNSQR +#define SUNSQR(A) ((A)*(A)) +#endif + +/* + * ----------------------------------------------------------------- + * Function : SUNRsqrt + * ----------------------------------------------------------------- + * Usage : realtype sqrt_x; + * sqrt_x = SUNRsqrt(x); + * ----------------------------------------------------------------- + * SUNRsqrt(x) returns the square root of x. If x < ZERO, then + * SUNRsqrt returns ZERO. + * ----------------------------------------------------------------- + */ + +#ifndef SUNRsqrt +#if defined(SUNDIALS_USE_GENERIC_MATH) +#define SUNRsqrt(x) ((x) <= RCONST(0.0) ? (RCONST(0.0)) : ((realtype) sqrt((double) (x)))) +#elif defined(SUNDIALS_DOUBLE_PRECISION) +#define SUNRsqrt(x) ((x) <= RCONST(0.0) ? (RCONST(0.0)) : (sqrt((x)))) +#elif defined(SUNDIALS_SINGLE_PRECISION) +#define SUNRsqrt(x) ((x) <= RCONST(0.0) ? (RCONST(0.0)) : (sqrtf((x)))) +#elif defined(SUNDIALS_EXTENDED_PRECISION) +#define SUNRsqrt(x) ((x) <= RCONST(0.0) ? (RCONST(0.0)) : (sqrtl((x)))) +#endif +#endif + +/* + * ----------------------------------------------------------------- + * Function : SUNRabs + * ----------------------------------------------------------------- + * Usage : realtype abs_x; + * abs_x = SUNRabs(x); + * ----------------------------------------------------------------- + * SUNRabs(x) returns the absolute value of x. + * ----------------------------------------------------------------- + */ + +#ifndef SUNRabs +#if defined(SUNDIALS_USE_GENERIC_MATH) +#define SUNRabs(x) ((realtype) fabs((double) (x))) +#elif defined(SUNDIALS_DOUBLE_PRECISION) +#define SUNRabs(x) (fabs((x))) +#elif defined(SUNDIALS_SINGLE_PRECISION) +#define SUNRabs(x) (fabsf((x))) +#elif defined(SUNDIALS_EXTENDED_PRECISION) +#define SUNRabs(x) (fabsl((x))) +#endif +#endif + +/* + * ----------------------------------------------------------------- + * Function : SUNRexp + * ----------------------------------------------------------------- + * Usage : realtype exp_x; + * exp_x = SUNRexp(x); + * ----------------------------------------------------------------- + * SUNRexp(x) returns e^x (base-e exponential function). + * ----------------------------------------------------------------- + */ + +#ifndef SUNRexp +#if defined(SUNDIALS_USE_GENERIC_MATH) +#define SUNRexp(x) ((realtype) exp((double) (x))) +#elif defined(SUNDIALS_DOUBLE_PRECISION) +#define SUNRexp(x) (exp((x))) +#elif defined(SUNDIALS_SINGLE_PRECISION) +#define SUNRexp(x) (expf((x))) +#elif defined(SUNDIALS_EXTENDED_PRECISION) +#define SUNRexp(x) (expl((x))) +#endif +#endif + +/* + * ----------------------------------------------------------------- + * Function : SUNRpowerI + * ----------------------------------------------------------------- + * Usage : int exponent; + * realtype base, ans; + * ans = SUNRpowerI(base,exponent); + * ----------------------------------------------------------------- + * SUNRpowerI returns the value of base^exponent, where base is of type + * realtype and exponent is of type int. + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT realtype SUNRpowerI(realtype base, int exponent); + +/* + * ----------------------------------------------------------------- + * Function : SUNRpowerR + * ----------------------------------------------------------------- + * Usage : realtype base, exponent, ans; + * ans = SUNRpowerR(base,exponent); + * ----------------------------------------------------------------- + * SUNRpowerR returns the value of base^exponent, where both base and + * exponent are of type realtype. If base < ZERO, then SUNRpowerR + * returns ZERO. + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT realtype SUNRpowerR(realtype base, realtype exponent); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_matrix.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_matrix.h new file mode 100644 index 0000000..2ac25c7 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_matrix.h @@ -0,0 +1,116 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * David Gardner, Carol Woodward, 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 the header file for a generic matrix package. + * It defines the SUNMatrix structure (_generic_SUNMatrix) which + * contains the following fields: + * - an implementation-dependent 'content' field which contains + * the description and actual data of the matrix + * - an 'ops' filed which contains a structure listing operations + * acting on such matrices + * ----------------------------------------------------------------- + * This header file contains: + * - enumeration constants for all SUNDIALS-defined matrix types, + * as well as a generic type for user-supplied matrix types, + * - type declarations for the _generic_SUNMatrix and + * _generic_SUNMatrix_Ops structures, as well as references to + * pointers to such structures (SUNMatrix), and + * - prototypes for the matrix functions which operate on + * SUNMatrix objects. + * ----------------------------------------------------------------- + * At a minimum, a particular implementation of a SUNMatrix must + * do the following: + * - specify the 'content' field of SUNMatrix, + * - implement the operations on those SUNMatrix objects, + * - provide a constructor routine for new SUNMatrix objects + * + * Additionally, a SUNMatrix implementation may provide the following: + * - macros to access the underlying SUNMatrix data + * - a routine to print the content of a SUNMatrix + * -----------------------------------------------------------------*/ + +#ifndef _SUNMATRIX_H +#define _SUNMATRIX_H + +#include <sundials/sundials_types.h> +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/* ----------------------------------------------------------------- + * Implemented SUNMatrix types + * ----------------------------------------------------------------- */ + +typedef enum { + SUNMATRIX_DENSE, + SUNMATRIX_BAND, + SUNMATRIX_SPARSE, + SUNMATRIX_CUSTOM +} SUNMatrix_ID; + + +/* ----------------------------------------------------------------- + * Generic definition of SUNMatrix + * ----------------------------------------------------------------- */ + +/* Forward reference for pointer to SUNMatrix_Ops object */ +typedef struct _generic_SUNMatrix_Ops *SUNMatrix_Ops; + +/* Forward reference for pointer to SUNMatrix object */ +typedef struct _generic_SUNMatrix *SUNMatrix; + +/* Structure containing function pointers to matrix operations */ +struct _generic_SUNMatrix_Ops { + SUNMatrix_ID (*getid)(SUNMatrix); + SUNMatrix (*clone)(SUNMatrix); + void (*destroy)(SUNMatrix); + int (*zero)(SUNMatrix); + int (*copy)(SUNMatrix, SUNMatrix); + int (*scaleadd)(realtype, SUNMatrix, SUNMatrix); + int (*scaleaddi)(realtype, SUNMatrix); + int (*matvec)(SUNMatrix, N_Vector, N_Vector); + int (*space)(SUNMatrix, long int*, long int*); +}; + +/* A matrix is a structure with an implementation-dependent + 'content' field, and a pointer to a structure of matrix + operations corresponding to that implementation. */ +struct _generic_SUNMatrix { + void *content; + struct _generic_SUNMatrix_Ops *ops; +}; + + +/* ----------------------------------------------------------------- + * Functions exported by SUNMatrix module + * ----------------------------------------------------------------- */ + +SUNDIALS_EXPORT SUNMatrix_ID SUNMatGetID(SUNMatrix A); +SUNDIALS_EXPORT SUNMatrix SUNMatClone(SUNMatrix A); +SUNDIALS_EXPORT void SUNMatDestroy(SUNMatrix A); +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 SUNMatMatvec(SUNMatrix A, N_Vector x, N_Vector y); +SUNDIALS_EXPORT int SUNMatSpace(SUNMatrix A, long int *lenrw, + long int *leniw); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_mpi.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_mpi.h new file mode 100644 index 0000000..bf80bcd --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_mpi.h @@ -0,0 +1,54 @@ +/* ----------------------------------------------------------------- + * 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 <sundials/sundials_types.h> +#include <sundials/sundials_mpi_types.h> + + +#if SUNDIALS_MPI_ENABLED + +#include <mpi.h> +#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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_mpi_types.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_mpi_types.h new file mode 100644 index 0000000..ea034d6 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_mpi_types.h @@ -0,0 +1,35 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Scott Cohen, Alan Hindmarsh, Radu Serban, + * Aaron Collier, and 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. + * -----------------------------------------------------------------*/ + +#include <sundials/sundials_types.h> + +/* define MPI data types */ + +#if defined(SUNDIALS_SINGLE_PRECISION) + #define PVEC_REAL_MPI_TYPE MPI_FLOAT +#elif defined(SUNDIALS_DOUBLE_PRECISION) + #define PVEC_REAL_MPI_TYPE MPI_DOUBLE +#elif defined(SUNDIALS_EXTENDED_PRECISION) + #define PVEC_REAL_MPI_TYPE MPI_LONG_DOUBLE +#endif + +#if defined(SUNDIALS_INT64_T) + #define PVEC_INTEGER_MPI_TYPE MPI_INT64_T +#elif defined(SUNDIALS_INT32_T) + #define PVEC_INTEGER_MPI_TYPE MPI_INT32_T +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_nonlinearsolver.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_nonlinearsolver.h new file mode 100644 index 0000000..0930136 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_nonlinearsolver.h @@ -0,0 +1,191 @@ +/* ----------------------------------------------------------------------------- + * 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 is the header file for a generic nonlinear solver package. It defines + * the SUNNonlinearSolver structure (_generic_SUNNonlinearSolver) which contains + * the following fields: + * - an implementation-dependent 'content' field which contains any internal + * data required by the solver + * - an 'ops' filed which contains a structure listing operations acting on/by + * such solvers + * + * We consider iterative nonlinear solvers for systems in both root finding + * (F(y) = 0) or fixed-point (G(y) = y) form. As a result, some of the routines + * are applicable only to one type of nonlinear solver. + * ----------------------------------------------------------------------------- + * This header file contains: + * - function types supplied to a SUNNonlinearSolver, + * - enumeration constants for SUNDIALS-defined nonlinear solver types, + * - type declarations for the _generic_SUNNonlinearSolver and + * _generic_SUNNonlinearSolver_Ops structures, as well as references to + * pointers to such structures (SUNNonlinearSolver), + * - prototypes for the nonlinear solver functions which operate + * on/by SUNNonlinearSolver objects, and + * - return codes for SUNLinearSolver objects. + * ----------------------------------------------------------------------------- + * At a minimum, a particular implementation of a SUNNonlinearSolver must do the + * following: + * - specify the 'content' field of a SUNNonlinearSolver, + * - implement the operations on/by the SUNNonlinearSovler objects, + * - provide a constructor routine for new SUNNonlinearSolver objects + * + * Additionally, a SUNNonlinearSolver implementation may provide the following: + * - "Set" routines to control solver-specific parameters/options + * - "Get" routines to access solver-specific performance metrics + * ---------------------------------------------------------------------------*/ + +#ifndef _SUNNONLINEARSOLVER_H +#define _SUNNONLINEARSOLVER_H + +#include <sundials/sundials_types.h> +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/* ----------------------------------------------------------------------------- + * Forward references for SUNNonlinearSolver types defined below + * ---------------------------------------------------------------------------*/ + +/* Forward reference for pointer to SUNNonlinearSolver_Ops object */ +typedef struct _generic_SUNNonlinearSolver_Ops *SUNNonlinearSolver_Ops; + +/* Forward reference for pointer to SUNNonlinearSolver object */ +typedef struct _generic_SUNNonlinearSolver *SUNNonlinearSolver; + + +/* ----------------------------------------------------------------------------- + * Integrator supplied function types + * ---------------------------------------------------------------------------*/ + +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 (*SUNNonlinSolLSolveFn)(N_Vector y, N_Vector b, void* mem); + +typedef int (*SUNNonlinSolConvTestFn)(SUNNonlinearSolver NLS, N_Vector y, + N_Vector del, realtype tol, N_Vector ewt, + void* mem); + + +/* ----------------------------------------------------------------------------- + * SUNNonlinearSolver types + * ---------------------------------------------------------------------------*/ + +typedef enum { + SUNNONLINEARSOLVER_ROOTFIND, + SUNNONLINEARSOLVER_FIXEDPOINT +} SUNNonlinearSolver_Type; + + +/* ----------------------------------------------------------------------------- + * Generic definition of SUNNonlinearSolver + * ---------------------------------------------------------------------------*/ + +/* Structure containing function pointers to nonlinear solver operations */ +struct _generic_SUNNonlinearSolver_Ops { + SUNNonlinearSolver_Type (*gettype)(SUNNonlinearSolver); + int (*initialize)(SUNNonlinearSolver); + int (*setup)(SUNNonlinearSolver, N_Vector, void*); + int (*solve)(SUNNonlinearSolver, N_Vector, N_Vector, N_Vector, realtype, + booleantype, void*); + int (*free)(SUNNonlinearSolver); + int (*setsysfn)(SUNNonlinearSolver, SUNNonlinSolSysFn); + int (*setlsetupfn)(SUNNonlinearSolver, SUNNonlinSolLSetupFn); + int (*setlsolvefn)(SUNNonlinearSolver, SUNNonlinSolLSolveFn); + int (*setctestfn)(SUNNonlinearSolver, SUNNonlinSolConvTestFn); + int (*setmaxiters)(SUNNonlinearSolver, int); + int (*getnumiters)(SUNNonlinearSolver, long int*); + int (*getcuriter)(SUNNonlinearSolver, int*); + int (*getnumconvfails)(SUNNonlinearSolver, long int*); +}; + +/* A nonlinear solver is a structure with an implementation-dependent 'content' + field, and a pointer to a structure of solver nonlinear solver operations + corresponding to that implementation. */ +struct _generic_SUNNonlinearSolver { + void *content; + struct _generic_SUNNonlinearSolver_Ops *ops; +}; + + +/* ----------------------------------------------------------------------------- + * Functions exported by SUNNonlinearSolver module + * ---------------------------------------------------------------------------*/ + +/* core functions */ +SUNDIALS_EXPORT SUNNonlinearSolver_Type SUNNonlinSolGetType(SUNNonlinearSolver NLS); + +SUNDIALS_EXPORT int SUNNonlinSolInitialize(SUNNonlinearSolver NLS); + +SUNDIALS_EXPORT int SUNNonlinSolSetup(SUNNonlinearSolver NLS, + N_Vector y, void* mem); + +SUNDIALS_EXPORT int SUNNonlinSolSolve(SUNNonlinearSolver NLS, + N_Vector y0, N_Vector y, + N_Vector w, realtype tol, + booleantype callLSetup, void *mem); + +SUNDIALS_EXPORT int SUNNonlinSolFree(SUNNonlinearSolver NLS); + +/* set functions */ +SUNDIALS_EXPORT int SUNNonlinSolSetSysFn(SUNNonlinearSolver NLS, + SUNNonlinSolSysFn SysFn); + +SUNDIALS_EXPORT int SUNNonlinSolSetLSetupFn(SUNNonlinearSolver NLS, + SUNNonlinSolLSetupFn SetupFn); + +SUNDIALS_EXPORT int SUNNonlinSolSetLSolveFn(SUNNonlinearSolver NLS, + SUNNonlinSolLSolveFn SolveFn); + +SUNDIALS_EXPORT int SUNNonlinSolSetConvTestFn(SUNNonlinearSolver NLS, + SUNNonlinSolConvTestFn CTestFn); + +SUNDIALS_EXPORT int SUNNonlinSolSetMaxIters(SUNNonlinearSolver NLS, + int maxiters); +/* get functions */ +SUNDIALS_EXPORT int SUNNonlinSolGetNumIters(SUNNonlinearSolver NLS, + long int *niters); + +SUNDIALS_EXPORT int SUNNonlinSolGetCurIter(SUNNonlinearSolver NLS, + int *iter); + +SUNDIALS_EXPORT int SUNNonlinSolGetNumConvFails(SUNNonlinearSolver NLS, + long int *nconvfails); + + +/* ----------------------------------------------------------------------------- + * SUNNonlinearSolver return values + * ---------------------------------------------------------------------------*/ + +#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 */ + +/* 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 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_nvector.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_nvector.h new file mode 100644 index 0000000..810dad6 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_nvector.h @@ -0,0 +1,229 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Radu Serban 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 a generic NVECTOR package. + * It defines the N_Vector structure (_generic_N_Vector) which + * contains the following fields: + * - an implementation-dependent 'content' field which contains + * the description and actual data of the vector + * - an 'ops' filed which contains a structure listing operations + * acting on such vectors + * ----------------------------------------------------------------- + * This header file contains: + * - enumeration constants for all SUNDIALS-defined vector types, + * as well as a generic type for user-supplied vector types, + * - type declarations for the _generic_N_Vector and + * _generic_N_Vector_Ops structures, as well as references to + * pointers to such structures (N_Vector), and + * - prototypes for the vector functions which operate on + * N_Vector objects. + * ----------------------------------------------------------------- + * At a minimum, a particular implementation of an NVECTOR must + * do the following: + * - specify the 'content' field of N_Vector, + * - implement the operations on those N_Vector objects, + * - provide a constructor routine for new N_Vector objects + * + * Additionally, an NVECTOR implementation may provide the following: + * - macros to access the underlying N_Vector data + * - a constructor for an array of N_Vectors + * - a constructor for an empty N_Vector (i.e., a new N_Vector with + * a NULL data pointer). + * - a routine to print the content of an N_Vector + * -----------------------------------------------------------------*/ + +#ifndef _NVECTOR_H +#define _NVECTOR_H + +#include <sundials/sundials_types.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/* ----------------------------------------------------------------- + * Implemented N_Vector types + * ----------------------------------------------------------------- */ + +typedef enum { + 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_CUSTOM +} N_Vector_ID; + + +/* ----------------------------------------------------------------- + * Generic definition of N_Vector + * ----------------------------------------------------------------- */ + +/* Forward reference for pointer to N_Vector_Ops object */ +typedef struct _generic_N_Vector_Ops *N_Vector_Ops; + +/* Forward reference for pointer to N_Vector object */ +typedef 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); + + /* standard vector operations */ + void (*nvlinearsum)(realtype, N_Vector, realtype, N_Vector, N_Vector); + void (*nvconst)(realtype, N_Vector); + void (*nvprod)(N_Vector, N_Vector, N_Vector); + void (*nvdiv)(N_Vector, N_Vector, N_Vector); + void (*nvscale)(realtype, N_Vector, N_Vector); + void (*nvabs)(N_Vector, N_Vector); + void (*nvinv)(N_Vector, N_Vector); + void (*nvaddconst)(N_Vector, realtype, N_Vector); + realtype (*nvdotprod)(N_Vector, N_Vector); + realtype (*nvmaxnorm)(N_Vector); + realtype (*nvwrmsnorm)(N_Vector, N_Vector); + realtype (*nvwrmsnormmask)(N_Vector, N_Vector, N_Vector); + realtype (*nvmin)(N_Vector); + realtype (*nvwl2norm)(N_Vector, N_Vector); + realtype (*nvl1norm)(N_Vector); + void (*nvcompare)(realtype, N_Vector, N_Vector); + booleantype (*nvinvtest)(N_Vector, N_Vector); + booleantype (*nvconstrmask)(N_Vector, N_Vector, N_Vector); + realtype (*nvminquotient)(N_Vector, N_Vector); + + /* fused vector operations */ + int (*nvlinearcombination)(int, realtype*, N_Vector*, N_Vector); + int (*nvscaleaddmulti)(int, realtype*, N_Vector, N_Vector*, N_Vector*); + int (*nvdotprodmulti)(int, N_Vector, N_Vector*, realtype*); + + /* vector array operations */ + int (*nvlinearsumvectorarray)(int, realtype, N_Vector*, realtype, N_Vector*, + N_Vector*); + 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*); +}; + +/* A vector is a structure with an implementation-dependent + 'content' field, and a pointer to a structure of vector + operations corresponding to that implementation. */ +struct _generic_N_Vector { + void *content; + struct _generic_N_Vector_Ops *ops; +}; + + +/* ----------------------------------------------------------------- + * Functions exported by NVECTOR module + * ----------------------------------------------------------------- */ + +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); +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); + +/* standard vector operations */ +SUNDIALS_EXPORT void N_VLinearSum(realtype a, N_Vector x, realtype b, + N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VConst(realtype c, N_Vector z); +SUNDIALS_EXPORT void N_VProd(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VDiv(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VScale(realtype c, N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAbs(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VInv(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAddConst(N_Vector x, realtype b, N_Vector z); +SUNDIALS_EXPORT realtype N_VDotProd(N_Vector x, N_Vector y); +SUNDIALS_EXPORT realtype N_VMaxNorm(N_Vector x); +SUNDIALS_EXPORT realtype N_VWrmsNorm(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWrmsNormMask(N_Vector x, N_Vector w, N_Vector id); +SUNDIALS_EXPORT realtype N_VMin(N_Vector x); +SUNDIALS_EXPORT realtype N_VWL2Norm(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VL1Norm(N_Vector x); +SUNDIALS_EXPORT void N_VCompare(realtype c, N_Vector x, N_Vector z); +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 */ +SUNDIALS_EXPORT int N_VLinearCombination(int nvec, realtype* c, N_Vector* X, + N_Vector z); + +SUNDIALS_EXPORT int N_VScaleAddMulti(int nvec, realtype* a, N_Vector x, + N_Vector* Y, N_Vector* Z); + +SUNDIALS_EXPORT int N_VDotProdMulti(int nvec, N_Vector x, N_Vector* Y, + realtype* dotprods); + +/* vector array operations */ +SUNDIALS_EXPORT int N_VLinearSumVectorArray(int nvec, + realtype a, N_Vector* X, + realtype b, N_Vector* Y, + N_Vector* Z); + +SUNDIALS_EXPORT int N_VScaleVectorArray(int nvec, realtype* c, N_Vector* X, + N_Vector* Z); + +SUNDIALS_EXPORT int N_VConstVectorArray(int nvec, realtype c, N_Vector* Z); + +SUNDIALS_EXPORT int N_VWrmsNormVectorArray(int nvec, N_Vector* X, N_Vector* W, + realtype* nrm); + +SUNDIALS_EXPORT int N_VWrmsNormMaskVectorArray(int nvec, N_Vector* X, + N_Vector* W, N_Vector id, + realtype* nrm); + +SUNDIALS_EXPORT int N_VScaleAddMultiVectorArray(int nvec, int nsum, + realtype* a, N_Vector* X, + N_Vector** Y, N_Vector** Z); + +SUNDIALS_EXPORT int N_VLinearCombinationVectorArray(int nvec, int nsum, + realtype* c, N_Vector** X, + N_Vector* Z); + + +/* ----------------------------------------------------------------- + * 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); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_nvector_senswrapper.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_nvector_senswrapper.h new file mode 100644 index 0000000..728ded6 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_nvector_senswrapper.h @@ -0,0 +1,104 @@ +/* ----------------------------------------------------------------------------- + * 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 is the header file for the implementation of the NVECTOR SensWrapper. + * + * Part I contains declarations specific to the implementation of the + * vector wrapper. + * + * Part II defines accessor macros that allow the user to efficiently access + * the content of the vector wrapper data structure. + * + * Part III contains the prototype for the constructors N_VNewEmpty_SensWrapper + * and N_VNew_SensWrapper, as well as wrappers to NVECTOR vector operations. + * ---------------------------------------------------------------------------*/ + +#ifndef _NVECTOR_SENSWRAPPER_H +#define _NVECTOR_SENSWRAPPER_H + +#include <stdio.h> +#include <sundials/sundials_nvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*============================================================================== + PART I: NVector wrapper content structure + ============================================================================*/ + +struct _N_VectorContent_SensWrapper { + N_Vector* vecs; /* array of wrapped vectors */ + int nvecs; /* number of wrapped vectors */ + booleantype own_vecs; /* flag indicating if wrapper owns vectors */ +}; + +typedef struct _N_VectorContent_SensWrapper *N_VectorContent_SensWrapper; + +/*============================================================================== + PART II: Macros to access wrapper content + ============================================================================*/ + +#define NV_CONTENT_SW(v) ( (N_VectorContent_SensWrapper)(v->content) ) +#define NV_VECS_SW(v) ( NV_CONTENT_SW(v)->vecs ) +#define NV_NVECS_SW(v) ( NV_CONTENT_SW(v)->nvecs ) +#define NV_OWN_VECS_SW(v) ( NV_CONTENT_SW(v)->own_vecs ) +#define NV_VEC_SW(v,i) ( NV_VECS_SW(v)[i] ) + +/*============================================================================== + PART III: Exported functions + ============================================================================*/ + +/* constructor creates an empty vector wrapper */ +SUNDIALS_EXPORT N_Vector N_VNewEmpty_SensWrapper(int nvecs); +SUNDIALS_EXPORT N_Vector N_VNew_SensWrapper(int count, N_Vector w); + +/* clone operations */ +SUNDIALS_EXPORT N_Vector N_VCloneEmpty_SensWrapper(N_Vector w); +SUNDIALS_EXPORT N_Vector N_VClone_SensWrapper(N_Vector w); + +/* destructor */ +SUNDIALS_EXPORT void N_VDestroy_SensWrapper(N_Vector v); + +/* standard vector operations */ +SUNDIALS_EXPORT void N_VLinearSum_SensWrapper(realtype a, N_Vector x, + realtype b, N_Vector y, + N_Vector z); +SUNDIALS_EXPORT void N_VConst_SensWrapper(realtype c, N_Vector z); +SUNDIALS_EXPORT void N_VProd_SensWrapper(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VDiv_SensWrapper(N_Vector x, N_Vector y, N_Vector z); +SUNDIALS_EXPORT void N_VScale_SensWrapper(realtype c, N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAbs_SensWrapper(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VInv_SensWrapper(N_Vector x, N_Vector z); +SUNDIALS_EXPORT void N_VAddConst_SensWrapper(N_Vector x, realtype b, + N_Vector z); +SUNDIALS_EXPORT realtype N_VDotProd_SensWrapper(N_Vector x, N_Vector y); +SUNDIALS_EXPORT realtype N_VMaxNorm_SensWrapper(N_Vector x); +SUNDIALS_EXPORT realtype N_VWrmsNorm_SensWrapper(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VWrmsNormMask_SensWrapper(N_Vector x, N_Vector w, + N_Vector id); +SUNDIALS_EXPORT realtype N_VMin_SensWrapper(N_Vector x); +SUNDIALS_EXPORT realtype N_VWL2Norm_SensWrapper(N_Vector x, N_Vector w); +SUNDIALS_EXPORT realtype N_VL1Norm_SensWrapper(N_Vector x); +SUNDIALS_EXPORT void N_VCompare_SensWrapper(realtype c, N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VInvTest_SensWrapper(N_Vector x, N_Vector z); +SUNDIALS_EXPORT booleantype N_VConstrMask_SensWrapper(N_Vector c, N_Vector x, + N_Vector m); +SUNDIALS_EXPORT realtype N_VMinQuotient_SensWrapper(N_Vector num, + N_Vector denom); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_pcg.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_pcg.h new file mode 100644 index 0000000..2918c69 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_pcg.h @@ -0,0 +1,164 @@ +/*--------------------------------------------------------------- + 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 <sundials/sundials_iterative.h> + +#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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_sparse.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_sparse.h new file mode 100644 index 0000000..bcffb58 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_sparse.h @@ -0,0 +1,91 @@ +/* + * ----------------------------------------------------------------- + * $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 <stdio.h> + +#include <sundials/sundials_types.h> +#include <sundials/sundials_direct.h> + +#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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_spbcgs.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_spbcgs.h new file mode 100644 index 0000000..c6a57a4 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_spbcgs.h @@ -0,0 +1,204 @@ +/* + * ----------------------------------------------------------------- + * $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 <sundials/sundials_iterative.h> + +#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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_spfgmr.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_spfgmr.h new file mode 100644 index 0000000..e4a79a3 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_spfgmr.h @@ -0,0 +1,294 @@ +/* ----------------------------------------------------------------- + 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 <sundials/sundials_iterative.h> + +#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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_spgmr.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_spgmr.h new file mode 100644 index 0000000..53e0fc2 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_spgmr.h @@ -0,0 +1,301 @@ +/* + * ----------------------------------------------------------------- + * $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 <sundials/sundials_iterative.h> + +#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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_sptfqmr.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_sptfqmr.h new file mode 100644 index 0000000..f2bcea8 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_sptfqmr.h @@ -0,0 +1,259 @@ +/* + * ----------------------------------------------------------------- + * $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 <sundials/sundials_iterative.h> + +#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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_superlumt_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_superlumt_impl.h new file mode 100644 index 0000000..2717776 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_superlumt_impl.h @@ -0,0 +1,61 @@ +/* + * ----------------------------------------------------------------- + * $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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_types.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_types.h new file mode 100644 index 0000000..bba7c07 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_types.h @@ -0,0 +1,145 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Scott Cohen, Alan Hindmarsh, Radu Serban, + * Aaron Collier, and 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 exports three types: realtype, sunindextype and + * booleantype, as well as the constants SUNTRUE and SUNFALSE. + * + * Users should include the header file sundials_types.h in every + * program file and use the exported name realtype instead of + * float, double or long double. + * + * The constants SUNDIALS_SINGLE_PRECISION, SUNDIALS_DOUBLE_PRECISION + * and SUNDIALS_LONG_DOUBLE_PRECISION indicate the underlying data + * type of realtype. + * + * The legal types for realtype are float, double and long double. + * + * The constants SUNDIALS_INT64_T and SUNDIALS_INT32_T indicate + * the underlying data type of sunindextype -- the integer data type + * used for vector and matrix indices. + * + * Data types are set at the configuration stage. + * + * The macro RCONST gives the user a convenient way to define + * real-valued literal constants. To use the constant 1.0, for example, + * the user should write the following: + * + * #define ONE RCONST(1.0) + * + * If realtype is defined as a double, then RCONST(1.0) expands + * to 1.0. If realtype is defined as a float, then RCONST(1.0) + * expands to 1.0F. If realtype is defined as a long double, + * then RCONST(1.0) expands to 1.0L. There is never a need to + * explicitly cast 1.0 to (realtype). The macro can be used for + * literal constants only. It cannot be used for expressions. + * -----------------------------------------------------------------*/ + +#ifndef _SUNDIALSTYPES_H +#define _SUNDIALSTYPES_H + +#ifndef _SUNDIALS_CONFIG_H +#define _SUNDIALS_CONFIG_H +#include <sundials/sundials_config.h> +#endif + +#include <float.h> +#include <stdint.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* + *------------------------------------------------------------------ + * Type realtype + * Macro RCONST + * Constants BIG_REAL, SMALL_REAL, and UNIT_ROUNDOFF + *------------------------------------------------------------------ + */ + +#if defined(SUNDIALS_SINGLE_PRECISION) + +typedef float realtype; +# define RCONST(x) x##F +# define BIG_REAL FLT_MAX +# define SMALL_REAL FLT_MIN +# define UNIT_ROUNDOFF FLT_EPSILON + +#elif defined(SUNDIALS_DOUBLE_PRECISION) + +typedef double realtype; +# define RCONST(x) x +# define BIG_REAL DBL_MAX +# define SMALL_REAL DBL_MIN +# define UNIT_ROUNDOFF DBL_EPSILON + +#elif defined(SUNDIALS_EXTENDED_PRECISION) + +typedef long double realtype; +# define RCONST(x) x##L +# define BIG_REAL LDBL_MAX +# define SMALL_REAL LDBL_MIN +# define UNIT_ROUNDOFF LDBL_EPSILON + +#endif + + +/* + *------------------------------------------------------------------ + * Type : sunindextype + *------------------------------------------------------------------ + * Defines integer type to be used for vector and matrix indices. + * User can build sundials to use 32- or 64-bit signed integers. + * If compiler does not support portable data types, the SUNDIALS + * CMake build system tries to find a type of the desired size. + *------------------------------------------------------------------ + */ + +typedef SUNDIALS_INDEX_TYPE sunindextype; + +/* + *------------------------------------------------------------------ + * Type : booleantype + *------------------------------------------------------------------ + * Constants : SUNFALSE and SUNTRUE + *------------------------------------------------------------------ + * ANSI C does not have a built-in boolean data type. Below is the + * definition for a new type called booleantype. The advantage of + * using the name booleantype (instead of int) is an increase in + * code readability. It also allows the programmer to make a + * distinction between int and boolean data. Variables of type + * booleantype are intended to have only the two values SUNFALSE and + * SUNTRUE which are defined below to be equal to 0 and 1, + * respectively. + *------------------------------------------------------------------ + */ + +#ifndef booleantype +#define booleantype int +#endif + +#ifndef SUNFALSE +#define SUNFALSE 0 +#endif + +#ifndef SUNTRUE +#define SUNTRUE 1 +#endif + + +#ifdef __cplusplus +} +#endif + +#endif /* _SUNDIALSTYPES_H */ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_version.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_version.h new file mode 100644 index 0000000..e557405 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sundials/sundials_version.h @@ -0,0 +1,38 @@ +/* ----------------------------------------------------------------- + * 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 header file is for routines to get SUNDIALS version info + * -----------------------------------------------------------------*/ + +#ifndef _SUNDIALS_VERSION_H +#define _SUNDIALS_VERSION_H + +#include <sundials/sundials_config.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* Fill a string with SUNDIALS version information */ +SUNDIALS_EXPORT int SUNDIALSGetVersion(char *version, int len); + +/* Fills integers with the major, minor, and patch release version numbers and a + string with the release label.*/ +SUNDIALS_EXPORT int SUNDIALSGetVersionNumber(int *major, int *minor, int *patch, + char *label, int len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_band.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_band.h new file mode 100644 index 0000000..a4acb16 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_band.h @@ -0,0 +1,75 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds, Ashley Crawford @ 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 header file for the band implementation of the + * SUNLINSOL module, SUNLINSOL_BAND. + * + * Note: + * - The definition of the generic SUNLinearSolver structure can + * be found in the header file sundials_linearsolver.h. + * ----------------------------------------------------------------- + */ + +#ifndef _SUNLINSOL_BAND_H +#define _SUNLINSOL_BAND_H + +#include <sundials/sundials_linearsolver.h> +#include <sundials/sundials_matrix.h> +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_band.h> +#include <sunmatrix/sunmatrix_band.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* --------------------------------------- + * Band Implementation of SUNLinearSolver + * --------------------------------------- */ + +struct _SUNLinearSolverContent_Band { + sunindextype N; + sunindextype *pivots; + long int last_flag; +}; + +typedef struct _SUNLinearSolverContent_Band *SUNLinearSolverContent_Band; + + +/* -------------------------------------- + * Exported Functions for SUNLINSOL_BAND + * -------------------------------------- */ + +SUNDIALS_EXPORT SUNLinearSolver SUNLinSol_Band(N_Vector y, SUNMatrix A); + +/* deprecated */ +SUNDIALS_EXPORT SUNLinearSolver SUNBandLinearSolver(N_Vector y, + SUNMatrix A); + +SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType_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 int SUNLinSolSpace_Band(SUNLinearSolver S, + long int *lenrwLS, + long int *leniwLS); +SUNDIALS_EXPORT int SUNLinSolFree_Band(SUNLinearSolver S); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_dense.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_dense.h new file mode 100644 index 0000000..a2161cd --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_dense.h @@ -0,0 +1,79 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds, Ashley Crawford @ 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 header file for the dense implementation of the + * SUNLINSOL module, SUNLINSOL_DENSE. + * + * Notes: + * - The definition of the generic SUNLinearSolver structure can + * be found in the header file sundials_linearsolver.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' and 'indextype'. + * ----------------------------------------------------------------- + */ + +#ifndef _SUNLINSOL_DENSE_H +#define _SUNLINSOL_DENSE_H + +#include <sundials/sundials_linearsolver.h> +#include <sundials/sundials_matrix.h> +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_dense.h> +#include <sunmatrix/sunmatrix_dense.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* ---------------------------------------- + * Dense Implementation of SUNLinearSolver + * ---------------------------------------- */ + +struct _SUNLinearSolverContent_Dense { + sunindextype N; + sunindextype *pivots; + long int last_flag; +}; + +typedef struct _SUNLinearSolverContent_Dense *SUNLinearSolverContent_Dense; + +/* ---------------------------------------- + * Exported Functions for SUNLINSOL_DENSE + * ---------------------------------------- */ + +SUNDIALS_EXPORT SUNLinearSolver SUNLinSol_Dense(N_Vector y, SUNMatrix A); + +/* deprecated */ +SUNDIALS_EXPORT SUNLinearSolver SUNDenseLinearSolver(N_Vector y, + SUNMatrix A); + +SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType_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 int SUNLinSolSpace_Dense(SUNLinearSolver S, + long int *lenrwLS, + long int *leniwLS); +SUNDIALS_EXPORT int SUNLinSolFree_Dense(SUNLinearSolver S); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_klu.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_klu.h new file mode 100644 index 0000000..dca22db --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_klu.h @@ -0,0 +1,138 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * 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 + * 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 KLU implementation of the + * SUNLINSOL module, SUNLINSOL_KLU. + * + * Note: + * - The definition of the generic SUNLinearSolver structure can + * be found in the header file sundials_linearsolver.h. + * ----------------------------------------------------------------- + */ + +#ifndef _SUNLINSOL_KLU_H +#define _SUNLINSOL_KLU_H + +#include <sundials/sundials_linearsolver.h> +#include <sundials/sundials_matrix.h> +#include <sundials/sundials_nvector.h> +#include <sunmatrix/sunmatrix_sparse.h> +#ifndef _KLU_H +#include <klu.h> +#endif + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* Default KLU solver parameters */ +#define SUNKLU_ORDERING_DEFAULT 1 /* COLAMD */ +#define SUNKLU_REINIT_FULL 1 +#define SUNKLU_REINIT_PARTIAL 2 + +/* Interfaces to match 'sunindextype' with the correct KLU types/functions */ +#if defined(SUNDIALS_INT64_T) +#define sun_klu_symbolic klu_l_symbolic +#define sun_klu_numeric klu_l_numeric +#define sun_klu_common klu_l_common +#define sun_klu_analyze klu_l_analyze +#define sun_klu_factor klu_l_factor +#define sun_klu_refactor klu_l_refactor +#define sun_klu_rcond klu_l_rcond +#define sun_klu_condest klu_l_condest +#define sun_klu_defaults klu_l_defaults +#define sun_klu_free_symbolic klu_l_free_symbolic +#define sun_klu_free_numeric klu_l_free_numeric +#elif defined(SUNDIALS_INT32_T) +#define sun_klu_symbolic klu_symbolic +#define sun_klu_numeric klu_numeric +#define sun_klu_common klu_common +#define sun_klu_analyze klu_analyze +#define sun_klu_factor klu_factor +#define sun_klu_refactor klu_refactor +#define sun_klu_rcond klu_rcond +#define sun_klu_condest klu_condest +#define sun_klu_defaults klu_defaults +#define sun_klu_free_symbolic klu_free_symbolic +#define sun_klu_free_numeric klu_free_numeric +#else /* incompatible sunindextype for KLU */ +#error Incompatible sunindextype for KLU +#endif + +#if defined(SUNDIALS_DOUBLE_PRECISION) +#else +#error Incompatible realtype for KLU +#endif + +/* -------------------------------------- + * KLU Implementation of SUNLinearSolver + * -------------------------------------- */ + +/* Create a typedef for the KLU solver function pointer to suppress compiler + * warning messages about sunindextype vs internal KLU index types. */ + +typedef sunindextype (*KLUSolveFn)(sun_klu_symbolic*, sun_klu_numeric*, + sunindextype, sunindextype, + double*, sun_klu_common*); + +struct _SUNLinearSolverContent_KLU { + long int last_flag; + int first_factorize; + sun_klu_symbolic *symbolic; + sun_klu_numeric *numeric; + sun_klu_common common; + KLUSolveFn klu_solver; +}; + +typedef struct _SUNLinearSolverContent_KLU *SUNLinearSolverContent_KLU; + + +/* ------------------------------------- + * Exported Functions for SUNLINSOL_KLU + * ------------------------------------- */ + +SUNDIALS_EXPORT SUNLinearSolver SUNLinSol_KLU(N_Vector y, SUNMatrix A); +SUNDIALS_EXPORT int SUNLinSol_KLUReInit(SUNLinearSolver S, SUNMatrix A, + sunindextype nnz, int reinit_type); +SUNDIALS_EXPORT int SUNLinSol_KLUSetOrdering(SUNLinearSolver S, + int ordering_choice); + +/* deprecated */ +SUNDIALS_EXPORT SUNLinearSolver SUNKLU(N_Vector y, SUNMatrix A); +/* deprecated */ +SUNDIALS_EXPORT int SUNKLUReInit(SUNLinearSolver S, SUNMatrix A, + sunindextype nnz, int reinit_type); +/* deprecated */ +SUNDIALS_EXPORT int SUNKLUSetOrdering(SUNLinearSolver S, + int ordering_choice); + +SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType_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 int SUNLinSolSpace_KLU(SUNLinearSolver S, + long int *lenrwLS, + long int *leniwLS); +SUNDIALS_EXPORT int SUNLinSolFree_KLU(SUNLinearSolver S); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_lapackband.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_lapackband.h new file mode 100644 index 0000000..71aed4c --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_lapackband.h @@ -0,0 +1,92 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 header file for the LAPACK band implementation of the + * SUNLINSOL module, SUNLINSOL_LAPACKBAND. + * + * Note: + * - The definition of the generic SUNLinearSolver structure can + * be found in the header file sundials_linearsolver.h. + * ----------------------------------------------------------------- + */ + +#ifndef _SUNLINSOL_LAPBAND_H +#define _SUNLINSOL_LAPBAND_H + +#include <sundials/sundials_linearsolver.h> +#include <sundials/sundials_lapack.h> +#include <sundials/sundials_matrix.h> +#include <sundials/sundials_nvector.h> +#include <sunmatrix/sunmatrix_band.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* Interfaces to match 'realtype' with the correct LAPACK functions */ +#if defined(SUNDIALS_DOUBLE_PRECISION) +#define xgbtrf_f77 dgbtrf_f77 +#define xgbtrs_f77 dgbtrs_f77 +#elif defined(SUNDIALS_SINGLE_PRECISION) +#define xgbtrf_f77 sgbtrf_f77 +#define xgbtrs_f77 sgbtrs_f77 +#else +#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; +}; + +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 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 int SUNLinSolSpace_LapackBand(SUNLinearSolver S, + long int *lenrwLS, + long int *leniwLS); +SUNDIALS_EXPORT int SUNLinSolFree_LapackBand(SUNLinearSolver S); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_lapackdense.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_lapackdense.h new file mode 100644 index 0000000..cdc35d4 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_lapackdense.h @@ -0,0 +1,92 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 header file for the LAPACK dense implementation of the + * SUNLINSOL module, SUNLINSOL_LINPACKDENSE. + * + * Note: + * - The definition of the generic SUNLinearSolver structure can + * be found in the header file sundials_linearsolver.h. + * ----------------------------------------------------------------- + */ + +#ifndef _SUNLINSOL_LAPDENSE_H +#define _SUNLINSOL_LAPDENSE_H + +#include <sundials/sundials_linearsolver.h> +#include <sundials/sundials_lapack.h> +#include <sundials/sundials_matrix.h> +#include <sundials/sundials_nvector.h> +#include <sunmatrix/sunmatrix_dense.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* Interfaces to match 'realtype' with the correct LAPACK functions */ +#if defined(SUNDIALS_DOUBLE_PRECISION) +#define xgetrf_f77 dgetrf_f77 +#define xgetrs_f77 dgetrs_f77 +#elif defined(SUNDIALS_SINGLE_PRECISION) +#define xgetrf_f77 sgetrf_f77 +#define xgetrs_f77 sgetrs_f77 +#else +#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; +}; + +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 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 int SUNLinSolSpace_LapackDense(SUNLinearSolver S, + long int *lenrwLS, + long int *leniwLS); +SUNDIALS_EXPORT int SUNLinSolFree_LapackDense(SUNLinearSolver S); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_pcg.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_pcg.h new file mode 100644 index 0000000..17343fb --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_pcg.h @@ -0,0 +1,113 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds, Ashley Crawford @ 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 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 + * be found in the header file sundials_linearsolver.h. + * ----------------------------------------------------------------- + */ + +#ifndef _SUNLINSOL_PCG_H +#define _SUNLINSOL_PCG_H + +#include <sundials/sundials_linearsolver.h> +#include <sundials/sundials_matrix.h> +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_pcg.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* Default PCG solver parameters */ +#define SUNPCG_MAXL_DEFAULT 5 + +/* -------------------------------------- + * PCG Implementation of SUNLinearSolver + * -------------------------------------- */ + +struct _SUNLinearSolverContent_PCG { + int maxl; + int pretype; + int numiters; + realtype resnorm; + long int last_flag; + + ATimesFn ATimes; + void* ATData; + PSetupFn Psetup; + PSolveFn Psolve; + void* PData; + + N_Vector s; + N_Vector r; + N_Vector p; + N_Vector z; + N_Vector Ap; +}; + +typedef struct _SUNLinearSolverContent_PCG *SUNLinearSolverContent_PCG; + + +/* ------------------------------------- + * Exported Functions for SUNLINSOL_PCG + * ------------------------------------- */ + +SUNDIALS_EXPORT SUNLinearSolver SUNLinSol_PCG(N_Vector y, + int pretype, + int maxl); +SUNDIALS_EXPORT int SUNLinSol_PCGSetPrecType(SUNLinearSolver S, + int pretype); +SUNDIALS_EXPORT int SUNLinSol_PCGSetMaxl(SUNLinearSolver S, + int maxl); + +/* deprecated */ +SUNDIALS_EXPORT SUNLinearSolver SUNPCG(N_Vector y, int pretype, int maxl); +/* deprecated */ +SUNDIALS_EXPORT int SUNPCGSetPrecType(SUNLinearSolver S, int pretype); +/* deprecated */ +SUNDIALS_EXPORT int SUNPCGSetMaxl(SUNLinearSolver S, int maxl); + +SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType_PCG(SUNLinearSolver S); +SUNDIALS_EXPORT int SUNLinSolInitialize_PCG(SUNLinearSolver S); +SUNDIALS_EXPORT int SUNLinSolSetATimes_PCG(SUNLinearSolver S, void* A_data, + ATimesFn ATimes); +SUNDIALS_EXPORT int SUNLinSolSetPreconditioner_PCG(SUNLinearSolver S, + void* P_data, + PSetupFn Pset, + PSolveFn Psol); +SUNDIALS_EXPORT int SUNLinSolSetScalingVectors_PCG(SUNLinearSolver S, + N_Vector s, + N_Vector nul); +SUNDIALS_EXPORT int SUNLinSolSetup_PCG(SUNLinearSolver S, SUNMatrix nul); +SUNDIALS_EXPORT int SUNLinSolSolve_PCG(SUNLinearSolver S, SUNMatrix nul, + N_Vector x, N_Vector b, realtype tol); +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, + long int *leniwLS); +SUNDIALS_EXPORT int SUNLinSolFree_PCG(SUNLinearSolver S); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_spbcgs.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_spbcgs.h new file mode 100644 index 0000000..282b5af --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_spbcgs.h @@ -0,0 +1,120 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * Based on code sundials_spbcgs.h by: 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 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 + * be found in the header file sundials_linearsolver.h. + * ----------------------------------------------------------------- + */ + +#ifndef _SUNLINSOL_SPBCGS_H +#define _SUNLINSOL_SPBCGS_H + +#include <sundials/sundials_linearsolver.h> +#include <sundials/sundials_matrix.h> +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_spbcgs.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* Default SPBCGS solver parameters */ +#define SUNSPBCGS_MAXL_DEFAULT 5 + +/* ----------------------------------------- + * SPBCGS Implementation of SUNLinearSolver + * ---------------------------------------- */ + +struct _SUNLinearSolverContent_SPBCGS { + int maxl; + int pretype; + int numiters; + realtype resnorm; + long int last_flag; + + ATimesFn ATimes; + void* ATData; + PSetupFn Psetup; + PSolveFn Psolve; + void* PData; + + N_Vector s1; + N_Vector s2; + N_Vector r; + N_Vector r_star; + N_Vector p; + N_Vector q; + N_Vector u; + N_Vector Ap; + N_Vector vtemp; +}; + +typedef struct _SUNLinearSolverContent_SPBCGS *SUNLinearSolverContent_SPBCGS; + + +/* --------------------------------------- + *Exported Functions for SUNLINSOL_SPBCGS + * --------------------------------------- */ + +SUNDIALS_EXPORT SUNLinearSolver SUNLinSol_SPBCGS(N_Vector y, + int pretype, + int maxl); +SUNDIALS_EXPORT int SUNLinSol_SPBCGSSetPrecType(SUNLinearSolver S, + int pretype); +SUNDIALS_EXPORT int SUNLinSol_SPBCGSSetMaxl(SUNLinearSolver S, + int maxl); + +/* deprecated */ +SUNDIALS_EXPORT SUNLinearSolver SUNSPBCGS(N_Vector y, int pretype, int maxl); +/* deprecated */ +SUNDIALS_EXPORT int SUNSPBCGSSetPrecType(SUNLinearSolver S, int pretype); +/* deprecated */ +SUNDIALS_EXPORT int SUNSPBCGSSetMaxl(SUNLinearSolver S, int maxl); + +SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType_SPBCGS(SUNLinearSolver S); +SUNDIALS_EXPORT int SUNLinSolInitialize_SPBCGS(SUNLinearSolver S); +SUNDIALS_EXPORT int SUNLinSolSetATimes_SPBCGS(SUNLinearSolver S, void* A_data, + ATimesFn ATimes); +SUNDIALS_EXPORT int SUNLinSolSetPreconditioner_SPBCGS(SUNLinearSolver S, + void* P_data, + PSetupFn Pset, + PSolveFn Psol); +SUNDIALS_EXPORT int SUNLinSolSetScalingVectors_SPBCGS(SUNLinearSolver S, + N_Vector s1, + N_Vector s2); +SUNDIALS_EXPORT int SUNLinSolSetup_SPBCGS(SUNLinearSolver S, SUNMatrix A); +SUNDIALS_EXPORT int SUNLinSolSolve_SPBCGS(SUNLinearSolver S, SUNMatrix A, + N_Vector x, N_Vector b, realtype tol); +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, + long int *leniwLS); +SUNDIALS_EXPORT int SUNLinSolFree_SPBCGS(SUNLinearSolver S); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_spfgmr.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_spfgmr.h new file mode 100644 index 0000000..98cc92b --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_spfgmr.h @@ -0,0 +1,132 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * 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 + * 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 SPFGMR implementation of the + * SUNLINSOL module, SUNLINSOL_SPFGMR. The SPFGMR algorithm is based + * 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 + * be found in the header file sundials_linearsolver.h. + * ----------------------------------------------------------------- + */ + +#ifndef _SUNLINSOL_SPFGMR_H +#define _SUNLINSOL_SPFGMR_H + +#include <sundials/sundials_linearsolver.h> +#include <sundials/sundials_matrix.h> +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_spfgmr.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* Default SPFGMR solver parameters */ +#define SUNSPFGMR_MAXL_DEFAULT 5 +#define SUNSPFGMR_MAXRS_DEFAULT 0 +#define SUNSPFGMR_GSTYPE_DEFAULT MODIFIED_GS + +/* ----------------------------------------- + * SPFGMR Implementation of SUNLinearSolver + * ----------------------------------------- */ + +struct _SUNLinearSolverContent_SPFGMR { + int maxl; + int pretype; + int gstype; + int max_restarts; + int numiters; + realtype resnorm; + long int last_flag; + + ATimesFn ATimes; + void* ATData; + PSetupFn Psetup; + PSolveFn Psolve; + void* PData; + + N_Vector s1; + N_Vector s2; + N_Vector *V; + N_Vector *Z; + realtype **Hes; + realtype *givens; + N_Vector xcor; + realtype *yg; + N_Vector vtemp; + + realtype *cv; + N_Vector *Xv; +}; + +typedef struct _SUNLinearSolverContent_SPFGMR *SUNLinearSolverContent_SPFGMR; + +/* ---------------------------------------- + * Exported Functions for SUNLINSOL_SPFGMR + * ---------------------------------------- */ + +SUNDIALS_EXPORT SUNLinearSolver SUNLinSol_SPFGMR(N_Vector y, + int pretype, + int maxl); +SUNDIALS_EXPORT int SUNLinSol_SPFGMRSetPrecType(SUNLinearSolver S, + int pretype); +SUNDIALS_EXPORT int SUNLinSol_SPFGMRSetGSType(SUNLinearSolver S, + int gstype); +SUNDIALS_EXPORT int SUNLinSol_SPFGMRSetMaxRestarts(SUNLinearSolver S, + int maxrs); + +/* deprecated */ +SUNDIALS_EXPORT SUNLinearSolver SUNSPFGMR(N_Vector y, int pretype, int maxl); +/* deprecated */ +SUNDIALS_EXPORT int SUNSPFGMRSetPrecType(SUNLinearSolver S, int pretype); +/* deprecated */ +SUNDIALS_EXPORT int SUNSPFGMRSetGSType(SUNLinearSolver S, int gstype); +/* deprecated */ +SUNDIALS_EXPORT int SUNSPFGMRSetMaxRestarts(SUNLinearSolver S, int maxrs); + + +SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType_SPFGMR(SUNLinearSolver S); +SUNDIALS_EXPORT int SUNLinSolInitialize_SPFGMR(SUNLinearSolver S); +SUNDIALS_EXPORT int SUNLinSolSetATimes_SPFGMR(SUNLinearSolver S, void* A_data, + ATimesFn ATimes); +SUNDIALS_EXPORT int SUNLinSolSetPreconditioner_SPFGMR(SUNLinearSolver S, + void* P_data, + PSetupFn Pset, + PSolveFn Psol); +SUNDIALS_EXPORT int SUNLinSolSetScalingVectors_SPFGMR(SUNLinearSolver S, + N_Vector s1, + N_Vector s2); +SUNDIALS_EXPORT int SUNLinSolSetup_SPFGMR(SUNLinearSolver S, SUNMatrix A); +SUNDIALS_EXPORT int SUNLinSolSolve_SPFGMR(SUNLinearSolver S, SUNMatrix A, + N_Vector x, N_Vector b, realtype tol); +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, + long int *leniwLS); +SUNDIALS_EXPORT int SUNLinSolFree_SPFGMR(SUNLinearSolver S); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_spgmr.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_spgmr.h new file mode 100644 index 0000000..9c79252 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_spgmr.h @@ -0,0 +1,131 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * 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 + * 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 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 + * be found in the header file sundials_linearsolver.h. + * ----------------------------------------------------------------- + */ + +#ifndef _SUNLINSOL_SPGMR_H +#define _SUNLINSOL_SPGMR_H + +#include <sundials/sundials_linearsolver.h> +#include <sundials/sundials_matrix.h> +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_spgmr.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* Default SPGMR solver parameters */ +#define SUNSPGMR_MAXL_DEFAULT 5 +#define SUNSPGMR_MAXRS_DEFAULT 0 +#define SUNSPGMR_GSTYPE_DEFAULT MODIFIED_GS + +/* ---------------------------------------- + * SPGMR Implementation of SUNLinearSolver + * ---------------------------------------- */ + +struct _SUNLinearSolverContent_SPGMR { + int maxl; + int pretype; + int gstype; + int max_restarts; + int numiters; + realtype resnorm; + long int last_flag; + + ATimesFn ATimes; + void* ATData; + PSetupFn Psetup; + PSolveFn Psolve; + void* PData; + + N_Vector s1; + N_Vector s2; + N_Vector *V; + realtype **Hes; + realtype *givens; + N_Vector xcor; + realtype *yg; + N_Vector vtemp; + + realtype *cv; + N_Vector *Xv; +}; + +typedef struct _SUNLinearSolverContent_SPGMR *SUNLinearSolverContent_SPGMR; + + +/* --------------------------------------- + * Exported Functions for SUNLINSOL_SPGMR + * --------------------------------------- */ + +SUNDIALS_EXPORT SUNLinearSolver SUNLinSol_SPGMR(N_Vector y, + int pretype, + int maxl); +SUNDIALS_EXPORT int SUNLinSol_SPGMRSetPrecType(SUNLinearSolver S, + int pretype); +SUNDIALS_EXPORT int SUNLinSol_SPGMRSetGSType(SUNLinearSolver S, + int gstype); +SUNDIALS_EXPORT int SUNLinSol_SPGMRSetMaxRestarts(SUNLinearSolver S, + int maxrs); + +/* deprecated */ +SUNDIALS_EXPORT SUNLinearSolver SUNSPGMR(N_Vector y, int pretype, int maxl); +/* deprecated */ +SUNDIALS_EXPORT int SUNSPGMRSetPrecType(SUNLinearSolver S, int pretype); +/* deprecated */ +SUNDIALS_EXPORT int SUNSPGMRSetGSType(SUNLinearSolver S, int gstype); +/* deprecated */ +SUNDIALS_EXPORT int SUNSPGMRSetMaxRestarts(SUNLinearSolver S, int maxrs); + +SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType_SPGMR(SUNLinearSolver S); +SUNDIALS_EXPORT int SUNLinSolInitialize_SPGMR(SUNLinearSolver S); +SUNDIALS_EXPORT int SUNLinSolSetATimes_SPGMR(SUNLinearSolver S, void* A_data, + ATimesFn ATimes); +SUNDIALS_EXPORT int SUNLinSolSetPreconditioner_SPGMR(SUNLinearSolver S, + void* P_data, + PSetupFn Pset, + PSolveFn Psol); +SUNDIALS_EXPORT int SUNLinSolSetScalingVectors_SPGMR(SUNLinearSolver S, + N_Vector s1, + N_Vector s2); +SUNDIALS_EXPORT int SUNLinSolSetup_SPGMR(SUNLinearSolver S, SUNMatrix A); +SUNDIALS_EXPORT int SUNLinSolSolve_SPGMR(SUNLinearSolver S, SUNMatrix A, + N_Vector x, N_Vector b, realtype tol); +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, + long int *leniwLS); +SUNDIALS_EXPORT int SUNLinSolFree_SPGMR(SUNLinearSolver S); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_sptfqmr.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_sptfqmr.h new file mode 100644 index 0000000..57c1b46 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_sptfqmr.h @@ -0,0 +1,122 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * Based on code sundials_sptfqmr.h by: 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 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 + * be found in the header file sundials_linearsolver.h. + * ----------------------------------------------------------------- + */ + +#ifndef _SUNLINSOL_SPTFQMR_H +#define _SUNLINSOL_SPTFQMR_H + +#include <sundials/sundials_linearsolver.h> +#include <sundials/sundials_matrix.h> +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_sptfqmr.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* Default SPTFQMR solver parameters */ +#define SUNSPTFQMR_MAXL_DEFAULT 5 + +/* ------------------------------------------ + * SPTFQMR Implementation of SUNLinearSolver + * ------------------------------------------ */ + +struct _SUNLinearSolverContent_SPTFQMR { + int maxl; + int pretype; + int numiters; + realtype resnorm; + long int last_flag; + + ATimesFn ATimes; + void* ATData; + PSetupFn Psetup; + PSolveFn Psolve; + void* PData; + + N_Vector s1; + N_Vector s2; + 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; +}; + +typedef struct _SUNLinearSolverContent_SPTFQMR *SUNLinearSolverContent_SPTFQMR; + + /* ------------------------------------- + * Exported Functions SUNLINSOL_SPTFQMR + * -------------------------------------- */ + +SUNDIALS_EXPORT SUNLinearSolver SUNLinSol_SPTFQMR(N_Vector y, + int pretype, + int maxl); +SUNDIALS_EXPORT int SUNLinSol_SPTFQMRSetPrecType(SUNLinearSolver S, + int pretype); +SUNDIALS_EXPORT int SUNLinSol_SPTFQMRSetMaxl(SUNLinearSolver S, + int maxl); + +/* deprecated */ +SUNDIALS_EXPORT SUNLinearSolver SUNSPTFQMR(N_Vector y, int pretype, int maxl); +/* deprecated */ +SUNDIALS_EXPORT int SUNSPTFQMRSetPrecType(SUNLinearSolver S, int pretype); +/* deprecated */ +SUNDIALS_EXPORT int SUNSPTFQMRSetMaxl(SUNLinearSolver S, int maxl); + +SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType_SPTFQMR(SUNLinearSolver S); +SUNDIALS_EXPORT int SUNLinSolInitialize_SPTFQMR(SUNLinearSolver S); +SUNDIALS_EXPORT int SUNLinSolSetATimes_SPTFQMR(SUNLinearSolver S, void* A_data, + ATimesFn ATimes); +SUNDIALS_EXPORT int SUNLinSolSetPreconditioner_SPTFQMR(SUNLinearSolver S, + void* P_data, + PSetupFn Pset, + PSolveFn Psol); +SUNDIALS_EXPORT int SUNLinSolSetScalingVectors_SPTFQMR(SUNLinearSolver S, + N_Vector s1, + N_Vector s2); +SUNDIALS_EXPORT int SUNLinSolSetup_SPTFQMR(SUNLinearSolver S, SUNMatrix A); +SUNDIALS_EXPORT int SUNLinSolSolve_SPTFQMR(SUNLinearSolver S, SUNMatrix A, + N_Vector x, N_Vector b, realtype tol); +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, + long int *leniwLS); +SUNDIALS_EXPORT int SUNLinSolFree_SPTFQMR(SUNLinearSolver S); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_superlumt.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_superlumt.h new file mode 100644 index 0000000..962976b --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunlinsol/sunlinsol_superlumt.h @@ -0,0 +1,125 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * Based on codes sundials_superlumt_impl.h and <solver>_superlumt.h + * written by 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 + * ----------------------------------------------------------------- + * This is the header file for the SuperLUMT implementation of the + * SUNLINSOL module, SUNLINSOL_SUPERLUMT. + * + * Note: + * - The definition of the generic SUNLinearSolver structure can + * be found in the header file sundials_linearsolver.h. + * ----------------------------------------------------------------- + */ + +#ifndef _SUNLINSOL_SLUMT_H +#define _SUNLINSOL_SLUMT_H + +#include <sundials/sundials_linearsolver.h> +#include <sundials/sundials_matrix.h> +#include <sundials/sundials_nvector.h> +#include <sunmatrix/sunmatrix_sparse.h> + +/* Assume SuperLU_MT library was built with compatible index type */ +#if defined(SUNDIALS_INT64_T) +#define _LONGINT +#endif + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* Default SuperLU_MT solver parameters */ +#define SUNSLUMT_ORDERING_DEFAULT 3 /* COLAMD */ + +/* Interfaces to match 'realtype' with the correct SuperLUMT functions */ +#if defined(SUNDIALS_DOUBLE_PRECISION) +#ifndef _SLUMT_H +#define _SLUMT_H +#include "slu_mt_ddefs.h" +#endif +#define xgstrs dgstrs +#define pxgstrf pdgstrf +#define pxgstrf_init pdgstrf_init +#define xCreate_Dense_Matrix dCreate_Dense_Matrix +#define xCreate_CompCol_Matrix dCreate_CompCol_Matrix +#elif defined(SUNDIALS_SINGLE_PRECISION) +#ifndef _SLUMT_H +#define _SLUMT_H +#include "slu_mt_sdefs.h" +#endif +#define xgstrs sgstrs +#define pxgstrf psgstrf +#define pxgstrf_init psgstrf_init +#define xCreate_Dense_Matrix sCreate_Dense_Matrix +#define xCreate_CompCol_Matrix sCreate_CompCol_Matrix +#else /* incompatible sunindextype for SuperLUMT */ +#error Incompatible realtype for SuperLUMT +#endif + + +/* -------------------------------------------- + * SuperLUMT Implementation of SUNLinearSolver + * -------------------------------------------- */ + +struct _SUNLinearSolverContent_SuperLUMT { + long 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; + int ordering; + superlumt_options_t *options; +}; + +typedef struct _SUNLinearSolverContent_SuperLUMT *SUNLinearSolverContent_SuperLUMT; + + +/* ------------------------------------------- + * Exported Functions for SUNLINSOL_SUPERLUMT + * ------------------------------------------- */ + +SUNDIALS_EXPORT SUNLinearSolver SUNLinSol_SuperLUMT(N_Vector y, + SUNMatrix A, + int num_threads); +SUNDIALS_EXPORT int SUNLinSol_SuperLUMTSetOrdering(SUNLinearSolver S, + int ordering_choice); + +/* deprecated */ +SUNDIALS_EXPORT SUNLinearSolver SUNSuperLUMT(N_Vector y, SUNMatrix A, + int num_threads); +/* deprecated */ +SUNDIALS_EXPORT int SUNSuperLUMTSetOrdering(SUNLinearSolver S, + int ordering_choice); + +SUNDIALS_EXPORT SUNLinearSolver_Type SUNLinSolGetType_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, + long int *leniwLS); +SUNDIALS_EXPORT int SUNLinSolFree_SuperLUMT(SUNLinearSolver S); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunmatrix/sunmatrix_band.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunmatrix/sunmatrix_band.h new file mode 100644 index 0000000..ea0727d --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunmatrix/sunmatrix_band.h @@ -0,0 +1,129 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * David Gardner @ LLNL + * Based on code sundials_direct.h by: 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 band implementation of the + * SUNMATRIX module, SUNMATRIX_BAND. + * + * Notes: + * - The definition of the generic SUNMatrix structure can be found + * in the header file sundials_matrix.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' and 'indextype'. + * ----------------------------------------------------------------- + */ + +#ifndef _SUNMATRIX_BAND_H +#define _SUNMATRIX_BAND_H + +#include <stdio.h> +#include <sundials/sundials_matrix.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* --------------------------------- + * Band implementation of SUNMatrix + * --------------------------------- */ + +struct _SUNMatrixContent_Band { + sunindextype M; + sunindextype N; + sunindextype ldim; + sunindextype mu; + sunindextype ml; + sunindextype s_mu; + realtype *data; + sunindextype ldata; + realtype **cols; +}; + +typedef struct _SUNMatrixContent_Band *SUNMatrixContent_Band; + + +/* ------------------------------------ + * Macros for access to SUNMATRIX_BAND + * ------------------------------------ */ + +#define SM_CONTENT_B(A) ( (SUNMatrixContent_Band)(A->content) ) + +#define SM_ROWS_B(A) ( SM_CONTENT_B(A)->M ) + +#define SM_COLUMNS_B(A) ( SM_CONTENT_B(A)->N ) + +#define SM_LDATA_B(A) ( SM_CONTENT_B(A)->ldata ) + +#define SM_UBAND_B(A) ( SM_CONTENT_B(A)->mu ) + +#define SM_LBAND_B(A) ( SM_CONTENT_B(A)->ml ) + +#define SM_SUBAND_B(A) ( SM_CONTENT_B(A)->s_mu ) + +#define SM_LDIM_B(A) ( SM_CONTENT_B(A)->ldim ) + +#define SM_DATA_B(A) ( SM_CONTENT_B(A)->data ) + +#define SM_COLS_B(A) ( SM_CONTENT_B(A)->cols ) + +#define SM_COLUMN_B(A,j) ( ((SM_CONTENT_B(A)->cols)[j])+SM_SUBAND_B(A) ) + +#define SM_COLUMN_ELEMENT_B(col_j,i,j) (col_j[(i)-(j)]) + +#define SM_ELEMENT_B(A,i,j) ( (SM_CONTENT_B(A)->cols)[j][(i)-(j)+SM_SUBAND_B(A)] ) + + +/* ---------------------------------------- + * Exported Functions for SUNMATRIX_BAND + * ---------------------------------------- */ + +SUNDIALS_EXPORT SUNMatrix SUNBandMatrix(sunindextype N, sunindextype mu, + sunindextype ml); + +SUNDIALS_EXPORT SUNMatrix SUNBandMatrixStorage(sunindextype N, + sunindextype mu, + sunindextype ml, + sunindextype smu); + +SUNDIALS_EXPORT void SUNBandMatrix_Print(SUNMatrix A, FILE* outfile); + +SUNDIALS_EXPORT sunindextype SUNBandMatrix_Rows(SUNMatrix A); +SUNDIALS_EXPORT sunindextype SUNBandMatrix_Columns(SUNMatrix A); +SUNDIALS_EXPORT sunindextype SUNBandMatrix_LowerBandwidth(SUNMatrix A); +SUNDIALS_EXPORT sunindextype SUNBandMatrix_UpperBandwidth(SUNMatrix A); +SUNDIALS_EXPORT sunindextype SUNBandMatrix_StoredUpperBandwidth(SUNMatrix A); +SUNDIALS_EXPORT sunindextype SUNBandMatrix_LDim(SUNMatrix A); +SUNDIALS_EXPORT realtype* SUNBandMatrix_Data(SUNMatrix A); +SUNDIALS_EXPORT realtype** SUNBandMatrix_Cols(SUNMatrix A); +SUNDIALS_EXPORT realtype* SUNBandMatrix_Column(SUNMatrix A, sunindextype j); + +SUNDIALS_EXPORT SUNMatrix_ID SUNMatGetID_Band(SUNMatrix A); +SUNDIALS_EXPORT SUNMatrix SUNMatClone_Band(SUNMatrix A); +SUNDIALS_EXPORT void SUNMatDestroy_Band(SUNMatrix A); +SUNDIALS_EXPORT int SUNMatZero_Band(SUNMatrix A); +SUNDIALS_EXPORT int SUNMatCopy_Band(SUNMatrix A, SUNMatrix B); +SUNDIALS_EXPORT int SUNMatScaleAdd_Band(realtype c, SUNMatrix A, SUNMatrix B); +SUNDIALS_EXPORT int SUNMatScaleAddI_Band(realtype c, SUNMatrix A); +SUNDIALS_EXPORT int SUNMatMatvec_Band(SUNMatrix A, N_Vector x, N_Vector y); +SUNDIALS_EXPORT int SUNMatSpace_Band(SUNMatrix A, long int *lenrw, long int *leniw); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunmatrix/sunmatrix_dense.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunmatrix/sunmatrix_dense.h new file mode 100644 index 0000000..de40e56 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunmatrix/sunmatrix_dense.h @@ -0,0 +1,105 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * David Gardner @ LLNL + * Based on code sundials_direct.h by: 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 dense implementation of the + * SUNMATRIX module, SUNMATRIX_DENSE. + * + * Notes: + * - The definition of the generic SUNMatrix structure can be found + * in the header file sundials_matrix.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' and 'indextype'. + * ----------------------------------------------------------------- + */ + +#ifndef _SUNMATRIX_DENSE_H +#define _SUNMATRIX_DENSE_H + +#include <stdio.h> +#include <sundials/sundials_matrix.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* ---------------------------------- + * Dense implementation of SUNMatrix + * ---------------------------------- */ + +struct _SUNMatrixContent_Dense { + sunindextype M; + sunindextype N; + realtype *data; + sunindextype ldata; + realtype **cols; +}; + +typedef struct _SUNMatrixContent_Dense *SUNMatrixContent_Dense; + +/* ------------------------------------ + * Macros for access to SUNMATRIX_DENSE + * ------------------------------------ */ + +#define SM_CONTENT_D(A) ( (SUNMatrixContent_Dense)(A->content) ) + +#define SM_ROWS_D(A) ( SM_CONTENT_D(A)->M ) + +#define SM_COLUMNS_D(A) ( SM_CONTENT_D(A)->N ) + +#define SM_LDATA_D(A) ( SM_CONTENT_D(A)->ldata ) + +#define SM_DATA_D(A) ( SM_CONTENT_D(A)->data ) + +#define SM_COLS_D(A) ( SM_CONTENT_D(A)->cols ) + +#define SM_COLUMN_D(A,j) ( (SM_CONTENT_D(A)->cols)[j] ) + +#define SM_ELEMENT_D(A,i,j) ( (SM_CONTENT_D(A)->cols)[j][i] ) + +/* --------------------------------------- + * Exported Functions for SUNMATRIX_DENSE + * --------------------------------------- */ + +SUNDIALS_EXPORT SUNMatrix SUNDenseMatrix(sunindextype M, sunindextype N); + +SUNDIALS_EXPORT void SUNDenseMatrix_Print(SUNMatrix A, FILE* outfile); + +SUNDIALS_EXPORT sunindextype SUNDenseMatrix_Rows(SUNMatrix A); +SUNDIALS_EXPORT sunindextype SUNDenseMatrix_Columns(SUNMatrix A); +SUNDIALS_EXPORT sunindextype SUNDenseMatrix_LData(SUNMatrix A); +SUNDIALS_EXPORT realtype* SUNDenseMatrix_Data(SUNMatrix A); +SUNDIALS_EXPORT realtype** SUNDenseMatrix_Cols(SUNMatrix A); +SUNDIALS_EXPORT realtype* SUNDenseMatrix_Column(SUNMatrix A, sunindextype j); + +SUNDIALS_EXPORT SUNMatrix_ID SUNMatGetID_Dense(SUNMatrix A); +SUNDIALS_EXPORT SUNMatrix SUNMatClone_Dense(SUNMatrix A); +SUNDIALS_EXPORT void SUNMatDestroy_Dense(SUNMatrix A); +SUNDIALS_EXPORT int SUNMatZero_Dense(SUNMatrix A); +SUNDIALS_EXPORT int SUNMatCopy_Dense(SUNMatrix A, SUNMatrix B); +SUNDIALS_EXPORT int SUNMatScaleAdd_Dense(realtype c, SUNMatrix A, SUNMatrix B); +SUNDIALS_EXPORT int SUNMatScaleAddI_Dense(realtype c, SUNMatrix A); +SUNDIALS_EXPORT int SUNMatMatvec_Dense(SUNMatrix A, N_Vector x, N_Vector y); +SUNDIALS_EXPORT int SUNMatSpace_Dense(SUNMatrix A, long int *lenrw, long int *leniw); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunmatrix/sunmatrix_sparse.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunmatrix/sunmatrix_sparse.h new file mode 100644 index 0000000..aea60aa --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunmatrix/sunmatrix_sparse.h @@ -0,0 +1,143 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * David Gardner @ LLNL + * Based on code sundials_sparse.h by: Carol Woodward and + * Slaven Peles @ LLNL, and 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 header file for the sparse implementation of the + * SUNMATRIX module, SUNMATRIX_SPARSE. + * + * Notes: + * - The definition of the generic SUNMatrix structure can be found + * in the header file sundials_matrix.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' and 'indextype'. + * ----------------------------------------------------------------- + */ + +#ifndef _SUNMATRIX_SPARSE_H +#define _SUNMATRIX_SPARSE_H + +#include <stdio.h> +#include <sundials/sundials_matrix.h> +#include <sunmatrix/sunmatrix_dense.h> +#include <sunmatrix/sunmatrix_band.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* ------------------------ + * Matrix Type Definitions + * ------------------------ */ + +#define CSC_MAT 0 +#define CSR_MAT 1 + + +/* ------------------------------------------ + * Sparse Implementation of SUNMATRIX_SPARSE + * ------------------------------------------ */ + +struct _SUNMatrixContent_Sparse { + sunindextype M; + sunindextype N; + sunindextype NNZ; + sunindextype NP; + realtype *data; + int sparsetype; + sunindextype *indexvals; + sunindextype *indexptrs; + /* CSC indices */ + sunindextype **rowvals; + sunindextype **colptrs; + /* CSR indices */ + sunindextype **colvals; + sunindextype **rowptrs; +}; + +typedef struct _SUNMatrixContent_Sparse *SUNMatrixContent_Sparse; + + +/* --------------------------------------- + * Macros for access to SUNMATRIX_SPARSE + * --------------------------------------- */ + +#define SM_CONTENT_S(A) ( (SUNMatrixContent_Sparse)(A->content) ) + +#define SM_ROWS_S(A) ( SM_CONTENT_S(A)->M ) + +#define SM_COLUMNS_S(A) ( SM_CONTENT_S(A)->N ) + +#define SM_NNZ_S(A) ( SM_CONTENT_S(A)->NNZ ) + +#define SM_NP_S(A) ( SM_CONTENT_S(A)->NP ) + +#define SM_SPARSETYPE_S(A) ( SM_CONTENT_S(A)->sparsetype ) + +#define SM_DATA_S(A) ( SM_CONTENT_S(A)->data ) + +#define SM_INDEXVALS_S(A) ( SM_CONTENT_S(A)->indexvals ) + +#define SM_INDEXPTRS_S(A) ( SM_CONTENT_S(A)->indexptrs ) + +/* ---------------------------------------- + * Exported Functions for SUNMATRIX_SPARSE + * ---------------------------------------- */ + +SUNDIALS_EXPORT SUNMatrix SUNSparseMatrix(sunindextype M, sunindextype N, + sunindextype NNZ, int sparsetype); + +SUNDIALS_EXPORT SUNMatrix SUNSparseFromDenseMatrix(SUNMatrix A, + realtype droptol, + int sparsetype); + +SUNDIALS_EXPORT SUNMatrix SUNSparseFromBandMatrix(SUNMatrix A, + realtype droptol, + int sparsetype); + +SUNDIALS_EXPORT int SUNSparseMatrix_Realloc(SUNMatrix A); + +SUNDIALS_EXPORT int SUNSparseMatrix_Reallocate(SUNMatrix A, sunindextype NNZ); + +SUNDIALS_EXPORT void SUNSparseMatrix_Print(SUNMatrix A, FILE* outfile); + +SUNDIALS_EXPORT sunindextype SUNSparseMatrix_Rows(SUNMatrix A); +SUNDIALS_EXPORT sunindextype SUNSparseMatrix_Columns(SUNMatrix A); +SUNDIALS_EXPORT sunindextype SUNSparseMatrix_NNZ(SUNMatrix A); +SUNDIALS_EXPORT sunindextype SUNSparseMatrix_NP(SUNMatrix A); +SUNDIALS_EXPORT int SUNSparseMatrix_SparseType(SUNMatrix A); +SUNDIALS_EXPORT realtype* SUNSparseMatrix_Data(SUNMatrix A); +SUNDIALS_EXPORT sunindextype* SUNSparseMatrix_IndexValues(SUNMatrix A); +SUNDIALS_EXPORT sunindextype* SUNSparseMatrix_IndexPointers(SUNMatrix A); + +SUNDIALS_EXPORT SUNMatrix_ID SUNMatGetID_Sparse(SUNMatrix A); +SUNDIALS_EXPORT SUNMatrix SUNMatClone_Sparse(SUNMatrix A); +SUNDIALS_EXPORT void SUNMatDestroy_Sparse(SUNMatrix A); +SUNDIALS_EXPORT int SUNMatZero_Sparse(SUNMatrix A); +SUNDIALS_EXPORT int SUNMatCopy_Sparse(SUNMatrix A, SUNMatrix B); +SUNDIALS_EXPORT int SUNMatScaleAdd_Sparse(realtype c, SUNMatrix A, SUNMatrix B); +SUNDIALS_EXPORT int SUNMatScaleAddI_Sparse(realtype c, SUNMatrix A); +SUNDIALS_EXPORT int SUNMatMatvec_Sparse(SUNMatrix A, N_Vector x, N_Vector y); +SUNDIALS_EXPORT int SUNMatSpace_Sparse(SUNMatrix A, long int *lenrw, long int *leniw); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunnonlinsol/sunnonlinsol_fixedpoint.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunnonlinsol/sunnonlinsol_fixedpoint.h new file mode 100644 index 0000000..e75c42b --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunnonlinsol/sunnonlinsol_fixedpoint.h @@ -0,0 +1,113 @@ +/*----------------------------------------------------------------------------- + * Programmer(s): 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 header file for the SUNNonlinearSolver module implementation of + * the Anderson-accelerated fixed-point method. + * + * Part I defines the solver-specific content structure. + * + * Part II contains prototypes for the solver constructor and operations. + *---------------------------------------------------------------------------*/ + +#ifndef _SUNNONLINSOL_FIXEDPOINT_H +#define _SUNNONLINSOL_FIXEDPOINT_H + +#include "sundials/sundials_types.h" +#include "sundials/sundials_nvector.h" +#include "sundials/sundials_nonlinearsolver.h" + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*----------------------------------------------------------------------------- + I. Content structure + ---------------------------------------------------------------------------*/ + +struct _SUNNonlinearSolverContent_FixedPoint { + + /* functions provided by the integrator */ + SUNNonlinSolSysFn Sys; /* fixed-point iteration function */ + 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 */ +}; + +typedef struct _SUNNonlinearSolverContent_FixedPoint *SUNNonlinearSolverContent_FixedPoint; + +/* ----------------------------------------------------------------------------- + II: Exported functions + ---------------------------------------------------------------------------*/ + +/* Constructor to create solver and allocates memory */ +SUNDIALS_EXPORT SUNNonlinearSolver SUNNonlinSol_FixedPoint(N_Vector y, int m); +SUNDIALS_EXPORT SUNNonlinearSolver SUNNonlinSol_FixedPointSens(int count, N_Vector y, int m); + +/* core functions */ +SUNDIALS_EXPORT SUNNonlinearSolver_Type SUNNonlinSolGetType_FixedPoint(SUNNonlinearSolver NLS); + +SUNDIALS_EXPORT int SUNNonlinSolInitialize_FixedPoint(SUNNonlinearSolver NLS); + +SUNDIALS_EXPORT int SUNNonlinSolSolve_FixedPoint(SUNNonlinearSolver NLS, + N_Vector y0, N_Vector y, + N_Vector w, realtype tol, + booleantype callSetup, void *mem); + +SUNDIALS_EXPORT int SUNNonlinSolFree_FixedPoint(SUNNonlinearSolver NLS); + +/* set functions */ +SUNDIALS_EXPORT int SUNNonlinSolSetSysFn_FixedPoint(SUNNonlinearSolver NLS, + SUNNonlinSolSysFn SysFn); + +SUNDIALS_EXPORT int SUNNonlinSolSetConvTestFn_FixedPoint(SUNNonlinearSolver NLS, + SUNNonlinSolConvTestFn CTestFn); + +SUNDIALS_EXPORT int SUNNonlinSolSetMaxIters_FixedPoint(SUNNonlinearSolver NLS, + int maxiters); + +/* get functions */ +SUNDIALS_EXPORT int SUNNonlinSolGetNumIters_FixedPoint(SUNNonlinearSolver NLS, + long int *niters); + +SUNDIALS_EXPORT int SUNNonlinSolGetCurIter_FixedPoint(SUNNonlinearSolver NLS, + int *iter); + +SUNDIALS_EXPORT int SUNNonlinSolGetNumConvFails_FixedPoint(SUNNonlinearSolver NLS, + long int *nconvfails); + +SUNDIALS_EXPORT int SUNNonlinSolGetSysFn_FixedPoint(SUNNonlinearSolver NLS, + SUNNonlinSolSysFn *SysFn); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunnonlinsol/sunnonlinsol_newton.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunnonlinsol/sunnonlinsol_newton.h new file mode 100644 index 0000000..3db653c --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/include/sunnonlinsol/sunnonlinsol_newton.h @@ -0,0 +1,109 @@ +/* ----------------------------------------------------------------------------- + * 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 is the header file for the SUNNonlinearSolver module implementation of + * Newton's method. + * + * Part I defines the solver-specific content structure. + * + * Part II contains prototypes for the solver constructor and operations. + * ---------------------------------------------------------------------------*/ + +#ifndef _SUNNONLINSOL_NEWTON_H +#define _SUNNONLINSOL_NEWTON_H + +#include "sundials/sundials_types.h" +#include "sundials/sundials_nvector.h" +#include "sundials/sundials_nonlinearsolver.h" + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* ----------------------------------------------------------------------------- + * I. Content structure + * ---------------------------------------------------------------------------*/ + +struct _SUNNonlinearSolverContent_Newton { + + /* functions provided by the integrator */ + SUNNonlinSolSysFn Sys; /* nonlinear system residual function */ + SUNNonlinSolLSetupFn LSetup; /* linear solver setup function */ + SUNNonlinSolLSolveFn LSolve; /* linear solver solve function */ + SUNNonlinSolConvTestFn CTest; /* nonlinear solver convergence test function */ + + /* nonlinear solver variables */ + N_Vector delta; /* Newton update vector */ + booleantype jcur; /* Jacobian status, current = SUNTRUE / stale = SUNFALSE */ + int curiter; /* current number of iterations in a solve attempt */ + 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 */ +}; + +typedef struct _SUNNonlinearSolverContent_Newton *SUNNonlinearSolverContent_Newton; + +/* ----------------------------------------------------------------------------- + * II: Exported functions + * ---------------------------------------------------------------------------*/ + +/* Constructor to create solver and allocates memory */ +SUNDIALS_EXPORT SUNNonlinearSolver SUNNonlinSol_Newton(N_Vector y); +SUNDIALS_EXPORT SUNNonlinearSolver SUNNonlinSol_NewtonSens(int count, N_Vector y); + +/* core functions */ +SUNDIALS_EXPORT SUNNonlinearSolver_Type SUNNonlinSolGetType_Newton(SUNNonlinearSolver NLS); + +SUNDIALS_EXPORT int SUNNonlinSolInitialize_Newton(SUNNonlinearSolver NLS); + +SUNDIALS_EXPORT int SUNNonlinSolSolve_Newton(SUNNonlinearSolver NLS, + N_Vector y0, N_Vector y, + N_Vector w, realtype tol, + booleantype callLSetup, void *mem); + +SUNDIALS_EXPORT int SUNNonlinSolFree_Newton(SUNNonlinearSolver NLS); + +/* set functions */ +SUNDIALS_EXPORT int SUNNonlinSolSetSysFn_Newton(SUNNonlinearSolver NLS, + SUNNonlinSolSysFn SysFn); + +SUNDIALS_EXPORT int SUNNonlinSolSetLSetupFn_Newton(SUNNonlinearSolver NLS, + SUNNonlinSolLSetupFn LSetupFn); + +SUNDIALS_EXPORT int SUNNonlinSolSetLSolveFn_Newton(SUNNonlinearSolver NLS, + SUNNonlinSolLSolveFn LSolveFn); + +SUNDIALS_EXPORT int SUNNonlinSolSetConvTestFn_Newton(SUNNonlinearSolver NLS, + SUNNonlinSolConvTestFn CTestFn); + +SUNDIALS_EXPORT int SUNNonlinSolSetMaxIters_Newton(SUNNonlinearSolver NLS, + int maxiters); + +/* get functions */ +SUNDIALS_EXPORT int SUNNonlinSolGetNumIters_Newton(SUNNonlinearSolver NLS, + long int *niters); + +SUNDIALS_EXPORT int SUNNonlinSolGetCurIter_Newton(SUNNonlinearSolver NLS, + int *iter); + +SUNDIALS_EXPORT int SUNNonlinSolGetNumConvFails_Newton(SUNNonlinearSolver NLS, + long int *nconvfails); + +SUNDIALS_EXPORT int SUNNonlinSolGetSysFn_Newton(SUNNonlinearSolver NLS, + SUNNonlinSolSysFn *SysFn); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode.c new file mode 100644 index 0000000..65916ba --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode.c @@ -0,0 +1,2557 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 the main ARKode + * infrastructure. It is independent of the ARKode time step + * module, nonlinear solver, linear solver and vector modules in + * use. + *--------------------------------------------------------------*/ + +/*=============================================================== + Import Header Files + ===============================================================*/ +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> + +#include "arkode_impl.h" +#include <sundials/sundials_math.h> +#include <sundials/sundials_types.h> + +#define NO_DEBUG_OUTPUT +/* #define DEBUG_OUTPUT */ +#ifdef DEBUG_OUTPUT +#include <nvector/nvector_serial.h> +#endif + +#if defined(SUNDIALS_EXTENDED_PRECISION) +#define RSYM ".32Lg" +#else +#define RSYM ".16g" +#endif + + +/*=============================================================== + EXPORTED FUNCTIONS + ===============================================================*/ + +/*--------------------------------------------------------------- + arkCreate: + + arkCreate creates an internal memory block for a problem to + be solved by a time step module built on ARKode. If successful, + arkCreate returns a pointer to the problem memory. If an + initialization error occurs, arkCreate prints an error message + to standard err and returns NULL. + ---------------------------------------------------------------*/ +ARKodeMem arkCreate() +{ + int iret; + ARKodeMem ark_mem; + + ark_mem = NULL; + ark_mem = (ARKodeMem) malloc(sizeof(struct ARKodeMemRec)); + if (ark_mem == NULL) { + arkProcessError(NULL, 0, "ARKode", "arkCreate", + MSG_ARK_ARKMEM_FAIL); + return(NULL); + } + + /* Zero out ark_mem */ + memset(ark_mem, 0, sizeof(struct ARKodeMemRec)); + + /* 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_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; + + /* Initialize root finding variables */ + ark_mem->root_mem = NULL; + + /* Initialize diagnostics reporting variables */ + ark_mem->report = SUNFALSE; + ark_mem->diagfp = NULL; + + /* Initialize lrw and liw */ + ark_mem->lrw = 18; + 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; + + /* No user-supplied step postprocessing function yet */ + ark_mem->ProcessStep = NULL; + + /* Return pointer to ARKode memory block */ + return(ark_mem); +} + + +/*--------------------------------------------------------------- + arkResize: + + arkResize re-initializes ARKode's memory for a problem with a + changing vector size. It is assumed that the problem dynamics + before and after the vector resize will be comparable, so that + all time-stepping heuristics prior to calling arkResize + remain valid after the call. If instead the dynamics should be + re-calibrated, the ARKode memory structure should be deleted + with a call to *StepFree, and re-created with a call to + *StepCreate. + + To aid in the vector-resize operation, the user can supply a + vector resize function, that will take as input an N_Vector with + the previous size, and return as output a corresponding vector + of the new size. If this function (of type ARKVecResizeFn) is + not supplied (i.e. is set to NULL), then all existing N_Vectors + will be destroyed and re-cloned from the input vector. + + In the case that the dynamical time scale should be modified + slightly from the previous time scale, an input "hscale" is + allowed, that will re-scale the upcoming time step by the + specified factor. If a value <= 0 is specified, the default of + 1.0 will be used. + + Other arguments: + ark_mem Existing ARKode memory data structure. + y0 The newly-sized solution vector, holding + the current dependent variable values. + t0 The current value of the independent + variable. + resize_data User-supplied data structure that will be + passed to the supplied resize function. + + The return value is ARK_SUCCESS = 0 if no errors occurred, or + a negative value otherwise. + ---------------------------------------------------------------*/ +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; + + /* Check ark_mem */ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkResize", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + + /* Check if ark_mem was allocated */ + if (ark_mem->MallocDone == SUNFALSE) { + arkProcessError(ark_mem, ARK_NO_MALLOC, "ARKode", + "arkResize", MSG_ARK_NO_MALLOC); + return(ARK_NO_MALLOC); + } + + /* Check for legal input parameters */ + if (y0 == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkResize", MSG_ARK_NULL_Y0); + return(ARK_ILL_INPUT); + } + + /* Copy the input parameters into ARKode state */ + ark_mem->tcur = t0; + ark_mem->tn = t0; + + /* Update time-stepping parameters */ + /* adjust upcoming step size depending on hscale */ + if (hscale < 0.0) hscale = 1.0; + if (hscale != 1.0) { + + /* Encode hscale into ark_mem structure */ + ark_mem->eta = hscale; + ark_mem->hprime *= hscale; + + /* If next step would overtake tstop, adjust stepsize */ + if ( ark_mem->tstopset ) + if ( (ark_mem->tcur + ark_mem->hprime - ark_mem->tstop)*ark_mem->hprime > ZERO ) { + ark_mem->hprime = (ark_mem->tstop-ark_mem->tcur) * + (ONE-FOUR*ark_mem->uround); + ark_mem->eta = ark_mem->hprime/ark_mem->h; + } + + } + + /* Determing change in vector sizes */ + lrw1 = liw1 = 0; + if (y0->ops->nvspace != NULL) + N_VSpace(y0, &lrw1, &liw1); + lrw_diff = lrw1 - ark_mem->lrw1; + liw_diff = liw1 - ark_mem->liw1; + ark_mem->lrw1 = lrw1; + ark_mem->liw1 = liw1; + + /* Resize the ARKode vectors */ + /* Vabstol */ + ier = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + liw_diff, y0, &ark_mem->Vabstol); + if (ier != ARK_SUCCESS) return(ier); + /* VRabstol */ + ier = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + liw_diff, y0, &ark_mem->VRabstol); + if (ier != ARK_SUCCESS) return(ier); + /* ewt */ + ier = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + liw_diff, y0, &ark_mem->ewt); + if (ier != ARK_SUCCESS) return(ier); + /* 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, + liw_diff, y0, &ark_mem->rwt); + if (ier != ARK_SUCCESS) return(ier); + } + /* yn */ + ier = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + liw_diff, y0, &ark_mem->yn); + if (ier != ARK_SUCCESS) return(ier); + /* tempv* */ + ier = 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, + liw_diff, y0, &ark_mem->tempv2); + if (ier != ARK_SUCCESS) return(ier); + ier = 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, + liw_diff, y0, &ark_mem->tempv4); + if (ier != ARK_SUCCESS) return(ier); + + + /* 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", + "Interpolation module resize failure"); + return(ier); + } + } + + /* Copy y0 into ark_yn to set the current solution */ + N_VScale(ONE, y0, ark_mem->yn); + + /* Indicate that problem size is new */ + ark_mem->resized = SUNTRUE; + ark_mem->firststage = SUNTRUE; + + /* Problem has been successfully re-sized */ + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSStolerances, arkSVtolerances, arkWFtolerances: + + These functions specify the integration tolerances. One of them + SHOULD be called before the first call to arkEvolve; otherwise + default values of reltol=1e-4 and abstol=1e-9 will be used, + which may be entirely incorrect for a specific problem. + + arkSStolerances specifies scalar relative and absolute + tolerances. + + arkSVtolerances specifies scalar relative tolerance and a + vector absolute tolerance (a potentially different absolute + tolerance for each vector component). + + arkWFtolerances specifies a user-provides function (of type + ARKEwtFn) which will be called to set the error weight vector. + ---------------------------------------------------------------*/ +int arkSStolerances(ARKodeMem ark_mem, realtype reltol, realtype abstol) +{ + /* Check inputs */ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSStolerances", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + if (ark_mem->MallocDone == SUNFALSE) { + arkProcessError(ark_mem, ARK_NO_MALLOC, "ARKode", + "arkSStolerances", MSG_ARK_NO_MALLOC); + return(ARK_NO_MALLOC); + } + if (reltol < ZERO) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkSStolerances", MSG_ARK_BAD_RELTOL); + return(ARK_ILL_INPUT); + } + if (abstol < ZERO) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkSStolerances", MSG_ARK_BAD_ABSTOL); + return(ARK_ILL_INPUT); + } + + /* Copy tolerances into memory */ + ark_mem->reltol = reltol; + ark_mem->Sabstol = abstol; + ark_mem->itol = ARK_SS; + + /* enforce use of arkEwtSet */ + ark_mem->user_efun = SUNFALSE; + ark_mem->efun = arkEwtSet; + ark_mem->e_data = ark_mem; + + return(ARK_SUCCESS); +} + + +int arkSVtolerances(ARKodeMem ark_mem, realtype reltol, N_Vector abstol) +{ + /* Check inputs */ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSVtolerances", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + if (ark_mem->MallocDone == SUNFALSE) { + arkProcessError(ark_mem, ARK_NO_MALLOC, "ARKode", + "arkSVtolerances", MSG_ARK_NO_MALLOC); + return(ARK_NO_MALLOC); + } + if (reltol < ZERO) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkSVtolerances", MSG_ARK_BAD_RELTOL); + return(ARK_ILL_INPUT); + } + if (N_VMin(abstol) < ZERO) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkSVtolerances", MSG_ARK_BAD_ABSTOL); + return(ARK_ILL_INPUT); + } + + /* Copy tolerances into memory */ + if ( !(ark_mem->VabstolMallocDone) ) { + ark_mem->Vabstol = N_VClone(ark_mem->ewt); + ark_mem->lrw += ark_mem->lrw1; + ark_mem->liw += ark_mem->liw1; + ark_mem->VabstolMallocDone = SUNTRUE; + } + N_VScale(ONE, abstol, ark_mem->Vabstol); + ark_mem->reltol = reltol; + ark_mem->itol = ARK_SV; + + /* enforce use of arkEwtSet */ + ark_mem->user_efun = SUNFALSE; + ark_mem->efun = arkEwtSet; + ark_mem->e_data = ark_mem; + + return(ARK_SUCCESS); +} + + +int arkWFtolerances(ARKodeMem ark_mem, ARKEwtFn efun) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkWFtolerances", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + if (ark_mem->MallocDone == SUNFALSE) { + arkProcessError(ark_mem, ARK_NO_MALLOC, "ARKode", + "arkWFtolerances", MSG_ARK_NO_MALLOC); + return(ARK_NO_MALLOC); + } + + /* Copy tolerance data into memory */ + 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 */ + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkResStolerance, arkResVtolerance, arkResFtolerance: + + These functions specify the absolute residual tolerance. + Specification of the absolute residual tolerance is only + necessary for problems with non-identity mass matrices in which + the units of the solution vector y dramatically differ from the + units of the ODE right-hand side f(t,y). If this occurs, one + of these routines SHOULD be called before the first call to + ARKode; otherwise the default value of rabstol=1e-9 will be + used, which may be entirely incorrect for a specific problem. + + arkResStolerances specifies a scalar residual tolerance. + + arkResVtolerances specifies a vector residual tolerance + (a potentially different absolute residual tolerance for + each vector component). + + arkResFtolerances specifies a user-provides function (of + type ARKRwtFn) which will be called to set the residual + weight vector. + ---------------------------------------------------------------*/ +int arkResStolerance(ARKodeMem ark_mem, realtype rabstol) +{ + /* Check inputs */ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkResStolerances", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + if (ark_mem->MallocDone == SUNFALSE) { + arkProcessError(ark_mem, ARK_NO_MALLOC, "ARKode", + "arkResStolerances", MSG_ARK_NO_MALLOC); + return(ARK_NO_MALLOC); + } + if (rabstol < ZERO) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkResStolerances", MSG_ARK_BAD_RABSTOL); + return(ARK_ILL_INPUT); + } + + /* Allocate space for rwt if necessary */ + if (ark_mem->rwt_is_ewt) { + ark_mem->rwt_is_ewt = SUNFALSE; + ark_mem->rwt = N_VClone(ark_mem->ewt); + ark_mem->lrw += ark_mem->lrw1; + ark_mem->liw += ark_mem->liw1; + } + + /* Copy tolerances into memory */ + ark_mem->SRabstol = rabstol; + ark_mem->ritol = ARK_SS; + + /* enforce use of arkRwtSet */ + ark_mem->user_efun = SUNFALSE; + ark_mem->rfun = arkRwtSet; + ark_mem->r_data = ark_mem; + + return(ARK_SUCCESS); +} + + +int arkResVtolerance(ARKodeMem ark_mem, N_Vector rabstol) +{ + /* Check inputs */ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkResVtolerances", 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); + return(ARK_NO_MALLOC); + } + if (N_VMin(rabstol) < ZERO) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkResVtolerances", MSG_ARK_BAD_RABSTOL); + return(ARK_ILL_INPUT); + } + + /* Allocate space for rwt if necessary */ + if (ark_mem->rwt_is_ewt) { + ark_mem->rwt_is_ewt = SUNFALSE; + ark_mem->rwt = N_VClone(ark_mem->ewt); + ark_mem->lrw += ark_mem->lrw1; + ark_mem->liw += ark_mem->liw1; + } + + /* Copy tolerances into memory */ + if ( !(ark_mem->VRabstolMallocDone) ) { + ark_mem->VRabstol = N_VClone(ark_mem->rwt); + ark_mem->lrw += ark_mem->lrw1; + ark_mem->liw += ark_mem->liw1; + ark_mem->VRabstolMallocDone = SUNTRUE; + } + N_VScale(ONE, rabstol, ark_mem->VRabstol); + ark_mem->ritol = ARK_SV; + + + /* enforce use of arkRwtSet */ + ark_mem->user_efun = SUNFALSE; + ark_mem->rfun = arkRwtSet; + ark_mem->r_data = ark_mem; + + return(ARK_SUCCESS); +} + + +int arkResFtolerance(ARKodeMem ark_mem, ARKRwtFn rfun) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkResFtolerances", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + if (ark_mem->MallocDone == SUNFALSE) { + arkProcessError(ark_mem, ARK_NO_MALLOC, "ARKode", + "arkResFtolerances", MSG_ARK_NO_MALLOC); + return(ARK_NO_MALLOC); + } + + /* Allocate space for rwt if necessary */ + if (ark_mem->rwt_is_ewt) { + ark_mem->rwt_is_ewt = SUNFALSE; + ark_mem->rwt = N_VClone(ark_mem->ewt); + ark_mem->lrw += ark_mem->lrw1; + ark_mem->liw += ark_mem->liw1; + } + + /* Copy tolerance data into memory */ + 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 */ + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkEvolve: + + This routine is the main driver of ARKode-based integrators. + + It integrates over a time interval defined by the user, by + calling the time step module to do internal time steps. + + The first time that arkEvolve is called for a successfully + initialized problem, it computes a tentative initial step size. + + arkEvolve supports two modes as specified by itask: ARK_NORMAL and + ARK_ONE_STEP. In the ARK_NORMAL mode, the solver steps until + it reaches or passes tout and then interpolates to obtain + y(tout). In the ARK_ONE_STEP mode, it takes one internal step + and returns. The behavior of both modes can be over-rided + through user-specification of ark_tstop (through the + *StepSetStopTime function), in which case if a solver step + would pass tstop, the step is shortened so that it stops at + exactly the specified stop time, and hence interpolation of + y(tout) is not required. + ---------------------------------------------------------------*/ +int arkEvolve(ARKodeMem ark_mem, realtype tout, N_Vector yout, + realtype *tret, int itask) +{ + long int nstloc; + int retval, kflag, istate, ir, ier; + int ewtsetOK; + realtype troundoff, nrm; + booleantype inactive_roots; + + + /* Check and process inputs */ + + /* Check if ark_mem exists */ + if (ark_mem == NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkEvolve", + MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + + /* Check if ark_mem was allocated */ + if (ark_mem->MallocDone == SUNFALSE) { + arkProcessError(ark_mem, ARK_NO_MALLOC, "ARKode", "arkEvolve", + MSG_ARK_NO_MALLOC); + return(ARK_NO_MALLOC); + } + + /* Check for yout != NULL */ + if ((ark_mem->ycur = yout) == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkEvolve", + MSG_ARK_YOUT_NULL); + return(ARK_ILL_INPUT); + } + + /* Check for tret != NULL */ + if (tret == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkEvolve", + MSG_ARK_TRET_NULL); + return(ARK_ILL_INPUT); + } + + /* Check for valid itask */ + if ( (itask != ARK_NORMAL) && (itask != ARK_ONE_STEP) ) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkEvolve", + MSG_ARK_BAD_ITASK); + return(ARK_ILL_INPUT); + } + + /* store copy of itask if using root-finding */ + if (ark_mem->root_mem != NULL) { + if (itask == ARK_NORMAL) ark_mem->root_mem->toutc = tout; + ark_mem->root_mem->taskc = itask; + } + + + /* perform first-step-specific initializations: + - initialize tret values to initialization time + - 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); + } + + + /* perform first-step-after-resize initializations */ + if (ark_mem->nst > 0 && ark_mem->resized) { + ier = arkPostResizeSetup(ark_mem); + if (ier!= ARK_SUCCESS) return(ier); + } + + + /* perform stopping tests */ + if (ark_mem->nst > 0 && !ark_mem->resized) + if (arkStopTests(ark_mem, tout, yout, tret, itask, &ier)) + return(ier); + + + /*-------------------------------------------------- + Looping point for internal steps + + - update the ewt vector for the next 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 + - 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) + --------------------------------------------------*/ + nstloc = 0; + for(;;) { + + ark_mem->next_h = ark_mem->h; + + /* Reset and check ewt */ + if (ark_mem->nst > 0 && !ark_mem->resized) { + ewtsetOK = ark_mem->efun(ark_mem->yn, + ark_mem->ewt, + ark_mem->e_data); + if (ewtsetOK != 0) { + if (ark_mem->itol == ARK_WF) + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkEvolve", + MSG_ARK_EWT_NOW_FAIL, ark_mem->tcur); + else + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkEvolve", + MSG_ARK_EWT_NOW_BAD, ark_mem->tcur); + + istate = ARK_ILL_INPUT; + ark_mem->tretlast = *tret = ark_mem->tcur; + N_VScale(ONE, ark_mem->yn, yout); + break; + } + } + + /* Reset and check rwt */ + if (!ark_mem->rwt_is_ewt) { + if (ark_mem->nst > 0 && !ark_mem->resized) { + ewtsetOK = ark_mem->rfun(ark_mem->yn, + ark_mem->rwt, + ark_mem->r_data); + if (ewtsetOK != 0) { + if (ark_mem->itol == ARK_WF) + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkEvolve", + MSG_ARK_RWT_NOW_FAIL, ark_mem->tcur); + else + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkEvolve", + MSG_ARK_RWT_NOW_BAD, ark_mem->tcur); + + istate = ARK_ILL_INPUT; + ark_mem->tretlast = *tret = ark_mem->tcur; + N_VScale(ONE, ark_mem->yn, yout); + break; + } + } + } + + /* Check for too many steps */ + if ( (ark_mem->mxstep>0) && (nstloc >= ark_mem->mxstep) ) { + arkProcessError(ark_mem, ARK_TOO_MUCH_WORK, "ARKode", "arkEvolve", + MSG_ARK_MAX_STEPS, ark_mem->tcur); + istate = ARK_TOO_MUCH_WORK; + ark_mem->tretlast = *tret = ark_mem->tcur; + N_VScale(ONE, ark_mem->yn, yout); + break; + } + + /* Check for too much accuracy requested */ + nrm = N_VWrmsNorm(ark_mem->yn, ark_mem->ewt); + ark_mem->tolsf = ark_mem->uround * nrm; + if (ark_mem->tolsf > ONE) { + arkProcessError(ark_mem, ARK_TOO_MUCH_ACC, "ARKode", "arkEvolve", + MSG_ARK_TOO_MUCH_ACC, ark_mem->tcur); + istate = ARK_TOO_MUCH_ACC; + ark_mem->tretlast = *tret = ark_mem->tcur; + N_VScale(ONE, ark_mem->yn, yout); + ark_mem->tolsf *= TWO; + break; + } else { + ark_mem->tolsf = ONE; + } + + /* Check for h below roundoff level in tn */ + if (ark_mem->tcur + ark_mem->h == ark_mem->tcur) { + ark_mem->nhnil++; + if (ark_mem->nhnil <= ark_mem->mxhnil) + arkProcessError(ark_mem, ARK_WARNING, "ARKode", "arkEvolve", + MSG_ARK_HNIL, ark_mem->tcur, ark_mem->h); + if (ark_mem->nhnil == ark_mem->mxhnil) + arkProcessError(ark_mem, ARK_WARNING, "ARKode", "arkEvolve", + MSG_ARK_HNIL_DONE); + } + + /* Update parameter for upcoming step size */ + if ((ark_mem->nst > 0) && (ark_mem->hprime != ark_mem->h)) { + ark_mem->h = ark_mem->h * ark_mem->eta; + ark_mem->next_h = ark_mem->h; + } + if (ark_mem->fixedstep) { + ark_mem->h = ark_mem->hin; + ark_mem->next_h = ark_mem->h; + } + + /* Call time stepper module to take a step */ + kflag = ark_mem->step((void*) ark_mem); + + /* Process successful step, catch additional errors to send to arkHandleFailure */ + if (kflag == ARK_SUCCESS) + kflag = arkCompleteStep(ark_mem); + + /* Process failed step cases, and exit loop */ + if (kflag != ARK_SUCCESS) { + istate = arkHandleFailure(ark_mem, kflag); + ark_mem->tretlast = *tret = ark_mem->tcur; + N_VScale(ONE, ark_mem->yn, yout); + break; + } + + nstloc++; + + /* Check for root in last step taken. */ + if (ark_mem->root_mem != NULL) + if (ark_mem->root_mem->nrtfn > 0) { + + retval = arkRootCheck3((void*) ark_mem); + if (retval == RTFOUND) { /* A new root was found */ + ark_mem->root_mem->irfnd = 1; + istate = ARK_ROOT_RETURN; + ark_mem->tretlast = *tret = ark_mem->root_mem->tlo; + break; + } else if (retval == ARK_RTFUNC_FAIL) { /* g failed */ + arkProcessError(ark_mem, ARK_RTFUNC_FAIL, "ARKode", "arkEvolve", + MSG_ARK_RTFUNC_FAILED, ark_mem->root_mem->tlo); + istate = ARK_RTFUNC_FAIL; + break; + } + + /* If we are at the end of the first step and we still have + some event functions that are inactive, issue a warning + as this may indicate a user error in the implementation + of the root function. */ + if (ark_mem->nst==1) { + inactive_roots = SUNFALSE; + for (ir=0; ir<ark_mem->root_mem->nrtfn; ir++) { + if (!ark_mem->root_mem->gactive[ir]) { + inactive_roots = SUNTRUE; + break; + } + } + if ((ark_mem->root_mem->mxgnull > 0) && inactive_roots) { + arkProcessError(ark_mem, ARK_WARNING, "ARKode", "arkEvolve", + MSG_ARK_INACTIVE_ROOTS); + } + } + } + + /* In NORMAL mode, check if tout reached */ + if ( (itask == ARK_NORMAL) && + (ark_mem->tcur-tout)*ark_mem->h >= ZERO ) { + istate = ARK_SUCCESS; + ark_mem->tretlast = *tret = tout; + (void) arkGetDky(ark_mem, tout, 0, yout); + ark_mem->next_h = ark_mem->hprime; + break; + } + + /* Check if tn is at tstop or near tstop */ + if ( ark_mem->tstopset ) { + troundoff = FUZZ_FACTOR*ark_mem->uround * + (SUNRabs(ark_mem->tcur) + SUNRabs(ark_mem->h)); + if ( SUNRabs(ark_mem->tcur - ark_mem->tstop) <= troundoff) { + (void) arkGetDky(ark_mem, ark_mem->tstop, 0, yout); + ark_mem->tretlast = *tret = ark_mem->tstop; + ark_mem->tstopset = SUNFALSE; + istate = ARK_TSTOP_RETURN; + break; + } + if ( (ark_mem->tcur + ark_mem->hprime - ark_mem->tstop)*ark_mem->h > ZERO ) { + ark_mem->hprime = (ark_mem->tstop - ark_mem->tcur) * + (ONE-FOUR*ark_mem->uround); + ark_mem->eta = ark_mem->hprime/ark_mem->h; + } + } + + /* In ONE_STEP mode, copy y and exit loop */ + if (itask == ARK_ONE_STEP) { + istate = ARK_SUCCESS; + ark_mem->tretlast = *tret = ark_mem->tcur; + N_VScale(ONE, ark_mem->yn, yout); + ark_mem->next_h = ark_mem->hprime; + break; + } + + } /* end looping for internal steps */ + + return(istate); +} + + +/*--------------------------------------------------------------- + arkGetDky: + + 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. + ---------------------------------------------------------------*/ +int arkGetDky(ARKodeMem ark_mem, realtype t, int k, N_Vector dky) +{ + realtype s, tfuzz, tp, tn1; + int retval; + + /* Check all inputs for legality */ + if (ark_mem == NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", "arkGetDky", + MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + if (dky == NULL) { + arkProcessError(ark_mem, ARK_BAD_DKY, "ARKode", "arkGetDky", + MSG_ARK_NULL_DKY); + return(ARK_BAD_DKY); + } + if (ark_mem->interp == NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode", "arkGetDky", + "Missing interpolation structure"); + return(ARK_MEM_NULL); + } + + + /* Allow for some slack */ + tfuzz = FUZZ_FACTOR * ark_mem->uround * + (SUNRabs(ark_mem->tcur) + SUNRabs(ark_mem->hold)); + if (ark_mem->hold < ZERO) tfuzz = -tfuzz; + tp = ark_mem->tcur - ark_mem->hold - tfuzz; + tn1 = ark_mem->tcur + tfuzz; + if ((t-tp)*(t-tn1) > ZERO) { + arkProcessError(ark_mem, ARK_BAD_T, "ARKode", "arkGetDky", + MSG_ARK_BAD_T, t, ark_mem->tcur-ark_mem->hold, + ark_mem->tcur); + return(ARK_BAD_T); + } + + /* 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); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, retval, "ARKode", "arkGetDky", + "Error calling arkInterpEvaluate"); + return(retval); + } + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkFree: + + This routine frees the ARKode infrastructure memory. + ---------------------------------------------------------------*/ +void arkFree(void **arkode_mem) +{ + ARKodeMem ark_mem; + + if (*arkode_mem == NULL) return; + + ark_mem = (ARKodeMem) (*arkode_mem); + + arkFreeVectors(ark_mem); + if (ark_mem->interp != NULL) + arkInterpFree(&(ark_mem->interp)); + + if (ark_mem->root_mem != NULL) + (void) arkRootFree(*arkode_mem); + + free(*arkode_mem); + *arkode_mem = NULL; +} + + + +/*=============================================================== + 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 + + This routine is responsible for setting the residual weight + vector rwt, according to tol_type, as follows: + + (1) rwt[i] = 1 / (reltol * SUNRabs(M*ycur[i]) + rabstol), i=0,...,neq-1 + if tol_type = ARK_SS + (2) rwt[i] = 1 / (reltol * SUNRabs(M*ycur[i]) + rabstol[i]), i=0,...,neq-1 + if tol_type = ARK_SV + (3) unset if tol_type is any other value (occurs rwt=ewt) + + arkRwtSet returns 0 if rwt is successfully set as above to a + positive vector and -1 otherwise. In the latter case, rwt is + considered undefined. + + All the real work is done in the routines arkRwtSetSS, arkRwtSetSV. + ---------------------------------------------------------------*/ +int arkRwtSet(N_Vector y, N_Vector weight, void *data) +{ + ARKodeMem ark_mem; + N_Vector My; + int flag = 0; + + /* data points to ark_mem here */ + ark_mem = (ARKodeMem) data; + + /* return if rwt is just ewt */ + if (ark_mem->rwt_is_ewt) return(0); + + /* put M*y into ark_tempv1 */ + My = ark_mem->tempv1; + if (ark_mem->step_mmult != NULL) { + flag = ark_mem->step_mmult((void *) ark_mem, y, My); + if (flag != ARK_SUCCESS) return (ARK_MASSMULT_FAIL); + } else { /* this condition should not apply, but just in case */ + N_VScale(ONE, y, My); + } + + /* call appropriate routine to fill rwt */ + switch(ark_mem->ritol) { + case ARK_SS: + flag = arkRwtSetSS(ark_mem, My, weight); + break; + case ARK_SV: + flag = arkRwtSetSV(ark_mem, My, weight); + break; + } + + return(flag); +} + + +/*--------------------------------------------------------------- + arkErrHandler is the default error handling function. + It sends the error message to the stream pointed to by ark_errfp + ---------------------------------------------------------------*/ +void arkErrHandler(int error_code, const char *module, + const char *function, char *msg, void *data) +{ + ARKodeMem ark_mem; + char err_type[10]; + + /* data points to ark_mem here */ + ark_mem = (ARKodeMem) data; + + if (error_code == ARK_WARNING) + sprintf(err_type,"WARNING"); + else + sprintf(err_type,"ERROR"); + +#ifndef NO_FPRINTF_OUTPUT + if (ark_mem->errfp!=NULL) { + fprintf(ark_mem->errfp,"\n[%s %s] %s\n",module,err_type,function); + fprintf(ark_mem->errfp," %s\n\n",msg); + } +#endif + + return; +} + + + +/*=============================================================== + Private Helper Functions + ===============================================================*/ + +/*--------------------------------------------------------------- + arkInit: + + arkInit allocates and initializes memory for a problem. All + 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 + ARK_SUCCESS. This routine should be called by an ARKode + timestepper module (not by the user). This routine must be + called prior to calling arkEvolve to evolve the problem. + ---------------------------------------------------------------*/ +int arkInit(ARKodeMem ark_mem, realtype t0, N_Vector y0) +{ + booleantype stepperOK, nvectorOK, allocOK; + sunindextype lrw1, liw1; + + /* Check for legal input parameters */ + if (y0==NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkInit", MSG_ARK_NULL_Y0); + return(ARK_ILL_INPUT); + } + + /* Test if all required time stepper operations are implemented */ + stepperOK = arkCheckTimestepper(ark_mem); + if (!stepperOK) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkInit", + "Time stepper module is missing required functionality"); + return(ARK_ILL_INPUT); + } + + /* Test if all required vector operations are implemented */ + nvectorOK = arkCheckNvector(y0); + if (!nvectorOK) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkInit", MSG_ARK_BAD_NVECTOR); + return(ARK_ILL_INPUT); + } + + /* Set space requirements for one N_Vector */ + if (y0->ops->nvspace != NULL) { + N_VSpace(y0, &lrw1, &liw1); + } else { + lrw1 = 0; + liw1 = 0; + } + ark_mem->lrw1 = lrw1; + ark_mem->liw1 = liw1; + + + /* Allocate the solver vectors (using y0 as a template) */ + allocOK = arkAllocVectors(ark_mem, y0); + if (!allocOK) { + arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode", + "arkInit", MSG_ARK_MEM_FAIL); + return(ARK_MEM_FAIL); + } + + /* Initialize the interpolation structure to NULL */ + ark_mem->interp = NULL; + + /* All error checking is complete at this point */ + + /* Copy the input parameters into ARKode state */ + ark_mem->tcur = t0; + 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 */ + + /* Initialize yn */ + N_VScale(ONE, y0, ark_mem->yn); + + /* Initialize all the counters */ + ark_mem->nst = 0; + ark_mem->nhnil = 0; + + /* Initialize other integrator optional outputs */ + ark_mem->h0u = ZERO; + ark_mem->next_h = ZERO; + + /* Initially, rwt should point to ewt */ + ark_mem->rwt_is_ewt = SUNTRUE; + + /* Indicate that problem size is new */ + ark_mem->resized = SUNTRUE; + ark_mem->firststage = SUNTRUE; + + /* Problem has been successfully initialized */ + ark_mem->MallocDone = SUNTRUE; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkReInit: + + arkReInit re-initializes ARKode's memory for a problem, + assuming it has already been allocated in a prior arkInit + call. 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. This routine should only + be called after arkInit, and only when the problem dynamics + or desired solvers have changed dramatically, so that the + problem integration should resume as if started from scratch. + + The return value is ARK_SUCCESS = 0 if no errors occurred, or + a negative value otherwise. + ---------------------------------------------------------------*/ +int arkReInit(ARKodeMem ark_mem, realtype t0, N_Vector y0) +{ + /* Check if ark_mem was allocated */ + if (ark_mem->MallocDone == SUNFALSE) { + arkProcessError(ark_mem, ARK_NO_MALLOC, "ARKode", + "arkReInit", MSG_ARK_NO_MALLOC); + return(ARK_NO_MALLOC); + } + + /* Check for legal input parameters */ + if (y0 == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkReInit", MSG_ARK_NULL_Y0); + return(ARK_ILL_INPUT); + } + + /* Copy the input parameters into ARKode state */ + ark_mem->tcur = t0; + 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 */ + + /* 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 + the linear solver routines that were set during arkInit. */ + + /* Initialize yn */ + N_VScale(ONE, y0, ark_mem->yn); + + /* Initialize all the counters */ + ark_mem->nst = 0; + ark_mem->nhnil = 0; + + /* Indicate that problem size is new */ + ark_mem->resized = SUNTRUE; + ark_mem->firststage = SUNTRUE; + + /* Initialize other integrator optional outputs */ + ark_mem->h0u = ZERO; + ark_mem->next_h = ZERO; + + /* Problem has been successfully re-initialized */ + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkPrintMem: + + This routine outputs the ark_mem structure to a specified file + pointer. + ---------------------------------------------------------------*/ +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); + + /* output counters */ + fprintf(outfile, "ark_nhnil = %i\n", ark_mem->nhnil); + fprintf(outfile, "ark_nst = %li\n", ark_mem->nst); + + /* 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); + + /* 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); + +#ifdef DEBUG_OUTPUT + /* output vector quantities */ + if (ark_mem->Vabstol != NULL) { + fprintf(outfile, "ark_Vapbsol:\n"); + N_VPrint_Serial(ark_mem->Vabstol); + } + if (ark_mem->ewt != NULL) { + fprintf(outfile, "ark_ewt:\n"); + N_VPrint_Serial(ark_mem->ewt); + } + if (!ark_mem->rwt_is_ewt && ark_mem->rwt != NULL) { + fprintf(outfile, "ark_rwt:\n"); + N_VPrint_Serial(ark_mem->rwt); + } + if (ark_mem->ycur != NULL) { + fprintf(outfile, "ark_ycur:\n"); + N_VPrint_Serial(ark_mem->ycur); + } + if (ark_mem->yn != NULL) { + fprintf(outfile, "ark_yn:\n"); + N_VPrint_Serial(ark_mem->yn); + } + if (ark_mem->tempv1 != NULL) { + fprintf(outfile, "ark_tempv1:\n"); + N_VPrint_Serial(ark_mem->tempv1); + } + if (ark_mem->tempv2 != NULL) { + fprintf(outfile, "ark_tempv2:\n"); + N_VPrint_Serial(ark_mem->tempv2); + } + if (ark_mem->tempv3 != NULL) { + fprintf(outfile, "ark_tempv3:\n"); + N_VPrint_Serial(ark_mem->tempv3); + } + if (ark_mem->tempv4 != NULL) { + fprintf(outfile, "ark_tempv4:\n"); + N_VPrint_Serial(ark_mem->tempv4); + } +#endif + +} + + +/*--------------------------------------------------------------- + arkCheckTimestepper: + + This routine checks if all required time stepper function + pointers have been supplied. If any of them is missing it + returns SUNFALSE. + ---------------------------------------------------------------*/ +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) && + (ark_mem->step_fullrhs == NULL) ) + return(SUNFALSE); + return(SUNTRUE); +} + + +/*--------------------------------------------------------------- + arkCheckNvector: + + This routine checks if all required vector operations are + present. If any of them is missing it returns SUNFALSE. + ---------------------------------------------------------------*/ +booleantype arkCheckNvector(N_Vector tmpl) /* to be updated?? */ +{ + if ((tmpl->ops->nvclone == NULL) || + (tmpl->ops->nvdestroy == NULL) || + (tmpl->ops->nvlinearsum == NULL) || + (tmpl->ops->nvconst == NULL) || + (tmpl->ops->nvdiv == NULL) || + (tmpl->ops->nvscale == NULL) || + (tmpl->ops->nvabs == NULL) || + (tmpl->ops->nvinv == NULL) || + (tmpl->ops->nvaddconst == NULL) || + (tmpl->ops->nvmaxnorm == NULL) || + (tmpl->ops->nvwrmsnorm == NULL) || + (tmpl->ops->nvmin == NULL)) + return(SUNFALSE); + else + return(SUNTRUE); +} + + +/*--------------------------------------------------------------- + arkAllocVec: + + This routine allocates a single vector based on a template + vector. If the target vector already exists it is left alone; + otherwise it is allocated by cloning the input vector. If the + allocation is successful (or if the target vector already + exists) then this returns SUNTRUE. This routine also updates + the optional outputs lrw and liw, which are (respectively) the + lengths of the overall ARKode real and integer work spaces. + ---------------------------------------------------------------*/ +booleantype arkAllocVec(ARKodeMem ark_mem, + N_Vector tmpl, + N_Vector *v) +{ + if (*v == NULL) { + *v = N_VClone(tmpl); + if (*v == NULL) { + arkFreeVectors(ark_mem); + return(SUNFALSE); + } else { + ark_mem->lrw += ark_mem->lrw1; + ark_mem->liw += ark_mem->liw1; + } + } + return (SUNTRUE); +} + + +/*--------------------------------------------------------------- + arkFreeVec: + + This routine frees a single vector. If the target vector is + already NULL it is left alone; otherwise it is freed and the + optional outputs lrw and liw are updated accordingly. + ---------------------------------------------------------------*/ +void arkFreeVec(ARKodeMem ark_mem, N_Vector *v) +{ + if (*v != NULL) { + N_VDestroy(*v); + *v = NULL; + ark_mem->lrw -= ark_mem->lrw1; + ark_mem->liw -= ark_mem->liw1; + } +} + + +/*--------------------------------------------------------------- + arkResizeVec: + + This routine resizes a single vector based on a template + vector. If the ARKVecResizeFn function is non-NULL, then it + calls that routine to perform the single-vector resize; + otherwise it deallocates and reallocates the target vector based + on the template vector. If the resize is successful then this + returns SUNTRUE. This routine also updates the optional outputs + lrw and liw, which are (respectively) the lengths of the overall + ARKode real and integer work spaces. + ---------------------------------------------------------------*/ +int arkResizeVec(ARKodeMem ark_mem, ARKVecResizeFn resize, + void *resize_data, sunindextype lrw_diff, + sunindextype liw_diff, N_Vector tmpl, N_Vector *v) +{ + if (*v != NULL) { + if (resize == NULL) { + N_VDestroy(*v); + *v = N_VClone(tmpl); + } else { + if (resize(*v, tmpl, resize_data)) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkResizeVec", MSG_ARK_RESIZE_FAIL); + return(ARK_ILL_INPUT); + } + } + ark_mem->lrw += lrw_diff; + ark_mem->liw += liw_diff; + } + return(ARK_SUCCESS); +} + +/*--------------------------------------------------------------- + arkAllocVectors: + + This routine allocates the ARKode vectors ewt, yn, tempv* and + ftemp. If any of these vectors already exist, they are left + alone. Otherwise, it will allocate each vector by cloning the + input vector. If all memory allocations are successful, + arkAllocVectors returns SUNTRUE. Otherwise all vector memory + is freed and arkAllocVectors returns SUNFALSE. This routine + also updates the optional outputs lrw and liw, which are + (respectively) the lengths of the real and integer work spaces. + ---------------------------------------------------------------*/ +booleantype arkAllocVectors(ARKodeMem ark_mem, N_Vector tmpl) +{ + /* Allocate ewt if needed */ + if (!arkAllocVec(ark_mem, tmpl, &ark_mem->ewt)) + return(SUNFALSE); + + /* Set rwt to point at ewt */ + if (ark_mem->rwt_is_ewt) + ark_mem->rwt = ark_mem->ewt; + + /* Allocate yn if needed */ + if (!arkAllocVec(ark_mem, tmpl, &ark_mem->yn)) + return(SUNFALSE); + + /* Allocate tempv1 if needed */ + if (!arkAllocVec(ark_mem, tmpl, &ark_mem->tempv1)) + return(SUNFALSE); + + /* Allocate tempv2 if needed */ + if (!arkAllocVec(ark_mem, tmpl, &ark_mem->tempv2)) + return(SUNFALSE); + + /* Allocate tempv3 if needed */ + if (!arkAllocVec(ark_mem, tmpl, &ark_mem->tempv3)) + return(SUNFALSE); + + /* Allocate tempv4 if needed */ + if (!arkAllocVec(ark_mem, tmpl, &ark_mem->tempv4)) + return(SUNFALSE); + + return(SUNTRUE); +} + + +/*--------------------------------------------------------------- + arkFreeVectors + + This routine frees the ARKode vectors allocated in both + arkAllocVectors and arkAllocRKVectors. + ---------------------------------------------------------------*/ +void arkFreeVectors(ARKodeMem ark_mem) +{ + arkFreeVec(ark_mem, &ark_mem->ewt); + if (!ark_mem->rwt_is_ewt) + arkFreeVec(ark_mem, &ark_mem->rwt); + arkFreeVec(ark_mem, &ark_mem->tempv1); + arkFreeVec(ark_mem, &ark_mem->tempv2); + arkFreeVec(ark_mem, &ark_mem->tempv3); + arkFreeVec(ark_mem, &ark_mem->tempv4); + arkFreeVec(ark_mem, &ark_mem->yn); + arkFreeVec(ark_mem, &ark_mem->Vabstol); +} + + +/*--------------------------------------------------------------- + arkInitialSetup + + This routine performs all necessary items to prepare ARKode for + the first internal step, including: + - checks for valid initial step input or estimates first step + - input consistency checks + - checks the linear solver module (if applicable) + - initializes linear solver (if applicable) + ---------------------------------------------------------------*/ +int arkInitialSetup(ARKodeMem ark_mem, realtype tout) +{ + int retval, hflag, istate, ier; + realtype tout_hin, rh; + + /* Temporarily set ark_h */ + ark_mem->h = SUNRabs(tout - ark_mem->tcur); + if (ark_mem->h == ZERO) ark_mem->h = ONE; + + /* Set up the time stepper module */ + if (ark_mem->step_init == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkInitialSetup", "Time stepper module is missing"); + return(ARK_ILL_INPUT); + } + retval = ark_mem->step_init(ark_mem, 0); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, retval, "ARKode", "arkInitialSetup", + "Error in initialization of time stepper module"); + return(retval); + } + + /* 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", + "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; + + /* Load initial error weights */ + ier = ark_mem->efun(ark_mem->yn, + ark_mem->ewt, + ark_mem->e_data); + if (ier != 0) { + if (ark_mem->itol == ARK_WF) + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkInitialSetup", MSG_ARK_EWT_FAIL); + else + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkInitialSetup", MSG_ARK_BAD_EWT); + 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) { + if (ark_mem->itol == ARK_WF) + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkInitialSetup", MSG_ARK_RWT_FAIL); + else + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkInitialSetup", MSG_ARK_BAD_RWT); + return(ARK_ILL_INPUT); + } + } + + /* 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); + } + + /* 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); + } + + /* Test input tstop for legality. */ + if ( ark_mem->tstopset ) { + if ( (ark_mem->tstop - ark_mem->tcur)*(tout - ark_mem->tcur) <= ZERO ) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkInitialSetup", + MSG_ARK_BAD_TSTOP, ark_mem->tstop, ark_mem->tcur); + return(ARK_ILL_INPUT); + } + } + + /* Check input h for validity */ + ark_mem->h = ark_mem->hin; + if ( (ark_mem->h != ZERO) && + ((tout-ark_mem->tcur)*ark_mem->h < ZERO) ) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkInitialSetup", + MSG_ARK_BAD_H0); + return(ARK_ILL_INPUT); + } + if ((ark_mem->hin == ZERO) && (ark_mem->fixedstep)) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkInitialSetup", + "nonzero step size must be supplied when using fixed-step mode"); + return(ARK_ILL_INPUT); + } + + /* Estimate initial h if not set */ + if (ark_mem->h == ZERO) { + /* Again, temporarily set ark_h for estimating an optimal value */ + ark_mem->h = SUNRabs(tout - ark_mem->tcur); + if (ark_mem->h == ZERO) ark_mem->h = ONE; + /* Estimate the first step size */ + tout_hin = tout; + if ( ark_mem->tstopset && + (tout-ark_mem->tcur)*(tout-ark_mem->tstop) > ZERO ) + tout_hin = ark_mem->tstop; + hflag = arkHin(ark_mem, tout_hin); + if (hflag != ARK_SUCCESS) { + istate = arkHandleFailure(ark_mem, hflag); + return(istate); + } + } + + /* Enforce step size bounds */ + rh = SUNRabs(ark_mem->h)*ark_mem->hmax_inv; + if (rh > ONE) ark_mem->h /= rh; + if (SUNRabs(ark_mem->h) < ark_mem->hmin) + ark_mem->h *= ark_mem->hmin/SUNRabs(ark_mem->h); + /* Check for approach to tstop */ + if (ark_mem->tstopset) { + if ( (ark_mem->tcur + ark_mem->h - ark_mem->tstop)*ark_mem->h > ZERO ) { + ark_mem->h = (ark_mem->tstop - ark_mem->tcur)*(ONE-FOUR*ark_mem->uround); + } + } + + /* Set initial time step factors */ + ark_mem->h0u = ark_mem->h; + ark_mem->hprime = ark_mem->h; + + /* Check for zeros of root function g at and near t0. */ + if (ark_mem->root_mem != NULL) + if (ark_mem->root_mem->nrtfn > 0) { + retval = arkRootCheck1((void*) ark_mem); + + if (retval == ARK_RTFUNC_FAIL) { + arkProcessError(ark_mem, ARK_RTFUNC_FAIL, "ARKode", "arkRootCheck1", + MSG_ARK_RTFUNC_FAILED, ark_mem->tcur); + return(ARK_RTFUNC_FAIL); + } + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkPostResizeSetup + + This routine performs all necessary items to prepare ARKode for + the first internal step after a resize() call, including: + - re-initialize the linear solver + - re-initialize the interpolation structure + - check for approach to tstop + - check for root near t0 + ---------------------------------------------------------------*/ +int arkPostResizeSetup(ARKodeMem ark_mem) +{ + int retval, ier; + + /* Load updated error weights */ + ier = ark_mem->efun(ark_mem->yn, + ark_mem->ewt, + ark_mem->e_data); + if (ier != 0) { + if (ark_mem->itol == ARK_WF) + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkPostResizeSetup", MSG_ARK_EWT_FAIL); + else + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkPostResizeSetup", MSG_ARK_BAD_EWT); + return(ARK_ILL_INPUT); + } + + /* 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) { + if (ark_mem->itol == ARK_WF) + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkPostResizeSetup", MSG_ARK_RWT_FAIL); + else + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkPostResizeSetup", MSG_ARK_BAD_RWT); + return(ARK_ILL_INPUT); + } + } + + /* 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); + } + + /* Check for legal tstop (correct direction of integration) */ + if (ark_mem->tstopset) { + if ( (ark_mem->tstop - ark_mem->tcur)*ark_mem->h < ZERO ) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkPostResizeSetup", + MSG_ARK_BAD_TSTOP, ark_mem->tstop, ark_mem->tcur); + return(ARK_ILL_INPUT); + } + } + + /* 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) { + retval = arkRootCheck1((void*) ark_mem); + + if (retval == ARK_RTFUNC_FAIL) { + arkProcessError(ark_mem, ARK_RTFUNC_FAIL, "ARKode", "arkRootCheck1", + MSG_ARK_RTFUNC_FAILED, ark_mem->tcur); + return(ARK_RTFUNC_FAIL); + } + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkStopTests + + This routine performs relevant stopping tests: + - check for root in last step + - check if we passed tstop + - check if we passed tout (NORMAL mode) + - check if current tn was returned (ONE_STEP mode) + - check if we are close to tstop + (adjust step size if needed) + ---------------------------------------------------------------*/ +int arkStopTests(ARKodeMem ark_mem, realtype tout, N_Vector yout, + realtype *tret, int itask, int *ier) +{ + int irfndp, retval; + realtype troundoff; + + /* Estimate an infinitesimal time interval to be used as + a roundoff for time quantities (based on current time + and step size) */ + troundoff = FUZZ_FACTOR*ark_mem->uround * + (SUNRabs(ark_mem->tcur) + SUNRabs(ark_mem->h)); + + /* First, check for a root in the last step taken, other than the + last root found, if any. If itask = ARK_ONE_STEP and y(tn) was not + returned because of an intervening root, return y(tn) now. */ + if (ark_mem->root_mem != NULL) + if (ark_mem->root_mem->nrtfn > 0) { + + irfndp = ark_mem->root_mem->irfnd; + + retval = arkRootCheck2((void*) ark_mem); + + if (retval == CLOSERT) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkStopTests", + MSG_ARK_CLOSE_ROOTS, ark_mem->root_mem->tlo); + *ier = ARK_ILL_INPUT; + return(1); + } else if (retval == ARK_RTFUNC_FAIL) { + arkProcessError(ark_mem, ARK_RTFUNC_FAIL, "ARKode", "arkStopTests", + MSG_ARK_RTFUNC_FAILED, ark_mem->root_mem->tlo); + *ier = ARK_RTFUNC_FAIL; + return(1); + } else if (retval == RTFOUND) { + ark_mem->tretlast = *tret = ark_mem->root_mem->tlo; + *ier = ARK_ROOT_RETURN; + return(1); + } + + /* If tn is distinct from tretlast (within roundoff), + check remaining interval for roots */ + if ( SUNRabs(ark_mem->tcur - ark_mem->tretlast) > troundoff ) { + + retval = arkRootCheck3((void*) ark_mem); + + if (retval == ARK_SUCCESS) { /* no root found */ + ark_mem->root_mem->irfnd = 0; + if ((irfndp == 1) && (itask == ARK_ONE_STEP)) { + ark_mem->tretlast = *tret = ark_mem->tcur; + N_VScale(ONE, ark_mem->yn, yout); + *ier = ARK_SUCCESS; + return(1); + } + } else if (retval == RTFOUND) { /* a new root was found */ + ark_mem->root_mem->irfnd = 1; + ark_mem->tretlast = *tret = ark_mem->root_mem->tlo; + *ier = ARK_ROOT_RETURN; + return(1); + } else if (retval == ARK_RTFUNC_FAIL) { /* g failed */ + arkProcessError(ark_mem, ARK_RTFUNC_FAIL, "ARKode", "arkStopTests", + MSG_ARK_RTFUNC_FAILED, ark_mem->root_mem->tlo); + *ier = ARK_RTFUNC_FAIL; + return(1); + } + } + + } /* end of root stop check */ + + /* In ARK_NORMAL mode, test if tout was reached */ + if ( (itask == ARK_NORMAL) && + ((ark_mem->tcur-tout)*ark_mem->h >= ZERO) ) { + ark_mem->tretlast = *tret = tout; + *ier = arkGetDky(ark_mem, tout, 0, yout); + if (*ier != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkStopTests", MSG_ARK_BAD_TOUT, tout); + *ier = ARK_ILL_INPUT; + return(1); + } + *ier = ARK_SUCCESS; + return(1); + } + + /* In ARK_ONE_STEP mode, test if tn was returned */ + if ( itask == ARK_ONE_STEP && + SUNRabs(ark_mem->tcur - ark_mem->tretlast) > troundoff ) { + ark_mem->tretlast = *tret = ark_mem->tcur; + N_VScale(ONE, ark_mem->yn, yout); + *ier = ARK_SUCCESS; + return(1); + } + + /* Test for tn at tstop or near tstop */ + if ( ark_mem->tstopset ) { + + if ( SUNRabs(ark_mem->tcur - ark_mem->tstop) <= troundoff) { + *ier = arkGetDky(ark_mem, ark_mem->tstop, 0, yout); + if (*ier != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkStopTests", + MSG_ARK_BAD_TSTOP, ark_mem->tstop, ark_mem->tcur); + *ier = ARK_ILL_INPUT; + return(1); + } + ark_mem->tretlast = *tret = ark_mem->tstop; + ark_mem->tstopset = SUNFALSE; + *ier = ARK_TSTOP_RETURN; + return(1); + } + + /* If next step would overtake tstop, adjust stepsize */ + if ( (ark_mem->tcur + ark_mem->hprime - ark_mem->tstop)*ark_mem->h > ZERO ) { + ark_mem->hprime = (ark_mem->tstop - ark_mem->tcur)*(ONE-FOUR*ark_mem->uround); + ark_mem->eta = ark_mem->hprime/ark_mem->h; + } + } + + return(0); +} + + +/*--------------------------------------------------------------- + arkHin + + This routine computes a tentative initial step size h0. + If tout is too close to tn (= t0), then arkHin returns + ARK_TOO_CLOSE and h remains uninitialized. Note that here tout + is either the value passed to arkEvolve at the first call or the + value of tstop (if tstop is enabled and it is closer to t0=tn + than tout). If the RHS function fails unrecoverably, arkHin + returns ARK_RHSFUNC_FAIL. If the RHS function fails recoverably + too many times and recovery is not possible, arkHin returns + ARK_REPTD_RHSFUNC_ERR. Otherwise, arkHin sets h to the chosen + value h0 and returns ARK_SUCCESS. + + The algorithm used seeks to find h0 as a solution of + (WRMS norm of (h0^2 ydd / 2)) = 1, + where ydd = estimated second derivative of y. Although this + choice is based on an error expansion of the Backward Euler + method, and hence results in an overly-conservative time step + for our higher-order ARK methods, it does find an order-of- + magnitude estimate of the initial time scale of the solution. + Since this method is only used on the first time step, the + additional caution will not overly hinder solver efficiency. + + We start with an initial estimate equal to the geometric mean + of the lower and upper bounds on the step size. + + Loop up to H0_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. + + For each new proposed hg, we allow H0_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 + still cannot be found, fall back on a previous value if + possible, or else return ARK_REPTD_RHSFUNC_ERR. + + Finally, we apply a bias (0.5) and verify that h0 is within + bounds. + ---------------------------------------------------------------*/ +int arkHin(ARKodeMem ark_mem, realtype tout) +{ + int retval, sign, count1, count2; + realtype tdiff, tdist, tround, hlb, hub; + realtype hg, hgs, hs, hnew, hrat, h0, yddnrm; + booleantype hgOK; + + /* If tout is too close to tn, give up */ + if ((tdiff = tout-ark_mem->tcur) == ZERO) return(ARK_TOO_CLOSE); + + sign = (tdiff > ZERO) ? 1 : -1; + tdist = SUNRabs(tdiff); + tround = ark_mem->uround * SUNMAX(SUNRabs(ark_mem->tcur), SUNRabs(tout)); + + if (tdist < TWO*tround) return(ARK_TOO_CLOSE); + + /* 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. */ + hlb = H0_LBFACTOR * tround; + hub = arkUpperBoundH0(ark_mem, tdist); + + hg = SUNRsqrt(hlb*hub); + + if (hub < hlb) { + if (sign == -1) ark_mem->h = -hg; + else ark_mem->h = hg; + return(ARK_SUCCESS); + } + + /* Outer loop */ + hs = hg; /* safeguard against 'uninitialized variable' warning */ + for(count1 = 1; count1 <= H0_ITERS; count1++) { + + /* Attempts to estimate ydd */ + hgOK = SUNFALSE; + + for (count2 = 1; count2 <= H0_ITERS; count2++) { + hgs = hg*sign; + retval = arkYddNorm(ark_mem, hgs, &yddnrm); + /* If f() failed unrecoverably, give up */ + if (retval < 0) return(ARK_RHSFUNC_FAIL); + /* 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; + } + + /* If f() failed recoverably H0_ITERS times */ + if (!hgOK) { + /* Exit if this is the first or second pass. No recovery possible */ + if (count1 <= 2) return(ARK_REPTD_RHSFUNC_ERR); + /* We have a fall-back option. The value hs is a previous hnew which + passed through f(). Use it and break */ + hnew = hs; + break; + } + + /* The proposed step size is feasible. Save it. */ + hs = hg; + + /* 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 */ + if ((hrat > HALF) && (hrat < TWO)) break; + + /* After one pass, if ydd seems to be bad, use fall-back value. */ + if ((count1 > 1) && (hrat > TWO)) { + hnew = hg; + break; + } + + /* Send this value back through f() */ + hg = hnew; + } + + /* Apply bounds, bias factor, and attach sign */ + h0 = H0_BIAS*hnew; + if (h0 < hlb) h0 = hlb; + if (h0 > hub) h0 = hub; + if (sign == -1) h0 = -h0; + ark_mem->h = h0; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkUpperBoundH0 + + This routine sets an upper bound on abs(h0) based on + tdist = tn - t0 and the values of y[i]/y'[i]. + ---------------------------------------------------------------*/ +realtype arkUpperBoundH0(ARKodeMem ark_mem, realtype tdist) +{ + realtype hub_inv, hub; + N_Vector temp1, temp2; + + /* Bound based on |y0|/|y0'| -- allow at most an increase of + * H0_UBFACTOR in y0 (based on a forward Euler step). The weight + * factor is used as a safeguard against zero components in y0. */ + temp1 = ark_mem->tempv1; + temp2 = ark_mem->tempv2; + + N_VAbs(ark_mem->yn, temp2); + ark_mem->efun(ark_mem->yn, temp1, ark_mem->e_data); + N_VInv(temp1, temp1); + N_VLinearSum(H0_UBFACTOR, temp2, ONE, temp1, temp1); + + N_VAbs(ark_mem->interp->fnew, temp2); + + N_VDiv(temp2, temp1, temp1); + hub_inv = N_VMaxNorm(temp1); + + /* bound based on tdist -- allow at most a step of magnitude + * H0_UBFACTOR * tdist */ + hub = H0_UBFACTOR*tdist; + + /* Use the smaller of the two */ + if (hub*hub_inv > ONE) hub = ONE/hub_inv; + + return(hub); +} + + +/*--------------------------------------------------------------- + arkYddNorm + + This routine computes an estimate of the second derivative of y + using a difference quotient, and returns its WRMS norm. + ---------------------------------------------------------------*/ +int arkYddNorm(ARKodeMem ark_mem, realtype hg, realtype *yddnrm) +{ + int retval; + + if (ark_mem->interp == NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode", "arkYddNorm", + "Missing interpolation structure"); + return(ARK_MEM_NULL); + } + + /* increment y with a multiple of f */ + N_VLinearSum(hg, ark_mem->interp->fnew, 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, + ark_mem->ycur, + ark_mem->tempv1, 2); + 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); + + /* 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); + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkCompleteStep + + This routine performs various update operations when the step + solution is complete. It is assumed that the timestepper + module has stored the time-evolved solution in ark_mem->ycur, + and the step that gave rise to this solution in ark_mem->h. + We update the current time (tn), the current solution (yn), + increment the overall step counter nst, record the values hold + and tnew, reset the resized flag, allow for user-provided + postprocessing, and update the interpolation structure. + ---------------------------------------------------------------*/ +int arkCompleteStep(ARKodeMem ark_mem) +{ + int retval; + + /* Set current time to the end of the step (in case the last + stage time does not coincide with the step solution time). + 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. */ + ark_mem->tcur = ark_mem->tn + ark_mem->h; + if (ark_mem->tstopset) { + if ((ark_mem->tcur - ark_mem->tstop)*ark_mem->h > ZERO) + ark_mem->tcur = ark_mem->tstop; + } + + /* apply user-supplied step postprocessing function (if supplied) */ + 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); + } + + /* update interpolation structure */ + if (ark_mem->interp != NULL) { + retval = arkInterpUpdate(ark_mem, ark_mem->interp, + ark_mem->tcur, + (ark_mem->ProcessStep != NULL)); + if (retval != ARK_SUCCESS) return(retval); + } + + /* update yn to current solution */ + N_VScale(ONE, ark_mem->ycur, ark_mem->yn); + + /* update scalar quantities */ + ark_mem->nst++; + ark_mem->hold = ark_mem->h; + ark_mem->tn = ark_mem->tcur; + + /* turn off flag regarding resized problem */ + ark_mem->resized = SUNFALSE; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkHandleFailure + + This routine prints error messages for all cases of failure by + arkHin and ark_step. It returns to ARKode the value that ARKode + is to return to the user. + ---------------------------------------------------------------*/ +int arkHandleFailure(ARKodeMem ark_mem, int flag) +{ + + /* Depending on flag, print error message and return error flag */ + switch (flag) { + case ARK_ERR_FAILURE: + arkProcessError(ark_mem, ARK_ERR_FAILURE, "ARKode", "ARKode", + MSG_ARK_ERR_FAILS, ark_mem->tcur, ark_mem->h); + break; + case ARK_CONV_FAILURE: + arkProcessError(ark_mem, ARK_CONV_FAILURE, "ARKode", "ARKode", + MSG_ARK_CONV_FAILS, ark_mem->tcur, ark_mem->h); + break; + case ARK_LSETUP_FAIL: + arkProcessError(ark_mem, ARK_LSETUP_FAIL, "ARKode", "ARKode", + MSG_ARK_SETUP_FAILED, ark_mem->tcur); + break; + case ARK_LSOLVE_FAIL: + arkProcessError(ark_mem, ARK_LSOLVE_FAIL, "ARKode", "ARKode", + MSG_ARK_SOLVE_FAILED, ark_mem->tcur); + break; + case ARK_RHSFUNC_FAIL: + arkProcessError(ark_mem, ARK_RHSFUNC_FAIL, "ARKode", "ARKode", + MSG_ARK_RHSFUNC_FAILED, ark_mem->tcur); + break; + case ARK_UNREC_RHSFUNC_ERR: + arkProcessError(ark_mem, ARK_UNREC_RHSFUNC_ERR, "ARKode", "ARKode", + MSG_ARK_RHSFUNC_UNREC, ark_mem->tcur); + break; + case ARK_REPTD_RHSFUNC_ERR: + arkProcessError(ark_mem, ARK_REPTD_RHSFUNC_ERR, "ARKode", "ARKode", + MSG_ARK_RHSFUNC_REPTD, ark_mem->tcur); + break; + case ARK_RTFUNC_FAIL: + arkProcessError(ark_mem, ARK_RTFUNC_FAIL, "ARKode", "ARKode", + MSG_ARK_RTFUNC_FAILED, ark_mem->tcur); + break; + case ARK_TOO_CLOSE: + arkProcessError(ark_mem, ARK_TOO_CLOSE, "ARKode", "ARKode", + MSG_ARK_TOO_CLOSE); + break; + case ARK_MASSSOLVE_FAIL: + arkProcessError(ark_mem, ARK_MASSSOLVE_FAIL, "ARKode", "ARKode", + MSG_ARK_MASSSOLVE_FAIL); + break; + case ARK_NLS_SETUP_FAIL: + arkProcessError(ark_mem, ARK_NLS_SETUP_FAIL, "ARKode", "ARKode", + "At t = %Lg the nonlinear solver setup failed unrecoverably", + (long double) ark_mem->tcur); + break; + case ARK_VECTOROP_ERR: + arkProcessError(ark_mem, ARK_VECTOROP_ERR, "ARKode", "ARKode", + MSG_ARK_VECTOROP_ERR, ark_mem->tcur); + break; + case ARK_INNERSTEP_FAIL: + arkProcessError(ark_mem, ARK_INNERSTEP_FAIL, "ARKode", "ARKode", + MSG_ARK_INNERSTEP_FAILED, ark_mem->tcur); + break; + default: + /* This return should never happen */ + arkProcessError(ark_mem, ARK_UNRECOGNIZED_ERROR, "ARKode", "ARKode", + "ARKode encountered an unrecognized error. Please report this to the Sundials developers at sundials-users@llnl.gov"); + return(ARK_UNRECOGNIZED_ERROR); + } + + return(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. + ---------------------------------------------------------------*/ +int arkEwtSetSS(ARKodeMem ark_mem, N_Vector ycur, N_Vector weight) +{ + 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); + N_VInv(ark_mem->tempv1, weight); + return(0); +} + + +/*--------------------------------------------------------------- + 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. + ---------------------------------------------------------------*/ +int arkEwtSetSV(ARKodeMem ark_mem, N_Vector ycur, N_Vector weight) +{ + 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); + N_VInv(ark_mem->tempv1, weight); + return(0); +} + + +/*--------------------------------------------------------------- + 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. + ---------------------------------------------------------------*/ +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); + N_VInv(ark_mem->tempv1, weight); + return(0); +} + + +/*--------------------------------------------------------------- + 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. + ---------------------------------------------------------------*/ +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); + N_VInv(ark_mem->tempv1, weight); + return(0); +} + + +/*--------------------------------------------------------------- + arkExpStab is the default explicit stability estimation function + ---------------------------------------------------------------*/ +int arkExpStab(N_Vector y, realtype t, realtype *hstab, void *data) +{ + /* explicit stability not used by default, + set to zero to disable */ + *hstab = RCONST(0.0); + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkPredict_MaximumOrder + + 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). + ---------------------------------------------------------------*/ +int arkPredict_MaximumOrder(ARKodeMem ark_mem, realtype tau, N_Vector yguess) +{ + + /* verify that ark_mem and interpolation structure are provided */ + if (ark_mem == NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkPredict_MaximumOrder", + "ARKodeMem structure is NULL"); + return(ARK_MEM_NULL); + } + if (ark_mem->interp == NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode", + "arkPredict_MaximumOrder", + "ARKodeInterpMem structure is NULL"); + return(ARK_MEM_NULL); + } + + /* call the interpolation module to do the work */ + return(arkInterpEvaluate(ark_mem, ark_mem->interp, tau, + 0, ark_mem->dense_q, yguess)); +} + + +/*--------------------------------------------------------------- + arkPredict_VariableOrder + + This routine predicts the nonlinear implicit stage solution + using the ARKode interpolation module. The degree of the + interpolant is based on the level of extrapolation outside the + preceding time step. + ---------------------------------------------------------------*/ +int arkPredict_VariableOrder(ARKodeMem ark_mem, realtype tau, N_Vector yguess) +{ + int ord; + realtype tau_tol = 0.5; + realtype tau_tol2 = 0.75; + + /* verify that ark_mem and interpolation structure are provided */ + if (ark_mem == NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkPredict_VariableOrder", + "ARKodeMem structure is NULL"); + return(ARK_MEM_NULL); + } + if (ark_mem->interp == NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode", + "arkPredict_VariableOrder", + "ARKodeInterpMem structure is NULL"); + return(ARK_MEM_NULL); + } + + /* set the polynomial order based on tau input */ + if (tau <= tau_tol) { + ord = 3; + } else if (tau <= tau_tol2) { + ord = 2; + } else { + ord = 1; + } + + /* call the interpolation module to do the work */ + return(arkInterpEvaluate(ark_mem, ark_mem->interp, tau, + 0, ord, yguess)); +} + + +/*--------------------------------------------------------------- + arkPredict_CutoffOrder + + 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. + ---------------------------------------------------------------*/ +int arkPredict_CutoffOrder(ARKodeMem ark_mem, realtype tau, N_Vector yguess) +{ + int ord; + realtype tau_tol = 0.5; + + /* verify that ark_mem and interpolation structure are provided */ + if (ark_mem == NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkPredict_CutoffOrder", + "ARKodeMem structure is NULL"); + return(ARK_MEM_NULL); + } + if (ark_mem->interp == NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode", + "arkPredict_CutoffOrder", + "ARKodeInterpMem structure is NULL"); + return(ARK_MEM_NULL); + } + + /* set the polynomial order based on tau input */ + if (tau <= tau_tol) { + ord = ark_mem->dense_q; + } else { + ord = 1; + } + + /* call the interpolation module to do the work */ + return(arkInterpEvaluate(ark_mem, ark_mem->interp, tau, + 0, ord, yguess)); +} + + +/*--------------------------------------------------------------- + arkPredict_Bootstrap + + This routine predicts the nonlinear implicit stage solution + 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 + N_VLinearCombination(nvec, cvals, Xvecs, ftemp), + 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, + realtype tau, int nvec, realtype *cvals, + N_Vector *Xvecs, N_Vector yguess) +{ + realtype a0, a1, a2; + int i; + + /* verify that ark_mem and interpolation structure are provided */ + if (ark_mem == NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkPredict_Bootstrap", + "ARKodeMem structure is NULL"); + return(ARK_MEM_NULL); + } + if (ark_mem->interp == NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode", + "arkPredict_Bootstrap", + "ARKodeInterpMem structure is NULL"); + return(ARK_MEM_NULL); + } + + /* set coefficients for Hermite interpolant */ + a0 = ONE; + a2 = tau*tau/TWO/hj; + a1 = tau - a2; + + /* set arrays for fused vector operation; shift inputs for + f(t_n+hj,z_j) to end of queue */ + for (i=0; i<nvec; i++) { + cvals[2+i] = a2*cvals[i]; + Xvecs[2+i] = Xvecs[i]; + } + cvals[0] = a0; + Xvecs[0] = ark_mem->yn; + cvals[1] = a1; + Xvecs[1] = ark_mem->interp->fnew; + + /* call fused vector operation to compute prediction */ + return(N_VLinearCombination(nvec+2, cvals, Xvecs, yguess)); +} + + +/*--------------------------------------------------------------- + arkProcessError is a high level error handling function + - if ark_mem==NULL it prints the error message to stderr + - otherwise, it sets-up and calls the error handling function + pointed to by ark_ehfun + ---------------------------------------------------------------*/ +void arkProcessError(ARKodeMem ark_mem, int error_code, + const char *module, const char *fname, + const char *msgfmt, ...) +{ + va_list ap; + char msg[256]; + + /* Initialize the argument pointer variable + (msgfmt is the last required argument to arkProcessError) */ + va_start(ap, msgfmt); + + /* Compose the message */ + vsprintf(msg, msgfmt, ap); + + if (ark_mem == NULL) { /* We write to stderr */ + +#ifndef NO_FPRINTF_OUTPUT + fprintf(stderr, "\n[%s ERROR] %s\n ", module, fname); + fprintf(stderr, "%s\n\n", msg); +#endif + + } else { /* We can call ehfun */ + ark_mem->ehfun(error_code, module, fname, msg, + ark_mem->eh_data); + } + + /* Finalize argument processing */ + va_end(ap); + + return; +} + + +/*=============================================================== + EOF + ===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_adapt.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_adapt.c new file mode 100644 index 0000000..84619ff --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_adapt.c @@ -0,0 +1,427 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 ARKode's time step + * adaptivity utilities. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> + +#include "arkode_impl.h" +#include <sundials/sundials_math.h> +#include <sundials/sundials_types.h> + +#if defined(SUNDIALS_EXTENDED_PRECISION) +#define RSYM ".32Lg" +#else +#define RSYM ".16g" +#endif + + + +/*--------------------------------------------------------------- + arkAdaptInit: + + This routine creates and sets default values in an + ARKodeHAdaptMem structure. This returns a non-NULL structure + if no errors occurred, or a NULL value otherwise. + ---------------------------------------------------------------*/ +ARKodeHAdaptMem arkAdaptInit() +{ + ARKodeHAdaptMem hadapt_mem; + + /* allocate structure */ + hadapt_mem = (ARKodeHAdaptMem) malloc(sizeof(struct ARKodeHAdaptMemRec)); + if (hadapt_mem == NULL) return(NULL); + + /* initialize default values */ + 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; + return(hadapt_mem); +} + + +/*--------------------------------------------------------------- + arkPrintAdaptMem + + This routine outputs the time step adaptivity memory structure + to a specified file pointer. + ---------------------------------------------------------------*/ +void arkPrintAdaptMem(ARKodeHAdaptMem hadapt_mem, FILE *outfile) +{ + if (hadapt_mem != NULL) { + 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: 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", + hadapt_mem->ehist[0], + hadapt_mem->ehist[1], + hadapt_mem->ehist[2]); + fprintf(outfile, "ark_hadapt: hhist = %"RSYM" %"RSYM" %"RSYM"\n", + hadapt_mem->hhist[0], + hadapt_mem->hhist[1], + hadapt_mem->hhist[2]); + 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); + fprintf(outfile, "ark_hadapt: growth = %"RSYM"\n", hadapt_mem->growth); + fprintf(outfile, "ark_hadapt: lbound = %"RSYM"\n", hadapt_mem->lbound); + fprintf(outfile, "ark_hadapt: ubound = %"RSYM"\n", hadapt_mem->ubound); + 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: 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) { + fprintf(outfile, " ark_hadapt: Default explicit stability function\n"); + } else { + fprintf(outfile, " ark_hadapt: User provided explicit stability function\n"); + fprintf(outfile, " ark_hadapt: stability function data pointer = %p\n", + hadapt_mem->estab_data); + } + } +} + + + + +/*--------------------------------------------------------------- + arkAdapt is the time step adaptivity wrapper function. This + computes and sets the value of ark_eta inside of the ARKodeMem + data structure. + ---------------------------------------------------------------*/ +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 ier, k; + realtype h_acc, h_cfl, int_dir; + ARKodeMem ark_mem; + if (arkode_mem == NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkAdapt", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + + /* Set k as either p or q, based on pq flag */ + k = (pq) ? q : p; + + /* Call algorithm-specific error adaptivity method */ + switch (hadapt_mem->imethod) { + case(0): /* PID controller */ + ier = arkAdaptPID(hadapt_mem, k, hcur, &h_acc); + break; + case(1): /* PI controller */ + ier = arkAdaptPI(hadapt_mem, k, hcur, &h_acc); + break; + case(2): /* I controller */ + ier = arkAdaptI(hadapt_mem, k, hcur, &h_acc); + break; + case(3): /* explicit Gustafsson controller */ + ier = arkAdaptExpGus(hadapt_mem, k, nst, hcur, &h_acc); + break; + case(4): /* implicit Gustafsson controller */ + ier = arkAdaptImpGus(hadapt_mem, k, nst, hcur, &h_acc); + break; + case(5): /* imex Gustafsson controller */ + ier = arkAdaptImExGus(hadapt_mem, k, nst, hcur, &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], + hadapt_mem->ehist[0], + hadapt_mem->ehist[1], + hadapt_mem->ehist[2], + q, p, &h_acc, hadapt_mem->HAdapt_data); + break; + default: + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkAdapt", + "Illegal imethod."); + return (ARK_ILL_INPUT); + } + if (ier != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkAdapt", + "Error in accuracy-based adaptivity function."); + return (ARK_ILL_INPUT); + } + + /* determine direction of integration */ + int_dir = hcur / SUNRabs(hcur); + + /* Call explicit stability function */ + ier = hadapt_mem->expstab(ycur, tcur, &h_cfl, hadapt_mem->estab_data); + if (ier != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkAdapt", + "Error in explicit stability function."); + return (ARK_ILL_INPUT); + } + if (h_cfl <= 0.0) 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); + + /* enforce safety factors */ + h_acc *= hadapt_mem->safety; + h_cfl *= hadapt_mem->cfl * int_dir; + + /* enforce maximum bound on time step growth */ + 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)); + + /* Solver diagnostics reporting */ + if (ark_mem->report) + fprintf(ark_mem->diagfp, "%"RSYM" %"RSYM" ", h_acc, h_cfl); + + /* increment the relevant step counter, set desired step */ + if (SUNRabs(h_acc) < SUNRabs(h_cfl)) + hadapt_mem->nst_acc++; + else + hadapt_mem->nst_exp++; + h_acc = int_dir * SUNMIN(SUNRabs(h_acc), SUNRabs(h_cfl)); + + /* enforce adaptivity bounds to retain Jacobian/preconditioner accuracy */ + if ( (SUNRabs(h_acc) > SUNRabs(hcur*hadapt_mem->lbound*ONEMSM)) && + (SUNRabs(h_acc) < SUNRabs(hcur*hadapt_mem->ubound*ONEPSM)) ) + h_acc = hcur; + + /* set basic value of ark_eta */ + ark_mem->eta = h_acc / hcur; + + /* enforce minimum time step size */ + ark_mem->eta = SUNMAX(ark_mem->eta, + ark_mem->hmin / SUNRabs(hcur)); + + /* enforce maximum time step size */ + ark_mem->eta /= SUNMAX(ONE, SUNRabs(hcur) * + ark_mem->hmax_inv*ark_mem->eta); + + /* Solver diagnostics reporting */ + if (ark_mem->report) + fprintf(ark_mem->diagfp, "%"RSYM"\n", ark_mem->eta); + + return(ier); +} + + +/*--------------------------------------------------------------- + arkAdaptPID implements a PID time step control algorithm. + ---------------------------------------------------------------*/ +int arkAdaptPID(ARKodeHAdaptMem hadapt_mem, int k, realtype hcur, + realtype *hnew) +{ + realtype k1, k2, k3, e1, e2, e3, h_acc; + + /* set usable time-step adaptivity parameters */ + 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); + + /* compute estimated optimal time step size, set into output */ + h_acc = hcur * SUNRpowerR(e1,k1) * SUNRpowerR(e2,k2) * SUNRpowerR(e3,k3); + *hnew = h_acc; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkAdaptPI implements a PI time step control algorithm. + ---------------------------------------------------------------*/ +int arkAdaptPI(ARKodeHAdaptMem hadapt_mem, int k, realtype hcur, + 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); + + /* compute estimated optimal time step size, set into output */ + h_acc = hcur * SUNRpowerR(e1,k1) * SUNRpowerR(e2,k2); + *hnew = h_acc; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkAdaptI implements an I time step control algorithm. + ---------------------------------------------------------------*/ +int arkAdaptI(ARKodeHAdaptMem hadapt_mem, int k, realtype hcur, + 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); + + /* compute estimated optimal time step size, set into output */ + h_acc = hcur * SUNRpowerR(e1,k1); + *hnew = h_acc; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkAdaptExpGus implements the explicit Gustafsson time step + control algorithm. + ---------------------------------------------------------------*/ +int arkAdaptExpGus(ARKodeHAdaptMem hadapt_mem, int k, long int nst, + realtype hcur, realtype *hnew) +{ + realtype k1, k2, e1, e2, h_acc; + + /* modified method for first step */ + if (nst < 2) { + + k1 = -ONE / k; + e1 = SUNMAX(hadapt_mem->ehist[0], TINY); + h_acc = hcur * SUNRpowerR(e1,k1); + + /* general estimate */ + } else { + + 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); + h_acc = hcur * SUNRpowerR(e1,k1) * SUNRpowerR(e2,k2); + + } + *hnew = h_acc; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkAdaptImpGus implements the implicit Gustafsson time step + control algorithm. + ---------------------------------------------------------------*/ +int arkAdaptImpGus(ARKodeHAdaptMem hadapt_mem, int k, long int nst, + realtype hcur, realtype *hnew) +{ + realtype k1, k2, e1, e2, hrat, h_acc; + + /* modified method for first step */ + if (nst < 2) { + + k1 = -ONE / k; + e1 = SUNMAX(hadapt_mem->ehist[0], TINY); + h_acc = hcur * SUNRpowerR(e1,k1); + + /* general estimate */ + } else { + + 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]; + h_acc = hcur * hrat * SUNRpowerR(e1,k1) * SUNRpowerR(e2,k2); + + } + *hnew = h_acc; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkAdaptImExGus implements a combination implicit/explicit + Gustafsson time step control algorithm. + ---------------------------------------------------------------*/ +int arkAdaptImExGus(ARKodeHAdaptMem hadapt_mem, int k, long int nst, + realtype hcur, realtype *hnew) +{ + realtype k1, k2, k3, e1, e2, hrat, h_acc; + + /* modified method for first step */ + if (nst < 2) { + + k1 = -ONE / k; + e1 = SUNMAX(hadapt_mem->ehist[0], TINY); + h_acc = hcur * SUNRpowerR(e1,k1); + + /* general estimate */ + } else { + + 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]; + /* implicit estimate */ + h_acc = hcur * hrat * SUNRpowerR(e1,k3) * SUNRpowerR(e2,k3); + /* explicit estimate */ + h_acc = SUNMIN(h_acc, hcur * SUNRpowerR(e1,k1) * SUNRpowerR(e2,k2)); + + } + *hnew = h_acc; + + return(ARK_SUCCESS); +} + + +/*=============================================================== + EOF + ===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_adapt_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_adapt_impl.h new file mode 100644 index 0000000..4e48bce --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_adapt_impl.h @@ -0,0 +1,109 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * Implementation header file for ARKode's time step adaptivity + * utilities. + *--------------------------------------------------------------*/ + +#ifndef _ARKODE_ADAPT_IMPL_H +#define _ARKODE_ADAPT_IMPL_H + +#include <stdarg.h> +#include <arkode/arkode.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*=============================================================== + ARKode Time Step Adaptivity Data Structure +===============================================================*/ + +/* size constants for the adaptivity memory structure */ +#define ARK_ADAPT_LRW 19 +#define ARK_ADAPT_LIW 8 /* includes functin/data pointers */ + +/*--------------------------------------------------------------- + Types : struct ARKodeHAdaptMemRec, ARKodeHAdaptMem +----------------------------------------------------------------- + The type ARKodeHAdaptMem is type pointer to struct + ARKodeHAdaptMemRec. This structure contains fields to + keep track of temporal adaptivity. +---------------------------------------------------------------*/ +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 */ + 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 */ + int imethod; /* step adaptivity method to use: + -1 -> User-specified function above + 0 -> PID controller + 1 -> PI controller + 2 -> I controller + 3 -> explicit Gustafsson controller + 4 -> implicit Gustafsson controller + 5 -> imex Gustafsson controller */ + realtype cfl; /* cfl safety factor */ + realtype safety; /* accuracy safety factor on h */ + realtype bias; /* accuracy safety factor on LTE */ + realtype growth; /* maximum step growth safety factor */ + realtype lbound; /* eta lower bound to leave h unchanged */ + realtype ubound; /* eta upper bound to leave h unchanged */ + realtype k1; /* method-specific adaptivity parameters */ + realtype k2; + realtype k3; + + 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; + + +/*=============================================================== + ARKode Time Step Adaptivity Routines +===============================================================*/ + +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); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_arkstep.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_arkstep.c new file mode 100644 index 0000000..583ab80 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_arkstep.c @@ -0,0 +1,2608 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 ARKode's ARK time stepper + * module. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "arkode_impl.h" +#include "arkode_arkstep_impl.h" +#include <sundials/sundials_math.h> +#include <sunnonlinsol/sunnonlinsol_newton.h> + +#if defined(SUNDIALS_EXTENDED_PRECISION) +#define RSYM ".32Lg" +#else +#define RSYM ".16g" +#endif + +#define NO_DEBUG_OUTPUT +/* #define DEBUG_OUTPUT */ +#ifdef DEBUG_OUTPUT +#include <nvector/nvector_serial.h> +#endif + +/* constants */ +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + +#define FIXED_LIN_TOL + + +/*=============================================================== + ARKStep Exported functions -- Required + ===============================================================*/ + +void* ARKStepCreate(ARKRhsFn fe, ARKRhsFn fi, realtype t0, N_Vector y0) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + SUNNonlinearSolver NLS; + booleantype nvectorOK; + int retval; + + /* Check that at least one of fe, fi is supplied and is to be used */ + if (fe == NULL && fi == NULL) { + arkProcessError(NULL, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepCreate", MSG_ARK_NULL_F); + return(NULL); + } + + /* Check for legal input parameters */ + if (y0 == NULL) { + arkProcessError(NULL, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepCreate", MSG_ARK_NULL_Y0); + return(NULL); + } + + /* Test if all required vector operations are implemented */ + nvectorOK = arkStep_CheckNVector(y0); + if (!nvectorOK) { + arkProcessError(NULL, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepCreate", 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::ARKStep", + "ARKStepCreate", MSG_ARK_NO_MEM); + return(NULL); + } + + /* Allocate ARKodeARKStepMem structure, and initialize to zero */ + step_mem = NULL; + step_mem = (ARKodeARKStepMem) malloc(sizeof(struct ARKodeARKStepMemRec)); + if (step_mem == NULL) { + arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode::ARKStep", + "ARKStepCreate", MSG_ARK_ARKMEM_FAIL); + return(NULL); + } + memset(step_mem, 0, sizeof(struct ARKodeARKStepMemRec)); + + /* Attach step_mem structure and function pointers to ark_mem */ + ark_mem->step_attachlinsol = arkStep_AttachLinsol; + ark_mem->step_attachmasssol = arkStep_AttachMasssol; + ark_mem->step_disablelsetup = arkStep_DisableLSetup; + ark_mem->step_disablemsetup = arkStep_DisableMSetup; + ark_mem->step_getlinmem = arkStep_GetLmem; + ark_mem->step_getmassmem = arkStep_GetMassMem; + ark_mem->step_getimplicitrhs = arkStep_GetImplicitRHS; + ark_mem->step_mmult = NULL; + ark_mem->step_getgammas = arkStep_GetGammas; + ark_mem->step_init = arkStep_Init; + ark_mem->step_fullrhs = arkStep_FullRHS; + ark_mem->step = arkStep_TakeStep; + ark_mem->step_mem = (void*) step_mem; + + /* Set default values for ARKStep optional inputs */ + retval = ARKStepSetDefaults((void *)ark_mem); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, retval, "ARKode::ARKStep", + "ARKStepCreate", + "Error setting default solver options"); + return(NULL); + } + + /* Set implicit/explicit problem based on function pointers */ + step_mem->explicit = (fe == NULL) ? SUNFALSE : SUNTRUE; + step_mem->implicit = (fi == NULL) ? SUNFALSE : SUNTRUE; + + /* Allocate the general ARK stepper vectors using y0 as a template */ + /* NOTE: Fe, Fi, cvals and Xvecs will be allocated later on + (based on the number of ARK stages) */ + + /* Clone the input vector to create sdata, zpred and zcor */ + if (!arkAllocVec(ark_mem, y0, &(step_mem->sdata))) + return(NULL); + if (!arkAllocVec(ark_mem, y0, &(step_mem->zpred))) + return(NULL); + if (!arkAllocVec(ark_mem, y0, &(step_mem->zcor))) + return(NULL); + + /* Copy the input parameters into ARKode state */ + step_mem->fe = fe; + step_mem->fi = fi; + + /* Update the ARKode workspace requirements */ + 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) { + NLS = NULL; + NLS = SUNNonlinSol_Newton(y0); + if (NLS == NULL) { + arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode::ARKStep", + "ARKStepCreate", "Error creating default Newton solver"); + return(NULL); + } + retval = ARKStepSetNonlinearSolver(ark_mem, NLS); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode::ARKStep", + "ARKStepCreate", "Error attaching default Newton solver"); + return(NULL); + } + step_mem->ownNLS = SUNTRUE; + } + + /* 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->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->msolve_type = -1; + + /* Initialize initial error norm */ + step_mem->eRNrm = 1.0; + + /* 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; + + /* Initialize main ARKode infrastructure */ + retval = arkInit(ark_mem, t0, y0); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, retval, "ARKode::ARKStep", "ARKStepCreate", + "Unable to initialize main ARKode infrastructure"); + return(NULL); + } + + return((void *)ark_mem); +} + + +/*--------------------------------------------------------------- + ARKStepResize: + + This routine resizes the memory within the ARKStep module. + It first resizes the main ARKode infrastructure memory, and + then resizes its own data. + ---------------------------------------------------------------*/ +int ARKStepResize(void *arkode_mem, N_Vector y0, realtype hscale, + realtype t0, ARKVecResizeFn resize, void *resize_data) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + SUNNonlinearSolver NLS; + sunindextype lrw1, liw1, lrw_diff, liw_diff; + int i, retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepResize", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* Determing change in vector sizes */ + lrw1 = liw1 = 0; + if (y0->ops->nvspace != NULL) + N_VSpace(y0, &lrw1, &liw1); + lrw_diff = lrw1 - ark_mem->lrw1; + liw_diff = liw1 - ark_mem->liw1; + ark_mem->lrw1 = lrw1; + ark_mem->liw1 = liw1; + + /* resize ARKode infrastructure memory */ + retval = arkResize(ark_mem, y0, hscale, t0, resize, resize_data); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, retval, "ARKode::ARKStep", "ARKStepResize", + "Unable to resize main ARKode infrastructure"); + return(retval); + } + + /* 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); + 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); + 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); + if (retval != ARK_SUCCESS) return(retval); + } + + /* Resize the ARKStep vectors */ + /* Fe */ + if (step_mem->Fe != NULL) { + for (i=0; i<step_mem->stages; i++) { + retval = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + liw_diff, y0, &step_mem->Fe[i]); + if (retval != ARK_SUCCESS) return(retval); + } + } + /* Fi */ + if (step_mem->Fi != NULL) { + for (i=0; i<step_mem->stages; i++) { + retval = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + liw_diff, y0, &step_mem->Fi[i]); + if (retval != ARK_SUCCESS) return(retval); + } + } + + /* If a NLS object was previously used, destroy and recreate default Newton + NLS object (can be replaced by user-defined object if desired) */ + if ((step_mem->NLS != NULL) && (step_mem->ownNLS)) { + + /* destroy existing NLS object */ + retval = SUNNonlinSolFree(step_mem->NLS); + if (retval != ARK_SUCCESS) return(retval); + step_mem->NLS = NULL; + step_mem->ownNLS = SUNFALSE; + + /* create new Newton NLS object */ + NLS = NULL; + NLS = SUNNonlinSol_Newton(y0); + if (NLS == NULL) { + arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode::ARKStep", + "ARKStepResize", "Error creating default Newton solver"); + return(ARK_MEM_FAIL); + } + + /* attach new Newton NLS object to ARKStep */ + retval = ARKStepSetNonlinearSolver(ark_mem, NLS); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode::ARKStep", + "ARKStepResize", "Error attaching default Newton solver"); + return(ARK_MEM_FAIL); + } + step_mem->ownNLS = SUNTRUE; + + } + + /* reset nonlinear solver counters */ + if (step_mem->NLS != NULL) { + step_mem->ncfn = 0; + step_mem->nsetups = 0; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepReInit: + + This routine re-initializes the ARKStep module to solve a new + problem of the same size as was previously solved. + ---------------------------------------------------------------*/ +int ARKStepReInit(void* arkode_mem, ARKRhsFn fe, + ARKRhsFn fi, realtype t0, N_Vector y0) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepReInit", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* Check that at least one of fe, fi is supplied and is to be used */ + if (fe == NULL && fi == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepCreate", MSG_ARK_NULL_F); + return(ARK_ILL_INPUT); + } + + /* Check for legal input parameters */ + if (y0 == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepReInit", MSG_ARK_NULL_Y0); + 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; + + /* Copy the input parameters into ARKode state */ + 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; + + /* 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; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepSStolerances, ARKStepSVtolerances, ARKStepWFtolerances, + ARKStepResStolerance, ARKStepResVtolerance, ARKStepResFtolerance: + + These routines set integration tolerances (wrappers for general + ARKode utility routines) + ---------------------------------------------------------------*/ +int ARKStepSStolerances(void *arkode_mem, realtype reltol, realtype abstol) +{ + /* unpack ark_mem, call arkSStolerances, and return */ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepSStolerances", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + return(arkSStolerances(ark_mem, reltol, abstol)); +} + +int ARKStepSVtolerances(void *arkode_mem, realtype reltol, N_Vector abstol) +{ + /* unpack ark_mem, call arkSVtolerances, and return */ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepSVtolerances", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + return(arkSVtolerances(ark_mem, reltol, abstol)); +} + +int ARKStepWFtolerances(void *arkode_mem, ARKEwtFn efun) +{ + /* unpack ark_mem, call arkWFtolerances, and return */ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepWFtolerances", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + return(arkWFtolerances(ark_mem, efun)); +} + +int ARKStepResStolerance(void *arkode_mem, realtype rabstol) +{ + /* unpack ark_mem, call arkResStolerance, and return */ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepResStolerance", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + return(arkResStolerance(ark_mem, rabstol)); +} + +int ARKStepResVtolerance(void *arkode_mem, N_Vector rabstol) +{ + /* unpack ark_mem, call arkResVtolerance, and return */ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepResVtolerance", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + return(arkResVtolerance(ark_mem, rabstol)); +} + +int ARKStepResFtolerance(void *arkode_mem, ARKRwtFn rfun) +{ + /* unpack ark_mem, call arkResFtolerance, and return */ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepResFtolerance", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + return(arkResFtolerance(ark_mem, rfun)); +} + + +/*--------------------------------------------------------------- + ARKStepRootInit: + + Initialize (attach) a rootfinding problem to the stepper + (wrappers for general ARKode utility routine) + ---------------------------------------------------------------*/ +int ARKStepRootInit(void *arkode_mem, int nrtfn, ARKRootFn g) +{ + /* unpack ark_mem, call arkRootInit, and return */ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepRootInit", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + return(arkRootInit(ark_mem, nrtfn, g)); +} + + +/*--------------------------------------------------------------- + ARKStepEvolve: + + This is the main time-integration driver (wrappers for general + ARKode utility routine) + ---------------------------------------------------------------*/ +int ARKStepEvolve(void *arkode_mem, realtype tout, N_Vector yout, + realtype *tret, int itask) +{ + /* unpack ark_mem, call arkEvolve, and return */ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepEvolve", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + return(arkEvolve(ark_mem, tout, yout, tret, itask)); +} + + +/*--------------------------------------------------------------- + ARKStepGetDky: + + This returns interpolated output of the solution or its + derivatives over the most-recently-computed step (wrapper for + generic ARKode utility routine) + ---------------------------------------------------------------*/ +int ARKStepGetDky(void *arkode_mem, realtype t, int k, N_Vector dky) +{ + /* unpack ark_mem, call arkGetDky, and return */ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepGetDky", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + return(arkGetDky(ark_mem, t, k, dky)); +} + + +/*--------------------------------------------------------------- + ARKStepFree frees all ARKStep memory, and then calls an ARKode + utility routine to free the ARKode infrastructure memory. + ---------------------------------------------------------------*/ +void ARKStepFree(void **arkode_mem) +{ + int j; + sunindextype Bliw, Blrw; + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + + /* nothing to do if arkode_mem is already NULL */ + if (*arkode_mem == NULL) return; + + /* conditional frees on non-NULL ARKStep module */ + ark_mem = (ARKodeMem) (*arkode_mem); + if (ark_mem->step_mem != NULL) { + + 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); + ARKodeButcherTable_Free(step_mem->Be); + step_mem->Be = NULL; + ark_mem->liw -= Bliw; + ark_mem->lrw -= Blrw; + } + if (step_mem->Bi != NULL) { + ARKodeButcherTable_Space(step_mem->Bi, &Bliw, &Blrw); + ARKodeButcherTable_Free(step_mem->Bi); + step_mem->Bi = NULL; + ark_mem->liw -= Bliw; + ark_mem->lrw -= Blrw; + } + + /* free the nonlinear solver memory (if applicable) */ + if ((step_mem->NLS != NULL) && (step_mem->ownNLS)) { + SUNNonlinSolFree(step_mem->NLS); + step_mem->ownNLS = SUNFALSE; + } + step_mem->NLS = NULL; + + /* free the linear solver memory */ + if (step_mem->lfree != NULL) { + step_mem->lfree((void *) ark_mem); + step_mem->lmem = NULL; + } + + /* free the mass matrix solver memory */ + if (step_mem->mfree != NULL) { + step_mem->mfree((void *) ark_mem); + step_mem->mass_mem = NULL; + } + + /* free the sdata, zpred and zcor vectors */ + if (step_mem->sdata != NULL) { + arkFreeVec(ark_mem, &step_mem->sdata); + step_mem->sdata = NULL; + } + if (step_mem->zpred != NULL) { + arkFreeVec(ark_mem, &step_mem->zpred); + step_mem->zpred = NULL; + } + if (step_mem->zcor != NULL) { + arkFreeVec(ark_mem, &step_mem->zcor); + step_mem->zcor = NULL; + } + + /* free the RHS vectors */ + if (step_mem->Fe != NULL) { + for(j=0; j<step_mem->stages; j++) + arkFreeVec(ark_mem, &step_mem->Fe[j]); + free(step_mem->Fe); + step_mem->Fe = NULL; + ark_mem->liw -= step_mem->stages; + } + if (step_mem->Fi != NULL) { + for(j=0; j<step_mem->stages; j++) + arkFreeVec(ark_mem, &step_mem->Fi[j]); + free(step_mem->Fi); + step_mem->Fi = NULL; + ark_mem->liw -= step_mem->stages; + } + + /* free the reusable arrays for fused vector interface */ + if (step_mem->cvals != NULL) { + free(step_mem->cvals); + step_mem->cvals = NULL; + ark_mem->lrw -= (2*step_mem->stages + 1); + } + if (step_mem->Xvecs != NULL) { + free(step_mem->Xvecs); + step_mem->Xvecs = NULL; + ark_mem->liw -= (2*step_mem->stages + 1); + } + + /* free the time stepper module itself */ + free(ark_mem->step_mem); + ark_mem->step_mem = NULL; + + } + + /* free memory for overall ARKode infrastructure */ + arkFree(arkode_mem); +} + + +/*--------------------------------------------------------------- + ARKStepPrintMem: + + This routine outputs the memory from the ARKStep structure and + the main ARKode infrastructure to a specified file pointer + (useful when debugging). + ---------------------------------------------------------------*/ +void ARKStepPrintMem(void* arkode_mem, FILE* outfile) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepPrintMem", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return; + + /* if outfile==NULL, set it to stdout */ + if (outfile == NULL) outfile = stdout; + + /* output data from main ARKode infrastructure */ + arkPrintMem(ark_mem, outfile); + + /* output integer quantities */ + fprintf(outfile,"ARKStep: q = %i\n", step_mem->q); + fprintf(outfile,"ARKStep: p = %i\n", step_mem->p); + fprintf(outfile,"ARKStep: istage = %i\n", step_mem->istage); + 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); + fprintf(outfile,"ARKStep: msolve_type = %i\n", step_mem->msolve_type); + 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); + + /* output boolean quantities */ + fprintf(outfile,"ARKStep: user_linear = %i\n", step_mem->linear); + 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 */ + if (step_mem->Be != NULL) { + fprintf(outfile,"ARKStep: explicit Butcher table:\n"); + ARKodeButcherTable_Write(step_mem->Be, outfile); + } + if (step_mem->Bi != NULL) { + fprintf(outfile,"ARKStep: implicit Butcher table:\n"); + ARKodeButcherTable_Write(step_mem->Bi, outfile); + } + fprintf(outfile,"ARKStep: gamma = %"RSYM"\n", step_mem->gamma); + fprintf(outfile,"ARKStep: gammap = %"RSYM"\n", step_mem->gammap); + fprintf(outfile,"ARKStep: gamrat = %"RSYM"\n", step_mem->gamrat); + 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); + +#ifdef DEBUG_OUTPUT + /* output vector quantities */ + if (step_mem->sdata != NULL) { + fprintf(outfile, "ARKStep: sdata:\n"); + N_VPrint_Serial(step_mem->sdata); + } + if (step_mem->zpred != NULL) { + fprintf(outfile, "ARKStep: zpred:\n"); + N_VPrint_Serial(step_mem->zpred); + } + if (step_mem->zcor != NULL) { + fprintf(outfile, "ARKStep: zcor:\n"); + N_VPrint_Serial(step_mem->zcor); + } + if (step_mem->Fe != NULL) + for (i=0; i<step_mem->stages; i++) { + fprintf(outfile,"ARKStep: Fe[%i]:\n", i); + N_VPrint_Serial(step_mem->Fe[i]); + } + if (step_mem->Fi != NULL) + for (i=0; i<step_mem->stages; i++) { + fprintf(outfile,"ARKStep: Fi[%i]:\n", i); + N_VPrint_Serial(step_mem->Fi[i]); + } +#endif +} + + +/*=============================================================== + ARKStep Private functions + ===============================================================*/ + +/*--------------------------------------------------------------- + Interface routines supplied to ARKode + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + arkStep_AttachLinsol: + + This routine attaches the various set of system linear solver + interface routines, data structure, and solver type to the + ARKStep module. + ---------------------------------------------------------------*/ +int arkStep_AttachLinsol(void* arkode_mem, ARKLinsolInitFn linit, + ARKLinsolSetupFn lsetup, + ARKLinsolSolveFn lsolve, + ARKLinsolFreeFn lfree, + int lsolve_type, void *lmem) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "arkStep_AttachLinsol", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* free any existing system solver */ + if (step_mem->lfree != NULL) step_mem->lfree(arkode_mem); + + /* Attach the provided routines, data structure and solve type */ + step_mem->linit = linit; + step_mem->lsetup = lsetup; + step_mem->lsolve = lsolve; + step_mem->lfree = lfree; + step_mem->lmem = lmem; + step_mem->lsolve_type = lsolve_type; + + /* Reset all linear solver counters */ + step_mem->nsetups = 0; + step_mem->nstlp = 0; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkStep_AttachMasssol: + + This routine attaches the set of mass matrix linear solver + interface routines, data structure, and solver type to the + ARKStep module. + ---------------------------------------------------------------*/ +int arkStep_AttachMasssol(void* arkode_mem, ARKMassInitFn minit, + ARKMassSetupFn msetup, + ARKMassMultFn mmult, + ARKMassSolveFn msolve, + ARKMassFreeFn mfree, + int msolve_type, void *mass_mem) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "arkStep_AttachMasssol", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* free any existing mass matrix solver */ + if (step_mem->mfree != NULL) step_mem->mfree(arkode_mem); + + /* Attach the provided routines, data structure and solve type */ + step_mem->minit = minit; + step_mem->msetup = msetup; + step_mem->mmult = mmult; + step_mem->msolve = msolve; + step_mem->mfree = mfree; + step_mem->mass_mem = mass_mem; + step_mem->msolve_type = msolve_type; + + /* Attach mmult function pointer to ark_mem as well */ + ark_mem->step_mmult = mmult; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkStep_DisableLSetup: + + This routine NULLifies the lsetup function pointer in the + ARKStep module. + ---------------------------------------------------------------*/ +void arkStep_DisableLSetup(void* arkode_mem) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + + /* access ARKodeARKStepMem structure */ + if (arkode_mem==NULL) return; + ark_mem = (ARKodeMem) arkode_mem; + if (ark_mem->step_mem==NULL) return; + step_mem = (ARKodeARKStepMem) ark_mem->step_mem; + + /* nullify the lsetup function pointer */ + step_mem->lsetup = NULL; +} + + +/*--------------------------------------------------------------- + arkStep_DisableMSetup: + + This routine NULLifies the msetup function pointer in the + ARKStep module. + ---------------------------------------------------------------*/ +void arkStep_DisableMSetup(void* arkode_mem) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + + /* access ARKodeARKStepMem structure */ + if (arkode_mem==NULL) return; + ark_mem = (ARKodeMem) arkode_mem; + if (ark_mem->step_mem==NULL) return; + step_mem = (ARKodeARKStepMem) ark_mem->step_mem; + + /* nullify the msetup function pointer */ + step_mem->msetup = NULL; +} + + +/*--------------------------------------------------------------- + arkStep_GetLmem: + + This routine returns the system linear solver interface memory + structure, lmem. + ---------------------------------------------------------------*/ +void* arkStep_GetLmem(void* arkode_mem) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure, and return lmem */ + retval = arkStep_AccessStepMem(arkode_mem, "arkStep_GetLmem", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(NULL); + return(step_mem->lmem); +} + + +/*--------------------------------------------------------------- + arkStep_GetMassMem: + + This routine returns the mass matrix solver interface memory + structure, mass_mem. + ---------------------------------------------------------------*/ +void* arkStep_GetMassMem(void* arkode_mem) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure, and return mass_mem */ + retval = arkStep_AccessStepMem(arkode_mem, "arkStep_GetMassMem", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(NULL); + return(step_mem->mass_mem); +} + + +/*--------------------------------------------------------------- + arkStep_GetImplicitRHS: + + This routine returns the implicit RHS function pointer, fi. + ---------------------------------------------------------------*/ +ARKRhsFn arkStep_GetImplicitRHS(void* arkode_mem) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure, and return fi */ + retval = arkStep_AccessStepMem(arkode_mem, "arkStep_GetImplicitRHS", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(NULL); + return(step_mem->fi); +} + + +/*--------------------------------------------------------------- + arkStep_GetGammas: + + This routine fills the current value of gamma, and states + whether the gamma ratio fails the dgmax criteria. + ---------------------------------------------------------------*/ +int arkStep_GetGammas(void* arkode_mem, realtype *gamma, + realtype *gamrat, booleantype **jcur, + booleantype *dgamma_fail) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "arkStep_GetGammas", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* set outputs */ + step_mem = (ARKodeARKStepMem) ark_mem->step_mem; + *gamma = step_mem->gamma; + *gamrat = step_mem->gamrat; + *jcur = &step_mem->jcur; + *dgamma_fail = (SUNRabs(*gamrat - ONE) >= step_mem->dgmax); + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkStep_Init: + + 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). + + With init_type == 0, this routine: + - sets/checks the ARK Butcher tables to be used + - allocates any memory that depends on the number of ARK stages, + method order, or solver options + - checks for consistency between the system and mass matrix + linear solvers (if applicable) + - initializes and sets up the system and mass matrix linear + solvers (if applicable) + - initializes and sets up the nonlinear solver (if applicable) + - allocates the interpolation data structure (if needed based + on ARKStep solver options) + + With init_type == 1, this routine: + - checks for consistency between the system and mass matrix + linear solvers (if applicable) + - initializes and sets up the system and mass matrix linear + solvers (if applicable) + - initializes and sets up the nonlinear solver (if applicable) + ---------------------------------------------------------------*/ +int arkStep_Init(void* arkode_mem, int init_type) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + sunindextype Blrw, Bliw; + int j, retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "arkStep_Init", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* 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; + + /* Create Butcher tables (if not already set) */ + retval = arkStep_SetButcherTables(ark_mem); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", "arkStep_Init", + "Could not create Butcher table(s)"); + return(ARK_ILL_INPUT); + } + + /* Check that Butcher tables are OK */ + retval = arkStep_CheckButcherTables(ark_mem); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "arkStep_Init", "Error in Butcher table(s)"); + return(ARK_ILL_INPUT); + } + + /* note Butcher table space requirements */ + ARKodeButcherTable_Space(step_mem->Be, &Bliw, &Blrw); + ark_mem->liw += Bliw; + ark_mem->lrw += Blrw; + ARKodeButcherTable_Space(step_mem->Bi, &Bliw, &Blrw); + ark_mem->liw += Bliw; + ark_mem->lrw += Blrw; + + /* Allocate ARK RHS vector memory, update storage requirements */ + /* Allocate Fe[0] ... Fe[stages-1] if needed */ + if (step_mem->explicit) { + if (step_mem->Fe == NULL) + step_mem->Fe = (N_Vector *) calloc(step_mem->stages, sizeof(N_Vector)); + for (j=0; j<step_mem->stages; j++) { + if (!arkAllocVec(ark_mem, ark_mem->ewt, &(step_mem->Fe[j]))) + return(ARK_MEM_FAIL); + } + ark_mem->liw += step_mem->stages; /* pointers */ + } + + /* Allocate Fi[0] ... Fi[stages-1] if needed */ + if (step_mem->implicit) { + if (step_mem->Fi == NULL) + step_mem->Fi = (N_Vector *) calloc(step_mem->stages, sizeof(N_Vector)); + for (j=0; j<step_mem->stages; j++) { + if (!arkAllocVec(ark_mem, ark_mem->ewt, &(step_mem->Fi[j]))) + return(ARK_MEM_FAIL); + } + 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; + if (step_mem->cvals == NULL) { + step_mem->cvals = (realtype *) calloc(j, sizeof(realtype)); + if (step_mem->cvals == NULL) return(ARK_MEM_FAIL); + ark_mem->lrw += j; + } + if (step_mem->Xvecs == NULL) { + step_mem->Xvecs = (N_Vector *) calloc(j, sizeof(N_Vector)); + if (step_mem->Xvecs == NULL) return(ARK_MEM_FAIL); + ark_mem->liw += j; /* 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); + } + } + + } + + /* 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 */ + if (step_mem->lsolve_type != step_mem->msolve_type) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", "arkStep_Init", + "Incompatible linear and mass matrix solvers"); + return(ARK_ILL_INPUT); + } + } + + /* Perform mass matrix solver initialization and setup (if applicable) */ + if (step_mem->mass_mem != NULL) { + + /* Call minit (if it exists) */ + if (step_mem->minit != NULL) { + retval = step_mem->minit((void *) ark_mem); + if (retval != 0) { + arkProcessError(ark_mem, ARK_MASSINIT_FAIL, "ARKode::ARKStep", + "arkStep_Init", MSG_ARK_MASSINIT_FAIL); + return(ARK_MASSINIT_FAIL); + } + } + + /* Call msetup (if it exists) */ + if (step_mem->msetup != NULL) { + retval = step_mem->msetup((void *) ark_mem, ark_mem->tempv1, + ark_mem->tempv2, ark_mem->tempv3); + if (retval != 0) { + arkProcessError(ark_mem, ARK_MASSSETUP_FAIL, "ARKode::ARKStep", + "arkStep_Init", MSG_ARK_MASSSETUP_FAIL); + return(ARK_MASSSETUP_FAIL); + step_mem->msetuptime = ark_mem->tcur; + } + } + } + + /* Call linit (if it exists) */ + if (step_mem->linit) { + retval = step_mem->linit(ark_mem); + if (retval != 0) { + arkProcessError(ark_mem, ARK_LINIT_FAIL, "ARKode::ARKStep", + "arkStep_Init", MSG_ARK_LINIT_FAIL); + return(ARK_LINIT_FAIL); + } + } + + /* Initialize the nonlinear solver object (if it exists) */ + if (step_mem->NLS) { + retval = arkStep_NlsInit(ark_mem); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_NLS_INIT_FAIL, "ARKode::ARKStep", "arkStep_Init", + "Unable to initialize SUNNonlinearSolver object"); + return(ARK_NLS_INIT_FAIL); + } + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkStep_FullRHS: + + Rewriting the problem + My' = fe(t,y) + fi(t,y) + in the form + y' = M^{-1}*[ fe(t,y) + fi(t,y) ], + this routine computes the full right-hand side vector, + f = M^{-1}*[ fe(t,y) + fi(t,y) ] + + This will be called in one of three 'modes': + 0 -> called at the beginning of a simulation + 1 -> called at the end of a successful step + 2 -> called elsewhere (e.g. for dense output) + + If it is called in mode 0, we store the vectors fe(t,y) and + fi(t,y) in Fe[0] and Fi[0] for possible reuse in the first + stage of the subsequent time step. + + If it is called in mode 1 and the ARK method coefficients + 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 + store the intermediate parts so that they do not interfere + with the other two modes. + ---------------------------------------------------------------*/ +int arkStep_FullRHS(void* arkode_mem, realtype t, + N_Vector y, N_Vector f, int mode) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + booleantype recomputeRHS; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "arkStep_FullRHS", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* 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) ) + if (SUNRabs(step_mem->msetuptime - t) > FUZZ_FACTOR*ark_mem->uround) { + retval = step_mem->msetup((void *) ark_mem, f, ark_mem->tempv2, + ark_mem->tempv3); + if (retval != ARK_SUCCESS) return(ARK_MASSSETUP_FAIL); + step_mem->msetuptime = t; + } + + /* perform RHS functions contingent on 'mode' argument */ + switch(mode) { + + /* Mode 0: called at the beginning of a simulation + Store the vectors fe(t,y) and fi(t,y) in Fe[0] and Fi[0] for + possible reuse in the first stage of the subsequent time step */ + case 0: + + /* call fe if the problem has an explicit component */ + if (step_mem->explicit) { + retval = step_mem->fe(t, y, step_mem->Fe[0], ark_mem->user_data); + step_mem->nfe++; + if (retval != 0) { + arkProcessError(ark_mem, ARK_RHSFUNC_FAIL, "ARKode::ARKStep", + "arkStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); + return(ARK_RHSFUNC_FAIL); + } + } + + /* call fi if the problem has an implicit component */ + if (step_mem->implicit) { + retval = step_mem->fi(t, y, step_mem->Fi[0], ark_mem->user_data); + step_mem->nfi++; + if (retval != 0) { + arkProcessError(ark_mem, ARK_RHSFUNC_FAIL, "ARKode::ARKStep", + "arkStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); + return(ARK_RHSFUNC_FAIL); + } + } + + /* combine RHS vector(s) into output */ + if (step_mem->explicit && step_mem->implicit) { /* ImEx */ + N_VLinearSum(ONE, step_mem->Fi[0], ONE, step_mem->Fe[0], f); + } else if (step_mem->implicit) { /* implicit */ + N_VScale(ONE, step_mem->Fi[0], f); + } else { /* explicit */ + N_VScale(ONE, step_mem->Fe[0], f); + } + + break; + + + /* Mode 1: called at the end of a successful step + If the ARK method coefficients support it, we just copy the last stage RHS vectors + to fill f instead of calling fe() and fi(). + Copy the results to Fe[0] and Fi[0] if the ARK coefficients support it. */ + case 1: + + /* determine if explicit/implicit RHS functions need to be recomputed */ + recomputeRHS = SUNFALSE; + if ( step_mem->explicit && (SUNRabs(step_mem->Be->c[step_mem->stages-1]-ONE)>TINY) ) + recomputeRHS = SUNTRUE; + if ( step_mem->implicit && (SUNRabs(step_mem->Bi->c[step_mem->stages-1]-ONE)>TINY) ) + recomputeRHS = SUNTRUE; + + /* base RHS calls on recomputeRHS argument */ + if (recomputeRHS) { + + /* call fe if the problem has an explicit component */ + if (step_mem->explicit) { + retval = step_mem->fe(t, y, step_mem->Fe[0], ark_mem->user_data); + step_mem->nfe++; + if (retval != 0) { + arkProcessError(ark_mem, ARK_RHSFUNC_FAIL, "ARKode::ARKStep", + "arkStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); + return(ARK_RHSFUNC_FAIL); + } + } + + /* call fi if the problem has an implicit component */ + if (step_mem->implicit) { + retval = step_mem->fi(t, y, step_mem->Fi[0], ark_mem->user_data); + step_mem->nfi++; + if (retval != 0) { + arkProcessError(ark_mem, ARK_RHSFUNC_FAIL, "ARKode::ARKStep", + "arkStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); + return(ARK_RHSFUNC_FAIL); + } + } + } else { + if (step_mem->explicit) + N_VScale(ONE, step_mem->Fe[step_mem->stages-1], step_mem->Fe[0]); + if (step_mem->implicit) + N_VScale(ONE, step_mem->Fi[step_mem->stages-1], step_mem->Fi[0]); + } + + /* combine RHS vector(s) into output */ + if (step_mem->explicit && step_mem->implicit) { /* ImEx */ + N_VLinearSum(ONE, step_mem->Fi[0], ONE, step_mem->Fe[0], f); + } else if (step_mem->implicit) { /* implicit */ + N_VScale(ONE, step_mem->Fi[0], f); + } else { /* explicit */ + N_VScale(ONE, step_mem->Fe[0], f); + } + + break; + + /* Mode 2: called for dense output in-between steps or for estimation + of the initial time step size, store the intermediate calculations + in such a way as to not interfere with the other two modes */ + default: + + /* call fe if the problem has an explicit component (store in ark_tempv2) */ + if (step_mem->explicit) { + retval = step_mem->fe(t, y, ark_mem->tempv2, ark_mem->user_data); + step_mem->nfe++; + if (retval != 0) { + arkProcessError(ark_mem, ARK_RHSFUNC_FAIL, "ARKode::ARKStep", + "arkStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); + return(ARK_RHSFUNC_FAIL); + } + } + + /* call fi if the problem has an implicit component (store in sdata) */ + if (step_mem->implicit) { + retval = step_mem->fi(t, y, step_mem->sdata, ark_mem->user_data); + step_mem->nfi++; + if (retval != 0) { + arkProcessError(ark_mem, ARK_RHSFUNC_FAIL, "ARKode::ARKStep", + "arkStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); + return(ARK_RHSFUNC_FAIL); + } + } + + /* combine RHS vector(s) into output */ + if (step_mem->explicit && step_mem->implicit) { /* ImEx */ + N_VLinearSum(ONE, step_mem->sdata, ONE, ark_mem->tempv2, f); + } else if (step_mem->implicit) { /* implicit */ + N_VScale(ONE, step_mem->sdata, f); + } else { /* explicit */ + N_VScale(ONE, ark_mem->tempv2, f); + } + + break; + } + + + /* if M != I, then update f = M^{-1}*f */ + if (step_mem->mass_mem != NULL) { + retval = step_mem->msolve((void *) ark_mem, f, step_mem->nlscoef/ark_mem->h); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_MASSSOLVE_FAIL, "ARKode::ARKStep", + "arkStep_FullRHS", "Mass matrix solver failure"); + return(ARK_MASSSOLVE_FAIL); + } + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + 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. + ---------------------------------------------------------------*/ +int arkStep_TakeStep(void* arkode_mem) +{ + realtype dsm; + int retval, ncf, nef, is, nflag, kflag, eflag; + booleantype implicit_stage; + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + N_Vector zcor0; + + /* 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); + } + + /* Loop over internal stages to the step */ + for (is=0; is<step_mem->stages; 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); +#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; + + /* 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); + } + +#ifdef DEBUG_OUTPUT + 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); + +#ifdef DEBUG_OUTPUT + 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); + + /* perform implicit solve if required */ + if (implicit_stage) { + + /* perform implicit solve (result is stored in ark_mem->ycur) */ + nflag = arkStep_Nls(ark_mem, nflag); + +#ifdef DEBUG_OUTPUT + 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); + + /* If h reduced and step needs to be retried, break loop */ + if (kflag == PREDICT_AGAIN) break; + + /* Return if nonlinear solve failed and recovery not possible. */ + if (kflag != SOLVE_SUCCESS) return(kflag); + + /* otherwise no implicit solve is needed */ + } else { + + /* 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); + + /* 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); + + /* 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); + } + +#ifdef DEBUG_OUTPUT + printf("explicit solution:\n"); + N_VPrint_Serial(ark_mem->ycur); +#endif + + } + + /* 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); + } + + /* 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 + + /* Solver diagnostics reporting */ + if (ark_mem->report) + fprintf(ark_mem->diagfp, "ARKStep etest %li %"RSYM" %"RSYM"\n", + ark_mem->nst, ark_mem->h, dsm); + + /* Perform time accuracy error test (if failure, updates h for next try) */ + if (!ark_mem->fixedstep) + eflag = arkStep_DoErrorTest(ark_mem, &nflag, &nef, dsm); + +#ifdef DEBUG_OUTPUT + printf("error test flag = %i\n", eflag); +#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); + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + Internal utility routines + ---------------------------------------------------------------*/ + + +/*--------------------------------------------------------------- + arkStep_AccessStepMem: + + Shortcut routine to unpack ark_mem and step_mem structures from + void* pointer. If either is missing it returns ARK_MEM_NULL. + ---------------------------------------------------------------*/ +int arkStep_AccessStepMem(void* arkode_mem, const char *fname, + ARKodeMem *ark_mem, ARKodeARKStepMem *step_mem) +{ + + /* access ARKodeMem structure */ + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", + fname, MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + *ark_mem = (ARKodeMem) arkode_mem; + if ((*ark_mem)->step_mem==NULL) { + arkProcessError(*ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", + fname, MSG_ARKSTEP_NO_MEM); + return(ARK_MEM_NULL); + } + *step_mem = (ARKodeARKStepMem) (*ark_mem)->step_mem; + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkStep_CheckNVector: + + This routine checks if all required vector operations are + present. If any of them is missing it returns SUNFALSE. + ---------------------------------------------------------------*/ +booleantype arkStep_CheckNVector(N_Vector tmpl) +{ + if ( (tmpl->ops->nvclone == NULL) || + (tmpl->ops->nvdestroy == NULL) || + (tmpl->ops->nvlinearsum == NULL) || + (tmpl->ops->nvconst == NULL) || + (tmpl->ops->nvscale == NULL) || + (tmpl->ops->nvwrmsnorm == NULL) ) + return(SUNFALSE); + return(SUNTRUE); +} + + +/*--------------------------------------------------------------- + arkStep_SetButcherTables + + This routine determines the ERK/DIRK/ARK method to use, based + on the desired accuracy and information on whether the problem + is explicit, implicit or imex. + ---------------------------------------------------------------*/ +int arkStep_SetButcherTables(ARKodeMem ark_mem) +{ + int etable, itable; + ARKodeARKStepMem step_mem; + + /* access ARKodeARKStepMem structure */ + if (ark_mem->step_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", + "arkStep_SetButcherTables", MSG_ARKSTEP_NO_MEM); + return(ARK_MEM_NULL); + } + step_mem = (ARKodeARKStepMem) ark_mem->step_mem; + + /* if tables have already been specified, just return */ + if ( (step_mem->Be != NULL) || (step_mem->Bi != NULL) ) + return(ARK_SUCCESS); + + /* initialize table numbers to illegal values */ + etable = itable = -1; + + /**** ImEx methods ****/ + if (step_mem->explicit && step_mem->implicit) { + + switch (step_mem->q) { + + case(2): + case(3): + etable = DEFAULT_ARK_ETABLE_3; + itable = DEFAULT_ARK_ITABLE_3; + break; + case(4): + etable = DEFAULT_ARK_ETABLE_4; + itable = DEFAULT_ARK_ITABLE_4; + break; + case(5): + etable = DEFAULT_ARK_ETABLE_5; + itable = DEFAULT_ARK_ITABLE_5; + break; + default: /* no available method, set default */ + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "arkStep_SetButcherTables", + "No ImEx method at requested order, using q=5."); + etable = DEFAULT_ARK_ETABLE_5; + itable = DEFAULT_ARK_ITABLE_5; + break; + } + + /**** implicit methods ****/ + } else if (step_mem->implicit) { + + switch (step_mem->q) { + case(2): + itable = DEFAULT_DIRK_2; + break; + case(3): + itable = DEFAULT_DIRK_3; + break; + case(4): + itable = DEFAULT_DIRK_4; + break; + case(5): + itable = DEFAULT_DIRK_5;; + break; + default: /* no available method, set default */ + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "arkStep_SetButcherTables", + "No implicit method at requested order, using q=5."); + itable = DEFAULT_DIRK_5; + break; + } + + /**** explicit methods ****/ + } else { + + switch (step_mem->q) { + case(2): + etable = DEFAULT_ERK_2; + break; + case(3): + etable = DEFAULT_ERK_3; + break; + case(4): + etable = DEFAULT_ERK_4; + break; + case(5): + etable = DEFAULT_ERK_5; + break; + case(6): + etable = DEFAULT_ERK_6; + break; + case(7): + case(8): + etable = DEFAULT_ERK_8; + break; + default: /* no available method, set default */ + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "arkStep_SetButcherTables", + "No explicit method at requested order, using q=6."); + etable = DEFAULT_ERK_6; + break; + } + + } + + if (etable > -1) + step_mem->Be = ARKodeButcherTable_LoadERK(etable); + if (itable > -1) + step_mem->Bi = ARKodeButcherTable_LoadDIRK(itable); + + /* set [redundant] ARK stored values for stage numbers and method orders */ + if (step_mem->Be != NULL) { + step_mem->stages = step_mem->Be->stages; + step_mem->q = step_mem->Be->q; + step_mem->p = step_mem->Be->p; + } + if (step_mem->Bi != NULL) { + step_mem->stages = step_mem->Bi->stages; + step_mem->q = step_mem->Bi->q; + step_mem->p = step_mem->Bi->p; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkStep_CheckButcherTables + + This routine runs through the explicit and/or implicit Butcher + tables to ensure that they meet all necessary requirements, + including: + strictly lower-triangular (ERK) + lower-triangular with some nonzeros on diagonal (IRK) + method order q > 0 (all) + embedding order q > 0 (all -- if adaptive time-stepping enabled) + stages > 0 (all) + + Returns ARK_SUCCESS if tables pass, ARK_ILL_INPUT otherwise. + ---------------------------------------------------------------*/ +int arkStep_CheckButcherTables(ARKodeMem ark_mem) +{ + int i, j; + booleantype okay; + ARKodeARKStepMem step_mem; + realtype tol = RCONST(1.0e-12); + + /* access ARKodeARKStepMem structure */ + if (ark_mem->step_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", + "arkStep_CheckButcherTables", MSG_ARKSTEP_NO_MEM); + return(ARK_MEM_NULL); + } + step_mem = (ARKodeARKStepMem) ark_mem->step_mem; + + /* check that stages > 0 */ + if (step_mem->stages < 1) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "arkStep_CheckButcherTables", + "stages < 1!"); + return(ARK_ILL_INPUT); + } + + /* check that method order q > 0 */ + if (step_mem->q < 1) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "arkStep_CheckButcherTables", + "method order < 1!"); + return(ARK_ILL_INPUT); + } + + /* check that embedding order p > 0 */ + if ((step_mem->p < 1) && (!ark_mem->fixedstep)) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "arkStep_CheckButcherTables", + "embedding order < 1!"); + return(ARK_ILL_INPUT); + } + + /* check that embedding exists */ + if ((step_mem->p > 0) && (!ark_mem->fixedstep)) { + if (step_mem->implicit) { + if (step_mem->Bi->d == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "arkStep_CheckButcherTables", + "no implicit embedding!"); + return(ARK_ILL_INPUT); + } + } + if (step_mem->explicit) { + if (step_mem->Be->d == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "arkStep_CheckButcherTables", + "no explicit embedding!"); + return(ARK_ILL_INPUT); + } + } + } + + /* check that ERK table is strictly lower triangular */ + if (step_mem->explicit) { + okay = SUNTRUE; + for (i=0; i<step_mem->stages; i++) + for (j=i; j<step_mem->stages; j++) + if (SUNRabs(step_mem->Be->A[i][j]) > tol) + okay = SUNFALSE; + if (!okay) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "arkStep_CheckButcherTables", + "Ae Butcher table is implicit!"); + return(ARK_ILL_INPUT); + } + } + + /* check that IRK table is implicit and lower triangular */ + if (step_mem->implicit) { + okay = SUNFALSE; + for (i=0; i<step_mem->stages; i++) + if (SUNRabs(step_mem->Bi->A[i][i]) > tol) + okay = SUNTRUE; + if (!okay) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "arkStep_CheckButcherTables", + "Ai Butcher table is explicit!"); + return(ARK_ILL_INPUT); + } + + okay = SUNTRUE; + for (i=0; i<step_mem->stages; i++) + for (j=i+1; j<step_mem->stages; j++) + if (SUNRabs(step_mem->Bi->A[i][j]) > tol) + okay = SUNFALSE; + if (!okay) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "arkStep_CheckButcherTables", + "Ai Butcher table has entries above diagonal!"); + return(ARK_ILL_INPUT); + } + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkStep_Predict + + This routine computes the prediction for a specific internal + stage solution, storing the result in ypred. The + prediction is done using the interpolation structure in + extrapolation mode, hence stages "far" from the previous time + interval are predicted using lower order polynomials than the + "nearby" stages. + ---------------------------------------------------------------*/ +int arkStep_Predict(ARKodeMem ark_mem, int istage, N_Vector yguess) +{ + int i, retval, jstage, nvec; + realtype tau; + realtype h; + ARKodeARKStepMem step_mem; + realtype* cvals; + N_Vector* Xvecs; + + /* access ARKodeARKStepMem structure */ + if (ark_mem->step_mem == NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", + "arkStep_Predict", MSG_ARKSTEP_NO_MEM); + return(ARK_MEM_NULL); + } + step_mem = (ARKodeARKStepMem) ark_mem->step_mem; + + /* verify that interpolation structure is provided */ + if ((ark_mem->interp == NULL) && (step_mem->predictor > 0)) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", + "arkStep_Predict", + "Interpolation structure is NULL"); + return(ARK_MEM_NULL); + } + + /* local shortcuts to fused vector operations */ + cvals = step_mem->cvals; + Xvecs = step_mem->Xvecs; + + /* if the first step (or if resized), use initial condition as guess */ + if (ark_mem->nst == 0 || ark_mem->resized) { + N_VScale(ONE, ark_mem->yn, yguess); + return(ARK_SUCCESS); + } + + /* set evaluation time tau relative shift from previous successful time */ + tau = step_mem->Bi->c[istage]*ark_mem->h/ark_mem->hold; + + /* use requested predictor formula */ + switch (step_mem->predictor) { + + case 1: + + /***** Interpolatory Predictor 1 -- all to max order *****/ + retval = arkPredict_MaximumOrder(ark_mem, tau, yguess); + if (retval == ARK_SUCCESS) return(ARK_SUCCESS); + 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); + break; + + case 3: + + /***** 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); + break; + + case 4: + + /***** Bootstrap predictor: if any previous stage in step has nonzero c_i, + construct a quadratic Hermite interpolant for prediction; otherwise + use the trivial predictor. The actual calculations are performed in + arkPredict_Bootstrap, but here we need to determine the appropriate + stage, c_j, to use. *****/ + + /* this approach will not work (for now) when using a non-identity mass matrix */ + if (step_mem->mass_mem) break; + + /* determine if any previous stages in step meet criteria */ + jstage = -1; + for (i=0; i<istage; i++) + jstage = (step_mem->Bi->c[i] != ZERO) ? i : jstage; + + /* if using the trivial predictor, break */ + if (jstage == -1) break; + + /* find the "optimal" previous stage to use */ + for (i=0; i<istage; i++) + if ( (step_mem->Bi->c[i] > step_mem->Bi->c[jstage]) && + (step_mem->Bi->c[i] != ZERO) ) + jstage = i; + + /* set stage time, stage RHS and interpolation values */ + h = ark_mem->h * step_mem->Bi->c[jstage]; + tau = ark_mem->h * step_mem->Bi->c[istage]; + nvec = 0; + if (step_mem->implicit) { /* Implicit piece */ + cvals[nvec] = ONE; + Xvecs[nvec] = step_mem->Fi[jstage]; + nvec += 1; + } + if (step_mem->explicit) { /* Explicit piece */ + cvals[nvec] = ONE; + Xvecs[nvec] = step_mem->Fe[jstage]; + nvec += 1; + } + + /* call predictor routine */ + retval = arkPredict_Bootstrap(ark_mem, h, tau, nvec, cvals, Xvecs, yguess); + if (retval == ARK_SUCCESS) return(ARK_SUCCESS); + break; + + case 5: + + /***** Minimal correction predictor: use all previous stage + information in this step *****/ + + /* this approach will not work (for now) when using a non-identity mass matrix */ + if (step_mem->mass_mem != NULL) { + N_VScale(ONE, ark_mem->yn, yguess); + break; + } + + /* set arrays for fused vector operation */ + nvec = 0; + if (step_mem->explicit) { /* Explicit pieces */ + for (jstage=0; jstage<istage; jstage++) { + cvals[nvec] = ark_mem->h * step_mem->Be->A[istage][jstage]; + Xvecs[nvec] = step_mem->Fe[jstage]; + nvec += 1; + } + } + if (step_mem->implicit) { /* Implicit pieces */ + for (jstage=0; jstage<istage; jstage++) { + cvals[nvec] = ark_mem->h * step_mem->Bi->A[istage][jstage]; + Xvecs[nvec] = step_mem->Fi[jstage]; + nvec += 1; + } + } + cvals[nvec] = ONE; + Xvecs[nvec] = ark_mem->yn; + nvec += 1; + + /* compute predictor */ + retval = N_VLinearCombination(nvec, cvals, Xvecs, yguess); + if (retval != 0) return(ARK_VECTOROP_ERR); + + return(ARK_SUCCESS); + break; + + } + + /* if we made it here, use the trivial predictor (previous step solution) */ + N_VScale(ONE, ark_mem->yn, yguess); + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkStep_StageSetup + + This routine sets up the stage data for computing the RK + residual, along with the step- and method-related factors + gamma, gammap and gamrat. + + At the ith stage, we compute the residual vector: + r = -M*z + M*yn + h*sum_{j=0}^{i-1} Ae(i,j)*Fe(j) + + h*sum_{j=0}^{i} Ai(i,j)*Fi(j) + r = -M*(zp + zc) + M*yn + h*sum_{j=0}^{i-1} Ae(i,j)*Fe(j) + + h*sum_{j=0}^{i} Ai(i,j)*Fi(j) + r = (-M*zc + gamma*Fi(zi)) + (M*(yn - zp) + data) + where z = zp + zc. In the above form of the residual, + the first group corresponds to the current solution + correction, and the second group corresponds to existing data. + This routine computes this existing data, (M*(yn - zp) + data) + and stores in step_mem->sdata. + ---------------------------------------------------------------*/ +int arkStep_StageSetup(ARKodeMem ark_mem) +{ + /* local data */ + ARKodeARKStepMem step_mem; + int retval, i, j, nvec; + realtype* cvals; + N_Vector* Xvecs; + + /* access ARKodeARKStepMem structure */ + if (ark_mem->step_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", + "arkStep_StageSetup", MSG_ARKSTEP_NO_MEM); + return(ARK_MEM_NULL); + } + step_mem = (ARKodeARKStepMem) ark_mem->step_mem; + + /* Set shortcut to current stage index */ + i = step_mem->istage; + + /* local shortcuts for fused vector operations */ + cvals = step_mem->cvals; + Xvecs = step_mem->Xvecs; + + /* 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); + + } 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); + + /* If M!=I, replace sdata with M*sdata, so that sdata = M*(yn-zpred) */ + if (step_mem->mass_mem != NULL) { + N_VScale(ONE, step_mem->sdata, ark_mem->tempv1); + retval = step_mem->mmult((void *) ark_mem, ark_mem->tempv1, step_mem->sdata); + if (retval != ARK_SUCCESS) return (ARK_MASSMULT_FAIL); + } + + /* Update rhs with prior stage information */ + /* set arrays for fused vector operation */ + cvals[0] = ONE; + Xvecs[0] = step_mem->sdata; + nvec = 1; + if (step_mem->explicit) /* Explicit pieces */ + for (j=0; j<i; j++) { + cvals[nvec] = ark_mem->h * step_mem->Be->A[i][j]; + Xvecs[nvec] = step_mem->Fe[j]; + nvec += 1; + } + if (step_mem->implicit) /* Implicit pieces */ + for (j=0; j<i; j++) { + cvals[nvec] = ark_mem->h * step_mem->Bi->A[i][j]; + Xvecs[nvec] = step_mem->Fi[j]; + 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); + + } + + /* Update gamma (if the method contains an implicit component) */ + if (step_mem->implicit) { + step_mem->gamma = ark_mem->h * step_mem->Bi->A[i][i]; + if (ark_mem->firststage) + step_mem->gammap = step_mem->gamma; + step_mem->gamrat = (ark_mem->firststage) ? + ONE : step_mem->gamma / step_mem->gammap; /* protect x/x != 1.0 */ + } + + /* return with success */ + return (ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + 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 + + This routine calculates the final RK solution using the existing + data. This solution is placed directly in ark_ycur. This routine + also computes the error estimate ||y-ytilde||_WRMS, where ytilde + is the embedded solution, and the norm weights come from + ark_ewt. This norm value is returned. The vector form of this + 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) +{ + /* local data */ + realtype tend; + int retval, j, nvec; + N_Vector y, yerr; + realtype* cvals; + N_Vector* Xvecs; + ARKodeARKStepMem step_mem; + + /* access ARKodeARKStepMem structure */ + if (ark_mem->step_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", + "arkStep_ComputeSolutions", MSG_ARKSTEP_NO_MEM); + return(ARK_MEM_NULL); + } + step_mem = (ARKodeARKStepMem) ark_mem->step_mem; + + /* set N_Vector shortcuts, and shortcut to time at end of step */ + y = ark_mem->ycur; + yerr = ark_mem->tempv1; + tend = ark_mem->tn + ark_mem->h; + + /* local shortcuts for fused vector operations */ + cvals = step_mem->cvals; + Xvecs = step_mem->Xvecs; + + /* initialize output */ + *dsm = ZERO; + + /* Compute updated solution and error estimate based on whether + a non-identity mass matrix is present */ + if (step_mem->mass_mem != NULL) { /* M != I */ + + /* setup mass matrix */ + if (step_mem->msetup != NULL) + if (SUNRabs(step_mem->msetuptime - tend) > FUZZ_FACTOR*ark_mem->uround) { + retval = step_mem->msetup((void *) ark_mem, ark_mem->tempv1, + ark_mem->tempv2, ark_mem->tempv3); + if (retval != ARK_SUCCESS) return(ARK_MASSSETUP_FAIL); + step_mem->msetuptime = tend; + } + + /* compute y RHS (store in y) */ + /* set arrays for fused vector operation */ + nvec = 0; + for (j=0; j<step_mem->stages; j++) { + if (step_mem->explicit) { /* Explicit pieces */ + cvals[nvec] = ark_mem->h * step_mem->Be->b[j]; + Xvecs[nvec] = step_mem->Fe[j]; + nvec += 1; + } + if (step_mem->implicit) { /* Implicit pieces */ + cvals[nvec] = ark_mem->h * step_mem->Bi->b[j]; + Xvecs[nvec] = step_mem->Fi[j]; + nvec += 1; + } + } + + /* call fused vector operation to compute RHS */ + retval = N_VLinearCombination(nvec, cvals, Xvecs, y); + if (retval != 0) return(ARK_VECTOROP_ERR); + + /* 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 */ + N_VScale(ONE, ark_mem->yn, y); /* place old solution into y */ + return(CONV_FAIL); + } + + /* compute y = yn + update */ + N_VLinearSum(ONE, ark_mem->yn, ONE, y, y); + + + /* compute yerr (if step adaptivity enabled) */ + if (!ark_mem->fixedstep) { + + /* compute yerr RHS vector */ + /* set arrays for fused vector operation */ + nvec = 0; + for (j=0; j<step_mem->stages; j++) { + if (step_mem->explicit) { /* Explicit pieces */ + cvals[nvec] = ark_mem->h * (step_mem->Be->b[j] - step_mem->Be->d[j]); + Xvecs[nvec] = step_mem->Fe[j]; + nvec += 1; + } + if (step_mem->implicit) { /* Implicit pieces */ + cvals[nvec] = ark_mem->h * (step_mem->Bi->b[j] - step_mem->Bi->d[j]); + Xvecs[nvec] = step_mem->Fi[j]; + nvec += 1; + } + } + + /* call fused vector operation to compute yerr RHS */ + retval = N_VLinearCombination(nvec, cvals, Xvecs, yerr); + if (retval != 0) return(ARK_VECTOROP_ERR); + + /* 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 */ + return(CONV_FAIL); + } + /* fill error norm */ + *dsm = N_VWrmsNorm(yerr, ark_mem->ewt); + } + + } else { /* M == I */ + + /* Compute time step solution */ + /* set arrays for fused vector operation */ + cvals[0] = ONE; + Xvecs[0] = ark_mem->yn; + nvec = 1; + for (j=0; j<step_mem->stages; j++) { + if (step_mem->explicit) { /* Explicit pieces */ + cvals[nvec] = ark_mem->h * step_mem->Be->b[j]; + Xvecs[nvec] = step_mem->Fe[j]; + nvec += 1; + } + if (step_mem->implicit) { /* Implicit pieces */ + cvals[nvec] = ark_mem->h * step_mem->Bi->b[j]; + Xvecs[nvec] = step_mem->Fi[j]; + nvec += 1; + } + } + + /* call fused vector operation to do the work */ + retval = N_VLinearCombination(nvec, cvals, Xvecs, y); + if (retval != 0) return(ARK_VECTOROP_ERR); + + /* Compute yerr (if step adaptivity enabled) */ + if (!ark_mem->fixedstep) { + + /* set arrays for fused vector operation */ + nvec = 0; + for (j=0; j<step_mem->stages; j++) { + if (step_mem->explicit) { /* Explicit pieces */ + cvals[nvec] = ark_mem->h * (step_mem->Be->b[j] - step_mem->Be->d[j]); + Xvecs[nvec] = step_mem->Fe[j]; + nvec += 1; + } + if (step_mem->implicit) { /* Implicit pieces */ + cvals[nvec] = ark_mem->h * (step_mem->Bi->b[j] - step_mem->Bi->d[j]); + Xvecs[nvec] = step_mem->Fi[j]; + nvec += 1; + } + } + + /* call fused vector operation to do the work */ + retval = N_VLinearCombination(nvec, cvals, Xvecs, yerr); + if (retval != 0) return(ARK_VECTOROP_ERR); + + /* fill error norm */ + *dsm = N_VWrmsNorm(yerr, ark_mem->ewt); + } + + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkStep_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. Then set *nflagPtr to PREV_ERR_FAIL, + and return TRY_AGAIN. + ---------------------------------------------------------------*/ +int arkStep_DoErrorTest(ARKodeMem ark_mem, int *nflagPtr, + int *nefPtr, realtype dsm) +{ + realtype ehist2, hhist2; + int retval; + ARKodeHAdaptMem hadapt_mem; + ARKodeARKStepMem step_mem; + + /* 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); +} + + +/*--------------------------------------------------------------- + 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; + + /* 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; + + /* 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); + } + + /* 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); +} + + +/*=============================================================== + EOF + ===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_arkstep_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_arkstep_impl.h new file mode 100644 index 0000000..789edd5 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_arkstep_impl.h @@ -0,0 +1,203 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * Implementation header file for ARKode's ARK time stepper + * module. + *--------------------------------------------------------------*/ + +#ifndef _ARKODE_ARKSTEP_IMPL_H +#define _ARKODE_ARKSTEP_IMPL_H + +#include <arkode/arkode_arkstep.h> +#include "arkode_impl.h" +#include "arkode_ls_impl.h" + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*=============================================================== + ARK time step module constants -- move many items here from + arkode_impl.h + ===============================================================*/ + + +/*=============================================================== + ARK time step module data structure + ===============================================================*/ + +/*--------------------------------------------------------------- + Types : struct ARKodeARKStepMemRec, ARKodeARKStepMem + --------------------------------------------------------------- + The type ARKodeARKStepMem is type pointer to struct + ARKodeARKStepMemRec. This structure contains fields to + perform an additive Runge-Kutta time step. + ---------------------------------------------------------------*/ +typedef struct ARKodeARKStepMemRec { + + /* ARK problem specification */ + ARKRhsFn fe; /* My' = fe(t,y) + fi(t,y) */ + ARKRhsFn fi; + booleantype linear; /* SUNTRUE if fi is linear */ + booleantype linear_timedep; /* SUNTRUE if dfi/dy depends on t */ + booleantype explicit; /* SUNTRUE if fe is enabled */ + booleantype implicit; /* SUNTRUE if fi is enabled */ + + /* ARK method storage and parameters */ + N_Vector *Fe; /* explicit RHS at each stage */ + N_Vector *Fi; /* implicit RHS at each stage */ + N_Vector sdata; /* old stage data in residual */ + N_Vector zpred; /* predicted stage solution */ + N_Vector zcor; /* stage correction */ + int q; /* method order */ + int p; /* embedding order */ + int istage; /* current stage */ + int stages; /* number of stages */ + 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 */ + + /* (Non)Linear solver parameters & data */ + SUNNonlinearSolver NLS; /* generic SUNNonlinearSolver object */ + booleantype ownNLS; /* flag indicating ownership of NLS */ + realtype gamma; /* gamma = h * A(i,i) */ + realtype gammap; /* gamma at the last setup call */ + realtype gamrat; /* gamma / gammap */ + realtype dgmax; /* call lsetup if |gamma/gammap-1| >= dgmax */ + + int predictor; /* implicit prediction method to use */ + realtype crdown; /* nonlinear conv rate estimation constant */ + realtype rdiv; /* nonlin divergence if del/delp > rdiv */ + realtype crate; /* estimated nonlin convergence rate */ + realtype delp; /* norm of previous nonlinear solver update */ + realtype eRNrm; /* estimated residual norm, used in nonlin + and linear solver convergence tests */ + realtype nlscoef; /* coefficient in nonlin. convergence test */ + int mnewt; /* internal Newton iteration counter */ + + int msbp; /* positive => max # steps between lsetup + negative => call at each Newton iter */ + long int nstlp; /* step number of last setup call */ + + 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? */ + + /* Linear Solver Data */ + ARKLinsolInitFn linit; + ARKLinsolSetupFn lsetup; + ARKLinsolSolveFn lsolve; + ARKLinsolFreeFn lfree; + void *lmem; + int lsolve_type; /* interface type: 0=iterative; 1=direct; 2=custom */ + + /* Mass matrix solver data */ + ARKMassInitFn minit; + ARKMassSetupFn msetup; + ARKMassMultFn mmult; + ARKMassSolveFn msolve; + ARKMassFreeFn mfree; + void* mass_mem; + realtype msetuptime; /* "t" value at last msetup call */ + 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 */ + + /* Reusable arrays for fused vector operations */ + realtype *cvals; + N_Vector *Xvecs; + +} *ARKodeARKStepMem; + + +/*=============================================================== + ARK time step module private function prototypes + ===============================================================*/ + +/* Interface routines supplied to ARKode */ +int arkStep_AttachLinsol(void* arkode_mem, ARKLinsolInitFn linit, + ARKLinsolSetupFn lsetup, + ARKLinsolSolveFn lsolve, + ARKLinsolFreeFn lfree, + int lsolve_type, void *lmem); +int arkStep_AttachMasssol(void* arkode_mem, ARKMassInitFn minit, + ARKMassSetupFn msetup, + ARKMassMultFn mmult, + ARKMassSolveFn msolve, + ARKMassFreeFn lfree, + int msolve_type, void *mass_mem); +void arkStep_DisableLSetup(void* arkode_mem); +void arkStep_DisableMSetup(void* arkode_mem); +int arkStep_Init(void* arkode_mem, int init_type); +void* arkStep_GetLmem(void* arkode_mem); +void* arkStep_GetMassMem(void* arkode_mem); +ARKRhsFn arkStep_GetImplicitRHS(void* arkode_mem); +int arkStep_GetGammas(void* arkode_mem, realtype *gamma, + realtype *gamrat, booleantype **jcur, + 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); + +/* Internal utility routines */ +int arkStep_AccessStepMem(void* arkode_mem, const char *fname, + ARKodeMem *ark_mem, ARKodeARKStepMem *step_mem); +booleantype arkStep_CheckNVector(N_Vector tmpl); +int arkStep_SetButcherTables(ARKodeMem ark_mem); +int arkStep_CheckButcherTables(ARKodeMem ark_mem); +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_NlsConvTest(SUNNonlinearSolver NLS, N_Vector y, N_Vector del, + realtype tol, N_Vector ewt, void* arkode_mem); + +/*=============================================================== + Reusable ARKStep Error Messages + ===============================================================*/ + +/* Initialization and I/O error messages */ +#define MSG_ARKSTEP_NO_MEM "Time step module memory is NULL." +#define MSG_NLS_INIT_FAIL "The nonlinear solver's init routine failed." + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_arkstep_io.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_arkstep_io.c new file mode 100644 index 0000000..1d44627 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_arkstep_io.c @@ -0,0 +1,2619 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 the optional input and + * output functions for the ARKode ARKStep time stepper module. + * + * NOTE: many functions currently in arkode_io.c will move here, + * with slightly different names. The code transition will be + * minimal, but the documentation changes will be significant. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "arkode_arkstep_impl.h" +#include <sundials/sundials_math.h> +#include <sundials/sundials_types.h> + +#if defined(SUNDIALS_EXTENDED_PRECISION) +#define RSYM "Lg" +#else +#define RSYM "g" +#endif + + +/*=============================================================== + ARKStep Optional input functions (wrappers for generic ARKode + utility routines) + ===============================================================*/ + +/*--------------------------------------------------------------- + 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 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)); +} + +/*--------------------------------------------------------------- + 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)); +} + +/*--------------------------------------------------------------- + ARKStepSetDiagnostics: Specifies to enable solver diagnostics, + and specifies the FILE pointer for output (diagfp==NULL + disables output) + ---------------------------------------------------------------*/ +int ARKStepSetDiagnostics(void *arkode_mem, FILE *diagfp) +{ + 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)); +} + +/*--------------------------------------------------------------- + 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)); +} + +/*--------------------------------------------------------------- + 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)); +} + +/*--------------------------------------------------------------- + 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); + } + 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); + } + 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)); +} + +/*--------------------------------------------------------------- + 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. + ---------------------------------------------------------------*/ +int ARKStepSetFixedStep(void *arkode_mem, realtype hfixed) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetFixedStep", + &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)); +} + +/*--------------------------------------------------------------- + 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); + } + 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)); +} + +/*--------------------------------------------------------------- + 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 + documented in arkode_arkstep.h. + ---------------------------------------------------------------*/ +int ARKStepSetLinearSolver(void *arkode_mem, SUNLinearSolver LS, + SUNMatrix A) { + return(arkLSSetLinearSolver(arkode_mem, LS, A)); } +int ARKStepSetMassLinearSolver(void *arkode_mem, SUNLinearSolver LS, + SUNMatrix M, booleantype time_dep) { + return(arkLSSetMassLinearSolver(arkode_mem, LS, M, time_dep)); } +int ARKStepSetJacFn(void *arkode_mem, ARKLsJacFn jac) { + return(arkLSSetJacFn(arkode_mem, jac)); } +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 ARKStepSetEpsLin(void *arkode_mem, realtype eplifac) { + return(arkLSSetEpsLin(arkode_mem, eplifac)); } +int ARKStepSetMassEpsLin(void *arkode_mem, realtype eplifac) { + return(arkLSSetMassEpsLin(arkode_mem, eplifac)); } +int ARKStepSetPreconditioner(void *arkode_mem, ARKLsPrecSetupFn psetup, + ARKLsPrecSolveFn psolve) { + return(arkLSSetPreconditioner(arkode_mem, psetup, psolve)); } +int ARKStepSetMassPreconditioner(void *arkode_mem, ARKLsMassPrecSetupFn psetup, + ARKLsMassPrecSolveFn psolve) { + return(arkLSSetMassPreconditioner(arkode_mem, psetup, psolve)); } +int ARKStepSetJacTimes(void *arkode_mem, ARKLsJacTimesSetupFn jtsetup, + ARKLsJacTimesVecFn jtimes) { + return(arkLSSetJacTimes(arkode_mem, jtsetup, jtimes)); } +int ARKStepSetMassTimes(void *arkode_mem, ARKLsMassTimesSetupFn msetup, + ARKLsMassTimesVecFn mtimes, void *mtimes_data) { + return(arkLSSetMassTimes(arkode_mem, msetup, mtimes, mtimes_data)); } + + + +/*=============================================================== + ARKStep Optional output functions (wrappers for generic ARKode + utility routines) + ===============================================================*/ + +/*--------------------------------------------------------------- + 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 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)); } + +/*--------------------------------------------------------------- + These wrappers for ARKLs module 'get' routines all are + documented in arkode_arkstep.h. + ---------------------------------------------------------------*/ +int ARKStepGetLinWorkSpace(void *arkode_mem, long int *lenrwLS, long int *leniwLS) { + return(arkLSGetWorkSpace(arkode_mem, lenrwLS, leniwLS)); } +int ARKStepGetNumJacEvals(void *arkode_mem, long int *njevals) { + return(arkLSGetNumJacEvals(arkode_mem, njevals)); } +int ARKStepGetNumPrecEvals(void *arkode_mem, long int *npevals) { + return(arkLSGetNumPrecEvals(arkode_mem, npevals)); } +int ARKStepGetNumPrecSolves(void *arkode_mem, long int *npsolves) { + return(arkLSGetNumPrecSolves(arkode_mem, npsolves)); } +int ARKStepGetNumLinIters(void *arkode_mem, long int *nliters) { + return(arkLSGetNumLinIters(arkode_mem, nliters)); } +int ARKStepGetNumLinConvFails(void *arkode_mem, long int *nlcfails) { + return(arkLSGetNumConvFails(arkode_mem, nlcfails)); } +int ARKStepGetNumJTSetupEvals(void *arkode_mem, long int *njtsetups) { + return(arkLSGetNumJTSetupEvals(arkode_mem, 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)); } +int ARKStepGetLastLinFlag(void *arkode_mem, long int *flag) { + return(arkLSGetLastFlag(arkode_mem, flag)); } + +int ARKStepGetMassWorkSpace(void *arkode_mem, long int *lenrwMLS, long int *leniwMLS) { + return(arkLSGetMassWorkSpace(arkode_mem, lenrwMLS, leniwMLS)); } +int ARKStepGetNumMassSetups(void *arkode_mem, long int *nmsetups) { + return(arkLSGetNumMassSetups(arkode_mem, nmsetups)); } +int ARKStepGetNumMassMult(void *arkode_mem, long int *nmvevals) { + return(arkLSGetNumMassMult(arkode_mem, nmvevals)); } +int ARKStepGetNumMassSolves(void *arkode_mem, long int *nmsolves) { + return(arkLSGetNumMassSolves(arkode_mem, nmsolves)); } +int ARKStepGetNumMassPrecEvals(void *arkode_mem, long int *nmpevals) { + return(arkLSGetNumMassPrecEvals(arkode_mem, nmpevals)); } +int ARKStepGetNumMassPrecSolves(void *arkode_mem, long int *nmpsolves) { + return(arkLSGetNumMassPrecSolves(arkode_mem, nmpsolves)); } +int ARKStepGetNumMassIters(void *arkode_mem, long int *nmiters) { + return(arkLSGetNumMassIters(arkode_mem, nmiters)); } +int ARKStepGetNumMassConvFails(void *arkode_mem, long int *nmcfails) { + return(arkLSGetNumMassConvFails(arkode_mem, nmcfails)); } +int ARKStepGetNumMTSetups(void *arkode_mem, long int *nmtsetups) { + return(arkLSGetNumMTSetups(arkode_mem, nmtsetups)); } +int ARKStepGetLastMassFlag(void *arkode_mem, long int *flag) { + return(arkLSGetLastMassFlag(arkode_mem, flag)); } + +char *ARKStepGetLinReturnFlagName(long int flag) { + return(arkLSGetReturnFlagName(flag)); } + + + +/*=============================================================== + ARKStep optional input functions -- stepper-specific + ===============================================================*/ + +/*--------------------------------------------------------------- + ARKStepSetDefaults: + + Resets all ARKStep optional inputs to their default values. + 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). + ---------------------------------------------------------------*/ +int ARKStepSetDefaults(void* arkode_mem) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetDefaults", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* Set default ARKode infrastructure parameters */ + retval = arkSetDefaults(ark_mem); + if (retval != ARK_SUCCESS) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepSetDefaults", + "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 */ + 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 */ + step_mem->dgmax = DGMAX; /* max step change before recomputing J or P */ + step_mem->msbp = MSBP; /* max steps between updates to J or P */ + step_mem->stages = 0; /* no stages */ + step_mem->istage = 0; /* current stage */ + step_mem->Be = NULL; /* no Butcher tables */ + step_mem->Bi = NULL; + step_mem->NLS = NULL; /* no nonlinear solver object */ + step_mem->jcur = SUNFALSE; + step_mem->convfail = ARK_NO_FAILURES; + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepSetOptimalParams: + + Sets all adaptivity and solver parameters to our 'best guess' + values, for a given ARKStep integration method (ERK, DIRK, ARK), + a given method order, and a given nonlinear solver type. Should + only be called after the method order, solver, and integration + method have been set, and only if time step adaptivity is + enabled. + ---------------------------------------------------------------*/ +int ARKStepSetOptimalParams(void *arkode_mem) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + ARKodeHAdaptMem hadapt_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetOptimalParams", + &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", + "ARKStepSetOptimalParams", + MSG_ARKADAPT_NO_MEM); + return(ARK_MEM_NULL); + } + hadapt_mem = step_mem->hadapt_mem; + + /* Choose values based on method, order */ + + /* explicit */ + if (step_mem->explicit && !step_mem->implicit) { + hadapt_mem->imethod = 1; + hadapt_mem->safety = RCONST(0.99); + hadapt_mem->bias = RCONST(1.2); + hadapt_mem->growth = RCONST(25.0); + hadapt_mem->k1 = RCONST(0.8); + hadapt_mem->k2 = RCONST(0.31); + hadapt_mem->etamxf = RCONST(0.3); + + /* implicit */ + } else if (step_mem->implicit && !step_mem->explicit) { + switch (step_mem->q) { + case 2: /* just use standard defaults since better ones unknown */ + hadapt_mem->imethod = 0; + hadapt_mem->safety = SAFETY; + hadapt_mem->bias = BIAS; + hadapt_mem->growth = GROWTH; + 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; + break; + case 3: + hadapt_mem->imethod = 2; + hadapt_mem->safety = RCONST(0.957); + hadapt_mem->bias = RCONST(1.9); + hadapt_mem->growth = RCONST(17.6); + 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; + break; + case 4: + hadapt_mem->imethod = 0; + hadapt_mem->safety = RCONST(0.988); + hadapt_mem->bias = RCONST(1.2); + hadapt_mem->growth = RCONST(31.5); + hadapt_mem->k1 = RCONST(0.535); + hadapt_mem->k2 = RCONST(0.209); + hadapt_mem->k3 = RCONST(0.148); + 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; + break; + case 5: + hadapt_mem->imethod = 0; + hadapt_mem->safety = RCONST(0.937); + hadapt_mem->bias = RCONST(3.3); + hadapt_mem->growth = RCONST(22.0); + hadapt_mem->k1 = RCONST(0.56); + hadapt_mem->k2 = RCONST(0.338); + hadapt_mem->k3 = RCONST(0.14); + 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; + break; + } + + /* imex */ + } else { + switch (step_mem->q) { + case 3: + hadapt_mem->imethod = 0; + hadapt_mem->safety = RCONST(0.965); + hadapt_mem->bias = RCONST(1.42); + hadapt_mem->growth = RCONST(28.7); + hadapt_mem->k1 = RCONST(0.54); + hadapt_mem->k2 = RCONST(0.36); + hadapt_mem->k3 = RCONST(0.14); + 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; + break; + case 4: + hadapt_mem->imethod = 0; + hadapt_mem->safety = RCONST(0.97); + hadapt_mem->bias = RCONST(1.35); + hadapt_mem->growth = RCONST(25.0); + hadapt_mem->k1 = RCONST(0.543); + hadapt_mem->k2 = RCONST(0.297); + hadapt_mem->k3 = RCONST(0.14); + 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; + break; + case 5: + hadapt_mem->imethod = 1; + hadapt_mem->safety = RCONST(0.993); + hadapt_mem->bias = RCONST(1.15); + hadapt_mem->growth = RCONST(28.5); + hadapt_mem->k1 = RCONST(0.8); + hadapt_mem->k2 = RCONST(0.35); + 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; + break; + } + + } + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepSetOrder: + + Specifies the method order + + ** Note in documentation that this should not be called along + with ARKStepSetTable or ARKStepSetTableNum. 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 ARKStepSetOrder(void *arkode_mem, int ord) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetOrder", + &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->istage = 0; + step_mem->p = 0; + ARKodeButcherTable_Free(step_mem->Be); step_mem->Be = NULL; + ARKodeButcherTable_Free(step_mem->Bi); step_mem->Bi = NULL; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepSetLinear: + + Specifies that the implicit portion of the problem is linear, + and to tighten the linear solver tolerances while taking only + one Newton iteration. DO NOT USE IN COMBINATION WITH THE + FIXED-POINT SOLVER. Automatically tightens DeltaGammaMax + to ensure that step size changes cause Jacobian recomputation. + + The argument should be 1 or 0, where 1 indicates that the + Jacobian of fi with respect to y depends on time, and + 0 indicates that it is not time dependent. Alternately, when + using an iterative linear solver this flag denotes time + dependence of the preconditioner. + ---------------------------------------------------------------*/ +int ARKStepSetLinear(void *arkode_mem, int timedepend) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetLinear", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* set parameters */ + step_mem->linear = SUNTRUE; + step_mem->linear_timedep = (timedepend == 1); + step_mem->dgmax = RCONST(100.0)*UNIT_ROUNDOFF; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepSetNonlinear: + + Specifies that the implicit portion of the problem is nonlinear. + Used to undo a previous call to ARKStepSetLinear. Automatically + loosens DeltaGammaMax back to default value. + ---------------------------------------------------------------*/ +int ARKStepSetNonlinear(void *arkode_mem) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetNonlinear", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* set parameters */ + step_mem->linear = SUNFALSE; + step_mem->linear_timedep = SUNTRUE; + step_mem->dgmax = DGMAX; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepSetExplicit: + + Specifies that the implicit portion of the problem is disabled, + and to use an explicit RK method. + ---------------------------------------------------------------*/ +int ARKStepSetExplicit(void *arkode_mem) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetExplicit", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* ensure that fe is defined */ + if (step_mem->fe == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepSetExplicit", MSG_ARK_MISSING_FE); + return(ARK_ILL_INPUT); + } + + /* set the relevant parameters */ + step_mem->explicit = SUNTRUE; + step_mem->implicit = SUNFALSE; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepSetImplicit: + + Specifies that the explicit portion of the problem is disabled, + and to use an implicit RK method. + ---------------------------------------------------------------*/ +int ARKStepSetImplicit(void *arkode_mem) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetImplicit", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* ensure that fi is defined */ + if (step_mem->fi == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepSetImplicit", MSG_ARK_MISSING_FI); + return(ARK_ILL_INPUT); + } + + /* set the relevant parameters */ + step_mem->implicit = SUNTRUE; + step_mem->explicit = SUNFALSE; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepSetImEx: + + Specifies that the specifies that problem has both implicit and + explicit parts, and to use an ARK method (this is the default). + ---------------------------------------------------------------*/ +int ARKStepSetImEx(void *arkode_mem) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetImEx", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* ensure that fe and fi are defined */ + if (step_mem->fe == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepSetImEx", MSG_ARK_MISSING_FE); + return(ARK_ILL_INPUT); + } + if (step_mem->fi == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepSetImEx", MSG_ARK_MISSING_FI); + return(ARK_ILL_INPUT); + } + + /* set the relevant parameters */ + step_mem->explicit = SUNTRUE; + step_mem->implicit = SUNTRUE; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepSetTables: + + Specifies to use customized Butcher tables for the system. + + If Bi is NULL, then this sets the integrator in 'explicit' mode. + + If Be is NULL, then this sets the integrator in 'implicit' mode. + + Returns ARK_ILL_INPUT if both Butcher tables are not supplied. + ---------------------------------------------------------------*/ +int ARKStepSetTables(void *arkode_mem, int q, int p, + ARKodeButcherTable Bi, ARKodeButcherTable Be) +{ + int retval; + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetTables", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* check for illegal inputs */ + if ((Bi == NULL) && (Be == NULL)) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepSetTables", + "At least one complete table must be supplied"); + return(ARK_ILL_INPUT); + } + + /* if both tables are set, check that they have the same number of stages */ + if ((Bi != NULL) && (Be != NULL)) { + if (Bi->stages != Be->stages) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepSetTables", + "Both tables must have the same number of stages"); + 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->Be); step_mem->Be = NULL; + ARKodeButcherTable_Free(step_mem->Bi); step_mem->Bi = NULL; + + /* + * determine mode (implicit/explicit/ImEx), and perform appropriate actions + */ + + /* explicit */ + if (Bi == NULL) { + + /* set the relevant parameters (use table q and p) */ + step_mem->stages = Be->stages; + step_mem->q = Be->q; + step_mem->p = Be->p; + + /* copy the table in step memory */ + step_mem->Be = ARKodeButcherTable_Copy(Be); + if (step_mem->Be == NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepSetTables", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + + /* set method as purely explicit */ + retval = ARKStepSetExplicit(arkode_mem); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepSetTables", + "Error in ARKStepSetExplicit"); + return(retval); + } + + /* implicit */ + } else if (Be == NULL) { + + /* set the relevant parameters (use table q and p) */ + step_mem->stages = Bi->stages; + step_mem->q = Bi->q; + step_mem->p = Bi->p; + + /* copy the table in step memory */ + step_mem->Bi = ARKodeButcherTable_Copy(Bi); + if (step_mem->Bi == NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepSetTables", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + + /* set method as purely implicit */ + retval = ARKStepSetImplicit(arkode_mem); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepSetTables", + "Error in ARKStepSetImplicit"); + return(ARK_ILL_INPUT); + } + + /* ImEx */ + } else { + + /* set the relevant parameters (use input q and p) */ + step_mem->stages = Bi->stages; + step_mem->q = q; + step_mem->p = p; + + /* copy the explicit table into step memory */ + step_mem->Be = ARKodeButcherTable_Copy(Be); + if (step_mem->Be == NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepSetTables", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + + /* copy the implicit table into step memory */ + step_mem->Bi = ARKodeButcherTable_Copy(Bi); + if (step_mem->Bi == NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepSetTables", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + + /* set method as ImEx */ + retval = ARKStepSetImEx(arkode_mem); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepSetTables", + "Error in ARKStepSetImEx"); + return(ARK_ILL_INPUT); + } + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepSetTableNum: + + Specifies to use pre-existing Butcher tables for the system, + based on the integer flags passed to + ARKodeButcherTable_LoadERK() and ARKodeButcherTable_LoadDIRK() + within the files arkode_butcher_erk.c and arkode_butcher_dirk.c + (automatically calls ARKStepSetImEx). + + If either argument is negative (illegal), then this disables the + corresponding table (e.g. itable = -1 -> explicit) + ---------------------------------------------------------------*/ +int ARKStepSetTableNum(void *arkode_mem, int itable, int etable) +{ + int flag, retval; + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetTableNum", + &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->Be); step_mem->Be = NULL; + ARKodeButcherTable_Free(step_mem->Bi); step_mem->Bi = NULL; + + + /* determine mode (implicit/explicit/ImEx), and perform + appropriate actions */ + + /* illegal inputs */ + if ((itable < 0) && (etable < 0)) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepSetTableNum", + "At least one valid table number must be supplied"); + return(ARK_ILL_INPUT); + + + /* explicit */ + } else if (itable < 0) { + + /* check that argument specifies an explicit table */ + if (etable<MIN_ERK_NUM || etable>MAX_ERK_NUM) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepSetTableNum", + "Illegal ERK table number"); + return(ARK_ILL_INPUT); + } + + /* fill in table based on argument */ + step_mem->Be = ARKodeButcherTable_LoadERK(etable); + if (step_mem->Be == NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepSetTableNum", + "Error setting explicit table with that index"); + return(ARK_ILL_INPUT); + } + step_mem->stages = step_mem->Be->stages; + step_mem->q = step_mem->Be->q; + step_mem->p = step_mem->Be->p; + + /* set method as purely explicit */ + flag = ARKStepSetExplicit(arkode_mem); + if (flag != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepSetTableNum", + "Error in ARKStepSetExplicit"); + return(flag); + } + + + /* implicit */ + } else if (etable < 0) { + + /* check that argument specifies an implicit table */ + if (itable<MIN_DIRK_NUM || itable>MAX_DIRK_NUM) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepSetTableNum", + "Illegal IRK table number"); + return(ARK_ILL_INPUT); + } + + /* fill in table based on argument */ + step_mem->Bi = ARKodeButcherTable_LoadDIRK(itable); + if (step_mem->Bi == NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepSetTableNum", + "Error setting table with that index"); + return(ARK_ILL_INPUT); + } + step_mem->stages = step_mem->Bi->stages; + step_mem->q = step_mem->Bi->q; + step_mem->p = step_mem->Bi->p; + + /* set method as purely implicit */ + flag = ARKStepSetImplicit(arkode_mem); + if (flag != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepSetTableNum", + "Error in ARKStepSetIxplicit"); + return(flag); + } + + + /* ImEx */ + } else { + + /* 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)) ) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepSetTableNum", + "Incompatible Butcher tables for ARK method"); + return(ARK_ILL_INPUT); + } + + /* fill in tables based on arguments */ + step_mem->Bi = ARKodeButcherTable_LoadDIRK(itable); + step_mem->Be = ARKodeButcherTable_LoadERK(etable); + if (step_mem->Bi == NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepSetTableNum", + "Illegal IRK table number"); + return(ARK_ILL_INPUT); + } + if (step_mem->Be == NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepSetTableNum", + "Illegal ERK table number"); + return(ARK_ILL_INPUT); + } + step_mem->stages = step_mem->Bi->stages; + step_mem->q = step_mem->Bi->q; + step_mem->p = step_mem->Bi->p; + + /* set method as ImEx */ + if (ARKStepSetImEx(arkode_mem) != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepSetTableNum", MSG_ARK_MISSING_F); + return(ARK_ILL_INPUT); + } + + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepSetCFLFraction: + + 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 ARKStepSetCFLFraction(void *arkode_mem, realtype cfl_frac) +{ + 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", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* if argument legal set it, otherwise set default */ + if (crdown <= ZERO) { + step_mem->crdown = CRDOWN; + } else { + step_mem->crdown = crdown; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepSetNonlinRDiv: + + Specifies the user-provided nonlinear convergence constant + rdiv. Legal values are strictly positive; illegal values + imply a reset to the default. + ---------------------------------------------------------------*/ +int ARKStepSetNonlinRDiv(void *arkode_mem, realtype rdiv) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetNonlinRDiv", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* if argument legal set it, otherwise set default */ + if (rdiv <= ZERO) { + step_mem->rdiv = RDIV; + } else { + step_mem->rdiv = rdiv; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepSetDeltaGammaMax: + + Specifies the user-provided linear setup decision constant + dgmax. Legal values are strictly positive; illegal values imply + a reset to the default. + ---------------------------------------------------------------*/ +int ARKStepSetDeltaGammaMax(void *arkode_mem, realtype dgmax) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetDeltaGammaMax", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* if argument legal set it, otherwise set default */ + if (dgmax <= ZERO) { + step_mem->dgmax = DGMAX; + } else { + step_mem->dgmax = dgmax; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepSetMaxStepsBetweenLSet: + + Specifies the user-provided linear setup decision constant + msbp. Positive values give the number of time steps to wait + before calling lsetup; negative values imply recomputation of + lsetup at each nonlinear solve; a zero value implies a reset + to the default. + ---------------------------------------------------------------*/ +int ARKStepSetMaxStepsBetweenLSet(void *arkode_mem, int msbp) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetMaxStepsBetweenLSet", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* if argument legal set it, otherwise set default */ + if (msbp == 0) { + step_mem->msbp = MSBP; + } else { + step_mem->msbp = msbp; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepSetPredictorMethod: + + Specifies the method to use for predicting implicit solutions. + Non-default choices are {1,2,3,4}, all others will use default + (trivial) predictor. + ---------------------------------------------------------------*/ +int ARKStepSetPredictorMethod(void *arkode_mem, int pred_method) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetPredictorMethod", + &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(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; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepSetMaxNonlinIters: + + Specifies the maximum number of nonlinear iterations during + one solve. A non-positive input implies a reset to the + default value. + ---------------------------------------------------------------*/ +int ARKStepSetMaxNonlinIters(void *arkode_mem, int maxcor) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetMaxNonlinIters", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* Return error message if no NLS module is present */ + if (step_mem->NLS == NULL) { + arkProcessError(ark_mem, ARK_NLS_OP_ERR, "ARKode::ARKStep", + "ARKStepSetMaxNonlinIters", + "No SUNNonlinearSolver object is present"); + return(ARK_ILL_INPUT); + } + + /* argument <= 0 sets default, otherwise set input */ + if (maxcor <= 0) { + step_mem->maxcor = MAXCOR; + } else { + step_mem->maxcor = maxcor; + } + + /* send argument to NLS structure */ + retval = SUNNonlinSolSetMaxIters(step_mem->NLS, step_mem->maxcor); + if (retval != SUN_NLS_SUCCESS) { + arkProcessError(ark_mem, ARK_NLS_OP_ERR, "ARKode::ARKStep", + "ARKStepSetMaxNonlinIters", + "Error setting maxcor in SUNNonlinearSolver object"); + return(ARK_NLS_OP_ERR); + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepSetNonlinConvCoef: + + Specifies the coefficient in the nonlinear solver convergence + test. A non-positive input implies a reset to the default value. + ---------------------------------------------------------------*/ +int ARKStepSetNonlinConvCoef(void *arkode_mem, realtype nlscoef) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetNonlinConvCoef", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* argument <= 0 sets default, otherwise set input */ + if (nlscoef <= ZERO) { + step_mem->nlscoef = NLSCOEF; + } else { + step_mem->nlscoef = nlscoef; + } + + return(ARK_SUCCESS); +} + + +/*=============================================================== + ARKStep optional output functions -- stepper-specific + ===============================================================*/ + +/*--------------------------------------------------------------- + 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 + ---------------------------------------------------------------*/ +int ARKStepGetNumAccSteps(void *arkode_mem, long int *nsteps) +{ + 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); +} + + +/*--------------------------------------------------------------- + ARKStepGetNumRhsEvals: + + Returns the current number of calls to fe and fi + ---------------------------------------------------------------*/ +int ARKStepGetNumRhsEvals(void *arkode_mem, long int *fe_evals, + long int *fi_evals) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepGetNumRhsEvals", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* get values from step_mem */ + *fe_evals = step_mem->nfe; + *fi_evals = step_mem->nfi; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepGetNumLinSolvSetups: + + Returns the current number of calls to the lsetup routine + ---------------------------------------------------------------*/ +int ARKStepGetNumLinSolvSetups(void *arkode_mem, long int *nlinsetups) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepGetNumLinSolvSetups", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* get value from step_mem */ + *nlinsetups = step_mem->nsetups; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + 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: + + Sets pointers to the explicit and implicit Butcher tables + currently in use. + ---------------------------------------------------------------*/ +int ARKStepGetCurrentButcherTables(void *arkode_mem, + ARKodeButcherTable *Bi, + ARKodeButcherTable *Be) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepGetCurrentButcherTables", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* get tables from step_mem */ + *Bi = step_mem->Bi; + *Be = step_mem->Be; + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepGetEstLocalErrors: (updated to the correct vector, but + need to verify that it is unchanged between filling the + estimated error and the end of the time step) + + Returns an estimate of the local error + ---------------------------------------------------------------*/ +int ARKStepGetEstLocalErrors(void *arkode_mem, N_Vector ele) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepGetEstLocalErrors", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* copy vector to output */ + N_VScale(ONE, ark_mem->tempv1, ele); + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepGetTimestepperStats: + + Returns integrator statistics + ---------------------------------------------------------------*/ +int ARKStepGetTimestepperStats(void *arkode_mem, long int *expsteps, + long int *accsteps, long int *step_attempts, + long int *fe_evals, long int *fi_evals, + long int *nlinsetups, long int *netfails) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepGetTimestepperStats", + &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 remaining outputs from step_mem */ + *step_attempts = step_mem->nst_attempts; + *fe_evals = step_mem->nfe; + *fi_evals = step_mem->nfi; + *nlinsetups = step_mem->nsetups; + *netfails = step_mem->netf; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepGetNumNonlinSolvIters: + + Returns the current number of nonlinear solver iterations + ---------------------------------------------------------------*/ +int ARKStepGetNumNonlinSolvIters(void *arkode_mem, long int *nniters) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepGetNumNonlinSolvIters", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* if a NLS object is present, set output from that; otherwise + we took zero iterations */ + if (step_mem->NLS) { + retval = SUNNonlinSolGetNumIters(step_mem->NLS, nniters); + if (retval != SUN_NLS_SUCCESS) { + arkProcessError(ark_mem, ARK_NLS_OP_ERR, "ARKode::ARKStep", + "ARKStepGetNumNonlinSolvIters", + "Error retrieving nniters from SUNNonlinearSolver"); + return(ARK_NLS_OP_ERR); + } + } else { + *nniters = 0; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepGetNumNonlinSolvConvFails: + + Returns the current number of nonlinear solver convergence fails + ---------------------------------------------------------------*/ +int ARKStepGetNumNonlinSolvConvFails(void *arkode_mem, long int *nncfails) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepGetNumNonlinSolvConvFails", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* set output from step_mem */ + *nncfails = step_mem->ncfn; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepGetNonlinSolvStats: + + Returns nonlinear solver statistics + ---------------------------------------------------------------*/ +int ARKStepGetNonlinSolvStats(void *arkode_mem, long int *nniters, + long int *nncfails) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepGetNonlinSolvStats", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* set outputs from NLS module and step_mem structure (if present); + otherwise there were zero iterations and no nonlinear failures */ + if (step_mem->NLS) { + retval = SUNNonlinSolGetNumIters(step_mem->NLS, nniters); + if (retval != SUN_NLS_SUCCESS) { + arkProcessError(ark_mem, ARK_NLS_OP_ERR, "ARKode::ARKStep", + "ARKStepGetNonlinSolvStats", + "Error retrieving nniters from SUNNonlinearSolver"); + return(ARK_NLS_OP_ERR); + } + *nncfails = step_mem->ncfn; + } else { + *nniters = 0; + *nncfails = 0; + } + + return(ARK_SUCCESS); +} + + +/*=============================================================== + ARKStep parameter output + ===============================================================*/ + +/*--------------------------------------------------------------- + ARKStepWriteParameters: + + Outputs all solver parameters to the provided file pointer. + ---------------------------------------------------------------*/ +int ARKStepWriteParameters(void *arkode_mem, FILE *fp) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int flag, retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepWriteParameters", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* output ARKode infrastructure parameters first */ + flag = arkWriteParameters(ark_mem, fp); + if (flag != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepWriteParameters", + "Error writing ARKode infrastructure parameters"); + return(flag); + } + + /* print integrator parameters to file */ + fprintf(fp, "ARKStep time step module parameters:\n"); + fprintf(fp, " Method order %i\n",step_mem->q); + if (step_mem->linear) { + fprintf(fp, " Linear implicit problem"); + if (step_mem->linear_timedep) { + fprintf(fp, " (time-dependent Jacobian)\n"); + } else { + fprintf(fp, " (time-independent Jacobian)\n"); + } + } + if (step_mem->explicit && step_mem->implicit) { + fprintf(fp, " ImEx integrator\n"); + } else if (step_mem->implicit) { + fprintf(fp, " Implicit integrator\n"); + } 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); + fprintf(fp, " Nonlinear convergence rate constant = %"RSYM"\n",step_mem->crdown); + fprintf(fp, " Nonlinear divergence tolerance = %"RSYM"\n",step_mem->rdiv); + fprintf(fp, " Gamma factor LSetup tolerance = %"RSYM"\n",step_mem->dgmax); + fprintf(fp, " Number of steps between LSetup calls = %i\n",step_mem->msbp); + } + fprintf(fp, "\n"); + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKStepWriteButcher: + + Outputs Butcher tables to the provided file pointer. + ---------------------------------------------------------------*/ +int ARKStepWriteButcher(void *arkode_mem, FILE *fp) +{ + int retval; + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepWriteButcher", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* check that Butcher table is non-NULL (otherwise report error) */ + if ((step_mem->Be == NULL) && (step_mem->Bi == NULL)) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", + "ARKStepWriteButcher", "Butcher table memory is NULL"); + return(ARK_MEM_NULL); + } + + /* print Butcher tables to file */ + fprintf(fp, "\nARKStep Butcher tables (stages = %i):\n", step_mem->stages); + if (step_mem->explicit && (step_mem->Be != NULL)) { + fprintf(fp, " Explicit Butcher table:\n"); + ARKodeButcherTable_Write(step_mem->Be, fp); + } + fprintf(fp, "\n"); + if (step_mem->implicit && (step_mem->Bi != NULL)) { + fprintf(fp, " Implicit Butcher table:\n"); + ARKodeButcherTable_Write(step_mem->Bi, fp); + } + fprintf(fp, "\n"); + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + EOF + ---------------------------------------------------------------*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_arkstep_nls.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_arkstep_nls.c new file mode 100644 index 0000000..5382b2d --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_arkstep_nls.c @@ -0,0 +1,567 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 interface between ARKStep and the + * SUNNonlinearSolver object + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "arkode_impl.h" +#include "arkode_arkstep_impl.h" +#include <sundials/sundials_math.h> + +#if defined(SUNDIALS_EXTENDED_PRECISION) +#define RSYM ".32Lg" +#else +#define RSYM ".16g" +#endif + +/* constants */ +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + + +/*=============================================================== + Exported functions + ===============================================================*/ + +/*--------------------------------------------------------------- + ARKStepSetNonlinearSolver: + + This routine attaches a SUNNonlinearSolver object to the ARKStep + module. + ---------------------------------------------------------------*/ +int ARKStepSetNonlinearSolver(void *arkode_mem, SUNNonlinearSolver NLS) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "ARKStepSetNonlinearSolver", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* Return immediately if NLS input is NULL */ + if (NLS == NULL) { + arkProcessError(NULL, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepSetNonlinearSolver", + "The NLS input must be non-NULL"); + return(ARK_ILL_INPUT); + } + + /* 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", + "NLS does not support required operations"); + return(ARK_ILL_INPUT); + } + + /* free any existing nonlinear solver */ + if ((step_mem->NLS != NULL) && (step_mem->ownNLS)) + retval = SUNNonlinSolFree(step_mem->NLS); + + /* set SUNNonlinearSolver pointer */ + step_mem->NLS = NLS; + step_mem->ownNLS = SUNFALSE; + + /* set the nonlinear residual/fixed-point function, based on solver type */ + if (SUNNonlinSolGetType(NLS) == SUNNONLINEARSOLVER_ROOTFIND) { + retval = SUNNonlinSolSetSysFn(step_mem->NLS, arkStep_NlsResidual); + } else if (SUNNonlinSolGetType(NLS) == SUNNONLINEARSOLVER_FIXEDPOINT) { + retval = SUNNonlinSolSetSysFn(step_mem->NLS, arkStep_NlsFPFunction); + } else { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepSetNonlinearSolver", + "Invalid nonlinear solver type"); + return(ARK_ILL_INPUT); + } + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepSetNonlinearSolver", + "Setting nonlinear system function failed"); + return(ARK_ILL_INPUT); + } + + /* set convergence test function */ + retval = SUNNonlinSolSetConvTestFn(step_mem->NLS, arkStep_NlsConvTest); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepSetNonlinearSolver", + "Setting convergence test function failed"); + return(ARK_ILL_INPUT); + } + + /* set default nonlinear iterations */ + retval = SUNNonlinSolSetMaxIters(step_mem->NLS, step_mem->maxcor); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "ARKStepSetNonlinearSolver", + "Setting maximum number of nonlinear iterations failed"); + return(ARK_ILL_INPUT); + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + Utility routines called by ARKStep + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + arkStep_NlsInit: + + 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 + a re-size. + ---------------------------------------------------------------*/ +int arkStep_NlsInit(ARKodeMem ark_mem) +{ + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + if (ark_mem->step_mem==NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", + "arkStep_NlsInit", MSG_ARKSTEP_NO_MEM); + return(ARK_MEM_NULL); + } + step_mem = (ARKodeARKStepMem) ark_mem->step_mem; + + /* set the linear solver setup wrapper function */ + if (step_mem->lsetup) + retval = SUNNonlinSolSetLSetupFn(step_mem->NLS, arkStep_NlsLSetup); + else + retval = SUNNonlinSolSetLSetupFn(step_mem->NLS, NULL); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "arkStep_NlsInit", + "Setting the linear solver setup function failed"); + return(ARK_NLS_INIT_FAIL); + } + + /* set the linear solver solve wrapper function */ + if (step_mem->lsolve) + retval = SUNNonlinSolSetLSolveFn(step_mem->NLS, arkStep_NlsLSolve); + else + retval = SUNNonlinSolSetLSolveFn(step_mem->NLS, NULL); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "arkStep_NlsInit", + "Setting linear solver solve function failed"); + return(ARK_NLS_INIT_FAIL); + } + + /* initialize nonlinear solver */ + retval = SUNNonlinSolInitialize(step_mem->NLS); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ARKStep", + "arkStep_NlsInit", MSG_NLS_INIT_FAIL); + return(ARK_NLS_INIT_FAIL); + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkStep_Nls + + This routine attempts to solve the nonlinear system associated + with a single implicit step of the linear multistep method. + It calls the supplied SUNNonlinearSolver object to perform the + solve. + + Upon entry, the predicted solution is held in step_mem->zpred; + this array is never changed throughout this routine. If an + initial attempt at solving the nonlinear system fails (e.g. due + to a stale Jacobian), this allows for new attempts at the + solution. + + Upon a successful solve, the solution is held in ark_mem->ycur. + ---------------------------------------------------------------*/ +int arkStep_Nls(ARKodeMem ark_mem, int nflag) +{ + ARKodeARKStepMem step_mem; + booleantype callLSetup; + N_Vector zcor0; + int retval; + + /* access ARKodeARKStepMem structure */ + if (ark_mem->step_mem==NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", + "arkStep_Nls", MSG_ARKSTEP_NO_MEM); + return(ARK_MEM_NULL); + } + step_mem = (ARKodeARKStepMem) ark_mem->step_mem; + + /* If a linear solver 'setup' is supplied, set various flags for + determining whether it should be called */ + if (step_mem->lsetup) { + + /* Set interface 'convfail' flag for use inside lsetup */ + if (step_mem->linear) { + step_mem->convfail = (nflag == FIRST_CALL) ? ARK_NO_FAILURES : ARK_FAIL_OTHER; + } else { + 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); + if (step_mem->linear) { /* linearly-implicit problem */ + callLSetup = callLSetup || (step_mem->linear_timedep); + } else { /* nonlinearly-implicit problem */ + callLSetup = callLSetup || + (nflag == PREV_CONV_FAIL) || (nflag == PREV_ERR_FAIL) || + (ark_mem->nst >= step_mem->nstlp + abs(step_mem->msbp)); + } + } else { + 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); + + } + + /* on successful solve, reset the jcur flag */ + if (retval == ARK_SUCCESS) step_mem->jcur = SUNFALSE; + + return(retval); +} + + +/*--------------------------------------------------------------- + Interface routines supplied to SUNNonlinearSolver module + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + arkStep_NlsLSetup: + + 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) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "arkStep_NlsLSetup", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* update convfail based on jbad flag */ + if (jbad) + step_mem->convfail = ARK_FAIL_BAD_J; + + /* Use ARKode's tempv1, tempv2 and tempv3 as + temporary vectors for the linear solver setup routine */ + step_mem->nsetups++; + retval = step_mem->lsetup(ark_mem, step_mem->convfail, ark_mem->tcur, + ark_mem->ycur, step_mem->Fi[step_mem->istage], + &(step_mem->jcur), ark_mem->tempv1, + ark_mem->tempv2, ark_mem->tempv3); + + /* update Jacobian status */ + *jcur = step_mem->jcur; + + /* update flags and 'gamma' values for last lsetup call */ + ark_mem->firststage = SUNFALSE; + step_mem->gamrat = step_mem->crate = ONE; + step_mem->gammap = step_mem->gamma; + step_mem->nstlp = ark_mem->nst; + + if (retval < 0) return(ARK_LSETUP_FAIL); + if (retval > 0) return(CONV_FAIL); + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkStep_NlsLSolve: + + 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) +{ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval, nonlin_iter; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "arkStep_NlsLSolve", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* retrieve nonlinear solver iteration from module */ + retval = SUNNonlinSolGetCurIter(step_mem->NLS, &nonlin_iter); + if (retval != SUN_NLS_SUCCESS) + return(ARK_NLS_OP_ERR); + + /* call linear solver interface, and handle return value */ + retval = step_mem->lsolve(ark_mem, b, ark_mem->tcur, + ark_mem->ycur, step_mem->Fi[step_mem->istage], + step_mem->eRNrm, nonlin_iter); + + if (retval < 0) return(ARK_LSOLVE_FAIL); + if (retval > 0) return(retval); + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + 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 + compute the nonlinear residual r. + + At the ith stage, we compute the residual vector: + r = M*z - M*yn - h*sum_{j=0}^{i-1} Ae(i,j)*Fe(j) + - h*sum_{j=0}^{i} Ai(i,j)*Fi(j) + r = M*zp + M*zc - M*yn - h*sum_{j=0}^{i-1} Ae(i,j)*Fe(j) + - h*sum_{j=0}^{i} Ai(i,j)*Fi(j) + r = (M*zc - gamma*Fi(z)) - (M*yn - M*zp + data) + where the current stage solution z = zp + zc, and where + zc is stored in the input, zcor + (M*yn-M*zp+data) is stored in step_mem->sdata, + so we really just compute: + z = zp + zc (stored in ark_mem->ycur) + Fi(z) (stored step_mem->Fi[step_mem->istage]) + r = M*zc - gamma*Fi(z) - step_mem->sdata + ---------------------------------------------------------------*/ +int arkStep_NlsResidual(N_Vector zcor, N_Vector r, void* arkode_mem) +{ + /* temporary variables */ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + int retval; + realtype c[3]; + N_Vector X[3]; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "arkStep_NlsResidual", + &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, 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); + + /* put M*zcor in r */ + if (step_mem->mass_mem != NULL) { + retval = step_mem->mmult((void *) ark_mem, zcor, r); + if (retval != ARK_SUCCESS) return (ARK_MASSMULT_FAIL); + X[0] = r; + } else { + X[0] = zcor; + } + + /* update with My, sdata and gamma*fy */ + c[0] = ONE; + 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, r); + if (retval != 0) return(ARK_VECTOROP_ERR); + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkStep_NlsFPFunction: + + This routine evaluates the fixed point iteration function 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 guess and + implicit ODE RHS vector to compute the iteration function g. + + At the ith stage, the new stage solution z should solve: + z = yn + h*sum_{j=0}^{i-1} Ae(i,j)*Fe(j) + + h*sum_{j=0}^{i} Ai(i,j)*Fi(j) + <=> + z = yn + gamma*Fi(z) + h*sum_{j=0}^{i-1} ( Ae(i,j)*Fe(j) + + 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) + where the current nonlinear guess is z = zp + zc, and where + z is stored in the input, z, + 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 + ---------------------------------------------------------------*/ +int arkStep_NlsFPFunction(N_Vector z, 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 */ + retval = arkStep_AccessStepMem(arkode_mem, "arkStep_NlsFPFunction", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* compute implicit RHS and save for later */ + retval = step_mem->fi(ark_mem->tcur, z, + 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); + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkStep_NlsConvTest: + + This routine provides the nonlinear solver convergence test for + the additive Runge-Kutta method. We have two modes. + + Standard: + delnorm = ||del||_WRMS + if (m==0) crate = 1 + if (m>0) crate = max(crdown*crate, delnorm/delp) + dcon = min(crate, ONE) * del / nlscoef + if (dcon<=1) return convergence + if ((m >= 2) && (del > rdiv*delp)) return divergence + + Linearly-implicit mode: + if the user specifies that the problem is linearly + implicit, then we just declare 'success' no matter what + is provided. + ---------------------------------------------------------------*/ +int arkStep_NlsConvTest(SUNNonlinearSolver NLS, N_Vector y, N_Vector del, + realtype tol, N_Vector ewt, void* arkode_mem) +{ + /* temporary variables */ + ARKodeMem ark_mem; + ARKodeARKStepMem step_mem; + realtype delnrm, dcon; + int m, retval; + + /* access ARKodeARKStepMem structure */ + retval = arkStep_AccessStepMem(arkode_mem, "arkStep_NlsConvTest", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* if the problem is linearly implicit, just return success */ + if (step_mem->linear) + return(SUN_NLS_SUCCESS); + + /* compute the norm of the correction */ + delnrm = N_VWrmsNorm(del, ewt); + + /* get the current nonlinear solver iteration count */ + retval = SUNNonlinSolGetCurIter(NLS, &m); + if (retval != ARK_SUCCESS) return(ARK_MEM_NULL); + + /* update the stored estimate of the convergence rate (assumes linear convergence) */ + if (m > 0) + step_mem->crate = SUNMAX(step_mem->crdown*step_mem->crate, delnrm/step_mem->delp); + + /* compute our scaled error norm for testing convergence */ + dcon = SUNMIN(step_mem->crate, ONE) * delnrm / tol; + + /* check for convergence; if so return with success */ + if (dcon <= ONE) return(SUN_NLS_SUCCESS); + + /* check for divergence */ + if ((m >= 1) && (delnrm > step_mem->rdiv*step_mem->delp)) + return(SUN_NLS_CONV_RECVR); + + /* save norm of correction for next iteration */ + step_mem->delp = delnrm; + + /* return with flag that there is more work to do */ + return(SUN_NLS_CONTINUE); +} + + +/*=============================================================== + EOF + ===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_bandpre.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_bandpre.c new file mode 100644 index 0000000..e1e6f40 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_bandpre.c @@ -0,0 +1,542 @@ +/*--------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 + * 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 implementations of the banded difference + * quotient Jacobian-based preconditioner and solver routines for + * use with the ARKLS linear solver interface. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "arkode_impl.h" +#include "arkode_bandpre_impl.h" +#include "arkode_ls_impl.h" +#include <sundials/sundials_math.h> + +#define MIN_INC_MULT RCONST(1000.0) +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + + +/* Prototypes of ARKBandPrecSetup and ARKBandPrecSolve */ +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, + realtype gamma, realtype delta, + int lr, void *bp_data); + +/* Prototype for ARKBandPrecFree */ +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, + N_Vector ftemp, N_Vector ytemp); + + +/*--------------------------------------------------------------- + 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 + N_VGetArrayPointer exists. +---------------------------------------------------------------*/ +int ARKBandPrecInit(void *arkode_mem, sunindextype N, + sunindextype mu, sunindextype ml) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + ARKBandPrecData pdata; + sunindextype mup, mlp, storagemu; + int retval; + + /* access ARKLsMem structure */ + retval = arkLs_AccessLMem(arkode_mem, "ARKBandPrecInit", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* Test compatibility of NVECTOR package with the BAND preconditioner */ + if(ark_mem->tempv1->ops->nvgetarraypointer == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKBANDPRE", + "ARKBandPrecInit", MSG_BP_BAD_NVECTOR); + return(ARKLS_ILL_INPUT); + } + + /* Allocate data memory */ + pdata = NULL; + pdata = (ARKBandPrecData) malloc(sizeof *pdata); + if (pdata == NULL) { + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBANDPRE", + "ARKBandPrecInit", MSG_BP_MEM_FAIL); + return(ARKLS_MEM_FAIL); + } + + /* Load pointers and bandwidths into pdata block. */ + pdata->arkode_mem = arkode_mem; + pdata->N = N; + pdata->mu = mup = SUNMIN(N-1, SUNMAX(0,mu)); + pdata->ml = mlp = SUNMIN(N-1, SUNMAX(0,ml)); + + /* Initialize nfeBP counter */ + pdata->nfeBP = 0; + + /* Allocate memory for saved banded Jacobian approximation. */ + pdata->savedJ = NULL; + pdata->savedJ = SUNBandMatrixStorage(N, mup, mlp, mup); + if (pdata->savedJ == NULL) { + free(pdata); pdata = NULL; + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBANDPRE", + "ARKBandPrecInit", MSG_BP_MEM_FAIL); + return(ARKLS_MEM_FAIL); + } + + /* Allocate memory for banded preconditioner. */ + storagemu = SUNMIN(N-1, mup+mlp); + pdata->savedP = NULL; + pdata->savedP = SUNBandMatrixStorage(N, mup, mlp, storagemu); + if (pdata->savedP == NULL) { + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBANDPRE", + "ARKBandPrecInit", MSG_BP_MEM_FAIL); + return(ARKLS_MEM_FAIL); + } + + /* Allocate memory for banded linear solver */ + pdata->LS = NULL; + pdata->LS = SUNLinSol_Band(ark_mem->tempv1, pdata->savedP); + if (pdata->LS == NULL) { + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + 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); + if (pdata->tmp1 == NULL) { + SUNLinSolFree(pdata->LS); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBANDPRE", + "ARKBandPrecInit", MSG_BP_MEM_FAIL); + return(ARKLS_MEM_FAIL); + } + pdata->tmp2 = NULL; + pdata->tmp2 = N_VClone(ark_mem->tempv1); + if (pdata->tmp2 == NULL) { + SUNLinSolFree(pdata->LS); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + N_VDestroy(pdata->tmp1); + free(pdata); pdata = NULL; + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBANDPRE", + "ARKBandPrecInit", MSG_BP_MEM_FAIL); + return(ARKLS_MEM_FAIL); + } + + /* initialize band linear solver object */ + retval = SUNLinSolInitialize(pdata->LS); + if (retval != SUNLS_SUCCESS) { + SUNLinSolFree(pdata->LS); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + N_VDestroy(pdata->tmp1); + N_VDestroy(pdata->tmp2); + free(pdata); pdata = NULL; + 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); + + /* Point to the new P_data field in the LS memory */ + arkls_mem->P_data = pdata; + + /* Attach the pfree function */ + arkls_mem->pfree = ARKBandPrecFree; + + /* Attach preconditioner solve and setup functions */ + retval = arkLSSetPreconditioner(arkode_mem, + ARKBandPrecSetup, + ARKBandPrecSolve); + return(retval); +} + + +int ARKBandPrecGetWorkSpace(void *arkode_mem, long int *lenrwBP, + long int *leniwBP) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + ARKBandPrecData pdata; + sunindextype lrw1, liw1; + long int lrw, liw; + int retval; + + /* access ARKLsMem structure */ + retval = arkLs_AccessLMem(arkode_mem, "ARKBandPrecGetWorkSpace", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* Return immediately if ARKBandPrecData is NULL */ + if (arkls_mem->P_data == NULL) { + 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 */ + *leniwBP = 4; + *lenrwBP = 0; + if (ark_mem->tempv1->ops->nvspace) { + N_VSpace(ark_mem->tempv1, &lrw1, &liw1); + *leniwBP += 2*liw1; + *lenrwBP += 2*lrw1; + } + if (pdata->savedJ->ops->space) { + retval = SUNMatSpace(pdata->savedJ, &lrw, &liw); + if (retval == 0) { + *leniwBP += liw; + *lenrwBP += lrw; + } + } + if (pdata->savedP->ops->space) { + retval = SUNMatSpace(pdata->savedP, &lrw, &liw); + if (retval == 0) { + *leniwBP += liw; + *lenrwBP += lrw; + } + } + if (pdata->LS->ops->space) { + retval = SUNLinSolSpace(pdata->LS, &lrw, &liw); + if (retval == SUNLS_SUCCESS) { + *leniwBP += liw; + *lenrwBP += lrw; + } + } + + return(ARKLS_SUCCESS); +} + + +int ARKBandPrecGetNumRhsEvals(void *arkode_mem, long int *nfevalsBP) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + ARKBandPrecData pdata; + int retval; + + /* access ARKLsMem structure */ + retval = arkLs_AccessLMem(arkode_mem, "ARKBandPrecGetNumRhsEvals", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* Return immediately if ARKBandPrecData is NULL */ + if (arkls_mem->P_data == NULL) { + arkProcessError(ark_mem, ARKLS_PMEM_NULL, "ARKBANDPRE", + "ARKBandPrecGetNumRhsEvals", MSG_BP_PMEM_NULL); + return(ARKLS_PMEM_NULL); + } + pdata = (ARKBandPrecData) arkls_mem->P_data; + + /* set output */ + *nfevalsBP = pdata->nfeBP; + + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKBandPrecSetup: + + Together ARKBandPrecSetup and ARKBandPrecSolve use a banded + difference quotient Jacobian to create a preconditioner. + ARKBandPrecSetup calculates a new J, if necessary, then + calculates P = I - gamma*J, and does an LU factorization of P. + + The parameters of ARKBandPrecSetup 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 + from scratch. + jok == SUNTRUE means that Jacobian data from the + previous PrecSetup call will be reused + (with the current value of gamma). + A ARKBandPrecSetup 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 ARKBandPrecond 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 ARKBandPrecInit) + + The value to be returned by the ARKBandPrecSetup function is + 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, + 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; + + ark_mem = (ARKodeMem) pdata->arkode_mem; + + if (jok) { + + /* If jok = SUNTRUE, use saved copy of J. */ + *jcurPtr = SUNFALSE; + retval = SUNMatCopy(pdata->savedJ, pdata->savedP); + if (retval < 0) { + arkProcessError(ark_mem, -1, "ARKBANDPRE", + "ARKBandPrecSetup", MSG_BP_SUNMAT_FAIL); + return(-1); + } + if (retval > 0) { + return(1); + } + + } else { + + /* If jok = SUNFALSE, call ARKBandPDQJac for new J value. */ + *jcurPtr = SUNTRUE; + retval = SUNMatZero(pdata->savedJ); + if (retval < 0) { + arkProcessError(ark_mem, -1, "ARKBANDPRE", + "ARKBandPrecSetup", MSG_BP_SUNMAT_FAIL); + return(-1); + } + if (retval > 0) { + return(1); + } + + retval = ARKBandPDQJac(pdata, t, y, fy, + pdata->tmp1, pdata->tmp2); + if (retval < 0) { + arkProcessError(ark_mem, -1, "ARKBANDPRE", + "ARKBandPrecSetup", MSG_BP_RHSFUNC_FAILED); + return(-1); + } + if (retval > 0) { + return(1); + } + + retval = SUNMatCopy(pdata->savedJ, pdata->savedP); + if (retval < 0) { + arkProcessError(ark_mem, -1, "ARKBANDPRE", + "ARKBandPrecSetup", MSG_BP_SUNMAT_FAIL); + return(-1); + } + if (retval > 0) { + return(1); + } + + } + + /* Scale and add identity to get savedP = I - gamma*J. */ + retval = SUNMatScaleAddI(-gamma, pdata->savedP); + if (retval) { + 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); +} + + +/*--------------------------------------------------------------- + ARKBandPrecSolve: + + ARKBandPrecSolve solves a linear system P z = r, where P is the + matrix computed by ARKBandPrecond. + + The parameters of ARKBandPrecSolve 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 ARKBandPrecInit) + + z is the output vector computed by ARKBandPrecSolve. + + 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, + realtype gamma, realtype delta, + int lr, void *bp_data) +{ + ARKBandPrecData pdata; + int retval; + + /* Assume matrix and linear solver have already been allocated. */ + pdata = (ARKBandPrecData) bp_data; + + /* Call banded solver object to do the work */ + retval = SUNLinSolSolve(pdata->LS, pdata->savedP, z, r, ZERO); + return(retval); +} + + +/*--------------------------------------------------------------- + ARKBandPrecFree: + + Frees data associated with the ARKBand preconditioner. +---------------------------------------------------------------*/ +static int ARKBandPrecFree(ARKodeMem ark_mem) +{ + ARKLsMem arkls_mem; + void* ark_step_lmem; + ARKBandPrecData 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); + if (ark_step_lmem == NULL) return(0); + arkls_mem = (ARKLsMem) ark_step_lmem; + if (arkls_mem->P_data == NULL) return(0); + pdata = (ARKBandPrecData) arkls_mem->P_data; + + SUNLinSolFree(pdata->LS); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + N_VDestroy(pdata->tmp1); + N_VDestroy(pdata->tmp2); + + free(pdata); + pdata = NULL; + + return(0); +} + + +/*--------------------------------------------------------------- + ARKBandPDQJac: + + This routine generates a banded difference quotient approximation to + the Jacobian of f(t,y). It assumes that a band matrix of type + DlsMat 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 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, + N_Vector ftemp, N_Vector ytemp) +{ + ARKodeMem ark_mem; + ARKRhsFn fi; + realtype fnorm, minInc, inc, inc_inv, srur; + sunindextype group, i, j, width, ngroups, i1, i2; + realtype *col_j, *ewt_data, *fy_data, *ftemp_data, *y_data, *ytemp_data; + int retval; + + ark_mem = (ARKodeMem) pdata->arkode_mem; + + /* Access implicit RHS function */ + 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. */ + 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); + + /* Load ytemp with y = predicted y vector. */ + N_VScale(ONE, y, ytemp); + + /* Set minimum increment based on uround and norm of f. */ + srur = SUNRsqrt(ark_mem->uround); + fnorm = N_VWrmsNorm(fy, ark_mem->rwt); + minInc = (fnorm != ZERO) ? + (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]); + ytemp_data[j] += inc; + } + + /* Evaluate f with incremented y. */ + retval = fi(t, ytemp, ftemp, ark_mem->user_data); + pdata->nfeBP++; + if (retval != 0) return(retval); + + /* Restore ytemp, then form and load difference quotients. */ + for (j = group-1; j < pdata->N; j += width) { + ytemp_data[j] = y_data[j]; + col_j = SUNBandMatrix_Column(pdata->savedJ,j); + inc = SUNMAX(srur*SUNRabs(y_data[j]), minInc/ewt_data[j]); + inc_inv = ONE/inc; + i1 = SUNMAX(0, j-pdata->mu); + i2 = SUNMIN(j+pdata->ml, pdata->N-1); + for (i=i1; i <= i2; i++) + SM_COLUMN_ELEMENT_B(col_j,i,j) = + inc_inv * (ftemp_data[i] - fy_data[i]); + } + } + + return(0); +} + + +/*--------------------------------------------------------------- + EOF +---------------------------------------------------------------*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_bandpre_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_bandpre_impl.h new file mode 100644 index 0000000..ff203a4 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_bandpre_impl.h @@ -0,0 +1,72 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * Implementation header file for the ARKBANDPRE module. + *--------------------------------------------------------------*/ + +#ifndef _ARKBANDPRE_IMPL_H +#define _ARKBANDPRE_IMPL_H + +#include <arkode/arkode_bandpre.h> +#include <sunmatrix/sunmatrix_band.h> +#include <sunlinsol/sunlinsol_band.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*--------------------------------------------------------------- + Type: ARKBandPrecData +---------------------------------------------------------------*/ + +typedef struct ARKBandPrecDataRec { + + /* Data set by user in ARKBandPrecInit */ + sunindextype N; + sunindextype ml, mu; + + /* Data set by ARKBandPrecSetup */ + SUNMatrix savedJ; + SUNMatrix savedP; + SUNLinearSolver LS; + N_Vector tmp1; + N_Vector tmp2; + + /* Rhs calls */ + long int nfeBP; + + /* Pointer to arkode_mem */ + void *arkode_mem; + +} *ARKBandPrecData; + + +/*--------------------------------------------------------------- + ARKBANDPRE error messages +---------------------------------------------------------------*/ + +#define MSG_BP_MEM_NULL "Integrator memory is NULL." +#define MSG_BP_LMEM_NULL "Linear solver memory is NULL. The SPILS interface must be attached." +#define MSG_BP_MEM_FAIL "A memory request failed." +#define MSG_BP_BAD_NVECTOR "A required vector operation is not implemented." +#define MSG_BP_SUNMAT_FAIL "An error arose from a SUNBandMatrix routine." +#define MSG_BP_SUNLS_FAIL "An error arose from a SUNBandLinearSolver routine." +#define MSG_BP_PMEM_NULL "Band preconditioner memory is NULL. ARKBandPrecInit must be called." +#define MSG_BP_RHSFUNC_FAILED "The right-hand side routine failed in an unrecoverable manner." + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_bbdpre.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_bbdpre.c new file mode 100644 index 0000000..e364617 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_bbdpre.c @@ -0,0 +1,666 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 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 + * of NVECTOR. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "arkode_impl.h" +#include "arkode_bbdpre_impl.h" +#include "arkode_ls_impl.h" +#include <sundials/sundials_math.h> +#include <nvector/nvector_serial.h> + + +#define MIN_INC_MULT RCONST(1000.0) +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + + +/* Prototypes of functions ARKBBDPrecSetup and ARKBBDPrecSolve */ +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, + realtype gamma, realtype delta, + int lr, void *bbd_data); + +/* Prototype for ARKBBDPrecFree */ +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, + N_Vector ytemp, N_Vector gtemp); + + +/*--------------------------------------------------------------- + User-Callable Functions: initialization, reinit and free +---------------------------------------------------------------*/ +int ARKBBDPrecInit(void *arkode_mem, sunindextype Nlocal, + sunindextype mudq, sunindextype mldq, + sunindextype mukeep, sunindextype mlkeep, + realtype dqrely, + ARKLocalFn gloc, ARKCommFn cfn) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + ARKBBDPrecData pdata; + sunindextype muk, mlk, storage_mu, lrw1, liw1; + long int lrw, liw; + int retval; + + /* access ARKMilsMem structure */ + retval = arkLs_AccessLMem(arkode_mem, "ARKBBDPrecInit", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* Test compatibility of NVECTOR package with the BBD preconditioner */ + if(ark_mem->tempv1->ops->nvgetarraypointer == NULL) { + 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); + if (pdata == NULL) { + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", + "ARKBBDPrecInit", MSG_BBD_MEM_FAIL); + return(ARKLS_MEM_FAIL); + } + + /* Set pointers to gloc and cfn; load half-bandwidths */ + pdata->arkode_mem = arkode_mem; + pdata->gloc = gloc; + pdata->cfn = cfn; + pdata->mudq = SUNMIN(Nlocal-1, SUNMAX(0,mudq)); + pdata->mldq = SUNMIN(Nlocal-1, SUNMAX(0,mldq)); + muk = SUNMIN(Nlocal-1, SUNMAX(0,mukeep)); + mlk = SUNMIN(Nlocal-1, SUNMAX(0,mlkeep)); + pdata->mukeep = muk; + pdata->mlkeep = mlk; + + /* 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", + "ARKBBDPrecInit", MSG_BBD_MEM_FAIL); + return(ARKLS_MEM_FAIL); + } + + /* Allocate memory for preconditioner matrix */ + storage_mu = SUNMIN(Nlocal-1, muk + mlk); + pdata->savedP = NULL; + pdata->savedP = SUNBandMatrixStorage(Nlocal, muk, mlk, storage_mu); + if (pdata->savedP == NULL) { + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", + "ARKBBDPrecInit", MSG_BBD_MEM_FAIL); + return(ARKLS_MEM_FAIL); + } + + /* Allocate memory for temporary N_Vectors */ + pdata->zlocal = NULL; + pdata->zlocal = N_VNewEmpty_Serial(Nlocal); + if (pdata->zlocal == NULL) { + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", + "ARKBBDPrecInit", MSG_BBD_MEM_FAIL); + return(ARKLS_MEM_FAIL); + } + pdata->rlocal = NULL; + pdata->rlocal = N_VNewEmpty_Serial(Nlocal); + if (pdata->rlocal == NULL) { + N_VDestroy(pdata->zlocal); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", + "ARKBBDPrecInit", MSG_BBD_MEM_FAIL); + return(ARKLS_MEM_FAIL); + } + pdata->tmp1 = NULL; + pdata->tmp1 = N_VClone(ark_mem->tempv1); + if (pdata->tmp1 == NULL) { + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", + "ARKBBDPrecInit", MSG_BBD_MEM_FAIL); + return(ARKLS_MEM_FAIL); + } + pdata->tmp2 = NULL; + pdata->tmp2 = N_VClone(ark_mem->tempv1); + if (pdata->tmp2 == NULL) { + N_VDestroy(pdata->tmp1); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", + "ARKBBDPrecInit", MSG_BBD_MEM_FAIL); + return(ARKLS_MEM_FAIL); + } + pdata->tmp3 = NULL; + pdata->tmp3 = N_VClone(ark_mem->tempv1); + if (pdata->tmp3 == NULL) { + N_VDestroy(pdata->tmp1); + N_VDestroy(pdata->tmp2); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", + "ARKBBDPrecInit", MSG_BBD_MEM_FAIL); + return(ARKLS_MEM_FAIL); + } + + /* Allocate memory for banded linear solver */ + pdata->LS = NULL; + pdata->LS = SUNLinSol_Band(pdata->rlocal, pdata->savedP); + if (pdata->LS == NULL) { + N_VDestroy(pdata->tmp1); + N_VDestroy(pdata->tmp2); + N_VDestroy(pdata->tmp3); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKBBDPRE", + "ARKBBDPrecInit", MSG_BBD_MEM_FAIL); + return(ARKLS_MEM_FAIL); + } + + /* initialize band linear solver object */ + retval = SUNLinSolInitialize(pdata->LS); + if (pdata->LS == NULL) { + N_VDestroy(pdata->tmp1); + N_VDestroy(pdata->tmp2); + N_VDestroy(pdata->tmp3); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + SUNLinSolFree(pdata->LS); + free(pdata); pdata = NULL; + 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) ? + dqrely : SUNRsqrt(ark_mem->uround); + + /* Store Nlocal to be used in ARKBBDPrecSetup */ + pdata->n_local = Nlocal; + + /* Set work space sizes and initialize nge */ + pdata->rpwsize = 0; + pdata->ipwsize = 0; + if (ark_mem->tempv1->ops->nvspace) { + N_VSpace(ark_mem->tempv1, &lrw1, &liw1); + pdata->rpwsize += 3*lrw1; + pdata->ipwsize += 3*liw1; + } + if (pdata->rlocal->ops->nvspace) { + N_VSpace(pdata->rlocal, &lrw1, &liw1); + pdata->rpwsize += 2*lrw1; + pdata->ipwsize += 2*liw1; + } + if (pdata->savedJ->ops->space) { + retval = SUNMatSpace(pdata->savedJ, &lrw, &liw); + pdata->rpwsize += lrw; + pdata->ipwsize += liw; + } + if (pdata->savedP->ops->space) { + retval = SUNMatSpace(pdata->savedP, &lrw, &liw); + pdata->rpwsize += lrw; + pdata->ipwsize += liw; + } + if (pdata->LS->ops->space) { + retval = SUNLinSolSpace(pdata->LS, &lrw, &liw); + pdata->rpwsize += lrw; + pdata->ipwsize += liw; + } + pdata->nge = 0; + + /* make sure P_data is free from any previous allocations */ + if (arkls_mem->pfree) + arkls_mem->pfree(ark_mem); + + /* Point to the new P_data field in the LS memory */ + arkls_mem->P_data = pdata; + + /* Attach the pfree function */ + arkls_mem->pfree = ARKBBDPrecFree; + + /* Attach preconditioner solve and setup functions */ + retval = arkLSSetPreconditioner(arkode_mem, + ARKBBDPrecSetup, + ARKBBDPrecSolve); + + return(retval); +} + + +/*-------------------------------------------------------------*/ +int ARKBBDPrecReInit(void *arkode_mem, sunindextype mudq, + sunindextype mldq, realtype dqrely) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + ARKBBDPrecData pdata; + sunindextype Nlocal; + int retval; + + /* access ARKMilsMem structure */ + retval = arkLs_AccessLMem(arkode_mem, "ARKBBDPrecReInit", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* Return immediately ARKBBDPrecData is NULL */ + if (arkls_mem->P_data == NULL) { + 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 */ + Nlocal = pdata->n_local; + pdata->mudq = SUNMIN(Nlocal-1, SUNMAX(0,mudq)); + pdata->mldq = SUNMIN(Nlocal-1, SUNMAX(0,mldq)); + + /* Set dqrely based on input dqrely (0 implies default). */ + pdata->dqrely = (dqrely > ZERO) ? + dqrely : SUNRsqrt(ark_mem->uround); + + /* Re-initialize nge */ + pdata->nge = 0; + + return(ARKLS_SUCCESS); +} + + +/*-------------------------------------------------------------*/ +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); + if (retval != ARK_SUCCESS) return(retval); + + /* Return immediately ARKBBDPrecData is NULL */ + if (arkls_mem->P_data == NULL) { + arkProcessError(ark_mem, ARKLS_PMEM_NULL, "ARKBBDPRE", + "ARKBBDPrecGetWorkSpace", MSG_BBD_PMEM_NULL); + return(ARKLS_PMEM_NULL); + } + pdata = (ARKBBDPrecData) arkls_mem->P_data; + + /* set outputs */ + *lenrwBBDP = pdata->rpwsize; + *leniwBBDP = pdata->ipwsize; + + return(ARKLS_SUCCESS); +} + + +/*-------------------------------------------------------------*/ +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); + if (retval != ARK_SUCCESS) return(retval); + + /* Return immediately if ARKBBDPrecData is NULL */ + if (arkls_mem->P_data == NULL) { + arkProcessError(ark_mem, ARKLS_PMEM_NULL, "ARKBBDPRE", + "ARKBBDPrecGetNumGfnEvals", MSG_BBD_PMEM_NULL); + return(ARKLS_PMEM_NULL); + } + pdata = (ARKBBDPrecData) arkls_mem->P_data; + + /* set output */ + *ngevalsBBDP = pdata->nge; + + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + ARKBBDPrecSetup: + + ARKBBDPrecSetup 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. + + 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: + + 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 + from scratch. + jok == SUNTRUE means that Jacobian data from the + previous ARKBBDPrecon call can be reused + (with the current value of gamma). + A ARKBBDPrecon 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 ARKBBDPrecon 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 + ARKBBDPrecInit + + Return value: + The value returned by this ARKBBDPrecSetup function is the int + 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, + realtype gamma, void *bbd_data) +{ + sunindextype ier; + ARKBBDPrecData pdata; + ARKodeMem ark_mem; + int retval; + + pdata = (ARKBBDPrecData) bbd_data; + + ark_mem = (ARKodeMem) pdata->arkode_mem; + + /* If jok = SUNTRUE, use saved copy of J */ + if (jok) { + *jcurPtr = SUNFALSE; + retval = SUNMatCopy(pdata->savedJ, pdata->savedP); + if (retval < 0) { + arkProcessError(ark_mem, -1, "ARKBBDPRE", + "ARKBBDPrecSetup", MSG_BBD_SUNMAT_FAIL); + return(-1); + } + if (retval > 0) { + return(1); + } + + /* Otherwise call ARKBBDDQJac for new J value */ + } else { + + *jcurPtr = SUNTRUE; + retval = SUNMatZero(pdata->savedJ); + if (retval < 0) { + arkProcessError(ark_mem, -1, "ARKBBDPRE", + "ARKBBDPrecSetup", MSG_BBD_SUNMAT_FAIL); + return(-1); + } + if (retval > 0) { + return(1); + } + + retval = ARKBBDDQJac(pdata, t, y, pdata->tmp1, + pdata->tmp2, pdata->tmp3); + if (retval < 0) { + arkProcessError(ark_mem, -1, "ARKBBDPRE", "ARKBBDPrecSetup", + MSG_BBD_FUNC_FAILED); + return(-1); + } + if (retval > 0) { + return(1); + } + + retval = SUNMatCopy(pdata->savedJ, pdata->savedP); + if (retval < 0) { + arkProcessError(ark_mem, -1, "ARKBBDPRE", + "ARKBBDPrecSetup", MSG_BBD_SUNMAT_FAIL); + return(-1); + } + if (retval > 0) { + return(1); + } + + } + + /* Scale and add I to get P = I - gamma*J */ + retval = SUNMatScaleAddI(-gamma, pdata->savedP); + if (retval) { + 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); +} + + +/*--------------------------------------------------------------- + ARKBBDPrecSolve: + + ARKBBDPrecSolve solves a linear system P z = r, with the + band-block-diagonal preconditioner matrix P generated and + factored by ARKBBDPrecSetup. + + The parameters of ARKBBDPrecSolve 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 + ARKBBDPrecInit. + + z is the output vector computed by ARKBBDPrecSolve. + + 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, + realtype gamma, realtype delta, + int lr, void *bbd_data) +{ + int retval; + ARKBBDPrecData pdata; + + pdata = (ARKBBDPrecData) bbd_data; + + /* 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, + pdata->rlocal, ZERO); + + /* Detach local data arrays from rlocal and zlocal */ + N_VSetArrayPointer(NULL, pdata->rlocal); + N_VSetArrayPointer(NULL, pdata->zlocal); + + return(retval); +} + + +/*-------------------------------------------------------------*/ +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); + if (ark_step_lmem == NULL) return(0); + arkls_mem = (ARKLsMem) ark_step_lmem; + if (arkls_mem->P_data == NULL) return(0); + pdata = (ARKBBDPrecData) arkls_mem->P_data; + + SUNLinSolFree(pdata->LS); + N_VDestroy(pdata->tmp1); + N_VDestroy(pdata->tmp2); + N_VDestroy(pdata->tmp3); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + + free(pdata); + pdata = NULL; + + return(0); +} + + +/*--------------------------------------------------------------- + ARKBBDDQJac: + + 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 + 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, + N_Vector ytemp, N_Vector gtemp) +{ + ARKodeMem ark_mem; + realtype gnorm, minInc, inc, inc_inv; + sunindextype group, i, j, width, ngroups, i1, i2; + realtype *y_data, *ewt_data, *gy_data, *gtemp_data, *ytemp_data, *col_j; + int retval; + + ark_mem = (ARKodeMem) pdata->arkode_mem; + + /* Load ytemp with y = predicted solution vector */ + N_VScale(ONE, y, ytemp); + + /* Call cfn and gloc to get base value of g(t,y) */ + if (pdata->cfn != NULL) { + retval = pdata->cfn(pdata->n_local, t, y, ark_mem->user_data); + if (retval != 0) return(retval); + } + + retval = pdata->gloc(pdata->n_local, t, ytemp, gy, + ark_mem->user_data); + pdata->nge++; + if (retval != 0) return(retval); + + /* Obtain pointers to the data for various vectors */ + y_data = N_VGetArrayPointer(y); + gy_data = N_VGetArrayPointer(gy); + ewt_data = N_VGetArrayPointer(ark_mem->ewt); + ytemp_data = N_VGetArrayPointer(ytemp); + gtemp_data = N_VGetArrayPointer(gtemp); + + /* Set minimum increment based on uround and norm of g */ + gnorm = N_VWrmsNorm(gy, ark_mem->rwt); + minInc = (gnorm != ZERO) ? + (MIN_INC_MULT * SUNRabs(ark_mem->h) * + ark_mem->uround * pdata->n_local * gnorm) : ONE; + + /* Set bandwidth and number of column groups for band differencing */ + width = pdata->mldq + pdata->mudq + 1; + ngroups = SUNMIN(width, pdata->n_local); + + /* 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]); + ytemp_data[j] += inc; + } + + /* Evaluate g with incremented y */ + 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) { + 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]); + inc_inv = ONE/inc; + i1 = SUNMAX(0, j-pdata->mukeep); + i2 = SUNMIN(j+pdata->mlkeep, pdata->n_local-1); + for (i=i1; i <= i2; i++) + SM_COLUMN_ELEMENT_B(col_j,i,j) = + inc_inv * (gtemp_data[i] - gy_data[i]); + } + } + + return(0); +} + + + +/*--------------------------------------------------------------- + EOF +---------------------------------------------------------------*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_bbdpre_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_bbdpre_impl.h new file mode 100644 index 0000000..8d1c36a --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_bbdpre_impl.h @@ -0,0 +1,81 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * Implementation header file for the ARKBBDPRE module. + *--------------------------------------------------------------*/ + +#ifndef _ARKBBDPRE_IMPL_H +#define _ARKBBDPRE_IMPL_H + +#include <arkode/arkode_bbdpre.h> +#include <sunmatrix/sunmatrix_band.h> +#include <sunlinsol/sunlinsol_band.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*--------------------------------------------------------------- + Type: ARKBBDPrecData +---------------------------------------------------------------*/ +typedef struct ARKBBDPrecDataRec { + + /* passed by user to ARKBBDPrecAlloc and used by PrecSetup/PrecSolve */ + sunindextype mudq, mldq, mukeep, mlkeep; + realtype dqrely; + ARKLocalFn gloc; + ARKCommFn cfn; + + /* set by ARKBBDPrecSetup and used by ARKBBDPrecSolve */ + SUNMatrix savedJ; + SUNMatrix savedP; + SUNLinearSolver LS; + N_Vector tmp1; + N_Vector tmp2; + N_Vector tmp3; + N_Vector zlocal; + N_Vector rlocal; + + /* set by ARKBBDPrecAlloc and used by ARKBBDPrecSetup */ + sunindextype n_local; + + /* available for optional output */ + long int rpwsize; + long int ipwsize; + long int nge; + + /* pointer to arkode_mem */ + void *arkode_mem; + +} *ARKBBDPrecData; + + +/*--------------------------------------------------------------- + ARKBBDPRE error messages +---------------------------------------------------------------*/ + +#define MSG_BBD_MEM_NULL "Integrator memory is NULL." +#define MSG_BBD_LMEM_NULL "Linear solver memory is NULL. One of the SPILS linear solvers must be attached." +#define MSG_BBD_MEM_FAIL "A memory request failed." +#define MSG_BBD_BAD_NVECTOR "A required vector operation is not implemented." +#define MSG_BBD_SUNMAT_FAIL "An error arose from a SUNBandMatrix routine." +#define MSG_BBD_SUNLS_FAIL "An error arose from a SUNBandLinearSolver routine." +#define MSG_BBD_PMEM_NULL "BBD peconditioner memory is NULL. ARKBBDPrecInit must be called." +#define MSG_BBD_FUNC_FAILED "The gloc or cfn routine failed in an unrecoverable manner." + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_butcher.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_butcher.c new file mode 100644 index 0000000..ccb3856 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_butcher.c @@ -0,0 +1,2140 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 Butcher table structure + * for the ARKode infrastructure. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "arkode_impl.h" +#include <sundials/sundials_math.h> + +#if defined(SUNDIALS_EXTENDED_PRECISION) +#define RSYM ".32Lg" +#else +#define RSYM ".16g" +#endif + +/* tolerance for checking order conditions */ +#define TOL (SUNRsqrt(UNIT_ROUNDOFF)) + +/* Private utility functions for checking method order */ +static int __mv(realtype **A, realtype *x, int s, realtype *b); +static int __vv(realtype *x, realtype *y, int s, realtype *z); +static int __vp(realtype *x, int l, int s, realtype *z); +static int __dot(realtype *x, realtype *y, int s, realtype *d); +static booleantype __rowsum(realtype **A, realtype *c, int s); +static booleantype __order1(realtype *b, int s); +static booleantype __order2(realtype *b, realtype *c, int s); +static booleantype __order3a(realtype *b, realtype *c1, realtype *c2, int s); +static booleantype __order3b(realtype *b, realtype **A, realtype *c, int s); +static booleantype __order4a(realtype *b, realtype *c1, realtype *c2, realtype *c3, int s); +static booleantype __order4b(realtype *b, realtype *c1, realtype **A, realtype *c2, int s); +static booleantype __order4c(realtype *b, realtype **A, realtype *c1, realtype *c2, int s); +static booleantype __order4d(realtype *b, realtype **A1, realtype **A2, realtype *c, int s); +static booleantype __order5a(realtype *b, realtype *c1, realtype *c2, realtype *c3, realtype *c4, int s); +static booleantype __order5b(realtype *b, realtype *c1, realtype *c2, realtype **A, realtype *c3, int s); +static booleantype __order5c(realtype *b, realtype **A1, realtype *c1, realtype **A2, realtype *c2, int s); +static booleantype __order5d(realtype *b, realtype *c1, realtype **A, realtype *c2, realtype *c3, int s); +static booleantype __order5e(realtype *b, realtype **A, realtype *c1, realtype *c2, realtype *c3, int s); +static booleantype __order5f(realtype *b, realtype *c1, realtype **A1, realtype **A2, realtype *c2, int s); +static booleantype __order5g(realtype *b, realtype **A1, realtype *c1, realtype **A2, realtype *c2, int s); +static booleantype __order5h(realtype *b, realtype **A1, realtype **A2, realtype *c1, realtype *c2, int s); +static booleantype __order5i(realtype *b, realtype **A1, realtype **A2, realtype **A3, realtype *c, int s); +static booleantype __order6a(realtype *b, realtype *c1, realtype *c2, realtype *c3, realtype *c4, realtype *c5, int s); +static booleantype __order6b(realtype *b, realtype *c1, realtype *c2, realtype *c3, realtype **A, realtype *c4, int s); +static booleantype __order6c(realtype *b, realtype *c1, realtype **A1, realtype *c2, realtype **A2, realtype *c3, int s); +static booleantype __order6d(realtype *b, realtype *c1, realtype *c2, realtype **A, realtype *c3, realtype *c4, int s); +static booleantype __order6e(realtype *b, realtype *c1, realtype *c2, realtype **A1, realtype **A2, realtype *c3, int s); +static booleantype __order6f(realtype *b, realtype **A1, realtype **A2, realtype *c1, realtype **A3, realtype *c2, int s); +static booleantype __order6g(realtype *b, realtype *c1, realtype **A, realtype *c2, realtype *c3, realtype *c4, int s); +static booleantype __order6h(realtype *b, realtype *c1, realtype **A1, realtype *c2, realtype **A2, realtype *c3, int s); +static booleantype __order6i(realtype *b, realtype *c1, realtype **A1, realtype **A2, realtype *c2, realtype *c3, int s); +static booleantype __order6j(realtype *b, realtype *c1, realtype **A1, realtype **A2, realtype **A3, realtype *c2, int s); +static booleantype __order6k(realtype *b, realtype **A, realtype *c1, realtype *c2, realtype *c3, realtype *c4, int s); +static booleantype __order6l(realtype *b, realtype **A1, realtype *c1, realtype *c2, realtype **A2, realtype *c3, int s); +static booleantype __order6m(realtype *b, realtype **A1, realtype **A2, realtype *c1, realtype **A3, realtype *c2, int s); +static booleantype __order6n(realtype *b, realtype **A1, realtype *c1, realtype **A2, realtype *c2, realtype *c3, int s); +static booleantype __order6o(realtype *b, realtype **A1, realtype *c1, realtype **A2, realtype **A3, realtype *c2, int s); +static booleantype __order6p(realtype *b, realtype **A1, realtype **A2, realtype *c1, realtype *c2, realtype *c3, int s); +static booleantype __order6q(realtype *b, realtype **A1, realtype **A2, realtype *c1, realtype **A3, realtype *c2, int s); +static booleantype __order6r(realtype *b, realtype **A1, realtype **A2, realtype **A3, realtype *c1, realtype *c2, int s); +static booleantype __order6s(realtype *b, realtype **A1, realtype **A2, realtype **A3, realtype **A4, realtype *c, int s); +static int __ButcherSimplifyingAssumptions(realtype **A, realtype *b, realtype *c, int s); + + +/*--------------------------------------------------------------- + Routine to allocate an empty Butcher table structure + ---------------------------------------------------------------*/ +ARKodeButcherTable ARKodeButcherTable_Alloc(int stages, booleantype embedded) +{ + int i; + ARKodeButcherTable B; + + /* Check for legal 'stages' value */ + if (stages < 1) return(NULL); + + /* Allocate Butcher table structure */ + B = NULL; + B = (ARKodeButcherTable) malloc(sizeof(struct ARKodeButcherTableMem)); + if (B == NULL) return(NULL); + + /* initialize pointers in B structure to NULL */ + B->A = NULL; + B->b = NULL; + B->c = NULL; + B->d = NULL; + + /* set stages into B structure */ + B->stages = stages; + + /* + * Allocate fields within Butcher table structure + */ + + /* allocate rows of A */ + B->A = (realtype **) calloc( stages, sizeof(realtype*) ); + if (B->A == NULL) { ARKodeButcherTable_Free(B); return(NULL); } + + /* initialize each row of A to NULL */ + for (i=0; i<stages; i++) + B->A[i] = NULL; + + /* allocate columns of A */ + for (i=0; i<stages; i++) { + B->A[i] = (realtype *) calloc( stages, sizeof(realtype) ); + if (B->A[i] == NULL) { ARKodeButcherTable_Free(B); return(NULL); } + } + + B->b = (realtype *) calloc( stages, sizeof(realtype) ); + if (B->b == NULL) { ARKodeButcherTable_Free(B); return(NULL); } + + B->c = (realtype *) calloc( stages, sizeof(realtype) ); + if (B->c == NULL) { ARKodeButcherTable_Free(B); return(NULL); } + + if (embedded) { + B->d = (realtype *) calloc( stages, sizeof(realtype) ); + if (B->d == NULL) { ARKodeButcherTable_Free(B); return(NULL); } + } + + /* initialize order parameters */ + B->q = 0; + B->p = 0; + + return(B); +} + + +/*--------------------------------------------------------------- + Routine to allocate and fill a Butcher table structure + ---------------------------------------------------------------*/ +ARKodeButcherTable ARKodeButcherTable_Create(int s, int q, int p, realtype *c, + realtype *A, realtype *b, + realtype *d) +{ + int i, j; + ARKodeButcherTable B; + booleantype embedded; + + /* Check for legal number of stages */ + if (s < 1) return(NULL); + + /* Does the table have an embedding? */ + embedded = (d != NULL) ? SUNTRUE : SUNFALSE; + + /* Allocate Butcher table structure */ + B = ARKodeButcherTable_Alloc(s, embedded); + if (B == NULL) return(NULL); + + /* set the relevant parameters */ + B->stages = s; + B->q = q; + B->p = p; + + for (i=0; i<s; i++) { + B->c[i] = c[i]; + B->b[i] = b[i]; + for (j=0; j<s; j++) { + B->A[i][j] = A[i*s + j]; + } + } + + if (embedded) + for (i=0; i<s; i++) + B->d[i] = d[i]; + + return(B); +} + + +/*--------------------------------------------------------------- + Routine to copy a Butcher table structure + ---------------------------------------------------------------*/ +ARKodeButcherTable ARKodeButcherTable_Copy(ARKodeButcherTable B) +{ + int i, j, s; + ARKodeButcherTable Bcopy; + booleantype embedded; + + /* Check for legal input */ + if (B == NULL) return(NULL); + + /* Get the number of stages */ + s = B->stages; + + /* Does the table have an embedding? */ + embedded = (B->d != NULL) ? SUNTRUE : SUNFALSE; + + /* Allocate Butcher table structure */ + Bcopy = ARKodeButcherTable_Alloc(s, embedded); + if (Bcopy == NULL) return(NULL); + + /* set the relevant parameters */ + Bcopy->stages = B->stages; + Bcopy->q = B->q; + Bcopy->p = B->p; + + /* Copy Butcher table */ + for (i=0; i<s; i++) { + Bcopy->c[i] = B->c[i]; + Bcopy->b[i] = B->b[i]; + for (j=0; j<s; j++) { + Bcopy->A[i][j] = B->A[i][j]; + } + } + + if (embedded) + for (i=0; i<s; i++) + Bcopy->d[i] = B->d[i]; + + return(Bcopy); +} + + +/*--------------------------------------------------------------- + Routine to query the Butcher table structure workspace size + ---------------------------------------------------------------*/ +void ARKodeButcherTable_Space(ARKodeButcherTable B, sunindextype *liw, + sunindextype *lrw) +{ + /* initialize outputs and return if B is not allocated */ + *liw = 0; *lrw = 0; + if (B == NULL) return; + + /* fill outputs based on B */ + *liw = 3; + if (B->d != NULL) { + *lrw = B->stages * (B->stages + 3); + } else { + *lrw = B->stages * (B->stages + 2); + } +} + + +/*--------------------------------------------------------------- + Routine to free a Butcher table structure + ---------------------------------------------------------------*/ +void ARKodeButcherTable_Free(ARKodeButcherTable B) +{ + int i; + + /* Free each field within Butcher table structure, and then + free structure itself */ + if (B != NULL) { + if (B->d != NULL) free(B->d); + if (B->c != NULL) free(B->c); + if (B->b != NULL) free(B->b); + if (B->A != NULL) { + for (i=0; i<B->stages; i++) + if (B->A[i] != NULL) free(B->A[i]); + free(B->A); + } + + free(B); + } +} + + +/*--------------------------------------------------------------- + Routine to print a Butcher table structure + ---------------------------------------------------------------*/ +void ARKodeButcherTable_Write(ARKodeButcherTable B, FILE *outfile) +{ + int i, j; + + /* check for vaild table */ + if (B == NULL) return; + if (B->A == NULL) return; + for (i=0; i<B->stages; i++) + if (B->A[i] == NULL) return; + if (B->c == NULL) return; + if (B->b == NULL) return; + + fprintf(outfile, " A = \n"); + for (i=0; i<B->stages; i++) { + fprintf(outfile, " "); + for (j=0; j<B->stages; j++) + fprintf(outfile, "%"RSYM" ", B->A[i][j]); + fprintf(outfile, "\n"); + } + + fprintf(outfile, " c = "); + for (i=0; i<B->stages; i++) + fprintf(outfile, "%"RSYM" ", B->c[i]); + fprintf(outfile, "\n"); + + fprintf(outfile, " b = "); + for (i=0; i<B->stages; i++) + fprintf(outfile, "%"RSYM" ", B->b[i]); + fprintf(outfile, "\n"); + + if (B->d != NULL) { + fprintf(outfile, " d = "); + for (i=0; i<B->stages; i++) + fprintf(outfile, "%"RSYM" ", B->d[i]); + fprintf(outfile, "\n"); + } +} + + +/*--------------------------------------------------------------- + Routine to determine the analytical order of accuracy for a + specified Butcher table. We check the analytical [necessary] + order conditions up through order 6. After that, we revert to + the [sufficient] Butcher simplifying assumptions. + + Inputs: + B: Butcher table to check + outfile: file pointer to print results; if NULL then no + outputs are printed + + Outputs: + q: measured order of accuracy for method + p: measured order of accuracy for embedding [0 if not present] + + Return values: + 0 (success): internal {q,p} values match analytical order + 1 (warning): internal {q,p} values are lower than analytical + order, or method achieves maximum order possible with this + routine and internal {q,p} are higher. + -1 (failure): internal p and q values are higher than analytical + order + -2 (failure): NULL-valued B (or critical contents) + + Note: for embedded methods, if the return flags for p and q would + differ, failure takes precedence over warning, which takes + precedence over success. + ---------------------------------------------------------------*/ +int ARKodeButcherTable_CheckOrder(ARKodeButcherTable B, int *q, int *p, FILE *outfile) +{ + /* local variables */ + int q_SA, p_SA, i, s; + realtype **A, *b, *c, *d; + booleantype alltrue; + (*q) = (*p) = 0; + + /* verify non-NULL Butcher table structure and contents */ + if (B == NULL) return(-2); + if (B->stages < 1) return(-2); + if (B->A == NULL) return(-2); + for (i=0; i<B->stages; i++) + if (B->A[i] == NULL) return(-2); + if (B->c == NULL) return(-2); + if (B->b == NULL) return(-2); + + /* set shortcuts for Butcher table components */ + A = B->A; + b = B->b; + c = B->c; + d = B->d; + s = B->stages; + + /* check method order */ + if (outfile) fprintf(outfile,"ARKodeButcherTable_CheckOrder:\n"); + + /* row sum condition */ + if (__rowsum(A, c, s)) { + (*q) = 0; + } else { + (*q) = -1; + if (outfile) fprintf(outfile," method fails row sum condition\n"); + } + /* order 1 condition */ + if ((*q) == 0) { + if (__order1(b, s)) { + (*q) = 1; + } else { + if (outfile) fprintf(outfile," method fails order 1 condition\n"); + } + } + /* order 2 condition */ + if ((*q) == 1) { + if (__order2(b, c, s)) { + (*q) = 2; + } else { + if (outfile) fprintf(outfile," method fails order 2 condition\n"); + } + } + /* order 3 conditions */ + if ((*q) == 2) { + alltrue = SUNTRUE; + if (!__order3a(b, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 3 condition A\n"); + } + if (!__order3b(b, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 3 condition B\n"); + } + if (alltrue) (*q) = 3; + } + /* order 4 conditions */ + if ((*q) == 3) { + alltrue = SUNTRUE; + if (!__order4a(b, c, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 4 condition A\n"); + } + if (!__order4b(b, c, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 4 condition B\n"); + } + if (!__order4c(b, A, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 4 condition C\n"); + } + if (!__order4d(b, A, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 4 condition D\n"); + } + if (alltrue) (*q) = 4; + } + /* order 5 conditions */ + if ((*q) == 4) { + alltrue = SUNTRUE; + if (!__order5a(b, c, c, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 5 condition A\n"); + } + if (!__order5b(b, c, c, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 5 condition B\n"); + } + if (!__order5c(b, A, c, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 5 condition C\n"); + } + if (!__order5d(b, c, A, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 5 condition D\n"); + } + if (!__order5e(b, A, c, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 5 condition E\n"); + } + if (!__order5f(b, c, A, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 5 condition F\n"); + } + if (!__order5g(b, A, c, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 5 condition G\n"); + } + if (!__order5h(b, A, A, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 5 condition H\n"); + } + if (!__order5i(b, A, A, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 5 condition I\n"); + } + if (alltrue) (*q) = 5; + } + /* order 6 conditions */ + if ((*q) == 5) { + alltrue = SUNTRUE; + if (!__order6a(b, c, c, c, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 6 condition A\n"); + } + if (!__order6b(b, c, c, c, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 6 condition B\n"); + } + if (!__order6c(b, c, A, c, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 6 condition C\n"); + } + if (!__order6d(b, c, c, A, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 6 condition D\n"); + } + if (!__order6e(b, c, c, A, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 6 condition E\n"); + } + if (!__order6f(b, A, A, c, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 6 condition F\n"); + } + if (!__order6g(b, c, A, c, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 6 condition G\n"); + } + if (!__order6h(b, c, A, c, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 6 condition H\n"); + } + if (!__order6i(b, c, A, A, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 6 condition I\n"); + } + if (!__order6j(b, c, A, A, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 6 condition J\n"); + } + if (!__order6k(b, A, c, c, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 6 condition K\n"); + } + if (!__order6l(b, A, c, c, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 6 condition L\n"); + } + if (!__order6m(b, A, A, c, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 6 condition M\n"); + } + if (!__order6n(b, A, c, A, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 6 condition N\n"); + } + if (!__order6o(b, A, c, A, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 6 condition O\n"); + } + if (!__order6p(b, A, A, c, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 6 condition P\n"); + } + if (!__order6q(b, A, A, c, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 6 condition Q\n"); + } + if (!__order6r(b, A, A, A, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 6 condition R\n"); + } + if (!__order6s(b, A, A, A, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," method fails order 6 condition S\n"); + } + if (alltrue) (*q) = 6; + } + /* higher order conditions (via simplifying assumptions) */ + if ((*q) == 6) { + if (outfile) fprintf(outfile," method order >= 6; reverting to simplifying assumptions\n"); + q_SA = __ButcherSimplifyingAssumptions(A, b, c, s); + (*q) = SUNMAX((*q), q_SA); + if (outfile) fprintf(outfile," method order = %i\n", (*q)); + } + + /* check embedding order */ + if (d) { + if (outfile) fprintf(outfile,"\n"); + b = d; + + /* row sum condition */ + if (__rowsum(A, c, s)) { + (*p) = 0; + } else { + (*p) = -1; + if (outfile) fprintf(outfile," embedding fails row sum condition\n"); + } + /* order 1 condition */ + if ((*p) == 0) { + if (__order1(b, s)) { + (*p) = 1; + } else { + if (outfile) fprintf(outfile," embedding fails order 1 condition\n"); + } + } + /* order 2 condition */ + if ((*p) == 1) { + if (__order2(b, c, s)) { + (*p) = 2; + } else { + if (outfile) fprintf(outfile," embedding fails order 2 condition\n"); + } + } + /* order 3 conditions */ + if ((*p) == 2) { + alltrue = SUNTRUE; + if (!__order3a(b, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 3 condition A\n"); + } + if (!__order3b(b, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 3 condition B\n"); + } + if (alltrue) (*p) = 3; + } + /* order 4 conditions */ + if ((*p) == 3) { + alltrue = SUNTRUE; + if (!__order4a(b, c, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 4 condition A\n"); + } + if (!__order4b(b, c, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 4 condition B\n"); + } + if (!__order4c(b, A, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 4 condition C\n"); + } + if (!__order4d(b, A, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 4 condition D\n"); + } + if (alltrue) (*p) = 4; + } + /* order 5 conditions */ + if ((*p) == 4) { + alltrue = SUNTRUE; + if (!__order5a(b, c, c, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 5 condition A\n"); + } + if (!__order5b(b, c, c, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 5 condition B\n"); + } + if (!__order5c(b, A, c, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 5 condition C\n"); + } + if (!__order5d(b, c, A, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 5 condition D\n"); + } + if (!__order5e(b, A, c, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 5 condition E\n"); + } + if (!__order5f(b, c, A, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 5 condition F\n"); + } + if (!__order5g(b, A, c, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 5 condition G\n"); + } + if (!__order5h(b, A, A, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 5 condition H\n"); + } + if (!__order5i(b, A, A, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 5 condition I\n"); + } + if (alltrue) (*p) = 5; + } + /* order 6 conditions */ + if ((*p) == 5) { + alltrue = SUNTRUE; + if (!__order6a(b, c, c, c, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 6 condition A\n"); + } + if (!__order6b(b, c, c, c, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 6 condition B\n"); + } + if (!__order6c(b, c, A, c, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 6 condition C\n"); + } + if (!__order6d(b, c, c, A, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 6 condition D\n"); + } + if (!__order6e(b, c, c, A, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 6 condition E\n"); + } + if (!__order6f(b, A, A, c, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 6 condition F\n"); + } + if (!__order6g(b, c, A, c, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 6 condition G\n"); + } + if (!__order6h(b, c, A, c, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 6 condition H\n"); + } + if (!__order6i(b, c, A, A, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 6 condition I\n"); + } + if (!__order6j(b, c, A, A, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 6 condition J\n"); + } + if (!__order6k(b, A, c, c, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 6 condition K\n"); + } + if (!__order6l(b, A, c, c, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 6 condition L\n"); + } + if (!__order6m(b, A, A, c, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 6 condition M\n"); + } + if (!__order6n(b, A, c, A, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 6 condition N\n"); + } + if (!__order6o(b, A, c, A, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 6 condition O\n"); + } + if (!__order6p(b, A, A, c, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 6 condition P\n"); + } + if (!__order6q(b, A, A, c, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 6 condition Q\n"); + } + if (!__order6r(b, A, A, A, c, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 6 condition R\n"); + } + if (!__order6s(b, A, A, A, A, c, s)) { + alltrue = SUNFALSE; + if (outfile) fprintf(outfile," embedding fails order 6 condition S\n"); + } + if (alltrue) (*p) = 6; + } + /* higher order conditions (via simplifying assumptions) */ + if ((*p) == 6) { + if (outfile) fprintf(outfile," embedding order >= 6; reverting to simplifying assumptions\n"); + p_SA = __ButcherSimplifyingAssumptions(A, b, c, s); + (*p) = SUNMAX((*p), p_SA); + if (outfile) fprintf(outfile," embedding order = %i\n", (*p)); + } + } + + /* compare results against stored values and return */ + + /* check failure modes first */ + if (((*q) < B->q) && ((*q) < 6)) return(-1); + if (d) + if (((*p) < B->p) && ((*p) < 6)) return(-1); + + /* check warning modes */ + if ((*q) > B->q) return(1); + if (d) + if ((*p) > B->p) return(1); + if (((*q) < B->q) && ((*q) >= 6)) return(1); + if (d) + if (((*p) < B->p) && ((*p) >= 6)) return(1); + + /* return success */ + return(0); +} + + +/*--------------------------------------------------------------- + Routine to determine the analytical order of accuracy for a + specified pair of Butcher tables in an ARK pair. We check the + analytical order conditions up through order 6. + + Inputs: + B1, B2: Butcher tables to check + outfile: file pointer to print results; if NULL then no + outputs are printed + + Outputs: + q: measured order of accuracy for method + p: measured order of accuracy for embedding [0 if not present] + + Return values: + 0 (success): completed checks + 1 (warning): internal {q,p} values are lower than analytical + order, or method achieves maximum order possible with this + routine and internal {q,p} are higher. + -1 (failure): NULL-valued B1, B2 (or critical contents) + + Note: for embedded methods, if the return flags for p and q would + differ, warning takes precedence over success. + ---------------------------------------------------------------*/ +int ARKodeButcherTable_CheckARKOrder(ARKodeButcherTable B1, + ARKodeButcherTable B2, + int *q, int *p, FILE *outfile) +{ + /* local variables */ + int i, j, k, l, m, n, s; + booleantype alltrue; + realtype **A[2], *b[2], *c[2], *d[2]; + (*q) = (*p) = 0; + + /* verify non-NULL Butcher table structure and contents */ + if (B1 == NULL) return(-1); + if (B1->stages < 1) return(-1); + if (B1->A == NULL) return(-1); + for (i=0; i<B1->stages; i++) + if (B1->A[i] == NULL) return(-1); + if (B1->c == NULL) return(-1); + if (B1->b == NULL) return(-1); + if (B2 == NULL) return(-1); + if (B2->stages < 1) return(-1); + if (B2->A == NULL) return(-1); + for (i=0; i<B2->stages; i++) + if (B2->A[i] == NULL) return(-1); + if (B2->c == NULL) return(-1); + if (B2->b == NULL) return(-1); + if (B1->stages != B2->stages) return(-1); + + /* set shortcuts for Butcher table components */ + A[0] = B1->A; + b[0] = B1->b; + c[0] = B1->c; + d[0] = B1->d; + A[1] = B2->A; + b[1] = B2->b; + c[1] = B2->c; + d[1] = B1->d; + s = B1->stages; + + /* check method order */ + if (outfile) fprintf(outfile,"ARKodeButcherTable_CheckARKOrder:\n"); + + /* row sum conditions */ + if (__rowsum(A[0], c[0], s) && __rowsum(A[1], c[1], s)) { + (*q) = 0; + } else { + (*q) = -1; + if (outfile) fprintf(outfile," method fails row sum conditions\n"); + } + /* order 1 conditions */ + if ((*q) == 0) { + if (__order1(b[0], s) && __order1(b[1], s)) { + (*q) = 1; + } else { + if (outfile) fprintf(outfile," method fails order 1 conditions\n"); + } + } + /* order 2 conditions */ + if ((*q) == 1) { + alltrue = SUNTRUE; + for (i=0; i<2; i++) + for (j=0; j<2; j++) + alltrue = (alltrue && __order2(b[i], c[j], s)); + if (alltrue) { + (*q) = 2; + } else { + if (outfile) fprintf(outfile," method fails order 2 conditions\n"); + } + } + /* order 3 conditions */ + if ((*q) == 2) { + alltrue = SUNTRUE; + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + alltrue = (alltrue && __order3a(b[i], c[j], c[k], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 3 conditions A\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + alltrue = (alltrue && __order3b(b[i], A[j], c[k], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 3 conditions B\n"); + if (alltrue) (*q) = 3; + } + /* order 4 conditions */ + if ((*q) == 3) { + alltrue = SUNTRUE; + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + alltrue = (alltrue && __order4a(b[i], c[j], c[k], c[l], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 4 conditions A\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + alltrue = (alltrue && __order4b(b[i], c[j], A[k], c[l], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 4 conditions B\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + alltrue = (alltrue && __order4c(b[i], A[j], c[k], c[l], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 4 conditions C\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + alltrue = (alltrue && __order4d(b[i], A[j], A[k], c[l], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 4 conditions D\n"); + if (alltrue) (*q) = 4; + } + /* order 5 conditions */ + if ((*q) == 4) { + alltrue = SUNTRUE; + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + alltrue = (alltrue && __order5a(b[i], c[j], c[k], c[l], c[m], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 5 conditions A\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + alltrue = (alltrue && __order5b(b[i], c[j], c[k], A[l], c[m], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 5 conditions B\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + alltrue = (alltrue && __order5c(b[i], A[j], c[k], A[l], c[m], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 5 conditions C\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + alltrue = (alltrue && __order5d(b[i], c[j], A[k], c[l], c[m], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 5 conditions D\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + alltrue = (alltrue && __order5e(b[i], A[j], c[k], c[l], c[m], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 5 conditions E\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + alltrue = (alltrue && __order5f(b[i], c[j], A[k], A[l], c[m], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 5 conditions F\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + alltrue = (alltrue && __order5g(b[i], A[j], c[k], A[l], c[m], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 5 conditions G\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + alltrue = (alltrue && __order5h(b[i], A[j], A[k], c[l], c[m], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 5 conditions H\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + alltrue = (alltrue && __order5i(b[i], A[j], A[k], A[l], c[m], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 5 conditions I\n"); + if (alltrue) (*q) = 5; + } + /* order 6 conditions */ + if ((*q) == 5) { + alltrue = SUNTRUE; + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6a(b[i], c[j], c[k], c[l], c[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 6 conditions A\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6b(b[i], c[j], c[k], c[l], A[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 6 conditions B\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6c(b[i], c[j], A[k], c[l], A[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 6 conditions C\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6d(b[i], c[j], c[k], A[l], c[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 6 conditions D\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6e(b[i], c[j], c[k], A[l], A[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 6 conditions E\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6f(b[i], A[j], A[k], c[l], A[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 6 conditions F\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6g(b[i], c[j], A[k], c[l], c[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 6 conditions G\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6h(b[i], c[j], A[k], c[l], A[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 6 conditions H\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6i(b[i], c[j], A[k], A[l], c[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 6 conditions I\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6j(b[i], c[j], A[k], A[l], A[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 6 conditions J\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6k(b[i], A[j], c[k], c[l], c[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 6 conditions K\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6l(b[i], A[j], c[k], c[l], A[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 6 conditions L\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6m(b[i], A[j], A[k], c[l], A[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 6 conditions M\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6n(b[i], A[j], c[k], A[l], c[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 6 conditions N\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6o(b[i], A[j], c[k], A[l], A[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 6 conditions O\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6p(b[i], A[j], A[k], c[l], c[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 6 conditions P\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6q(b[i], A[j], A[k], c[l], A[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 6 conditions Q\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6r(b[i], A[j], A[k], A[l], c[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 6 conditions R\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6s(b[i], A[j], A[k], A[l], A[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," method fails order 6 conditions S\n"); + if (alltrue) (*q) = 6; + } + + /* check embedding order */ + if (d[0] && d[1]) { + if (outfile) fprintf(outfile,"\n"); + + /* row sum conditions */ + if (__rowsum(A[0], c[0], s) && __rowsum(A[1], c[1], s)) { + (*p) = 0; + } else { + (*p) = -1; + if (outfile) fprintf(outfile," embedding fails row sum conditions\n"); + } + /* order 1 conditions */ + if ((*p) == 0) { + if (__order1(d[0], s) && __order1(d[1], s)) { + (*p) = 1; + } else { + if (outfile) fprintf(outfile," embedding fails order 1 conditions\n"); + } + } + /* order 2 conditions */ + if ((*p) == 1) { + alltrue = SUNTRUE; + for (i=0; i<2; i++) + for (j=0; j<2; j++) + alltrue = (alltrue && __order2(d[i], c[j], s)); + if (alltrue) { + (*p) = 2; + } else { + if (outfile) fprintf(outfile," embedding fails order 2 conditions\n"); + } + } + /* order 3 conditions */ + if ((*p) == 2) { + alltrue = SUNTRUE; + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + alltrue = (alltrue && __order3a(d[i], c[j], c[k], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 3 conditions A\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + alltrue = (alltrue && __order3b(d[i], A[j], c[k], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 3 conditions B\n"); + if (alltrue) (*p) = 3; + } + /* order 4 conditions */ + if ((*p) == 3) { + alltrue = SUNTRUE; + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + alltrue = (alltrue && __order4a(d[i], c[j], c[k], c[l], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 4 conditions A\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + alltrue = (alltrue && __order4b(d[i], c[j], A[k], c[l], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 4 conditions B\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + alltrue = (alltrue && __order4c(d[i], A[j], c[k], c[l], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 4 conditions C\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + alltrue = (alltrue && __order4d(d[i], A[j], A[k], c[l], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 4 conditions D\n"); + if (alltrue) (*p) = 4; + } + /* order 5 conditions */ + if ((*p) == 4) { + alltrue = SUNTRUE; + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + alltrue = (alltrue && __order5a(d[i], c[j], c[k], c[l], c[m], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 5 conditions A\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + alltrue = (alltrue && __order5b(d[i], c[j], c[k], A[l], c[m], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 5 conditions B\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + alltrue = (alltrue && __order5c(d[i], A[j], c[k], A[l], c[m], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 5 conditions C\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + alltrue = (alltrue && __order5d(d[i], c[j], A[k], c[l], c[m], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 5 conditions D\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + alltrue = (alltrue && __order5e(d[i], A[j], c[k], c[l], c[m], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 5 conditions E\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + alltrue = (alltrue && __order5f(d[i], c[j], A[k], A[l], c[m], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 5 conditions F\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + alltrue = (alltrue && __order5g(d[i], A[j], c[k], A[l], c[m], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 5 conditions G\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + alltrue = (alltrue && __order5h(d[i], A[j], A[k], c[l], c[m], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 5 conditions H\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + alltrue = (alltrue && __order5i(d[i], A[j], A[k], A[l], c[m], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 5 conditions I\n"); + if (alltrue) (*p) = 5; + } + /* order 6 conditions */ + if ((*p) == 5) { + alltrue = SUNTRUE; + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6a(d[i], c[j], c[k], c[l], c[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 6 conditions A\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6b(d[i], c[j], c[k], c[l], A[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 6 conditions B\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6c(d[i], c[j], A[k], c[l], A[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 6 conditions C\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6d(d[i], c[j], c[k], A[l], c[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 6 conditions D\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6e(d[i], c[j], c[k], A[l], A[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 6 conditions E\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6f(d[i], A[j], A[k], c[l], A[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 6 conditions F\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6g(d[i], c[j], A[k], c[l], c[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 6 conditions G\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6h(d[i], c[j], A[k], c[l], A[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 6 conditions H\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6i(d[i], c[j], A[k], A[l], c[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 6 conditions I\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6j(d[i], c[j], A[k], A[l], A[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 6 conditions J\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6k(d[i], A[j], c[k], c[l], c[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 6 conditions K\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6l(d[i], A[j], c[k], c[l], A[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 6 conditions L\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6m(d[i], A[j], A[k], c[l], A[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 6 conditions M\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6n(d[i], A[j], c[k], A[l], c[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 6 conditions N\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6o(d[i], A[j], c[k], A[l], A[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 6 conditions O\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6p(d[i], A[j], A[k], c[l], c[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 6 conditions P\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6q(d[i], A[j], A[k], c[l], A[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 6 conditions Q\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6r(d[i], A[j], A[k], A[l], c[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 6 conditions R\n"); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + for (k=0; k<2; k++) + for (l=0; l<2; l++) + for (m=0; m<2; m++) + for (n=0; n<2; n++) + alltrue = (alltrue && __order6s(d[i], A[j], A[k], A[l], A[m], c[n], s)); + if ( (!alltrue) && outfile) fprintf(outfile," embedding fails order 6 conditions S\n"); + if (alltrue) (*p) = 6; + } + } + + /* compare results against stored values and return */ + + /* check warning modes */ + if ((*q) > B1->q) return(1); + if ((*q) > B2->q) return(1); + if (d[0] && d[1]) { + if ((*p) > B1->p) return(1); + if ((*p) > B2->p) return(1); + } + if (((*q) < B1->q) && ((*q) == 6)) return(1); + if (((*q) < B2->q) && ((*q) == 6)) return(1); + if (d[0] && d[1]) { + if (((*p) < B1->p) && ((*p) == 6)) return(1); + if (((*p) < B2->p) && ((*p) == 6)) return(1); + } + + /* return success */ + return(0); +} + + +/*--------------------------------------------------------------- + Private utility routines for checking method order + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + Utility routine to compute small dense matrix-vector product + b = A*x + Here A is (s x s), x and b are (s x 1). Returns 0 on success, + nonzero on failure. + ---------------------------------------------------------------*/ +static int __mv(realtype **A, realtype *x, int s, realtype *b) +{ + int i, j; + if ((A == NULL) || (x == NULL) || (b == NULL) || (s < 1)) + return(1); + for (i=0; i<s; i++) b[i] = RCONST(0.0); + for (i=0; i<s; i++) + for (j=0; j<s; j++) + b[i] += A[i][j]*x[j]; + return(0); +} + + +/*--------------------------------------------------------------- + Utility routine to compute small vector .* vector product + z = x.*y [Matlab notation] + Here all vectors are (s x 1). Returns 0 on success, + nonzero on failure. + ---------------------------------------------------------------*/ +static int __vv(realtype *x, realtype *y, int s, realtype *z) +{ + int i; + if ((x == NULL) || (y == NULL) || (z == NULL) || (s < 1)) + return(1); + for (i=0; i<s; i++) + z[i] = x[i]*y[i]; + return(0); +} + + +/*--------------------------------------------------------------- + Utility routine to compute small vector .^ int + z = x.^l [Matlab notation] + Here all vectors are (s x 1). Returns 0 on success, + nonzero on failure. + ---------------------------------------------------------------*/ +static int __vp(realtype *x, int l, int s, realtype *z) +{ + int i; + if ((x == NULL) || (z == NULL) || (s < 1) || (s < 0)) + return(1); + for (i=0; i<s; i++) + z[i] = SUNRpowerI(x[i],l); + return(0); +} + + +/*--------------------------------------------------------------- + Utility routine to compute small vector dot product: + d = dot(x,y) + Here x and y are (s x 1), and d is scalar. Returns 0 on success, + nonzero on failure. + ---------------------------------------------------------------*/ +static int __dot(realtype *x, realtype *y, int s, realtype *d) +{ + int i; + if ((x == NULL) || (y == NULL) || (d == NULL) || (s < 1)) + return(1); + (*d) = RCONST(0.0); + for (i=0; i<s; i++) + (*d) += x[i]*y[i]; + return(0); +} + + +/*--------------------------------------------------------------- + Utility routines to check specific order conditions. Each + returns SUNTRUE on success, SUNFALSE on failure. + Order 0: __rowsum + Order 1: __order1 + Order 2: __order2 + Order 3: __order3a and __order3b + Order 4: __order4a through __order4d + Order 5: __order5a through __order5i + Order 6: __order6a through __order6s + ---------------------------------------------------------------*/ + +/* c(i) = sum(A(i,:)) */ +static booleantype __rowsum(realtype **A, realtype *c, int s) +{ + int i, j; + realtype rsum; + for (i=0; i<s; i++) { + rsum = RCONST(0.0); + for (j=0; j<s; j++) + rsum += A[i][j]; + if (SUNRabs(rsum - c[i]) > TOL) + return(SUNFALSE); + } + return(SUNTRUE); +} + +/* b'*e = 1 */ +static booleantype __order1(realtype *b, int s) +{ + int i; + realtype err = RCONST(1.0); + for (i=0; i<s; i++) + err -= b[i]; + return (SUNRabs(err) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*c = 1/2 */ +static booleantype __order2(realtype *b, realtype *c, int s) +{ + realtype bc; + if (__dot(b,c,s,&bc)) return(SUNFALSE); + return (SUNRabs(bc - RCONST(0.5)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*(c1.*c2) = 1/3 */ +static booleantype __order3a(realtype *b, realtype *c1, realtype *c2, int s) +{ + realtype bcc; + realtype *tmp = calloc( s, sizeof(realtype) ); + if (__vv(c1,c2,s,tmp)) { free(tmp); return(SUNFALSE); } + if (__dot(b,tmp,s,&bcc)) return(SUNFALSE); + free(tmp); + return (SUNRabs(bcc - RCONST(1.0)/RCONST(3.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*(A*c) = 1/6 */ +static booleantype __order3b(realtype *b, realtype **A, realtype *c, int s) +{ + realtype bAc; + realtype *tmp = calloc( s, sizeof(realtype) ); + if (__mv(A,c,s,tmp)) { free(tmp); return(SUNFALSE); } + if (__dot(b,tmp,s,&bAc)) return(SUNFALSE); + free(tmp); + return (SUNRabs(bAc - RCONST(1.0)/RCONST(6.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*(c1.*c2.*c3) = 1/4 */ +static booleantype __order4a(realtype *b, realtype *c1, realtype *c2, realtype *c3, int s) +{ + realtype bccc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__vv(c1,c2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c3,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(b,tmp2,s,&bccc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bccc - RCONST(0.25)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* (b.*c1)'*(A*c2) = 1/8 */ +static booleantype __order4b(realtype *b, realtype *c1, realtype **A, realtype *c2, int s) +{ + realtype bcAc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__vv(b,c1,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A,c2,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(tmp1,tmp2,s,&bcAc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bcAc - RCONST(0.125)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*A*(c1.*c2) = 1/12 */ +static booleantype __order4c(realtype *b, realtype **A, realtype *c1, realtype *c2, int s) +{ + realtype bAcc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__vv(c1,c2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(b,tmp2,s,&bAcc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bAcc - RCONST(1.0)/RCONST(12.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*A1*A2*c = 1/24 */ +static booleantype __order4d(realtype *b, realtype **A1, realtype **A2, realtype *c, int s) +{ + realtype bAAc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__mv(A2,c,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A1,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(b,tmp2,s,&bAAc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bAAc - RCONST(1.0)/RCONST(24.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*(c1.*c2.*c3.*c4) = 1/5 */ +static booleantype __order5a(realtype *b, realtype *c1, realtype *c2, realtype *c3, realtype *c4, int s) +{ + realtype bcccc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__vv(c1,c2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c3,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c4,tmp2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(b,tmp1,s,&bcccc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bcccc - RCONST(0.2)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* (b.*c1.*c2)'*(A*c3) = 1/10 */ +static booleantype __order5b(realtype *b, realtype *c1, realtype *c2, realtype **A, realtype *c3, int s) +{ + realtype bccAc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__vv(c1,c2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(b,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A,c3,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(tmp1,tmp2,s,&bccAc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bccAc - RCONST(0.1)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*((A1*c1).*(A2*c2)) = 1/20 */ +static booleantype __order5c(realtype *b, realtype **A1, realtype *c1, realtype **A2, realtype *c2, int s) +{ + realtype bAcAc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + realtype *tmp3 = calloc( s, sizeof(realtype) ); + if (__mv(A1,c1,s,tmp1)) { free(tmp1); free(tmp2); free(tmp3); return(SUNFALSE); } + if (__mv(A2,c2,s,tmp2)) { free(tmp1); free(tmp2); free(tmp3); return(SUNFALSE); } + if (__vv(tmp1,tmp2,s,tmp3)) { free(tmp1); free(tmp2); free(tmp3); return(SUNFALSE); } + if (__dot(b,tmp3,s,&bAcAc)) return(SUNFALSE); + free(tmp1); free(tmp2); free(tmp3); + return (SUNRabs(bAcAc - RCONST(0.05)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* (b.*c1)'*A*(c2.*c3) = 1/15 */ +static booleantype __order5d(realtype *b, realtype *c1, realtype **A, realtype *c2, realtype *c3, int s) +{ + realtype bcAcc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__vv(c2,c3,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(b,c1,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(tmp1,tmp2,s,&bcAcc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bcAcc - RCONST(1.0)/RCONST(15.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*A*(c1.*c2.*c3) = 1/20 */ +static booleantype __order5e(realtype *b, realtype **A, realtype *c1, realtype *c2, realtype *c3, int s) +{ + realtype bAccc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__vv(c1,c2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c3,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A,tmp2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(b,tmp1,s,&bAccc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bAccc - RCONST(0.05)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* (b.*c1)'*A1*A2*c2 = 1/30 */ +static booleantype __order5f(realtype *b, realtype *c1, realtype **A1, realtype **A2, realtype *c2, int s) +{ + realtype bcAAc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__mv(A2,c2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A1,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(b,c1,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(tmp1,tmp2,s,&bcAAc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bcAAc - RCONST(1.0)/RCONST(30.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*A1*(c1.*(A2*c2)) = 1/40 */ +static booleantype __order5g(realtype *b, realtype **A1, realtype *c1, realtype **A2, realtype *c2, int s) +{ + realtype bAcAc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__mv(A2,c2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c1,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A1,tmp2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(b,tmp1,s,&bAcAc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bAcAc - RCONST(1.0)/RCONST(40.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*A1*A2*(c1.*c2) = 1/60 */ +static booleantype __order5h(realtype *b, realtype **A1, realtype **A2, realtype *c1, realtype *c2, int s) +{ + realtype bAAcc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__vv(c1,c2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A2,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A1,tmp2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(b,tmp1,s,&bAAcc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bAAcc - RCONST(1.0)/RCONST(60.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*A1*A2*A3*c = 1/120 */ +static booleantype __order5i(realtype *b, realtype **A1, realtype **A2, realtype **A3, realtype *c, int s) +{ + realtype bAAAc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__mv(A3,c,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A2,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A1,tmp2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(b,tmp1,s,&bAAAc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bAAAc - RCONST(1.0)/RCONST(120.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*(c1.*c2.*c3.*c4.*c5) = 1/6 */ +static booleantype __order6a(realtype *b, realtype *c1, realtype *c2, realtype *c3, realtype *c4, realtype *c5, int s) +{ + realtype bccccc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__vv(c1,c2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c3,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c4,tmp2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c5,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(b,tmp2,s,&bccccc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bccccc - RCONST(1.0)/RCONST(6.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* (b.*c1.*c2.*c3)'*(A*c4) = 1/12 */ +static booleantype __order6b(realtype *b, realtype *c1, realtype *c2, realtype *c3, realtype **A, realtype *c4, int s) +{ + realtype bcccAc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__vv(b,c1,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c2,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c3,tmp2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A,c4,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(tmp1,tmp2,s,&bcccAc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bcccAc - RCONST(1.0)/RCONST(12.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*(c1.*(A1*c2).*(A2*c3)) = 1/24 */ +static booleantype __order6c(realtype *b, realtype *c1, realtype **A1, realtype *c2, realtype **A2, realtype *c3, int s) +{ + realtype bcAc2; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + realtype *tmp3 = calloc( s, sizeof(realtype) ); + if (__mv(A2,c3,s,tmp1)) { free(tmp1); free(tmp2); free(tmp3); return(SUNFALSE); } + if (__mv(A1,c2,s,tmp2)) { free(tmp1); free(tmp2); free(tmp3); return(SUNFALSE); } + if (__vv(tmp1,tmp2,s,tmp3)) { free(tmp1); free(tmp2); free(tmp3); return(SUNFALSE); } + if (__vv(c1,tmp3,s,tmp1)) { free(tmp1); free(tmp2); free(tmp3); return(SUNFALSE); } + if (__dot(b,tmp1,s,&bcAc2)) return(SUNFALSE); + free(tmp1); free(tmp2); free(tmp3); + return (SUNRabs(bcAc2 - RCONST(1.0)/RCONST(24.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* (b.*c1.*c2)'*A*(c3.*c4) = 1/18 */ +static booleantype __order6d(realtype *b, realtype *c1, realtype *c2, realtype **A, realtype *c3, realtype *c4, int s) +{ + realtype bccAcc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + realtype *tmp3 = calloc( s, sizeof(realtype) ); + if (__vv(c3,c4,s,tmp1)) { free(tmp1); free(tmp2); free(tmp3); return(SUNFALSE); } + if (__mv(A,tmp1,s,tmp2)) { free(tmp1); free(tmp2); free(tmp3); return(SUNFALSE); } + if (__vv(c1,c2,s,tmp1)) { free(tmp1); free(tmp2); free(tmp3); return(SUNFALSE); } + if (__vv(b,tmp1,s,tmp3)) { free(tmp1); free(tmp2); free(tmp3); return(SUNFALSE); } + if (__dot(tmp2,tmp3,s,&bccAcc)) return(SUNFALSE); + free(tmp1); free(tmp2); free(tmp3); + return (SUNRabs(bccAcc - RCONST(1.0)/RCONST(18.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* (b.*(c1.*c2))'*A1*A2*c3 = 1/36 */ +static booleantype __order6e(realtype *b, realtype *c1, realtype *c2, realtype **A1, realtype **A2, realtype *c3, int s) +{ + realtype bccAAc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + realtype *tmp3 = calloc( s, sizeof(realtype) ); + if (__vv(c1,c2,s,tmp1)) { free(tmp1); free(tmp2); free(tmp3); return(SUNFALSE); } + if (__vv(b,tmp1,s,tmp2)) { free(tmp1); free(tmp2); free(tmp3); return(SUNFALSE); } + if (__mv(A2,c3,s,tmp1)) { free(tmp1); free(tmp2); free(tmp3); return(SUNFALSE); } + if (__mv(A1,tmp1,s,tmp3)) { free(tmp1); free(tmp2); free(tmp3); return(SUNFALSE); } + if (__dot(tmp2,tmp3,s,&bccAAc)) return(SUNFALSE); + free(tmp1); free(tmp2); free(tmp3); + return (SUNRabs(bccAAc - RCONST(1.0)/RCONST(36.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*((A1*A2*c1).*(A3*c2)) = 1/72 */ +static booleantype __order6f(realtype *b, realtype **A1, realtype **A2, realtype *c1, realtype **A3, realtype *c2, int s) +{ + realtype bAAcAc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + realtype *tmp3 = calloc( s, sizeof(realtype) ); + if (__mv(A2,c1,s,tmp1)) { free(tmp1); free(tmp2); free(tmp3); return(SUNFALSE); } + if (__mv(A1,tmp1,s,tmp2)) { free(tmp1); free(tmp2); free(tmp3); return(SUNFALSE); } + if (__mv(A3,c2,s,tmp1)) { free(tmp1); free(tmp2); free(tmp3); return(SUNFALSE); } + if (__vv(tmp1,tmp2,s,tmp3)) { free(tmp1); free(tmp2); free(tmp3); return(SUNFALSE); } + if (__dot(b,tmp3,s,&bAAcAc)) return(SUNFALSE); + free(tmp1); free(tmp2); free(tmp3); + return (SUNRabs(bAAcAc - RCONST(1.0)/RCONST(72.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*(c1.*(A*(c2.*c3.*c4))) = 1/24 */ +static booleantype __order6g(realtype *b, realtype *c1, realtype **A, realtype *c2, realtype *c3, realtype *c4, int s) +{ + realtype bcAccc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__vv(c2,c3,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c4,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A,tmp2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c1,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(b,tmp2,s,&bcAccc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bcAccc - RCONST(1.0)/RCONST(24.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*(c1.*(A1*(c2.*(A2*c3)))) = 1/48 */ +static booleantype __order6h(realtype *b, realtype *c1, realtype **A1, realtype *c2, realtype **A2, realtype *c3, int s) +{ + realtype bcAcAc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__mv(A2,c3,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c2,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A1,tmp2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c1,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(b,tmp2,s,&bcAcAc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bcAcAc - RCONST(1.0)/RCONST(48.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*(c1.*(A1*A2*(c2.*c3))) = 1/72 */ +static booleantype __order6i(realtype *b, realtype *c1, realtype **A1, realtype **A2, realtype *c2, realtype *c3, int s) +{ + realtype bcAAcc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__vv(c2,c3,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A2,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A1,tmp2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c1,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(b,tmp2,s,&bcAAcc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bcAAcc - RCONST(1.0)/RCONST(72.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*(c1.*(A1*A2*A3*c2)) = 1/144 */ +static booleantype __order6j(realtype *b, realtype *c1, realtype **A1, realtype **A2, realtype **A3, realtype *c2, int s) +{ + realtype bcAAAc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__mv(A3,c2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A2,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A1,tmp2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c1,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(b,tmp2,s,&bcAAAc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bcAAAc - RCONST(1.0)/RCONST(144.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*A*(c1.*c2.*c3.*c4) = 1/30 */ +static booleantype __order6k(realtype *b, realtype **A, realtype *c1, realtype *c2, realtype *c3, realtype *c4, int s) +{ + realtype bAcccc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__vv(c1,c2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c3,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c4,tmp2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(b,tmp2,s,&bAcccc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bAcccc - RCONST(1.0)/RCONST(30.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*A1*(c1.*c2.*(A2*c3)) = 1/60 */ +static booleantype __order6l(realtype *b, realtype **A1, realtype *c1, realtype *c2, realtype **A2, realtype *c3, int s) +{ + realtype bAccAc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__mv(A2,c3,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c2,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c1,tmp2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A1,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(b,tmp2,s,&bAccAc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bAccAc - RCONST(1.0)/RCONST(60.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*A1*((A2*c1).*(A3*c2)) = 1/120 */ +static booleantype __order6m(realtype *b, realtype **A1, realtype **A2, realtype *c1, realtype **A3, realtype *c2, int s) +{ + realtype bAAcAc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + realtype *tmp3 = calloc( s, sizeof(realtype) ); + if (__mv(A3,c2,s,tmp1)) { free(tmp1); free(tmp2); free(tmp3); return(SUNFALSE); } + if (__mv(A2,c1,s,tmp2)) { free(tmp1); free(tmp2); free(tmp3); return(SUNFALSE); } + if (__vv(tmp1,tmp2,s,tmp3)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A1,tmp3,s,tmp1)) { free(tmp1); free(tmp2); free(tmp3); return(SUNFALSE); } + if (__dot(b,tmp1,s,&bAAcAc)) return(SUNFALSE); + free(tmp1); free(tmp2); free(tmp3); + return (SUNRabs(bAAcAc - RCONST(1.0)/RCONST(120.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*A1*(c1.*(A2*(c2.*c3))) = 1/90 */ +static booleantype __order6n(realtype *b, realtype **A1, realtype *c1, realtype **A2, realtype *c2, realtype *c3, int s) +{ + realtype bAcAcc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__vv(c2,c3,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A2,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c1,tmp2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A1,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(b,tmp2,s,&bAcAcc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bAcAcc - RCONST(1.0)/RCONST(90.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*A1*(c1.*(A2*A3*c2)) = 1/180 */ +static booleantype __order6o(realtype *b, realtype **A1, realtype *c1, realtype **A2, realtype **A3, realtype *c2, int s) +{ + realtype bAcAAc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__mv(A3,c2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A2,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c1,tmp2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A1,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(b,tmp2,s,&bAcAAc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bAcAAc - RCONST(1.0)/RCONST(180.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*A1*A2*(c1.*c2.*c3) = 1/120 */ +static booleantype __order6p(realtype *b, realtype **A1, realtype **A2, realtype *c1, realtype *c2, realtype *c3, int s) +{ + realtype bAAccc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__vv(c1,c2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c3,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A2,tmp2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A1,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(b,tmp2,s,&bAAccc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bAAccc - RCONST(1.0)/RCONST(120.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*A1*A2*(c1.*(A3*c2)) = 1/240 */ +static booleantype __order6q(realtype *b, realtype **A1, realtype **A2, realtype *c1, realtype **A3, realtype *c2, int s) +{ + realtype bAAcAc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__mv(A3,c2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__vv(c1,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A2,tmp2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A1,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(b,tmp2,s,&bAAcAc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bAAcAc - RCONST(1.0)/RCONST(240.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*A1*A2*A3*(c1.*c2) = 1/360 */ +static booleantype __order6r(realtype *b, realtype **A1, realtype **A2, realtype **A3, realtype *c1, realtype *c2, int s) +{ + realtype bAAAcc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__vv(c1,c2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A3,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A2,tmp2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A1,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(b,tmp2,s,&bAAAcc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bAAAcc - RCONST(1.0)/RCONST(360.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + +/* b'*A1*A2*A3*A4*c = 1/720 */ +static booleantype __order6s(realtype *b, realtype **A1, realtype **A2, realtype **A3, realtype **A4, realtype *c, int s) +{ + realtype bAAAAc; + realtype *tmp1 = calloc( s, sizeof(realtype) ); + realtype *tmp2 = calloc( s, sizeof(realtype) ); + if (__mv(A4,c,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A2,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A2,tmp2,s,tmp1)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__mv(A1,tmp1,s,tmp2)) { free(tmp1); free(tmp2); return(SUNFALSE); } + if (__dot(b,tmp2,s,&bAAAAc)) return(SUNFALSE); + free(tmp1); free(tmp2); + return (SUNRabs(bAAAAc - RCONST(1.0)/RCONST(720.0)) > TOL) ? SUNFALSE : SUNTRUE; +} + + +/*--------------------------------------------------------------- + Utility routine to check Butcher's simplifying assumptions. + Returns the maximum predicted order. + ---------------------------------------------------------------*/ +static int __ButcherSimplifyingAssumptions(realtype **A, realtype *b, realtype *c, int s) +{ + int P, Q, R, i, j, k, q; + realtype RHS, LHS; + booleantype alltrue; + realtype *tmp = calloc( s, sizeof(realtype) ); + + /* B(P) */ + P = 0; + for (i=1; i<1000; i++) { + if (__vp(c,i-1,s,tmp)) { free(tmp); return(0); } + if (__dot(b,tmp,s,&LHS)) { free(tmp); return(0); } + RHS = RCONST(1.0)/i; + if (SUNRabs(RHS-LHS) > TOL) + break; + P++; + } + + /* C(Q) */ + Q = 0; + for (k=1; k<1000; k++) { + alltrue = SUNTRUE; + for (i=0; i<s; i++) { + if (__vp(c,k-1,s,tmp)) { free(tmp); return(0); } + if (__dot(A[i],tmp,s,&LHS)) { free(tmp); return(0); } + RHS = SUNRpowerI(c[i],k) / k; + if (SUNRabs(RHS-LHS) > TOL) { + alltrue = SUNFALSE; + break; + } + } + if (alltrue) { + Q++; + } else { + break; + } + } + + /* D(R) */ + R = 0; + for (k=1; k<1000; k++) { + alltrue = SUNTRUE; + for (j=0; j<s; j++) { + LHS = RCONST(0.0); + for (i=0; i<s; i++) + LHS += A[i][j]*b[i]*SUNRpowerI(c[i],k-1); + RHS = b[j]/k*(RCONST(1.0)-SUNRpowerI(c[j],k)); + if (SUNRabs(RHS-LHS) > TOL) { + alltrue = SUNFALSE; + break; + } + } + if (alltrue) { + R++; + } else { + break; + } + } + + /* determine q, clean up and return */ + q = 0; + for (i=1; i<=P; i++) { + if ((q > Q+R+1) || (q > 2*Q+2)) + break; + q++; + } + free(tmp); + return(q); +} + +/*--------------------------------------------------------------- + EOF + ---------------------------------------------------------------*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_butcher_dirk.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_butcher_dirk.c new file mode 100644 index 0000000..7bd1021 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_butcher_dirk.c @@ -0,0 +1,509 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 built-in DIRK Butcher + * tables. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "arkode_impl.h" +#include <arkode/arkode_butcher_dirk.h> +#include <sundials/sundials_math.h> + +#if defined(SUNDIALS_EXTENDED_PRECISION) +#define RSYM ".32Lg" +#else +#define RSYM ".16g" +#endif + + +/*--------------------------------------------------------------- + Returns Butcher table structure for pre-set DIRK methods. + + Input: imeth -- integer key for the desired method (see below) + + Allowed 'method' names and properties (those in an ARK pair are + marked with a *). All method names are of the form + <name>_s_p_q. The method 'type' is one of + SDIRK -- singly-diagonally implicit Runge Kutta + ESDIRK -- explicit [1st stage] singly-diagonally implicit Runge Kutta + The 'A-stable' and 'L-stable' columns are based on numerical estimates + of each property. The 'QP' column denotes whether the coefficients + of the method are known precisely enough for use in 'long double' + (128-bit) calculations. + + imeth type A-stable L-stable QP + ---------------------------------------------------------- + SDIRK_2_1_2 SDIRK Y N Y + BILLINGTON_3_3_2 SDIRK N N N + TRBDF2_3_3_2 ESDIRK N N Y + KVAERNO_4_2_3 ESDIRK Y Y N + ARK324L2SA_DIRK_4_2_3* ESDIRK Y Y N + CASH_5_2_4 SDIRK Y Y N + CASH_5_3_4 SDIRK Y Y N + 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 + KVAERNO_7_4_5 ESDIRK Y Y N + ARK548L2SA_DIRK_8_4_5* ESDIRK Y Y N + ---------------------------------------------------------- + + ---------------------------------------------------------------*/ +ARKodeButcherTable ARKodeButcherTable_LoadDIRK(int imethod) +{ + + ARKodeButcherTable B; + B = NULL; + + /* fill in coefficients based on method name */ + switch(imethod) { + + case(SDIRK_2_1_2): /* SDIRK-2-1 (A,B stable) */ + B = ARKodeButcherTable_Alloc(2, SUNTRUE); + B->q = 2; + B->p = 1; + + B->A[0][0] = RCONST(1.0); + B->A[1][0] = RCONST(-1.0); + B->A[1][1] = RCONST(1.0); + + B->b[0] = RCONST(0.5); + B->b[1] = RCONST(0.5); + + B->d[0] = RCONST(1.0); + + B->c[0] = RCONST(1.0); + B->c[1] = RCONST(0.0); + break; + + case(BILLINGTON_3_3_2): /* Billington-SDIRK */ + B = ARKodeButcherTable_Alloc(3, SUNTRUE); + B->q = 2; + B->p = 3; + + B->A[0][0] = RCONST(0.292893218813); + B->A[1][0] = RCONST(0.798989873223); + B->A[1][1] = RCONST(0.292893218813); + B->A[2][0] = RCONST(0.740789228841); + B->A[2][1] = RCONST(0.259210771159); + B->A[2][2] = RCONST(0.292893218813); + + B->d[0] = RCONST(0.691665115992); + B->d[1] = RCONST(0.503597029883); + B->d[2] = RCONST(-0.195262145876); + + B->b[0] = RCONST(0.740789228840); + B->b[1] = RCONST(0.259210771159); + + B->c[0] = RCONST(0.292893218813); + B->c[1] = RCONST(1.091883092037); + B->c[2] = RCONST(1.292893218813); + break; + + case(TRBDF2_3_3_2): /* TRBDF2-ESDIRK */ + B = ARKodeButcherTable_Alloc(3, SUNTRUE); + B->q = 2; + B->p = 3; + + B->A[1][0] = (RCONST(2.0)-SUNRsqrt(RCONST(2.0)))/RCONST(2.0); + B->A[1][1] = (RCONST(2.0)-SUNRsqrt(RCONST(2.0)))/RCONST(2.0); + B->A[2][0] = SUNRsqrt(RCONST(2.0))/RCONST(4.0); + B->A[2][1] = SUNRsqrt(RCONST(2.0))/RCONST(4.0); + B->A[2][2] = (RCONST(2.0)-SUNRsqrt(RCONST(2.0)))/RCONST(2.0); + + B->d[0] = (RCONST(1.0)-SUNRsqrt(RCONST(2.0))/RCONST(4.0))/RCONST(3.0); + B->d[1] = (RCONST(3.0)*SUNRsqrt(RCONST(2.0))/RCONST(4.0)+RCONST(1.0))/RCONST(3.0); + B->d[2] = (RCONST(2.0)-SUNRsqrt(RCONST(2.0)))/RCONST(6.0); + + B->b[0] = SUNRsqrt(RCONST(2.0))/RCONST(4.0); + B->b[1] = SUNRsqrt(RCONST(2.0))/RCONST(4.0); + B->b[2] = (RCONST(2.0)-SUNRsqrt(RCONST(2.0)))/RCONST(2.0); + + B->c[1] = RCONST(2.0)-SUNRsqrt(RCONST(2.0)); + B->c[2] = RCONST(1.0); + break; + + case(KVAERNO_4_2_3): /* Kvaerno(4,2,3)-ESDIRK */ + B = ARKodeButcherTable_Alloc(4, SUNTRUE); + B->q = 3; + B->p = 2; + B->A[1][0] = RCONST(0.4358665215); + B->A[1][1] = RCONST(0.4358665215); + B->A[2][0] = RCONST(0.490563388419108); + B->A[2][1] = RCONST(0.073570090080892); + B->A[2][2] = RCONST(0.4358665215); + B->A[3][0] = RCONST(0.308809969973036); + B->A[3][1] = RCONST(1.490563388254106); + B->A[3][2] = RCONST(-1.235239879727145); + B->A[3][3] = RCONST(0.4358665215); + + B->b[0] = RCONST(0.308809969973036); + B->b[1] = RCONST(1.490563388254106); + B->b[2] = RCONST(-1.235239879727145); + B->b[3] = RCONST(0.4358665215); + + B->d[0] = RCONST(0.490563388419108); + B->d[1] = RCONST(0.073570090080892); + B->d[2] = RCONST(0.4358665215); + + B->c[1] = RCONST(0.871733043); + B->c[2] = RCONST(1.0); + B->c[3] = RCONST(1.0); + break; + + case(ARK324L2SA_DIRK_4_2_3): /* ARK3(2)4L[2]SA-ESDIRK */ + B = ARKodeButcherTable_Alloc(4, SUNTRUE); + B->q = 3; + B->p = 2; + B->A[1][0] = RCONST(1767732205903.0)/RCONST(4055673282236.0); + B->A[1][1] = RCONST(1767732205903.0)/RCONST(4055673282236.0); + B->A[2][0] = RCONST(2746238789719.0)/RCONST(10658868560708.0); + B->A[2][1] = RCONST(-640167445237.0)/RCONST(6845629431997.0); + B->A[2][2] = RCONST(1767732205903.0)/RCONST(4055673282236.0); + B->A[3][0] = RCONST(1471266399579.0)/RCONST(7840856788654.0); + B->A[3][1] = RCONST(-4482444167858.0)/RCONST(7529755066697.0); + B->A[3][2] = RCONST(11266239266428.0)/RCONST(11593286722821.0); + B->A[3][3] = RCONST(1767732205903.0)/RCONST(4055673282236.0); + + B->b[0] = RCONST(1471266399579.0)/RCONST(7840856788654.0); + B->b[1] = RCONST(-4482444167858.0)/RCONST(7529755066697.0); + B->b[2] = RCONST(11266239266428.0)/RCONST(11593286722821.0); + B->b[3] = RCONST(1767732205903.0)/RCONST(4055673282236.0); + + B->d[0] = RCONST(2756255671327.0)/RCONST(12835298489170.0); + B->d[1] = RCONST(-10771552573575.0)/RCONST(22201958757719.0); + B->d[2] = RCONST(9247589265047.0)/RCONST(10645013368117.0); + B->d[3] = RCONST(2193209047091.0)/RCONST(5459859503100.0); + + B->c[1] = RCONST(1767732205903.0)/RCONST(2027836641118.0); + B->c[2] = RCONST(3.0)/RCONST(5.0); + B->c[3] = RCONST(1.0); + break; + + case(CASH_5_2_4): /* Cash(5,2,4)-SDIRK */ + B = ARKodeButcherTable_Alloc(5, SUNTRUE); + B->q = 4; + B->p = 2; + B->A[0][0] = RCONST(0.435866521508); + B->A[1][0] = RCONST(-1.13586652150); + B->A[1][1] = RCONST(0.435866521508); + B->A[2][0] = RCONST(1.08543330679); + B->A[2][1] = RCONST(-0.721299828287); + B->A[2][2] = RCONST(0.435866521508); + B->A[3][0] = RCONST(0.416349501547); + B->A[3][1] = RCONST(0.190984004184); + B->A[3][2] = RCONST(-0.118643265417); + B->A[3][3] = RCONST(0.435866521508); + B->A[4][0] = RCONST(0.896869652944); + B->A[4][1] = RCONST(0.0182725272734); + B->A[4][2] = RCONST(-0.0845900310706); + B->A[4][3] = RCONST(-0.266418670647); + B->A[4][4] = RCONST(0.435866521508); + + B->b[0] = RCONST(0.896869652944); + B->b[1] = RCONST(0.0182725272734); + B->b[2] = RCONST(-0.0845900310706); + B->b[3] = RCONST(-0.266418670647); + B->b[4] = RCONST(0.435866521508); + + B->d[0] = (RCONST(-0.7)-RCONST(0.5))/(RCONST(-0.7)-RCONST(0.435866521508)); + B->d[1] = (RCONST(0.5)-RCONST(0.435866521508))/(RCONST(-0.7)-RCONST(0.435866521508)); + + B->c[0] = RCONST(0.435866521508); + B->c[1] = RCONST(-0.7); + B->c[2] = RCONST(0.8); + B->c[3] = RCONST(0.924556761814); + B->c[4] = RCONST(1.0); + break; + + case(CASH_5_3_4): /* Cash(5,3,4)-SDIRK */ + B = ARKodeButcherTable_Alloc(5, SUNTRUE); + B->q = 4; + B->p = 3; + B->A[0][0] = RCONST(0.435866521508); + B->A[1][0] = RCONST(-1.13586652150); + B->A[1][1] = RCONST(0.435866521508); + B->A[2][0] = RCONST(1.08543330679); + B->A[2][1] = RCONST(-0.721299828287); + B->A[2][2] = RCONST(0.435866521508); + B->A[3][0] = RCONST(0.416349501547); + B->A[3][1] = RCONST(0.190984004184); + B->A[3][2] = RCONST(-0.118643265417); + B->A[3][3] = RCONST(0.435866521508); + B->A[4][0] = RCONST(0.896869652944); + B->A[4][1] = RCONST(0.0182725272734); + B->A[4][2] = RCONST(-0.0845900310706); + B->A[4][3] = RCONST(-0.266418670647); + B->A[4][4] = RCONST(0.435866521508); + + B->b[0] = RCONST(0.896869652944); + B->b[1] = RCONST(0.0182725272734); + B->b[2] = RCONST(-0.0845900310706); + B->b[3] = RCONST(-0.266418670647); + B->b[4] = RCONST(0.435866521508); + + B->d[0] = RCONST(0.776691932910); + B->d[1] = RCONST(0.0297472791484); + B->d[2] = RCONST(-0.0267440239074); + B->d[3] = RCONST(0.220304811849); + + B->c[0] = RCONST(0.435866521508); + B->c[1] = RCONST(-0.7); + B->c[2] = RCONST(0.8); + B->c[3] = RCONST(0.924556761814); + B->c[4] = RCONST(1.0); + break; + + case(SDIRK_5_3_4): /* SDIRK-5-4 */ + B = ARKodeButcherTable_Alloc(5, SUNTRUE); + B->q = 4; + B->p = 3; + B->A[0][0] = RCONST(0.25); + B->A[1][0] = RCONST(0.5); + B->A[1][1] = RCONST(0.25); + B->A[2][0] = RCONST(17.0)/RCONST(50.0); + B->A[2][1] = RCONST(-1.0)/RCONST(25.0); + B->A[2][2] = RCONST(0.25); + B->A[3][0] = RCONST(371.0)/RCONST(1360.0); + B->A[3][1] = RCONST(-137.0)/RCONST(2720.0); + B->A[3][2] = RCONST(15.0)/RCONST(544.0); + B->A[3][3] = RCONST(0.25); + B->A[4][0] = RCONST(25.0)/RCONST(24.0); + B->A[4][1] = RCONST(-49.0)/RCONST(48.0); + B->A[4][2] = RCONST(125.0)/RCONST(16.0); + B->A[4][3] = RCONST(-85.0)/RCONST(12.0); + B->A[4][4] = RCONST(0.25); + + B->b[0] = RCONST(25.0)/RCONST(24.0); + B->b[1] = RCONST(-49.0)/RCONST(48.0); + B->b[2] = RCONST(125.0)/RCONST(16.0); + B->b[3] = RCONST(-85.0)/RCONST(12.0); + B->b[4] = RCONST(0.25); + + B->d[0] = RCONST(59.0)/RCONST(48.0); + B->d[1] = RCONST(-17.0)/RCONST(96.0); + B->d[2] = RCONST(225.0)/RCONST(32.0); + B->d[3] = RCONST(-85.0)/RCONST(12.0); + + B->c[0] = RCONST(0.25); + B->c[1] = RCONST(0.75); + B->c[2] = RCONST(11.0)/RCONST(20.0); + B->c[3] = RCONST(0.5); + B->c[4] = RCONST(1.0); + break; + + case(KVAERNO_5_3_4): /* Kvaerno(5,3,4)-ESDIRK */ + B = ARKodeButcherTable_Alloc(5, SUNTRUE); + B->q = 4; + B->p = 3; + B->A[1][0] = RCONST(0.4358665215); + B->A[1][1] = RCONST(0.4358665215); + B->A[2][0] = RCONST(0.140737774731968); + B->A[2][1] = RCONST(-0.108365551378832); + B->A[2][2] = RCONST(0.4358665215); + B->A[3][0] = RCONST(0.102399400616089); + B->A[3][1] = RCONST(-0.376878452267324); + B->A[3][2] = RCONST(0.838612530151233); + B->A[3][3] = RCONST(0.4358665215); + B->A[4][0] = RCONST(0.157024897860995); + B->A[4][1] = RCONST(0.117330441357768); + B->A[4][2] = RCONST(0.61667803039168); + B->A[4][3] = RCONST(-0.326899891110444); + B->A[4][4] = RCONST(0.4358665215); + + B->b[0] = RCONST(0.157024897860995); + B->b[1] = RCONST(0.117330441357768); + B->b[2] = RCONST(0.61667803039168); + B->b[3] = RCONST(-0.326899891110444); + B->b[4] = RCONST(0.4358665215); + + B->d[0] = RCONST(0.102399400616089); + B->d[1] = RCONST(-0.376878452267324); + B->d[2] = RCONST(0.838612530151233); + B->d[3] = RCONST(0.4358665215); + + B->c[1] = RCONST(0.871733043); + B->c[2] = RCONST(0.468238744853136); + B->c[3] = RCONST(1.0); + B->c[4] = RCONST(1.0); + break; + + case(ARK436L2SA_DIRK_6_3_4): /* ARK4(3)6L[2]SA-ESDIRK */ + B = ARKodeButcherTable_Alloc(6, SUNTRUE); + B->q = 4; + B->p = 3; + B->A[1][0] = RCONST(1.0)/RCONST(4.0); + B->A[1][1] = RCONST(1.0)/RCONST(4.0); + B->A[2][0] = RCONST(8611.0)/RCONST(62500.0); + B->A[2][1] = RCONST(-1743.0)/RCONST(31250.0); + B->A[2][2] = RCONST(1.0)/RCONST(4.0); + B->A[3][0] = RCONST(5012029.0)/RCONST(34652500.0); + B->A[3][1] = RCONST(-654441.0)/RCONST(2922500.0); + B->A[3][2] = RCONST(174375.0)/RCONST(388108.0); + B->A[3][3] = RCONST(1.0)/RCONST(4.0); + B->A[4][0] = RCONST(15267082809.0)/RCONST(155376265600.0); + B->A[4][1] = RCONST(-71443401.0)/RCONST(120774400.0); + B->A[4][2] = RCONST(730878875.0)/RCONST(902184768.0); + B->A[4][3] = RCONST(2285395.0)/RCONST(8070912.0); + B->A[4][4] = RCONST(1.0)/RCONST(4.0); + B->A[5][0] = RCONST(82889.0)/RCONST(524892.0); + B->A[5][2] = RCONST(15625.0)/RCONST(83664.0); + B->A[5][3] = RCONST(69875.0)/RCONST(102672.0); + B->A[5][4] = RCONST(-2260.0)/RCONST(8211.0); + B->A[5][5] = RCONST(1.0)/RCONST(4.0); + + B->b[0] = RCONST(82889.0)/RCONST(524892.0); + B->b[2] = RCONST(15625.0)/RCONST(83664.0); + B->b[3] = RCONST(69875.0)/RCONST(102672.0); + B->b[4] = RCONST(-2260.0)/RCONST(8211.0); + B->b[5] = RCONST(1.0)/RCONST(4.0); + + B->c[1] = RCONST(1.0)/RCONST(2.0); + B->c[2] = RCONST(83.0)/RCONST(250.0); + B->c[3] = RCONST(31.0)/RCONST(50.0); + B->c[4] = RCONST(17.0)/RCONST(20.0); + B->c[5] = RCONST(1.0); + + B->d[0] = RCONST(4586570599.0)/RCONST(29645900160.0); + B->d[2] = RCONST(178811875.0)/RCONST(945068544.0); + B->d[3] = RCONST(814220225.0)/RCONST(1159782912.0); + B->d[4] = RCONST(-3700637.0)/RCONST(11593932.0); + B->d[5] = RCONST(61727.0)/RCONST(225920.0); + break; + + case(KVAERNO_7_4_5): /* Kvaerno(7,4,5)-ESDIRK */ + B = ARKodeButcherTable_Alloc(7, SUNTRUE); + B->q = 5; + B->p = 4; + B->A[1][0] = RCONST(0.26); + B->A[1][1] = RCONST(0.26); + B->A[2][0] = RCONST(0.13); + B->A[2][1] = RCONST(0.84033320996790809); + B->A[2][2] = RCONST(0.26); + B->A[3][0] = RCONST(0.22371961478320505); + B->A[3][1] = RCONST(0.47675532319799699); + B->A[3][2] = RCONST(-0.06470895363112615); + B->A[3][3] = RCONST(0.26); + B->A[4][0] = RCONST(0.16648564323248321); + B->A[4][1] = RCONST(0.10450018841591720); + B->A[4][2] = RCONST(0.03631482272098715); + B->A[4][3] = RCONST(-0.13090704451073998); + B->A[4][4] = RCONST(0.26); + B->A[5][0] = RCONST(0.13855640231268224); + B->A[5][2] = RCONST(-0.04245337201752043); + B->A[5][3] = RCONST(0.02446657898003141); + B->A[5][4] = RCONST(0.61943039072480676); + B->A[5][5] = RCONST(0.26); + B->A[6][0] = RCONST(0.13659751177640291); + B->A[6][2] = RCONST(-0.05496908796538376); + B->A[6][3] = RCONST(-0.04118626728321046); + B->A[6][4] = RCONST(0.62993304899016403); + B->A[6][5] = RCONST(0.06962479448202728); + B->A[6][6] = RCONST(0.26); + + B->b[0] = RCONST(0.13659751177640291); + B->b[2] = RCONST(-0.05496908796538376); + B->b[3] = RCONST(-0.04118626728321046); + B->b[4] = RCONST(0.62993304899016403); + B->b[5] = RCONST(0.06962479448202728); + B->b[6] = RCONST(0.26); + + B->d[0] = RCONST(0.13855640231268224); + B->d[2] = RCONST(-0.04245337201752043); + B->d[3] = RCONST(0.02446657898003141); + B->d[4] = RCONST(0.61943039072480676); + B->d[5] = RCONST(0.26); + + B->c[1] = RCONST(0.52); + B->c[2] = RCONST(1.230333209967908); + B->c[3] = RCONST(0.895765984350076); + B->c[4] = RCONST(0.436393609858648); + B->c[5] = RCONST(1.0); + B->c[6] = RCONST(1.0); + break; + + case(ARK548L2SA_DIRK_8_4_5): /* ARK5(4)8L[2]SA-ESDIRK */ + B = ARKodeButcherTable_Alloc(8, SUNTRUE); + B->q = 5; + B->p = 4; + B->A[1][0] = RCONST(41.0)/RCONST(200.0); + B->A[1][1] = RCONST(41.0)/RCONST(200.0); + B->A[2][0] = RCONST(41.0)/RCONST(400.0); + B->A[2][1] = RCONST(-567603406766.0)/RCONST(11931857230679.0); + B->A[2][2] = RCONST(41.0)/RCONST(200.0); + B->A[3][0] = RCONST(683785636431.0)/RCONST(9252920307686.0); + B->A[3][2] = RCONST(-110385047103.0)/RCONST(1367015193373.0); + B->A[3][3] = RCONST(41.0)/RCONST(200.0); + B->A[4][0] = RCONST(3016520224154.0)/RCONST(10081342136671.0); + B->A[4][2] = RCONST(30586259806659.0)/RCONST(12414158314087.0); + B->A[4][3] = RCONST(-22760509404356.0)/RCONST(11113319521817.0); + B->A[4][4] = RCONST(41.0)/RCONST(200.0); + B->A[5][0] = RCONST(218866479029.0)/RCONST(1489978393911.0); + B->A[5][2] = RCONST(638256894668.0)/RCONST(5436446318841.0); + B->A[5][3] = RCONST(-1179710474555.0)/RCONST(5321154724896.0); + B->A[5][4] = RCONST(-60928119172.0)/RCONST(8023461067671.0); + B->A[5][5] = RCONST(41.0)/RCONST(200.0); + B->A[6][0] = RCONST(1020004230633.0)/RCONST(5715676835656.0); + B->A[6][2] = RCONST(25762820946817.0)/RCONST(25263940353407.0); + B->A[6][3] = RCONST(-2161375909145.0)/RCONST(9755907335909.0); + B->A[6][4] = RCONST(-211217309593.0)/RCONST(5846859502534.0); + B->A[6][5] = RCONST(-4269925059573.0)/RCONST(7827059040749.0); + B->A[6][6] = RCONST(41.0)/RCONST(200.0); + B->A[7][0] = RCONST(-872700587467.0)/RCONST(9133579230613.0); + B->A[7][3] = RCONST(22348218063261.0)/RCONST(9555858737531.0); + B->A[7][4] = RCONST(-1143369518992.0)/RCONST(8141816002931.0); + B->A[7][5] = RCONST(-39379526789629.0)/RCONST(19018526304540.0); + B->A[7][6] = RCONST(32727382324388.0)/RCONST(42900044865799.0); + B->A[7][7] = RCONST(41.0)/RCONST(200.0); + + B->b[0] = RCONST(-872700587467.0)/RCONST(9133579230613.0); + B->b[3] = RCONST(22348218063261.0)/RCONST(9555858737531.0); + B->b[4] = RCONST(-1143369518992.0)/RCONST(8141816002931.0); + B->b[5] = RCONST(-39379526789629.0)/RCONST(19018526304540.0); + B->b[6] = RCONST(32727382324388.0)/RCONST(42900044865799.0); + B->b[7] = RCONST(41.0)/RCONST(200.0); + + B->d[0] = RCONST(-975461918565.0)/RCONST(9796059967033.0); + B->d[3] = RCONST(78070527104295.0)/RCONST(32432590147079.0); + B->d[4] = RCONST(-548382580838.0)/RCONST(3424219808633.0); + B->d[5] = RCONST(-33438840321285.0)/RCONST(15594753105479.0); + B->d[6] = RCONST(3629800801594.0)/RCONST(4656183773603.0); + B->d[7] = RCONST(4035322873751.0)/RCONST(18575991585200.0); + + B->c[1] = RCONST(41.0)/RCONST(100.0); + B->c[2] = RCONST(2935347310677.0)/RCONST(11292855782101.0); + B->c[3] = RCONST(1426016391358.0)/RCONST(7196633302097.0); + B->c[4] = RCONST(92.0)/RCONST(100.0); + B->c[5] = RCONST(24.0)/RCONST(100.0); + B->c[6] = RCONST(3.0)/RCONST(5.0); + B->c[7] = RCONST(1.0); + break; + + default: + + arkProcessError(NULL, ARK_ILL_INPUT, "ARKode", + "ARKodeButcherTable_LoadDIRK", + "Unknown Butcher table"); + return(NULL); + + } + + return(B); +} + + +/*--------------------------------------------------------------- + EOF + ---------------------------------------------------------------*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_butcher_erk.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_butcher_erk.c new file mode 100644 index 0000000..8642ce8 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_butcher_erk.c @@ -0,0 +1,607 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 built-in ERK Butcher + * tables. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "arkode_impl.h" +#include <arkode/arkode_butcher_erk.h> +#include <sundials/sundials_math.h> + +#if defined(SUNDIALS_EXTENDED_PRECISION) +#define RSYM ".32Lg" +#else +#define RSYM ".16g" +#endif + + +/*--------------------------------------------------------------- + Returns Butcher table structure for pre-set Runge Kutta methods. + + Input: imeth -- integer key for the desired method (see below) + + Allowed 'method' names and properties are listed in the table + below. Methods with an embedding have names are of the form + <name>_s_p_q where s is the number of stages, p us the embedding + order, and q is the method order. Similarly, fixed step methods + have names of the form <name>_s_q. + + Methods in an ARK pair are marked with a *. + + Methods that satisfy the additional third order multirate + infinitesimal step condition and are suppored by the MRIStep + module (c_i > c_{i-1} and c_s != 1) are marked with a ^. + + The 'QP' column denotes whether the coefficients of the method + are known precisely enough for use in 'long double' (128-bit) + calculations. + + imeth QP + -------------------------------- + HEUN_EULER_2_1_2 Y + BOGACKI_SHAMPINE_4_2_3 Y + ARK324L2SA_ERK_4_2_3* N + ZONNEVELD_5_3_4 Y + ARK436L2SA_ERK_6_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 + VERNER_8_5_6 Y + FEHLBERG_13_7_8 Y + -------------------------------- + KNOTH_WOLKE_3_3^ Y + -------------------------------- + + ---------------------------------------------------------------*/ +ARKodeButcherTable ARKodeButcherTable_LoadERK(int imethod) +{ + + ARKodeButcherTable B; + B = NULL; + + /* fill in coefficients based on method name */ + switch(imethod) { + + /* ========================================================== + * METHODS WITH EMBEDDINGS + * ========================================================*/ + + case(HEUN_EULER_2_1_2): /* Heun-Euler-ERK */ + B = ARKodeButcherTable_Alloc(2, SUNTRUE); + B->q = 2; + B->p = 1; + + B->A[1][0] = RCONST(1.0); + + B->b[0] = RCONST(1.0)/RCONST(2.0); + B->b[1] = RCONST(1.0)/RCONST(2.0); + + B->d[0] = RCONST(1.0); + + B->c[1] = RCONST(1.0); + break; + + case(BOGACKI_SHAMPINE_4_2_3): /* Bogacki-Shampine-ERK */ + B = ARKodeButcherTable_Alloc(4, SUNTRUE); + B->q = 3; + B->p = 2; + B->A[1][0] = RCONST(1.0)/RCONST(2.0); + B->A[2][1] = RCONST(3.0)/RCONST(4.0); + B->A[3][0] = RCONST(2.0)/RCONST(9.0); + B->A[3][1] = RCONST(1.0)/RCONST(3.0); + B->A[3][2] = RCONST(4.0)/RCONST(9.0); + + B->b[0] = RCONST(2.0)/RCONST(9.0); + B->b[1] = RCONST(1.0)/RCONST(3.0); + B->b[2] = RCONST(4.0)/RCONST(9.0); + + B->d[0] = RCONST(7.0)/RCONST(24.0); + B->d[1] = RCONST(1.0)/RCONST(4.0); + B->d[2] = RCONST(1.0)/RCONST(3.0); + B->d[3] = RCONST(1.0)/RCONST(8.0); + + B->c[1] = RCONST(1.0)/RCONST(2.0); + B->c[2] = RCONST(3.0)/RCONST(4.0); + B->c[3] = RCONST(1.0); + break; + + case(ARK324L2SA_ERK_4_2_3): /* ARK3(2)4L[2]SA-ERK */ + B = ARKodeButcherTable_Alloc(4, SUNTRUE); + B->q = 3; + B->p = 2; + B->A[1][0] = RCONST(1767732205903.0)/RCONST(2027836641118.0); + B->A[2][0] = RCONST(5535828885825.0)/RCONST(10492691773637.0); + B->A[2][1] = RCONST(788022342437.0)/RCONST(10882634858940.0); + B->A[3][0] = RCONST(6485989280629.0)/RCONST(16251701735622.0); + B->A[3][1] = RCONST(-4246266847089.0)/RCONST(9704473918619.0); + B->A[3][2] = RCONST(10755448449292.0)/RCONST(10357097424841.0); + + B->b[0] = RCONST(1471266399579.0)/RCONST(7840856788654.0); + B->b[1] = RCONST(-4482444167858.0)/RCONST(7529755066697.0); + B->b[2] = RCONST(11266239266428.0)/RCONST(11593286722821.0); + B->b[3] = RCONST(1767732205903.0)/RCONST(4055673282236.0); + + B->d[0] = RCONST(2756255671327.0)/RCONST(12835298489170.0); + B->d[1] = RCONST(-10771552573575.0)/RCONST(22201958757719.0); + B->d[2] = RCONST(9247589265047.0)/RCONST(10645013368117.0); + B->d[3] = RCONST(2193209047091.0)/RCONST(5459859503100.0); + + B->c[1] = RCONST(1767732205903.0)/RCONST(2027836641118.0); + B->c[2] = RCONST(3.0)/RCONST(5.0); + B->c[3] = RCONST(1.0); + break; + + case(ZONNEVELD_5_3_4): /* Zonneveld */ + B = ARKodeButcherTable_Alloc(5, SUNTRUE); + B->q = 4; + B->p = 3; + B->A[1][0] = RCONST(0.5); + B->A[2][1] = RCONST(0.5); + B->A[3][2] = RCONST(1.0); + B->A[4][0] = RCONST(5.0)/RCONST(32.0); + B->A[4][1] = RCONST(7.0)/RCONST(32.0); + B->A[4][2] = RCONST(13.0)/RCONST(32.0); + B->A[4][3] = RCONST(-1.0)/RCONST(32.0); + + B->b[0] = RCONST(1.0)/RCONST(6.0); + B->b[1] = RCONST(1.0)/RCONST(3.0); + B->b[2] = RCONST(1.0)/RCONST(3.0); + B->b[3] = RCONST(1.0)/RCONST(6.0); + + B->d[0] = RCONST(-1.0)/RCONST(2.0); + B->d[1] = RCONST(7.0)/RCONST(3.0); + B->d[2] = RCONST(7.0)/RCONST(3.0); + B->d[3] = RCONST(13.0)/RCONST(6.0); + B->d[4] = RCONST(-16.0)/RCONST(3.0); + + B->c[1] = RCONST(0.5); + B->c[2] = RCONST(0.5); + B->c[3] = RCONST(1.0); + B->c[4] = RCONST(0.75); + break; + + case(ARK436L2SA_ERK_6_3_4): /* ARK4(3)6L[2]SA-ERK */ + B = ARKodeButcherTable_Alloc(6, SUNTRUE); + B->q = 4; + B->p = 3; + B->A[1][0] = RCONST(0.5); + B->A[2][0] = RCONST(13861.0)/RCONST(62500.0); + B->A[2][1] = RCONST(6889.0)/RCONST(62500.0); + B->A[3][0] = RCONST(-116923316275.0)/RCONST(2393684061468.0); + B->A[3][1] = RCONST(-2731218467317.0)/RCONST(15368042101831.0); + B->A[3][2] = RCONST(9408046702089.0)/RCONST(11113171139209.0); + B->A[4][0] = RCONST(-451086348788.0)/RCONST(2902428689909.0); + B->A[4][1] = RCONST(-2682348792572.0)/RCONST(7519795681897.0); + B->A[4][2] = RCONST(12662868775082.0)/RCONST(11960479115383.0); + B->A[4][3] = RCONST(3355817975965.0)/RCONST(11060851509271.0); + B->A[5][0] = RCONST(647845179188.0)/RCONST(3216320057751.0); + B->A[5][1] = RCONST(73281519250.0)/RCONST(8382639484533.0); + B->A[5][2] = RCONST(552539513391.0)/RCONST(3454668386233.0); + B->A[5][3] = RCONST(3354512671639.0)/RCONST(8306763924573.0); + B->A[5][4] = RCONST(4040.0)/RCONST(17871.0); + + B->b[0] = RCONST(82889.0)/RCONST(524892.0); + B->b[2] = RCONST(15625.0)/RCONST(83664.0); + B->b[3] = RCONST(69875.0)/RCONST(102672.0); + B->b[4] = RCONST(-2260.0)/RCONST(8211.0); + B->b[5] = RCONST(1.0)/RCONST(4.0); + + B->d[0] = RCONST(4586570599.0)/RCONST(29645900160.0); + B->d[2] = RCONST(178811875.0)/RCONST(945068544.0); + B->d[3] = RCONST(814220225.0)/RCONST(1159782912.0); + B->d[4] = RCONST(-3700637.0)/RCONST(11593932.0); + B->d[5] = RCONST(61727.0)/RCONST(225920.0); + + B->c[1] = RCONST(1.0)/RCONST(2.0); + B->c[2] = RCONST(83.0)/RCONST(250.0); + B->c[3] = RCONST(31.0)/RCONST(50.0); + B->c[4] = RCONST(17.0)/RCONST(20.0); + B->c[5] = RCONST(1.0); + break; + + case(SAYFY_ABURUB_6_3_4): /* Sayfy-Aburub-4-3-ERK */ + B = ARKodeButcherTable_Alloc(6, SUNTRUE); + B->q = 4; + B->p = 3; + B->A[1][0] = RCONST(1.0)/RCONST(2.0); + B->A[2][0] = RCONST(-1.0); + B->A[2][1] = RCONST(2.0); + B->A[3][0] = RCONST(1.0)/RCONST(6.0); + B->A[3][1] = RCONST(2.0)/RCONST(3.0); + B->A[3][2] = RCONST(1.0)/RCONST(6.0); + B->A[4][0] = RCONST(0.137); + B->A[4][1] = RCONST(0.226); + B->A[4][2] = RCONST(0.137); + B->A[5][0] = RCONST(0.452); + B->A[5][1] = RCONST(-0.904); + B->A[5][2] = RCONST(-0.548); + B->A[5][4] = RCONST(2.0); + + B->b[0] = RCONST(1.0)/RCONST(6.0); + B->b[1] = RCONST(1.0)/RCONST(3.0); + B->b[2] = RCONST(1.0)/RCONST(12.0); + B->b[3] = RCONST(0.0); + B->b[4] = RCONST(1.0)/RCONST(3.0); + B->b[5] = RCONST(1.0)/RCONST(12.0); + + B->d[0] = RCONST(1.0)/RCONST(6.0); + B->d[1] = RCONST(2.0)/RCONST(3.0); + B->d[2] = RCONST(1.0)/RCONST(6.0); + + B->c[1] = RCONST(1.0)/RCONST(2.0); + B->c[2] = RCONST(1.0); + B->c[3] = RCONST(1.0); + B->c[4] = RCONST(1.0)/RCONST(2.0); + B->c[5] = RCONST(1.0); + break; + + case(CASH_KARP_6_4_5): /* Cash-Karp-ERK */ + B = ARKodeButcherTable_Alloc(6, SUNTRUE); + B->q = 5; + B->p = 4; + B->A[1][0] = RCONST(1.0)/RCONST(5.0); + B->A[2][0] = RCONST(3.0)/RCONST(40.0); + B->A[2][1] = RCONST(9.0)/RCONST(40.0); + B->A[3][0] = RCONST(3.0)/RCONST(10.0); + B->A[3][1] = RCONST(-9.0)/RCONST(10.0); + B->A[3][2] = RCONST(6.0)/RCONST(5.0); + B->A[4][0] = RCONST(-11.0)/RCONST(54.0); + B->A[4][1] = RCONST(5.0)/RCONST(2.0); + B->A[4][2] = RCONST(-70.0)/RCONST(27.0); + B->A[4][3] = RCONST(35.0)/RCONST(27.0); + B->A[5][0] = RCONST(1631.0)/RCONST(55296.0); + B->A[5][1] = RCONST(175.0)/RCONST(512.0); + B->A[5][2] = RCONST(575.0)/RCONST(13824.0); + B->A[5][3] = RCONST(44275.0)/RCONST(110592.0); + B->A[5][4] = RCONST(253.0)/RCONST(4096.0); + + B->b[0] = RCONST(37.0)/RCONST(378.0); + B->b[2] = RCONST(250.0)/RCONST(621.0); + B->b[3] = RCONST(125.0)/RCONST(594.0); + B->b[5] = RCONST(512.0)/RCONST(1771.0); + + B->d[0] = RCONST(2825.0)/RCONST(27648.0); + B->d[2] = RCONST(18575.0)/RCONST(48384.0); + B->d[3] = RCONST(13525.0)/RCONST(55296.0); + B->d[4] = RCONST(277.0)/RCONST(14336.0); + B->d[5] = RCONST(1.0)/RCONST(4.0); + + B->c[1] = RCONST(1.0)/RCONST(5.0); + B->c[2] = RCONST(3.0)/RCONST(10.0); + B->c[3] = RCONST(3.0)/RCONST(5.0); + B->c[4] = RCONST(1.0); + B->c[5] = RCONST(7.0)/RCONST(8.0); + break; + + case(FEHLBERG_6_4_5): /* Fehlberg-ERK */ + B = ARKodeButcherTable_Alloc(6, SUNTRUE); + B->q = 5; + B->p = 4; + B->A[1][0] = RCONST(1.0)/RCONST(4.0); + B->A[2][0] = RCONST(3.0)/RCONST(32.0); + B->A[2][1] = RCONST(9.0)/RCONST(32.0); + B->A[3][0] = RCONST(1932.0)/RCONST(2197.0); + B->A[3][1] = RCONST(-7200.0)/RCONST(2197.0); + B->A[3][2] = RCONST(7296.0)/RCONST(2197.0); + B->A[4][0] = RCONST(439.0)/RCONST(216.0); + B->A[4][1] = RCONST(-8.0); + B->A[4][2] = RCONST(3680.0)/RCONST(513.0); + B->A[4][3] = RCONST(-845.0)/RCONST(4104.0); + B->A[5][0] = RCONST(-8.0)/RCONST(27.0); + B->A[5][1] = RCONST(2.0); + B->A[5][2] = RCONST(-3544.0)/RCONST(2565.0); + B->A[5][3] = RCONST(1859.0)/RCONST(4104.0); + B->A[5][4] = RCONST(-11.0)/RCONST(40.0); + + B->b[0] = RCONST(16.0)/RCONST(135.0); + B->b[2] = RCONST(6656.0)/RCONST(12825.0); + B->b[3] = RCONST(28561.0)/RCONST(56430.0); + B->b[4] = RCONST(-9.0)/RCONST(50.0); + B->b[5] = RCONST(2.0)/RCONST(55.0); + + B->d[0] = RCONST(25.0)/RCONST(216.0); + B->d[2] = RCONST(1408.0)/RCONST(2565.0); + B->d[3] = RCONST(2197.0)/RCONST(4104.0); + B->d[4] = RCONST(-1.0)/RCONST(5.0); + + B->c[1] = RCONST(1.0)/RCONST(4.0); + B->c[2] = RCONST(3.0)/RCONST(8.0); + B->c[3] = RCONST(12.0)/RCONST(13.0); + B->c[4] = RCONST(1.0); + B->c[5] = RCONST(1.0)/RCONST(2.0); + break; + + case(DORMAND_PRINCE_7_4_5): /* Dormand-Prince-ERK */ + B = ARKodeButcherTable_Alloc(7, SUNTRUE); + B->q = 5; + B->p = 4; + B->A[1][0] = RCONST(1.0)/RCONST(5.0); + B->A[2][0] = RCONST(3.0)/RCONST(40.0); + B->A[2][1] = RCONST(9.0)/RCONST(40.0); + B->A[3][0] = RCONST(44.0)/RCONST(45.0); + B->A[3][1] = RCONST(-56.0)/RCONST(15.0); + B->A[3][2] = RCONST(32.0)/RCONST(9.0); + B->A[4][0] = RCONST(19372.0)/RCONST(6561.0); + B->A[4][1] = RCONST(-25360.0)/RCONST(2187.0); + B->A[4][2] = RCONST(64448.0)/RCONST(6561.0); + B->A[4][3] = RCONST(-212.0)/RCONST(729.0); + B->A[5][0] = RCONST(9017.0)/RCONST(3168.0); + B->A[5][1] = RCONST(-355.0)/RCONST(33.0); + B->A[5][2] = RCONST(46732.0)/RCONST(5247.0); + B->A[5][3] = RCONST(49.0)/RCONST(176.0); + B->A[5][4] = RCONST(-5103.0)/RCONST(18656.0); + B->A[6][0] = RCONST(35.0)/RCONST(384.0); + B->A[6][2] = RCONST(500.0)/RCONST(1113.0); + B->A[6][3] = RCONST(125.0)/RCONST(192.0); + B->A[6][4] = RCONST(-2187.0)/RCONST(6784.0); + B->A[6][5] = RCONST(11.0)/RCONST(84.0); + + B->b[0] = RCONST(35.0)/RCONST(384.0); + B->b[2] = RCONST(500.0)/RCONST(1113.0); + B->b[3] = RCONST(125.0)/RCONST(192.0); + B->b[4] = RCONST(-2187.0)/RCONST(6784.0); + B->b[5] = RCONST(11.0)/RCONST(84.0); + + B->d[0] = RCONST(5179.0)/RCONST(57600.0); + B->d[2] = RCONST(7571.0)/RCONST(16695.0); + B->d[3] = RCONST(393.0)/RCONST(640.0); + B->d[4] = RCONST(-92097.0)/RCONST(339200.0); + B->d[5] = RCONST(187.0)/RCONST(2100.0); + B->d[6] = RCONST(1.0)/RCONST(40.0); + + B->c[1] = RCONST(1.0)/RCONST(5.0); + B->c[2] = RCONST(3.0)/RCONST(10.0); + B->c[3] = RCONST(4.0)/RCONST(5.0); + B->c[4] = RCONST(8.0)/RCONST(9.0); + B->c[5] = RCONST(1.0); + B->c[6] = RCONST(1.0); + break; + + case(ARK548L2SA_ERK_8_4_5): /* ARK5(4)8L[2]SA-ERK */ + B = ARKodeButcherTable_Alloc(8, SUNTRUE); + B->q = 5; + B->p = 4; + B->A[1][0] = RCONST(41.0)/RCONST(100.0); + B->A[2][0] = RCONST(367902744464.0)/RCONST(2072280473677.0); + B->A[2][1] = RCONST(677623207551.0)/RCONST(8224143866563.0); + B->A[3][0] = RCONST(1268023523408.0)/RCONST(10340822734521.0); + B->A[3][2] = RCONST(1029933939417.0)/RCONST(13636558850479.0); + B->A[4][0] = RCONST(14463281900351.0)/RCONST(6315353703477.0); + B->A[4][2] = RCONST(66114435211212.0)/RCONST(5879490589093.0); + B->A[4][3] = RCONST(-54053170152839.0)/RCONST(4284798021562.0); + B->A[5][0] = RCONST(14090043504691.0)/RCONST(34967701212078.0); + B->A[5][2] = RCONST(15191511035443.0)/RCONST(11219624916014.0); + B->A[5][3] = RCONST(-18461159152457.0)/RCONST(12425892160975.0); + B->A[5][4] = RCONST(-281667163811.0)/RCONST(9011619295870.0); + B->A[6][0] = RCONST(19230459214898.0)/RCONST(13134317526959.0); + B->A[6][2] = RCONST(21275331358303.0)/RCONST(2942455364971.0); + B->A[6][3] = RCONST(-38145345988419.0)/RCONST(4862620318723.0); + B->A[6][4] = RCONST(-1.0)/RCONST(8.0); + B->A[6][5] = RCONST(-1.0)/RCONST(8.0); + B->A[7][0] = RCONST(-19977161125411.0)/RCONST(11928030595625.0); + B->A[7][2] = RCONST(-40795976796054.0)/RCONST(6384907823539.0); + B->A[7][3] = RCONST(177454434618887.0)/RCONST(12078138498510.0); + B->A[7][4] = RCONST(782672205425.0)/RCONST(8267701900261.0); + B->A[7][5] = RCONST(-69563011059811.0)/RCONST(9646580694205.0); + B->A[7][6] = RCONST(7356628210526.0)/RCONST(4942186776405.0); + + B->b[0] = RCONST(-872700587467.0)/RCONST(9133579230613.0); + B->b[3] = RCONST(22348218063261.0)/RCONST(9555858737531.0); + B->b[4] = RCONST(-1143369518992.0)/RCONST(8141816002931.0); + B->b[5] = RCONST(-39379526789629.0)/RCONST(19018526304540.0); + B->b[6] = RCONST(32727382324388.0)/RCONST(42900044865799.0); + B->b[7] = RCONST(41.0)/RCONST(200.0); + + B->d[0] = RCONST(-975461918565.0)/RCONST(9796059967033.0); + B->d[3] = RCONST(78070527104295.0)/RCONST(32432590147079.0); + B->d[4] = RCONST(-548382580838.0)/RCONST(3424219808633.0); + B->d[5] = RCONST(-33438840321285.0)/RCONST(15594753105479.0); + B->d[6] = RCONST(3629800801594.0)/RCONST(4656183773603.0); + B->d[7] = RCONST(4035322873751.0)/RCONST(18575991585200.0); + + B->c[1] = RCONST(41.0)/RCONST(100.0); + B->c[2] = RCONST(2935347310677.0)/RCONST(11292855782101.0); + B->c[3] = RCONST(1426016391358.0)/RCONST(7196633302097.0); + B->c[4] = RCONST(92.0)/RCONST(100.0); + B->c[5] = RCONST(24.0)/RCONST(100.0); + B->c[6] = RCONST(3.0)/RCONST(5.0); + B->c[7] = RCONST(1.0); + break; + + case(VERNER_8_5_6): /* Verner-6-5 */ + B = ARKodeButcherTable_Alloc(8, SUNTRUE); + B->q = 6; + B->p = 5; + B->A[1][0] = RCONST(1.0)/RCONST(6.0); + B->A[2][0] = RCONST(4.0)/RCONST(75.0); + B->A[2][1] = RCONST(16.0)/RCONST(75.0); + B->A[3][0] = RCONST(5.0)/RCONST(6.0); + B->A[3][1] = RCONST(-8.0)/RCONST(3.0); + B->A[3][2] = RCONST(5.0)/RCONST(2.0); + B->A[4][0] = RCONST(-165.0)/RCONST(64.0); + B->A[4][1] = RCONST(55.0)/RCONST(6.0); + B->A[4][2] = RCONST(-425.0)/RCONST(64.0); + B->A[4][3] = RCONST(85.0)/RCONST(96.0); + B->A[5][0] = RCONST(12.0)/RCONST(5.0); + B->A[5][1] = RCONST(-8.0); + B->A[5][2] = RCONST(4015.0)/RCONST(612.0); + B->A[5][3] = RCONST(-11.0)/RCONST(36.0); + B->A[5][4] = RCONST(88.0)/RCONST(255.0); + B->A[6][0] = RCONST(-8263.0)/RCONST(15000.0); + B->A[6][1] = RCONST(124.0)/RCONST(75.0); + B->A[6][2] = RCONST(-643.0)/RCONST(680.0); + B->A[6][3] = RCONST(-81.0)/RCONST(250.0); + B->A[6][4] = RCONST(2484.0)/RCONST(10625.0); + B->A[7][0] = RCONST(3501.0)/RCONST(1720.0); + B->A[7][1] = RCONST(-300.0)/RCONST(43.0); + B->A[7][2] = RCONST(297275.0)/RCONST(52632.0); + B->A[7][3] = RCONST(-319.0)/RCONST(2322.0); + B->A[7][4] = RCONST(24068.0)/RCONST(84065.0); + B->A[7][6] = RCONST(3850.0)/RCONST(26703.0); + + B->b[0] = RCONST(3.0)/RCONST(40.0); + B->b[2] = RCONST(875.0)/RCONST(2244.0); + B->b[3] = RCONST(23.0)/RCONST(72.0); + B->b[4] = RCONST(264.0)/RCONST(1955.0); + B->b[6] = RCONST(125.0)/RCONST(11592.0); + B->b[7] = RCONST(43.0)/RCONST(616.0); + + B->d[0] = RCONST(13.0)/RCONST(160.0); + B->d[2] = RCONST(2375.0)/RCONST(5984.0); + B->d[3] = RCONST(5.0)/RCONST(16.0); + B->d[4] = RCONST(12.0)/RCONST(85.0); + B->d[5] = RCONST(3.0)/RCONST(44.0); + + B->c[0] = RCONST(0.0); + B->c[1] = RCONST(1.0)/RCONST(6.0); + B->c[2] = RCONST(4.0)/RCONST(15.0); + B->c[3] = RCONST(2.0)/RCONST(3.0); + B->c[4] = RCONST(5.0)/RCONST(6.0); + B->c[5] = RCONST(1.0); + B->c[6] = RCONST(1.0)/RCONST(15.0); + B->c[7] = RCONST(1.0); + break; + + case(FEHLBERG_13_7_8): /* Fehlberg-8-7 */ + B = ARKodeButcherTable_Alloc(13, SUNTRUE); + B->q = 8; + B->p = 7; + B->A[1][0] = RCONST(2.0)/RCONST(27.0); + B->A[2][0] = RCONST(1.0)/RCONST(36.0); + B->A[2][1] = RCONST(1.0)/RCONST(12.0); + B->A[3][0] = RCONST(1.0)/RCONST(24.0); + B->A[3][2] = RCONST(1.0)/RCONST(8.0); + B->A[4][0] = RCONST(5.0)/RCONST(12.0); + B->A[4][2] = RCONST(-25.0)/RCONST(16.0); + B->A[4][3] = RCONST(25.0)/RCONST(16.0); + B->A[5][0] = RCONST(1.0)/RCONST(20.0); + B->A[5][3] = RCONST(1.0)/RCONST(4.0); + B->A[5][4] = RCONST(1.0)/RCONST(5.0); + B->A[6][0] = RCONST(-25.0)/RCONST(108.0); + B->A[6][3] = RCONST(125.0)/RCONST(108.0); + B->A[6][4] = RCONST(-65.0)/RCONST(27.0); + B->A[6][5] = RCONST(125.0)/RCONST(54.0); + B->A[7][0] = RCONST(31.0)/RCONST(300.0); + B->A[7][4] = RCONST(61.0)/RCONST(225.0); + B->A[7][5] = RCONST(-2.0)/RCONST(9.0); + B->A[7][6] = RCONST(13.0)/RCONST(900.0); + B->A[8][0] = RCONST(2.0); + B->A[8][3] = RCONST(-53.0)/RCONST(6.0); + B->A[8][4] = RCONST(704.0)/RCONST(45.0); + B->A[8][5] = RCONST(-107.0)/RCONST(9.0); + B->A[8][6] = RCONST(67.0)/RCONST(90.0); + B->A[8][7] = RCONST(3.0); + B->A[9][0] = RCONST(-91.0)/RCONST(108.0); + B->A[9][3] = RCONST(23.0)/RCONST(108.0); + B->A[9][4] = RCONST(-976.0)/RCONST(135.0); + B->A[9][5] = RCONST(311.0)/RCONST(54.0); + B->A[9][6] = RCONST(-19.0)/RCONST(60.0); + B->A[9][7] = RCONST(17.0)/RCONST(6.0); + B->A[9][8] = RCONST(-1.0)/RCONST(12.0); + B->A[10][0] = RCONST(2383.0)/RCONST(4100.0); + B->A[10][3] = RCONST(-341.0)/RCONST(164.0); + B->A[10][4] = RCONST(4496.0)/RCONST(1025.0); + B->A[10][5] = RCONST(-301.0)/RCONST(82.0); + B->A[10][6] = RCONST(2133.0)/RCONST(4100.0); + B->A[10][7] = RCONST(45.0)/RCONST(82.0); + B->A[10][8] = RCONST(45.0)/RCONST(164.0); + B->A[10][9] = RCONST(18.0)/RCONST(41.0); + B->A[11][0] = RCONST(3.0)/RCONST(205.0); + B->A[11][5] = RCONST(-6.0)/RCONST(41.0); + B->A[11][6] = RCONST(-3.0)/RCONST(205.0); + B->A[11][7] = RCONST(-3.0)/RCONST(41.0); + B->A[11][8] = RCONST(3.0)/RCONST(41.0); + B->A[11][9] = RCONST(6.0)/RCONST(41.0); + B->A[12][0] = RCONST(-1777.0)/RCONST(4100.0); + B->A[12][3] = RCONST(-341.0)/RCONST(164.0); + B->A[12][4] = RCONST(4496.0)/RCONST(1025.0); + B->A[12][5] = RCONST(-289.0)/RCONST(82.0); + B->A[12][6] = RCONST(2193.0)/RCONST(4100.0); + B->A[12][7] = RCONST(51.0)/RCONST(82.0); + B->A[12][8] = RCONST(33.0)/RCONST(164.0); + B->A[12][9] = RCONST(12.0)/RCONST(41.0); + B->A[12][11] = RCONST(1.0); + + B->b[5] = RCONST(34.0)/RCONST(105.0); + B->b[6] = RCONST(9.0)/RCONST(35.0); + B->b[7] = RCONST(9.0)/RCONST(35.0); + B->b[8] = RCONST(9.0)/RCONST(280.0); + B->b[9] = RCONST(9.0)/RCONST(280.0); + B->b[11] = RCONST(41.0)/RCONST(840.0); + B->b[12] = RCONST(41.0)/RCONST(840.0); + + B->d[0] = RCONST(41.0)/RCONST(840.0); + B->d[5] = RCONST(34.0)/RCONST(105.0); + B->d[6] = RCONST(9.0)/RCONST(35.0); + B->d[7] = RCONST(9.0)/RCONST(35.0); + B->d[8] = RCONST(9.0)/RCONST(280.0); + B->d[9] = RCONST(9.0)/RCONST(280.0); + B->d[10] = RCONST(41.0)/RCONST(840.0); + + B->c[1] = RCONST(2.0)/RCONST(27.0); + B->c[2] = RCONST(1.0)/RCONST(9.0); + B->c[3] = RCONST(1.0)/RCONST(6.0); + B->c[4] = RCONST(5.0)/RCONST(12.0); + B->c[5] = RCONST(1.0)/RCONST(2.0); + B->c[6] = RCONST(5.0)/RCONST(6.0); + B->c[7] = RCONST(1.0)/RCONST(6.0); + B->c[8] = RCONST(2.0)/RCONST(3.0); + B->c[9] = RCONST(1.0)/RCONST(3.0); + B->c[10] = RCONST(1.0); + B->c[12] = RCONST(1.0); + break; + + /* ========================================================== + * FIXED STEP METHODS + * ========================================================*/ + + case(KNOTH_WOLKE_3_3): /* Knoth-Wolke-ERK */ + B = ARKodeButcherTable_Alloc(3, SUNFALSE); + B->q = 3; + B->p = 0; + B->A[1][0] = RCONST(1.0)/RCONST(3.0); + B->A[2][0] = RCONST(-3.0)/RCONST(16.0); + B->A[2][1] = RCONST(15.0)/RCONST(16.0); + + B->b[0] = RCONST(1.0)/RCONST(6.0); + B->b[1] = RCONST(3.0)/RCONST(10.0); + B->b[2] = RCONST(8.0)/RCONST(15.0); + + B->d = NULL; + + B->c[1] = RCONST(1.0)/RCONST(3.0); + B->c[2] = RCONST(3.0)/RCONST(4.0); + break; + + default: + + arkProcessError(NULL, ARK_ILL_INPUT, "ARKode", + "ARKodeButcherTable_LoadERK", + "Unknown Butcher table"); + return(NULL); + + } + + return(B); +} + + +/*--------------------------------------------------------------- + EOF + ---------------------------------------------------------------*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_erkstep.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_erkstep.c new file mode 100644 index 0000000..06f1e83 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_erkstep.c @@ -0,0 +1,1242 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 ARKode's ERK time stepper + * module. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "arkode_impl.h" +#include "arkode_erkstep_impl.h" +#include <sundials/sundials_math.h> + +#if defined(SUNDIALS_EXTENDED_PRECISION) +#define RSYM ".32Lg" +#else +#define RSYM ".16g" +#endif + +#define NO_DEBUG_OUTPUT +/* #define DEBUG_OUTPUT */ +#ifdef DEBUG_OUTPUT +#include <nvector/nvector_serial.h> +#endif + +/* constants */ +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + + + +/*=============================================================== + ERKStep Exported functions -- Required + ===============================================================*/ + +void* ERKStepCreate(ARKRhsFn f, realtype t0, N_Vector y0) +{ + ARKodeMem ark_mem; + ARKodeERKStepMem step_mem; + booleantype nvectorOK; + int retval; + + /* Check that f is supplied */ + if (f == NULL) { + arkProcessError(NULL, ARK_ILL_INPUT, "ARKode::ERKStep", + "ERKStepCreate", MSG_ARK_NULL_F); + return(NULL); + } + + /* Check for legal input parameters */ + if (y0 == NULL) { + arkProcessError(NULL, ARK_ILL_INPUT, "ARKode::ERKStep", + "ERKStepCreate", MSG_ARK_NULL_Y0); + return(NULL); + } + + /* Test if all required vector operations are implemented */ + nvectorOK = erkStep_CheckNVector(y0); + if (!nvectorOK) { + arkProcessError(NULL, ARK_ILL_INPUT, "ARKode::ERKStep", + "ERKStepCreate", 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::ERKStep", + "ERKStepCreate", MSG_ARK_NO_MEM); + return(NULL); + } + + /* Allocate ARKodeERKStepMem structure, and initialize to zero */ + step_mem = NULL; + step_mem = (ARKodeERKStepMem) malloc(sizeof(struct ARKodeERKStepMemRec)); + if (step_mem == NULL) { + arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode::ERKStep", + "ERKStepCreate", MSG_ARK_ARKMEM_FAIL); + return(NULL); + } + memset(step_mem, 0, sizeof(struct ARKodeERKStepMemRec)); + + /* Attach step_mem structure and function pointers to ark_mem */ + ark_mem->step_init = erkStep_Init; + ark_mem->step_fullrhs = erkStep_FullRHS; + ark_mem->step = erkStep_TakeStep; + ark_mem->step_mem = (void*) step_mem; + + /* Set default values for ERKStep optional inputs */ + retval = ERKStepSetDefaults((void *) ark_mem); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, retval, "ARKode::ERKStep", + "ERKStepCreate", + "Error setting default solver options"); + return(NULL); + } + + /* Allocate the general ERK stepper vectors using y0 as a template */ + /* NOTE: F, cvals and Xvecs will be allocated later on + (based on the number of ERK stages) */ + + /* Copy the input parameters into ARKode state */ + step_mem->f = f; + + /* Update the ARKode workspace requirements -- UPDATE */ + 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; + + /* Initialize main ARKode infrastructure */ + retval = arkInit(ark_mem, t0, y0); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, retval, "ARKode::ERKStep", "ERKStepCreate", + "Unable to initialize main ARKode infrastructure"); + return(NULL); + } + + return((void *)ark_mem); +} + + +/*--------------------------------------------------------------- + ERKStepResize: + + This routine resizes the memory within the ERKStep module. + It first resizes the main ARKode infrastructure memory, and + then resizes its own data. + ---------------------------------------------------------------*/ +int ERKStepResize(void *arkode_mem, N_Vector y0, realtype hscale, + realtype t0, ARKVecResizeFn resize, void *resize_data) +{ + ARKodeMem ark_mem; + ARKodeERKStepMem step_mem; + sunindextype lrw1, liw1, lrw_diff, liw_diff; + int i, retval; + + /* access ARKodeERKStepMem structure */ + retval = erkStep_AccessStepMem(arkode_mem, "ERKStepReSize", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* Determing change in vector sizes */ + lrw1 = liw1 = 0; + if (y0->ops->nvspace != NULL) + N_VSpace(y0, &lrw1, &liw1); + lrw_diff = lrw1 - ark_mem->lrw1; + liw_diff = liw1 - ark_mem->liw1; + ark_mem->lrw1 = lrw1; + ark_mem->liw1 = liw1; + + /* resize ARKode infrastructure memory */ + retval = arkResize(ark_mem, y0, hscale, t0, resize, resize_data); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, retval, "ARKode::ERKStep", "ERKStepResize", + "Unable to resize main ARKode infrastructure"); + return(retval); + } + + /* Resize the RHS vectors */ + for (i=0; i<step_mem->stages; i++) { + retval = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + liw_diff, y0, &step_mem->F[i]); + if (retval != ARK_SUCCESS) return(retval); + } + + return(ARK_SUCCESS); +} + + +int ERKStepReInit(void* arkode_mem, ARKRhsFn f, realtype t0, N_Vector y0) +{ + ARKodeMem ark_mem; + ARKodeERKStepMem step_mem; + int retval; + + /* access ARKodeERKStepMem structure */ + retval = erkStep_AccessStepMem(arkode_mem, "ERKStepReInit", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* Check that f is supplied */ + if (f == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ERKStep", + "ERKStepReInit", MSG_ARK_NULL_F); + return(ARK_ILL_INPUT); + } + + /* Check for legal input parameters */ + if (y0 == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ERKStep", + "ERKStepReInit", MSG_ARK_NULL_Y0); + return(ARK_ILL_INPUT); + } + + /* ReInitialize main ARKode infrastructure */ + retval = arkReInit(arkode_mem, t0, y0); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, retval, "ARKode::ERKStep", "ERKStepReInit", + "Unable to initialize main ARKode infrastructure"); + 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; + + return(ARK_SUCCESS); +} + + +int ERKStepSStolerances(void *arkode_mem, realtype reltol, realtype abstol) +{ + /* unpack ark_mem, call arkSStolerances, and return */ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", + "ERKStepSStolerances", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + return(arkSStolerances(ark_mem, reltol, abstol)); +} + + +int ERKStepSVtolerances(void *arkode_mem, realtype reltol, N_Vector abstol) +{ + /* unpack ark_mem, call arkSVtolerances, and return */ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", + "ERKStepSVtolerances", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + return(arkSVtolerances(ark_mem, reltol, abstol)); +} + + +int ERKStepWFtolerances(void *arkode_mem, ARKEwtFn efun) +{ + /* unpack ark_mem, call arkWFtolerances, and return */ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", + "ERKStepWFtolerances", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + return(arkWFtolerances(ark_mem, efun)); +} + + +int ERKStepRootInit(void *arkode_mem, int nrtfn, ARKRootFn g) +{ + /* unpack ark_mem, call arkRootInit, and return */ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", + "ERKStepRootInit", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + return(arkRootInit(ark_mem, nrtfn, g)); +} + + +int ERKStepEvolve(void *arkode_mem, realtype tout, N_Vector yout, + realtype *tret, int itask) +{ + /* unpack ark_mem, call arkEvolve, and return */ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", + "ERKStepEvolve", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + return(arkEvolve(ark_mem, tout, yout, tret, itask)); +} + + +int ERKStepGetDky(void *arkode_mem, realtype t, int k, N_Vector dky) +{ + /* unpack ark_mem, call arkGetDky, and return */ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ERKStep", + "ERKStepGetDky", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + return(arkGetDky(ark_mem, t, k, dky)); +} + + +/*--------------------------------------------------------------- + ERKStepFree frees all ERKStep memory, and then calls an ARKode + utility routine to free the ARKode infrastructure memory. + ---------------------------------------------------------------*/ +void ERKStepFree(void **arkode_mem) +{ + int j; + sunindextype Bliw, Blrw; + ARKodeMem ark_mem; + ARKodeERKStepMem step_mem; + + /* nothing to do if arkode_mem is already NULL */ + if (*arkode_mem == NULL) return; + + /* conditional frees on non-NULL ERKStep module */ + ark_mem = (ARKodeMem) (*arkode_mem); + if (ark_mem->step_mem != NULL) { + + 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); + ARKodeButcherTable_Free(step_mem->B); + step_mem->B = NULL; + ark_mem->liw -= Bliw; + ark_mem->lrw -= Blrw; + } + + /* free the RHS vectors */ + if (step_mem->F != NULL) { + for(j=0; j<step_mem->stages; j++) + arkFreeVec(ark_mem, &step_mem->F[j]); + free(step_mem->F); + step_mem->F = NULL; + ark_mem->liw -= step_mem->stages; + } + + /* free the reusable arrays for fused vector interface */ + if (step_mem->cvals != NULL) { + free(step_mem->cvals); + step_mem->cvals = NULL; + ark_mem->lrw -= (step_mem->stages + 1); + } + if (step_mem->Xvecs != NULL) { + free(step_mem->Xvecs); + step_mem->Xvecs = NULL; + ark_mem->liw -= (step_mem->stages + 1); + } + + /* free the time stepper module itself */ + free(ark_mem->step_mem); + ark_mem->step_mem = NULL; + + } + + /* free memory for overall ARKode infrastructure */ + arkFree(arkode_mem); +} + + +/*--------------------------------------------------------------- + ERKStepPrintMem: + + This routine outputs the memory from the ERKStep structure and + the main ARKode infrastructure to a specified file pointer + (useful when debugging). + ---------------------------------------------------------------*/ +void ERKStepPrintMem(void* arkode_mem, FILE* outfile) +{ + ARKodeMem ark_mem; + ARKodeERKStepMem step_mem; + int retval; + + /* access ARKodeERKStepMem structure */ + retval = erkStep_AccessStepMem(arkode_mem, "ERKStepPrintMem", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return; + + /* output data from main ARKode infrastructure */ + arkPrintMem(ark_mem, outfile); + + /* output integer quantities */ + 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 */ + for (i=0; i<step_mem->stages; i++) { + fprintf(outfile,"ERKStep: F[%i]:\n", i); + N_VPrint_Serial(step_mem->F[i]); + } +#endif +} + + + +/*=============================================================== + ERKStep Private functions + ===============================================================*/ + +/*--------------------------------------------------------------- + Interface routines supplied to ARKode + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + erkStep_Init: + + 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). + + With init_type == 0, this routine: + - sets/checks the ARK Butcher tables to be used + - allocates any memory that depends on the number of ARK + stages, method order, or solver options + + With init_type == 1, this routine does nothing. + ---------------------------------------------------------------*/ +int erkStep_Init(void* arkode_mem, int init_type) +{ + ARKodeMem ark_mem; + ARKodeERKStepMem step_mem; + 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; + } + + /* Set first step growth factor */ + if (step_mem->hadapt_mem != NULL) + step_mem->hadapt_mem->etamax = step_mem->hadapt_mem->etamx1; + + /* Create Butcher table (if not already set) */ + retval = erkStep_SetButcherTable(ark_mem); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ERKStep", "erkStep_Init", + "Could not create Butcher table"); + return(ARK_ILL_INPUT); + } + + /* Check that Butcher table are OK */ + retval = erkStep_CheckButcherTable(ark_mem); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ERKStep", + "erkStep_Init", "Error in Butcher table"); + return(ARK_ILL_INPUT); + } + + /* note Butcher table space requirements */ + ARKodeButcherTable_Space(step_mem->B, &Bliw, &Blrw); + ark_mem->liw += Bliw; + ark_mem->lrw += Blrw; + + /* Allocate ARK RHS vector memory, update storage requirements */ + /* Allocate F[0] ... F[stages-1] if needed */ + if (step_mem->F == NULL) + step_mem->F = (N_Vector *) calloc(step_mem->stages, sizeof(N_Vector)); + for (j=0; j<step_mem->stages; j++) { + if (!arkAllocVec(ark_mem, ark_mem->ewt, &(step_mem->F[j]))) + return(ARK_MEM_FAIL); + } + ark_mem->liw += step_mem->stages; /* pointers */ + + /* Allocate reusable arrays for fused vector interface */ + if (step_mem->cvals == NULL) { + step_mem->cvals = (realtype *) calloc(step_mem->stages+1, sizeof(realtype)); + if (step_mem->cvals == NULL) return(ARK_MEM_FAIL); + ark_mem->lrw += (step_mem->stages + 1); + } + if (step_mem->Xvecs == NULL) { + step_mem->Xvecs = (N_Vector *) calloc(step_mem->stages+1, sizeof(N_Vector)); + if (step_mem->Xvecs == NULL) return(ARK_MEM_FAIL); + ark_mem->liw += (step_mem->stages + 1); /* pointers */ + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + erkStep_FullRHS: + + This is just a wrapper to call the user-supplied RHS function, + f(t,y). + + This will be called in one of three 'modes': + 0 -> called at the beginning of a simulation + 1 -> called at the end of a successful step + 2 -> called elsewhere (e.g. for dense output) + + If it is called in mode 0, we store the vectors f(t,y) in F[0] + for possible reuse in the first stage of the subsequent time step. + + If it is called in mode 1 and the method coefficients + support it, we may just copy vectors F[stages] to fill f instead + of calling f(). + + Mode 2 is only called for dense output in-between steps, so we + strive to store the intermediate parts so that they do not + interfere with the other two modes. + ---------------------------------------------------------------*/ +int erkStep_FullRHS(void* arkode_mem, realtype t, + N_Vector y, N_Vector f, int mode) +{ + ARKodeMem ark_mem; + ARKodeERKStepMem step_mem; + int i, s, retval; + booleantype recomputeRHS; + + /* access ARKodeERKStepMem structure */ + retval = erkStep_AccessStepMem(arkode_mem, "erkStep_FullRHS", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* perform RHS functions contingent on 'mode' argument */ + switch(mode) { + + /* Mode 0: called at the beginning of a simulation + Store the vectors f(t,y) in F[0] for possible reuse + in the first stage of the subsequent time step */ + case 0: + + /* call f */ + retval = step_mem->f(t, y, step_mem->F[0], ark_mem->user_data); + step_mem->nfe++; + if (retval != 0) { + arkProcessError(ark_mem, ARK_RHSFUNC_FAIL, "ARKode::ERKStep", + "erkStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); + return(ARK_RHSFUNC_FAIL); + } + + /* copy RHS vector into output */ + N_VScale(ONE, step_mem->F[0], f); + + break; + + + /* Mode 1: called at the end of a successful step + If the method coefficients support it, we just copy the last stage RHS vectors + to fill f instead of calling f(t,y). + Copy the results to F[0] if the coefficients support it. */ + case 1: + + /* determine if explicit/implicit RHS functions need to be recomputed */ + recomputeRHS = SUNFALSE; + s = step_mem->B->stages; + for (i=0; i<s; i++) + if (SUNRabs(step_mem->B->b[i] - step_mem->B->A[s-1][i])>TINY) + recomputeRHS = SUNTRUE; + + /* base RHS calls on recomputeRHS argument */ + if (recomputeRHS) { + + /* call f */ + retval = step_mem->f(t, y, step_mem->F[0], ark_mem->user_data); + step_mem->nfe++; + if (retval != 0) { + arkProcessError(ark_mem, ARK_RHSFUNC_FAIL, "ARKode::ERKStep", + "erkStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); + return(ARK_RHSFUNC_FAIL); + } + + } else { + N_VScale(ONE, step_mem->F[step_mem->stages-1], step_mem->F[0]); + } + + /* copy RHS vector into output */ + N_VScale(ONE, step_mem->F[0], f); + + break; + + /* Mode 2: called for dense output in-between steps + store the intermediate calculations in such a way as to not + interfere with the other two modes */ + default: + + /* call f */ + retval = step_mem->f(t, y, f, ark_mem->user_data); + step_mem->nfe++; + if (retval != 0) { + arkProcessError(ark_mem, ARK_RHSFUNC_FAIL, "ARKode::ERKStep", + "erkStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); + return(ARK_RHSFUNC_FAIL); + } + + break; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + 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. + ---------------------------------------------------------------*/ +int erkStep_TakeStep(void* arkode_mem) +{ + realtype dsm; + int retval, nef, is, eflag, js, nvec; + realtype* cvals; + N_Vector* Xvecs; + ARKodeMem ark_mem; + ARKodeERKStepMem step_mem; + + /* access ARKodeERKStepMem structure */ + retval = erkStep_AccessStepMem(arkode_mem, "erkStep_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; + + 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]); +#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; is<step_mem->stages; is++) { + + /* 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); +#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; js<is; js++) { + cvals[nvec] = ark_mem->h * 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); + + /* 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("RHS:\n"); + N_VPrint_Serial(step_mem->F[is]); +#endif + + } /* loop over stages */ + + /* compute time-evolved solution (in ark_ycur), error estimate (in dsm) */ + retval = erkStep_ComputeSolutions(ark_mem, &dsm); + if (retval < 0) return(retval); /* msetup failure */ + +#ifdef DEBUG_OUTPUT + printf("error estimate = %"RSYM"\n", dsm); + printf("updated solution:\n"); + N_VPrint_Serial(ark_mem->ycur); +#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); + + /* Perform time accuracy error test (if failure, updates h for next try) */ + if (!ark_mem->fixedstep) + eflag = erkStep_DoErrorTest(ark_mem, &nef, dsm); + +#ifdef DEBUG_OUTPUT + printf("error test flag = %i\n", eflag); +#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); + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + Internal utility routines + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + erkStep_AccessStepMem: + + Shortcut routine to unpack ark_mem and step_mem structures from + void* pointer. If either is missing it returns ARK_MEM_NULL. + ---------------------------------------------------------------*/ +int erkStep_AccessStepMem(void* arkode_mem, const char *fname, + ARKodeMem *ark_mem, ARKodeERKStepMem *step_mem) +{ + + /* access ARKodeMem structure */ + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::ARKStep", + fname, MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + *ark_mem = (ARKodeMem) arkode_mem; + if ((*ark_mem)->step_mem==NULL) { + arkProcessError(*ark_mem, ARK_MEM_NULL, "ARKode::ARKStep", + fname, MSG_ERKSTEP_NO_MEM); + return(ARK_MEM_NULL); + } + *step_mem = (ARKodeERKStepMem) (*ark_mem)->step_mem; + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + erkStep_CheckNVector: + + This routine checks if all required vector operations are + present. If any of them is missing it returns SUNFALSE. + ---------------------------------------------------------------*/ +booleantype erkStep_CheckNVector(N_Vector tmpl) +{ + if ( (tmpl->ops->nvclone == NULL) || + (tmpl->ops->nvdestroy == NULL) || + (tmpl->ops->nvlinearsum == NULL) || + (tmpl->ops->nvconst == NULL) || + (tmpl->ops->nvscale == NULL) || + (tmpl->ops->nvwrmsnorm == NULL) ) + return(SUNFALSE); + return(SUNTRUE); +} + + +/*--------------------------------------------------------------- + erkStep_SetButcherTable + + This routine determines the ERK method to use, based on the + desired accuracy. + ---------------------------------------------------------------*/ +int erkStep_SetButcherTable(ARKodeMem ark_mem) +{ + int etable; + ARKodeERKStepMem step_mem; + + /* access ARKodeERKStepMem structure */ + if (ark_mem->step_mem==NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", + "erkStep_SetButcherTable", MSG_ERKSTEP_NO_MEM); + return(ARK_MEM_NULL); + } + step_mem = (ARKodeERKStepMem) ark_mem->step_mem; + + /* if table has already been specified, just return */ + if (step_mem->B != NULL) + return(ARK_SUCCESS); + + /* initialize table number to illegal values */ + etable = -1; + + /* select method based on order */ + switch (step_mem->q) { + case(2): + etable = DEFAULT_ERK_2; + break; + case(3): + etable = DEFAULT_ERK_3; + break; + case(4): + etable = DEFAULT_ERK_4; + break; + case(5): + etable = DEFAULT_ERK_5; + break; + case(6): + etable = DEFAULT_ERK_6; + break; + case(7): + case(8): + etable = DEFAULT_ERK_8; + break; + default: /* no available method, set default */ + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ERKStep", + "erkStep_SetButcherTable", + "No explicit method at requested order, using q=6."); + etable = DEFAULT_ERK_6; + break; + } + + if (etable > -1) + step_mem->B = ARKodeButcherTable_LoadERK(etable); + + /* set [redundant] stored values for stage numbers and method orders */ + if (step_mem->B != NULL) { + step_mem->stages = step_mem->B->stages; + step_mem->q = step_mem->B->q; + step_mem->p = step_mem->B->p; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + erkStep_CheckButcherTable + + This routine runs through the explicit Butcher table to ensure + that it meets all necessary requirements, including: + strictly lower-triangular (ERK) + method order q > 0 (all) + embedding order q > 0 (all -- if adaptive time-stepping enabled) + stages > 0 (all) + + Returns ARK_SUCCESS if tables pass, ARK_ILL_INPUT otherwise. + ---------------------------------------------------------------*/ +int erkStep_CheckButcherTable(ARKodeMem ark_mem) +{ + int i, j; + booleantype okay; + ARKodeERKStepMem step_mem; + realtype tol = RCONST(1.0e-12); + + /* access ARKodeERKStepMem structure */ + if (ark_mem->step_mem==NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", + "erkStep_CheckButcherTable", MSG_ERKSTEP_NO_MEM); + return(ARK_MEM_NULL); + } + step_mem = (ARKodeERKStepMem) ark_mem->step_mem; + + /* check that stages > 0 */ + if (step_mem->stages < 1) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ERKStep", + "erkStep_CheckButcherTable", + "stages < 1!"); + return(ARK_ILL_INPUT); + } + + /* check that method order q > 0 */ + if (step_mem->q < 1) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ERKStep", + "erkStep_CheckButcherTable", + "method order < 1!"); + return(ARK_ILL_INPUT); + } + + /* check that embedding order p > 0 */ + if ((step_mem->p < 1) && (!ark_mem->fixedstep)) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ERKStep", + "erkStep_CheckButcherTable", + "embedding order < 1!"); + return(ARK_ILL_INPUT); + } + + /* check that embedding exists */ + if ((step_mem->p > 0) && (!ark_mem->fixedstep)) { + if (step_mem->B->d == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ERKStep", + "erkStep_CheckButcherTable", + "no embedding!"); + return(ARK_ILL_INPUT); + } + } + + /* check that ERK table is strictly lower triangular */ + okay = SUNTRUE; + for (i=0; i<step_mem->stages; i++) + for (j=i; j<step_mem->stages; j++) + if (SUNRabs(step_mem->B->A[i][j]) > tol) + okay = SUNFALSE; + if (!okay) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::ERKStep", + "erkStep_CheckButcherTable", + "Ae Butcher table is implicit!"); + return(ARK_ILL_INPUT); + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + erkStep_ComputeSolutions + + This routine calculates the final RK solution using the existing + data. This solution is placed directly in ark_ycur. This routine + also computes the error estimate ||y-ytilde||_WRMS, where ytilde + is the embedded solution, and the norm weights come from + ark_ewt. This norm value is returned. The vector form of this + estimated error (y-ytilde) is stored in ark_tempv1, in case the + calling routine wishes to examine the error locations. + + 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) +{ + /* local data */ + int retval, j, nvec; + N_Vector y, yerr; + realtype* cvals; + N_Vector* Xvecs; + ARKodeERKStepMem step_mem; + + /* access ARKodeERKStepMem structure */ + if (ark_mem->step_mem==NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", + "erkStep_ComputeSolutions", MSG_ERKSTEP_NO_MEM); + return(ARK_MEM_NULL); + } + step_mem = (ARKodeERKStepMem) ark_mem->step_mem; + + /* set N_Vector shortcuts */ + y = ark_mem->ycur; + yerr = ark_mem->tempv1; + + /* local shortcuts for fused vector operations */ + cvals = step_mem->cvals; + Xvecs = step_mem->Xvecs; + + /* initialize output */ + *dsm = ZERO; + + + /* Compute time step solution */ + /* set arrays for fused vector operation */ + nvec = 0; + for (j=0; j<step_mem->stages; j++) { + cvals[nvec] = ark_mem->h * step_mem->B->b[j]; + Xvecs[nvec] = step_mem->F[j]; + 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, y); + if (retval != 0) return(ARK_VECTOROP_ERR); + + /* Compute yerr (if step adaptivity enabled) */ + if (!ark_mem->fixedstep) { + + /* set arrays for fused vector operation */ + nvec = 0; + for (j=0; j<step_mem->stages; j++) { + cvals[nvec] = ark_mem->h * (step_mem->B->b[j] - step_mem->B->d[j]); + Xvecs[nvec] = step_mem->F[j]; + nvec += 1; + } + + /* call fused vector operation to do the work */ + retval = N_VLinearCombination(nvec, cvals, Xvecs, yerr); + 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); + } + + /* 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); +} + + +/*=============================================================== + EOF + ===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_erkstep_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_erkstep_impl.h new file mode 100644 index 0000000..017ef41 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_erkstep_impl.h @@ -0,0 +1,108 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * Implementation header file for ARKode's ERK time stepper + * module. + *--------------------------------------------------------------*/ + +#ifndef _ARKODE_ERKSTEP_IMPL_H +#define _ARKODE_ERKSTEP_IMPL_H + +#include <arkode/arkode_erkstep.h> +#include "arkode_impl.h" + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*=============================================================== + ERK time step module constants -- move many items here from + arkode_impl.h + ===============================================================*/ + + + +/*=============================================================== + ERK time step module data structure + ===============================================================*/ + +/*--------------------------------------------------------------- + Types : struct ARKodeERKStepMemRec, ARKodeERKStepMem + --------------------------------------------------------------- + The type ARKodeERKStepMem is type pointer to struct + ARKodeERKStepMemRec. This structure contains fields to + perform an explicit Runge-Kutta time step. + ---------------------------------------------------------------*/ +typedef struct ARKodeERKStepMemRec { + + /* ERK problem specification */ + ARKRhsFn f; /* y' = f(t,y) */ + + /* ARK method storage and parameters */ + N_Vector *F; /* explicit RHS at each stage */ + int q; /* method order */ + int p; /* embedding order */ + 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 */ + + /* Reusable arrays for fused vector operations */ + realtype* cvals; + N_Vector* Xvecs; + +} *ARKodeERKStepMem; + + +/*=============================================================== + ERK time step module private function prototypes + ===============================================================*/ + +/* Interface routines supplied to ARKode */ +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); + +/* Internal utility routines */ +int erkStep_AccessStepMem(void* arkode_mem, const char *fname, + ARKodeMem *ark_mem, ARKodeERKStepMem *step_mem); +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 + ===============================================================*/ + +/* Initialization and I/O error messages */ +#define MSG_ERKSTEP_NO_MEM "Time step module memory is NULL." + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_erkstep_io.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_erkstep_io.c new file mode 100644 index 0000000..750bead --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_erkstep_io.c @@ -0,0 +1,1529 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 the optional input and + * output functions for the ARKode ERKStep time stepper module. + * + * NOTE: many functions currently in arkode_io.c will move here, + * with slightly different names. The code transition will be + * minimal, but the documentation changes will be significant. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "arkode_erkstep_impl.h" +#include <sundials/sundials_math.h> +#include <sundials/sundials_types.h> + +#if defined(SUNDIALS_EXTENDED_PRECISION) +#define RSYM "Lg" +#else +#define RSYM "g" +#endif + + +/*=============================================================== + ERKStep Optional input functions (wrappers for generic ARKode + utility routines) + ===============================================================*/ + +/*--------------------------------------------------------------- + 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 (itable<MIN_ERK_NUM || itable>MAX_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; + + /* 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); +} + + +/*--------------------------------------------------------------- + ERKStepSetAdaptivityMethod: + + 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 ERKStepSetAdaptivityMethod(void *arkode_mem, int imethod, + int idefault, int pq, + realtype *adapt_params) +{ + ARKodeMem ark_mem; + ARKodeERKStepMem step_mem; + ARKodeHAdaptMem hadapt_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetAdaptivityMethod", + &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]; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ERKStepSetAdaptivityFn: + + Specifies the user-provided time step adaptivity function to use. + ---------------------------------------------------------------*/ +int ERKStepSetAdaptivityFn(void *arkode_mem, ARKAdaptFn hfun, + void *h_data) +{ + ARKodeMem ark_mem; + ARKodeERKStepMem step_mem; + ARKodeHAdaptMem hadapt_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetAdaptivityFn", + &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; + } 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); + } + 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); +} + + +/*--------------------------------------------------------------- + ERKStepSetMaxEFailGrowth: + + 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 ERKStepSetMaxEFailGrowth(void *arkode_mem, realtype etamxf) +{ + ARKodeMem ark_mem; + ARKodeERKStepMem step_mem; + ARKodeHAdaptMem hadapt_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetMaxEFailGrowth", + &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", + "ERKStepSetMaxEFailGrowth", 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); +} + + +/*--------------------------------------------------------------- + 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; + + /* access ARKodeARKStepMem structure */ + retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetSmallNumEFails", + &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", + "ERKStepSetSmallNumEFails", 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); +} + + +/*--------------------------------------------------------------- + ERKStepSetStabilityFn: + + Specifies the user-provided explicit time step stability + function to use. A NULL input function implies a reset to + the default function (empty). + ---------------------------------------------------------------*/ +int ERKStepSetStabilityFn(void *arkode_mem, ARKExpStabFn EStab, + void *estab_data) +{ + ARKodeMem ark_mem; + ARKodeERKStepMem step_mem; + ARKodeHAdaptMem hadapt_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = erkStep_AccessStepMem(arkode_mem, "ERKStepSetStabilityFn", + &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", + "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; + } + + 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); + + /* argument <= 0 sets default, otherwise set input */ + if (maxnef <= 0) { + step_mem->maxnef = MAXNEF; + } else { + step_mem->maxnef = maxnef; + } + + return(ARK_SUCCESS); +} + + +/*=============================================================== + 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: + + Returns the current number of calls to fe and fi + ---------------------------------------------------------------*/ +int ERKStepGetNumRhsEvals(void *arkode_mem, long int *fevals) +{ + ARKodeMem ark_mem; + ARKodeERKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = erkStep_AccessStepMem(arkode_mem, "ERKStepGetNumRhsEvals", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* get values from step_mem */ + *fevals = step_mem->nfe; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + 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: + + Sets pointers to the Butcher table currently in use. + ---------------------------------------------------------------*/ +int ERKStepGetCurrentButcherTable(void *arkode_mem, + ARKodeButcherTable *B) +{ + ARKodeMem ark_mem; + ARKodeERKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = erkStep_AccessStepMem(arkode_mem, "ERKStepGetCurrentButcherTable", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* get tables from step_mem */ + *B = step_mem->B; + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ERKStepGetEstLocalErrors: (updated to the correct vector, but + need to verify that it is unchanged between filling the + estimated error and the end of the time step) + + Returns an estimate of the local error + ---------------------------------------------------------------*/ +int ERKStepGetEstLocalErrors(void *arkode_mem, N_Vector ele) +{ + ARKodeMem ark_mem; + ARKodeERKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = erkStep_AccessStepMem(arkode_mem, "ERKStepGetEstLocalErrors", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* copy vector to output */ + N_VScale(ONE, ark_mem->tempv1, ele); + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + ERKStepGetTimestepperStats: + + Returns integrator statistics + ---------------------------------------------------------------*/ +int ERKStepGetTimestepperStats(void *arkode_mem, long int *expsteps, + long int *accsteps, long int *attempts, + long int *fevals, long int *netfails) +{ + ARKodeMem ark_mem; + ARKodeERKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = erkStep_AccessStepMem(arkode_mem, "ERKStepGetTimestepperStats", + &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 remaining outputs from step_mem */ + *attempts = step_mem->nst_attempts; + *fevals = step_mem->nfe; + *netfails = step_mem->netf; + + return(ARK_SUCCESS); +} + + +/*=============================================================== + ERKStep parameter output + ===============================================================*/ + +/*--------------------------------------------------------------- + ERKStepWriteParameters: + + Outputs all solver parameters to the provided file pointer. + ---------------------------------------------------------------*/ +int ERKStepWriteParameters(void *arkode_mem, FILE *fp) +{ + ARKodeMem ark_mem; + ARKodeERKStepMem step_mem; + int retval; + + /* access ARKodeARKStepMem structure */ + retval = erkStep_AccessStepMem(arkode_mem, "ERKStepWriteParameters", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* output ARKode infrastructure parameters first */ + retval = arkWriteParameters(arkode_mem, fp); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", + "ERKStepWriteParameters", + "Error writing ARKode infrastructure parameters"); + return(retval); + } + + /* 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); +} + + +/*--------------------------------------------------------------- + ERKStepWriteButcher: + + Outputs Butcher tables to the provided file pointer. + ---------------------------------------------------------------*/ +int ERKStepWriteButcher(void *arkode_mem, FILE *fp) +{ + int retval; + ARKodeMem ark_mem; + ARKodeERKStepMem step_mem; + + /* access ARKodeARKStepMem structure */ + retval = erkStep_AccessStepMem(arkode_mem, "ERKStepWriteButcher", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* check that Butcher table is non-NULL (otherwise report error) */ + if (step_mem->B == NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::ERKStep", + "ERKStepWriteButcher", "Butcher table memory is NULL"); + return(ARK_MEM_NULL); + } + + /* print Butcher table to file */ + fprintf(fp, "\nERKStep Butcher table (stages = %i):\n", step_mem->stages); + ARKodeButcherTable_Write(step_mem->B, fp); + fprintf(fp, "\n"); + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + EOF + ---------------------------------------------------------------*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_impl.h new file mode 100644 index 0000000..cb868ca --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_impl.h @@ -0,0 +1,1085 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * Implementation header file for the main ARKode integrator. + *--------------------------------------------------------------*/ + +#ifndef _ARKODE_IMPL_H +#define _ARKODE_IMPL_H + +#include <stdarg.h> +#include <arkode/arkode.h> +#include <arkode/arkode_butcher.h> +#include "arkode_adapt_impl.h" +#include "arkode_interp_impl.h" +#include "arkode_root_impl.h" + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*=============================================================== + 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 */ + +/* 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 +#define ARK_SV 1 +#define ARK_WF 2 + + +/*=============================================================== + ARKode Routine-Specific Constants + ===============================================================*/ + +/*--------------------------------------------------------------- + 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 + ---------------------------------------------------------------*/ +#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 + + +/*--------------------------------------------------------------- + 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 + + +/*--------------------------------------------------------------- + Algorithmic constants + --------------------------------------------------------------- + ARKodeGetDky and arkStep: FUZZ_FACTOR + + 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 + 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) + +#define H0_LBFACTOR RCONST(100.0) +#define H0_UBFACTOR RCONST(0.1) +#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 */ + + +/*=============================================================== + ARKode Interface function definitions + ===============================================================*/ + +/* NOTE: documentation for the purpose of these functions is + located at the end of this file */ + +/* linear solver interface functions */ +typedef int (*ARKLinsolInitFn)(void* arkode_mem); +typedef int (*ARKLinsolSetupFn)(void* arkode_mem, int convfail, + realtype tpred, N_Vector ypred, + N_Vector fpred, + booleantype *jcurPtr, + N_Vector vtemp1, + N_Vector vtemp2, N_Vector vtemp3); +typedef int (*ARKLinsolSolveFn)(void* arkode_mem, N_Vector b, + realtype tcur, N_Vector ycur, + N_Vector fcur, realtype client_tol, + int mnewt); +typedef int (*ARKLinsolFreeFn)(void* arkode_mem); + +/* mass-matrix solver interface functions */ +typedef int (*ARKMassInitFn)(void *arkode_mem); +typedef int (*ARKMassSetupFn)(void *arkode_mem, N_Vector vtemp1, + N_Vector vtemp2, N_Vector vtemp3); +typedef int (*ARKMassMultFn)(void *arkode_mem, N_Vector v, + N_Vector Mv); +typedef int (*ARKMassSolveFn)(void *arkode_mem, N_Vector b, + realtype client_tol); +typedef int (*ARKMassFreeFn)(void *arkode_mem); + +/* time stepper interface functions */ +typedef int (*ARKTimestepInitFn)(void* arkode_mem, int init_type); +typedef int (*ARKTimestepAttachLinsolFn)(void* arkode_mem, + ARKLinsolInitFn linit, + ARKLinsolSetupFn lsetup, + ARKLinsolSolveFn lsolve, + ARKLinsolFreeFn lfree, + int lsolve_type, + void *lmem); +typedef int (*ARKTimestepAttachMasssolFn)(void* arkode_mem, + ARKMassInitFn minit, + ARKMassSetupFn msetup, + ARKMassMultFn mmult, + ARKMassSolveFn msolve, + ARKMassFreeFn mfree, + int msolve_type, + void *mass_mem); +typedef void (*ARKTimestepDisableLSetup)(void* arkode_mem); +typedef void (*ARKTimestepDisableMSetup)(void* arkode_mem); +typedef void* (*ARKTimestepGetLinMemFn)(void* arkode_mem); +typedef void* (*ARKTimestepGetMassMemFn)(void* arkode_mem); +typedef ARKRhsFn (*ARKTimestepGetImplicitRHSFn)(void* arkode_mem); +typedef int (*ARKTimestepGetGammasFn)(void* arkode_mem, + realtype *gamma, + realtype *gamrat, + booleantype **jcur, + 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); + + +/*=============================================================== + ARKode data structures + ===============================================================*/ + +/*--------------------------------------------------------------- + Types : struct ARKodeMassMemRec, ARKodeMassMem + --------------------------------------------------------------- + The type ARKodeMassMem is type pointer to struct + ARKodeMassMemRec. This structure contains data pertaining to + the use of a non-identity mass matrix. + ---------------------------------------------------------------*/ +typedef struct ARKodeMassMemRec { + + /* mass matrix linear solver interface function pointers */ + ARKMassInitFn minit; + ARKMassSetupFn msetup; + ARKMassMultFn mmult; + ARKMassSolveFn msolve; + ARKMassFreeFn mfree; + void* sol_mem; /* mass matrix solver interface data */ + int msolve_type; /* mass matrix interface type: + 0=iterative; 1=direct; 2=custom */ + +} *ARKodeMassMem; + + +/*--------------------------------------------------------------- + Types : struct ARKodeMemRec, ARKodeMem + --------------------------------------------------------------- + The type ARKodeMem is type pointer to struct ARKodeMemRec. + This structure contains fields to keep track of problem state. + ---------------------------------------------------------------*/ +typedef struct ARKodeMemRec { + + 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 */ + + /* Time stepper module */ + ARKTimestepAttachLinsolFn step_attachlinsol; + ARKTimestepAttachMasssolFn step_attachmasssol; + ARKTimestepDisableLSetup step_disablelsetup; + ARKTimestepDisableMSetup step_disablemsetup; + ARKTimestepGetLinMemFn step_getlinmem; + ARKTimestepGetMassMemFn step_getmassmem; + ARKTimestepGetImplicitRHSFn step_getimplicitrhs; + ARKMassMultFn step_mmult; + ARKTimestepGetGammasFn step_getgammas; + ARKTimestepInitFn step_init; + ARKTimestepFullRHSFn step_fullrhs; + ARKTimestepStepFn step; + 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 tempv3; + N_Vector tempv4; + + /* Temporal interpolation module */ + ARKodeInterpMem interp; + int dense_q; /* interpolation order (user request) */ + + /* 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 */ + + + /* 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 */ + + /* 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 */ + + /* Diagnostic output */ + booleantype report; /* flag to enable/disable diagnostic output */ + FILE *diagfp; /* diagnostic outputs are sent to diagfp */ + + /* Space requirements for ARKode */ + sunindextype lrw1; /* no. of realtype words in 1 N_Vector */ + sunindextype liw1; /* no. of integer words in 1 N_Vector */ + long int lrw; /* no. of realtype words in ARKode work vectors */ + long int liw; /* no. of integer words in ARKode work vectors */ + + /* Saved Values */ + realtype h0u; /* actual initial stepsize */ + realtype tn; /* time of last successful step */ + realtype hold; /* last successful h value used */ + realtype tolsf; /* tolerance scale factor (suggestion to user) */ + booleantype VabstolMallocDone; + booleantype VRabstolMallocDone; + booleantype MallocDone; + booleantype resized; /* denotes first step after ARKodeResize */ + booleantype firststage; /* denotes first stage in simulation */ + + /* Error handler function and error ouput file */ + ARKErrHandlerFn ehfun; /* error messages are handled by ehfun */ + void *eh_data; /* data pointer passed to ehfun */ + FILE *errfp; /* ARKode error messages are sent to errfp */ + + /* Rootfinding Data */ + ARKodeRootMem root_mem; /* root-finding structure */ + + /* User-supplied step solution post-processing function */ + ARKPostProcessStepFn ProcessStep; + +} *ARKodeMem; + + + +/*=============================================================== + Interface To Linear Solvers + ===============================================================*/ + +/*--------------------------------------------------------------- + Communication between ARKode and a ARKode Linear Solver + ----------------------------------------------------------------- + convfail (input to lsetup) + + ARK_NO_FAILURES : Either this is the first lsetup call for + this step, or the local error test failed on + the previous attempt at this step (but the + Newton iteration converged). + + ARK_FAIL_BAD_J : This value is passed to lsetup if + + (a) The previous Newton corrector iteration + did not converge and the linear solver's + setup routine indicated that its Jacobian- + related data is not current + or + (b) During the previous Newton corrector + iteration, the linear solver's solve + routine failed in a recoverable manner + and the linear solver's setup routine + indicated that its Jacobian-related data + is not current. + + ARK_FAIL_OTHER : During the current internal step try, the + previous Newton iteration failed to converge + even though the linear solver was using + current Jacobian-related data. + --------------------------------------------------------------*/ + +/* Constants for convfail (input to lsetup) */ +#define ARK_NO_FAILURES 0 +#define ARK_FAIL_BAD_J 1 +#define ARK_FAIL_OTHER 2 + +/*--------------------------------------------------------------- + ARKLinsolInitFn + --------------------------------------------------------------- + This function should complete initializations for a specific + ARKode linear solver interface, such as counters and statistics. + This should return 0 if it has successfully initialized the + ARKode linear solver interface and a negative value otherwise. + If an error does occur, an appropriate message should be sent + to the error handler function. + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + ARKLinsolSetupFn + --------------------------------------------------------------- + This function should prepare the linear solver interface for + subsequent calls to the ARKLinsolSolveFn routine. It may + recompute Jacobian-related data is it deems necessary. Its + parameters are as follows: + + arkode_mem - void* problem memory pointer of type ARKodeMem. See + the typedef earlier in this file. + + convfail - a flag to indicate any problem that occurred during + the solution of the nonlinear equation on the + current time step for which the linear solver is + being used. This flag can be used to help decide + whether the Jacobian data kept by a ARKode linear + solver needs to be updated or not. + Its possible values have been documented above. + + tpred - the time for the current ARKode internal step. + + ypred - the predicted y vector for the current ARKode internal + step. + + fpred - f(tpred, ypred). + + jcurPtr - a pointer to a boolean to be filled in by lsetup. + The function should set *jcurPtr=SUNTRUE if its Jacobian + data is current after the call and should set + *jcurPtr=SUNFALSE if its Jacobian data is not current. + Note: If lsetup calls for re-evaluation of + Jacobian data (based on convfail and ARKode state + data), it should return *jcurPtr=SUNTRUE always; + otherwise an infinite loop can result. + + vtemp1 - temporary N_Vector provided for use by lsetup. + + vtemp3 - temporary N_Vector provided for use by lsetup. + + vtemp3 - temporary N_Vector provided for use by lsetup. + + This routine should return 0 if successful, a positive value + for a recoverable error, and a negative value for an + unrecoverable error. + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + ARKLinsolSolveFn + --------------------------------------------------------------- + This routine must solve the linear equation P x = b, where + P is some approximation to (M - gamma J), M is the system mass + matrix, J = (df/dy)(tcur,ycur), and the RHS vector b is input. The + N-vector ycur contains the solver's current approximation to + y(tcur) and the vector fcur contains the N_Vector f(tcur,ycur). + The input client_tol contains the desired accuracy (in the wrms + norm) of the routine calling the solver; the ARKDLS solver + ignores this value and the ARKSPILS solver tightens it by the + factor eplifac. The input mnewt is the current nonlinear + iteration index (ignored by ARKDLS, used by ARKSPILS). + + Additional vectors that are set within the ARKode memory + structure, and that may be of use within an iterative linear + solver, include: + + ewt - the error weight vector (scaling for solution vector) + + rwt - the residual weight vector (scaling for rhs vector) + + The solution is to be returned in the vector b. This should + return a positive value for a recoverable error and a + negative value for an unrecoverable error. Success is + indicated by a 0 return value. + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + ARKLinsolFreeFn + --------------------------------------------------------------- + This should free up any memory allocated by the linear solver + interface. This routine is called once a problem has been + completed and the linear solver is no longer needed. It should + return 0 upon success, or a nonzero on failure. + ---------------------------------------------------------------*/ + + + +/*--------------------------------------------------------------- + ARKMassInitFn + --------------------------------------------------------------- + This function should complete initializations for a specific + mass matrix linear solver interface, such as counters and + statistics. A function of this type should return 0 if it + has successfully initialized the mass matrix linear solver and + a negative value otherwise. If an error does occur, an + appropriate message should be sent to the error handler function. + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + ARKMassSetupFn + --------------------------------------------------------------- + This should prepare the mass matrix solver interface for + subsequent calls to the ARKMassMultFn and ARKMassSolveFn + routines. It may recompute mass matrix related data is it deems + necessary. Its parameters are as follows: + + arkode_mem - void* problem memory pointer of type ARKodeMem. See + the typedef earlier in this file. + + vtemp1, vtemp2, vtemp3 - temporary N_Vectors + + This routine should return 0 if successful, and a negative + value for an unrecoverable error. + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + ARKMassMultFn + --------------------------------------------------------------- + This must compute the matrix-vector product, z = M*v, where M is + the system mass matrix the vector v is input, and the vector z + is output. The mmult routine returns a positive value for a + recoverable error and a negative value for an unrecoverable + error. Success is indicated by a 0 return value. + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + ARKMassSolveFn + --------------------------------------------------------------- + This must solve the linear equation M x = b, where M is the + system mass matrix, and the RHS vector b is input. The + realtype client_tol contains the desired accuracy (in the wrms + norm) of the routine calling the solver; the ARKDLS solver + ignore this value and the ARKSPILS solver tightens it by the + factor eplifac. The solution is to be returned in the vector b. + + Additional vectors that are set within the ARKode memory + structure, and that may be of use within an iterative linear + solver, include: + + ewt - the error weight vector (scaling for solution vector) + + rwt - the residual weight vector (scaling for rhs vector) + + This routine should return a positive value for a recoverable + error and a negative value for an unrecoverable error. Success + is indicated by a 0 return value. + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + ARKMassFreeFn + --------------------------------------------------------------- + This should free up any memory allocated by the mass matrix + solver interface. This routine is called once a problem has been + completed and the solver is no longer needed. It should return + 0 upon success, or a nonzero on failure. + ---------------------------------------------------------------*/ + + + + +/*=============================================================== + Interface to Time Steppers + ===============================================================*/ + +/*--------------------------------------------------------------- + ARKTimestepAttachLinsolFn + --------------------------------------------------------------- + This routine should attach the various set of system linear + 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). + + This routine should return 0 if it has successfully attached + these items and a negative value otherwise. If an error does + occur, an appropriate message should be sent to the ARKode + error handler function. + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + ARKTimestepAttachMasssolFn + --------------------------------------------------------------- + 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). + + This routine should return 0 if it has successfully attached + these items, and a negative value otherwise. If an error does + occur, an appropriate message should be sent to the ARKode + error handler function. + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + ARKTimestepDisableLSetup + --------------------------------------------------------------- + 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. + + This routine has no return value. + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + ARKTimestepDisableMSetup + --------------------------------------------------------------- + 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. + + This routine has no return value. + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + ARKTimestepGetLinMemFn + --------------------------------------------------------------- + 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). + + This routine should return NULL if no linear solver memory + structure is attached. + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + ARKTimestepGetMassMemFn + --------------------------------------------------------------- + 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). + + This routine should return NULL if no mass matrix solver memory + structure is attached. + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + ARKTimestepGetImplicitRHSFn + --------------------------------------------------------------- + This routine should return the implicit RHS function pointer for + the current nonlinear solve (if there are multiple); it is used + inside the linear solver interfaces for approximation of + Jacobian matrix elements and/or matrix-vector products. + + This routine should return NULL if no implicit RHS function is + active. + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + ARKTimestepGetGammasFn + --------------------------------------------------------------- + This routine should fill the current value of gamma, the ratio + of the current gamma value to the gamma value when the + Jacobian/preconditioner was last updated, a pointer to the + time step module internal booleantype variable indicating + whether the preconditioner is current, and a logic value + indicating whether the gamma value is sufficiently stale + to cause recomputation of Jacobian/preconditioner data. Here, + gamma is the coefficient preceding the RHS Jacobian + matrix, J, in the full nonlinear system Jacobian, + A = M - gamma*J. + + 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. + + The value of the logic flag is used as follows: if a previous + Newton iteration failed due to a bad Jacobian/preconditioner, + and this flag is SUNFALSE, this will trigger recalculation of + the Jacobian/preconditioner. + + This routine should return 0 if it has successfully attached + these items, and a negative value otherwise. If an error does + occur, an appropriate message should be sent to the ARKode + error handler function. + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + ARKTimestepInitFn + --------------------------------------------------------------- + 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. + + This routine should return 0 if it has successfully initialized + the ARKode time stepper module and a negative value otherwise. + If an error does occur, an appropriate message should be sent + to the error handler function. + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + ARKTimestepFullRHSFn + --------------------------------------------------------------- + This routine must compute the full ODE right-hand side function + at the inputs (t,y), and store the result in the N_Vector f. + Depending on the type of stepper, this may be just the single + ODE RHS function supplied (e.g. ERK, DIRK, IRK), or it may be + the sum of many ODE RHS functions (e.g. ARK, MRI). The 'mode' + flag indicates where this routine is called: + 0 -> called at the beginning of a simulation + 1 -> called at the end of a successful step + 2 -> called elsewhere (e.g. for dense output) + It is recommended that the stepper use the mode information to + maximize reuse between calls to this function and RHS + evaluations inside the stepper itself. + + This routine should return 0 if successful, and a negative value + otherwise. If an error does occur, an appropriate message + should be sent to the error handler function. + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + 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). + + It is assumed that this routine uses/modifies general problem + data directly out of the main ARKodeMem structure, but that all + method-specific data be stored in the step-module-specific data + structure. Relevant items in the ARKodeMem structure for this + purpose include: + - tcur -- the current "t" value + - ycur -- the current "y" value on input; should hold the + time-evolved solution on output + - h -- the suggested/maximum "h" value to use; if the step + eventually completes with a smaller "h" value, then that + 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 + to be saved to disk, the report flag indicates whether + 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. + ---------------------------------------------------------------*/ + + +/*=============================================================== + 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); + +/* Prototype of internal errHandler function */ +void arkErrHandler(int error_code, const char *module, + const char *function, char *msg, void *data); + +/* Prototype of internal explicit stability estimation function */ +int arkExpStab(N_Vector y, realtype t, realtype *hstab, void *user_data); + +/*=============================================================== + HIGH LEVEL ERROR HANDLER, USED THROUGHOUT ARKode + ===============================================================*/ + +void arkProcessError(ARKodeMem ark_mem, int error_code, + const char *module, const char *fname, + const char *msgfmt, ...); + +/*=============================================================== + ARKode PRIVATE FUNCTION PROTOTYPES + ===============================================================*/ +#ifdef __GNUC__ +#define SUNDIALS_UNUSED __attribute__ ((unused)) +#else +#define SUNDIALS_UNUSED +#endif + +int arkInit(ARKodeMem ark_mem, realtype t0, N_Vector y0); +int arkReInit(ARKodeMem ark_mem, realtype t0, N_Vector y0); +booleantype arkAllocVec(ARKodeMem ark_mem, + N_Vector tmpl, + N_Vector *v); +void arkFreeVec(ARKodeMem ark_mem, N_Vector *v); +int arkResizeVec(ARKodeMem ark_mem, + ARKVecResizeFn resize, + void *resize_data, + sunindextype lrw_diff, + sunindextype liw_diff, + N_Vector tmpl, + N_Vector *v); +void arkPrintMem(ARKodeMem ark_mem, FILE *outfile); +booleantype arkCheckTimestepper(ARKodeMem ark_mem); +booleantype arkCheckNvector(N_Vector tmpl); +booleantype arkAllocVectors(ARKodeMem ark_mem, + N_Vector tmpl); +void arkFreeVectors(ARKodeMem ark_mem); + +int arkInitialSetup(ARKodeMem ark_mem, realtype tout); +int arkPostResizeSetup(ARKodeMem ark_mem); +int arkStopTests(ARKodeMem ark_mem, realtype tout, N_Vector yout, + realtype *tret, int itask, int *ier); +int arkHin(ARKodeMem ark_mem, realtype tout); +realtype arkUpperBoundH0(ARKodeMem ark_mem, + realtype tdist); +int arkYddNorm(ARKodeMem ark_mem, realtype hg, + realtype *yddnrm); + +int arkCompleteStep(ARKodeMem ark_mem); +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 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); +int arkSStolerances(ARKodeMem ark_mem, realtype reltol, realtype abstol); +int arkSVtolerances(ARKodeMem ark_mem, realtype reltol, N_Vector abstol); +int arkWFtolerances(ARKodeMem ark_mem, ARKEwtFn efun); +int arkResStolerance(ARKodeMem ark_mem, realtype rabstol); +int arkResVtolerance(ARKodeMem ark_mem, N_Vector rabstol); +int arkResFtolerance(ARKodeMem ark_mem, ARKRwtFn rfun); +int arkRootInit(ARKodeMem ark_mem, int nrtfn, ARKRootFn g); +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); +int arkPredict_VariableOrder(ARKodeMem ark_mem, realtype tau, + N_Vector yguess); +int arkPredict_CutoffOrder(ARKodeMem ark_mem, realtype tau, + N_Vector yguess); +int arkPredict_Bootstrap(ARKodeMem ark_mem, realtype hj, + realtype tau, int nvec, realtype *cvals, + N_Vector *Xvecs, N_Vector yguess); + + +/*=============================================================== + Reusable ARKode Error Messages + ===============================================================*/ + +#if defined(SUNDIALS_EXTENDED_PRECISION) + +#define MSG_TIME "t = %Lg" +#define MSG_TIME_H "t = %Lg and h = %Lg" +#define MSG_TIME_INT "t = %Lg is not between tcur - hold = %Lg and tcur = %Lg." +#define MSG_TIME_TOUT "tout = %Lg" +#define MSG_TIME_TSTOP "tstop = %Lg" + +#elif defined(SUNDIALS_DOUBLE_PRECISION) + +#define MSG_TIME "t = %lg" +#define MSG_TIME_H "t = %lg and h = %lg" +#define MSG_TIME_INT "t = %lg is not between tcur - hold = %lg and tcur = %lg." +#define MSG_TIME_TOUT "tout = %lg" +#define MSG_TIME_TSTOP "tstop = %lg" + +#else + +#define MSG_TIME "t = %g" +#define MSG_TIME_H "t = %g and h = %g" +#define MSG_TIME_INT "t = %g is not between tcur - hold = %g and tcur = %g." +#define MSG_TIME_TOUT "tout = %g" +#define MSG_TIME_TSTOP "tstop = %g" + +#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." + +/* 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)." +#define MSG_ARK_EWT_NOW_BAD "At " MSG_TIME ", a component of ewt has become <= 0." +#define MSG_ARK_BAD_RWT "Initial rwt has component(s) equal to zero (illegal)." +#define MSG_ARK_RWT_NOW_BAD "At " MSG_TIME ", a component of rwt has become <= 0." +#define MSG_ARK_BAD_ITASK "Illegal value for itask." +#define MSG_ARK_BAD_H0 "h0 and tout - t0 inconsistent." +#define MSG_ARK_BAD_TOUT "Trouble interpolating at " MSG_TIME_TOUT ". tout too far back in direction of integration" +#define MSG_ARK_EWT_FAIL "The user-provide EwtSet function failed." +#define MSG_ARK_EWT_NOW_FAIL "At " MSG_TIME ", the user-provide EwtSet function failed." +#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." +#define MSG_ARK_TOO_MUCH_ACC "At " MSG_TIME ", too much accuracy requested." +#define MSG_ARK_HNIL "Internal " MSG_TIME_H " are such that t + h = t on the next step. The solver will continue anyway." +#define MSG_ARK_ERR_FAILS "At " MSG_TIME_H ", the error test failed repeatedly or with |h| = hmin." +#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_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_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." + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_interp.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_interp.c new file mode 100644 index 0000000..f0bf538 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_interp.c @@ -0,0 +1,611 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 ARKode's temporal + * interpolation utility. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <math.h> + +#include "arkode_impl.h" +#include <sundials/sundials_math.h> +#include <sundials/sundials_types.h> + +#if defined(SUNDIALS_EXTENDED_PRECISION) +#define RSYM ".32Lg" +#else +#define RSYM ".16g" +#endif + +#define NO_DEBUG_OUTPUT +#ifdef DEBUG_OUTPUT +#include <nvector/nvector_serial.h> +#endif + + +/*--------------------------------------------------------------- + arkInterpCreate: + + This routine creates an ARKodeInterpMem 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) +{ + 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; + + /* 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); + + /* 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); + + return(interp_mem); +} + + +/*--------------------------------------------------------------- + arkInterpResize: + + This routine resizes the internal vectors in an ARKodeInterpMem + structure. + ---------------------------------------------------------------*/ +int arkInterpResize(void* arkode_mem, ARKodeInterpMem interp_mem, + ARKVecResizeFn resize, void *resize_data, + sunindextype lrw_diff, sunindextype liw_diff, + N_Vector y0) +{ + int ier; + ARKodeMem ark_mem; + + /* access ARKodeMem structure */ + if (arkode_mem == NULL) return(ARK_MEM_NULL); + 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) { + ier = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + liw_diff, y0, &interp_mem->fnew); + if (ier != ARK_SUCCESS) return(ier); + } + if (interp_mem->yold != NULL) { + ier = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + liw_diff, y0, &interp_mem->yold); + if (ier != ARK_SUCCESS) return(ier); + } + if (interp_mem->fa != NULL) { + ier = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + liw_diff, y0, &interp_mem->fa); + if (ier != ARK_SUCCESS) return(ier); + } + if (interp_mem->fb != NULL) { + ier = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + liw_diff, y0, &interp_mem->fb); + 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; + + /* 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); + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkInterpFree: + + This routine frees an ARKodeInterpMem structure. + ---------------------------------------------------------------*/ +void arkInterpFree(ARKodeInterpMem *interp_mem) +{ + 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); + } +} + + +/*--------------------------------------------------------------- + arkPrintInterpMem + + This routine outputs the temporal interpolation memory structure + to a specified file pointer. + ---------------------------------------------------------------*/ +void arkPrintInterpMem(ARKodeInterpMem interp_mem, 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); +#ifdef DEBUG_OUTPUT + if (interp_mem->fold != NULL) { + fprintf(outfile, "ark_interp: fold:\n"); + N_VPrint_Serial(interp_mem->fold); + } + if (interp_mem->fnew != NULL) { + fprintf(outfile, "ark_interp: fnew:\n"); + N_VPrint_Serial(interp_mem->fnew); + } + if (interp_mem->yold != NULL) { + fprintf(outfile, "ark_interp: yold:\n"); + N_VPrint_Serial(interp_mem->yold); + } + if (interp_mem->ynew != NULL) { + fprintf(outfile, "ark_interp: ynew:\n"); + N_VPrint_Serial(interp_mem->ynew); + } + if (interp_mem->fa != NULL) { + fprintf(outfile, "ark_interp: fa:\n"); + N_VPrint_Serial(interp_mem->fa); + } + if (interp_mem->fb != NULL) { + fprintf(outfile, "ark_interp: fb:\n"); + N_VPrint_Serial(interp_mem->fb); + } +#endif + } +} + + +/*--------------------------------------------------------------- + arkInterpInit + + 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 + ---------------------------------------------------------------*/ +int arkInterpInit(void* arkode_mem, ARKodeInterpMem 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); + + /* 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); + + /* copy fnew into fold */ + N_VScale(ONE, interp->fnew, interp->fold); + + /* return with success */ + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkInterpUpdate + + 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. + ---------------------------------------------------------------*/ +int arkInterpUpdate(void* arkode_mem, ARKodeInterpMem interp, + realtype tnew, booleantype forceRHS) +{ + 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; + + /* 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); + + /* return with success */ + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkInterpEvaluate + + This routine evaluates a temporal interpolation/extrapolation + based on the data in the interpolation structure: + yold = y(told) + ynew = y(tnew) + 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: + {yold,ynew,fnew} for quadratic + {yold,ynew} for linear + {0.5*(yold+ynew)} for constant. + + Derivatives have lower accuracy than the interpolant + 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 0<tau<1 provide interpolation, + other values result in extrapolation. + ---------------------------------------------------------------*/ +int arkInterpEvaluate(void* arkode_mem, ARKodeInterpMem interp, + realtype tau, int d, int order, N_Vector yout) +{ + /* local variables */ + int q, retval; + realtype tval, a0, a1, tau2, tau3, tau4, tau5; + realtype h, h2, h3, h4, h5; + realtype a[7]; + N_Vector X[7]; + ARKodeMem ark_mem; + + /* access ARKodeMem structure */ + if (arkode_mem == NULL) return(ARK_MEM_NULL); + ark_mem = (ARKodeMem) arkode_mem; + + /* set constants */ + tau2 = tau*tau; + tau3 = tau*tau2; + tau4 = tau*tau3; + tau5 = tau*tau4; + + h = interp->h; + 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 */ + + /* error on illegal d */ + if (d < 0) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkInterpEvaluate", "Requested illegal derivative."); + return (ARK_ILL_INPUT); + } + + /* if d is too high, just return zeros */ + if (d > q) { + N_VConst(ZERO, yout); + return(ARK_SUCCESS); + } + + /* build polynomial based on order */ + switch (q) { + + case(0): /* constant interpolant, yout = 0.5*(yn+yp) */ + N_VLinearSum(HALF, interp->yold, HALF, interp->ynew, yout); + break; + + case(1): /* linear interpolant */ + if (d == 0) { + a0 = -tau; + a1 = ONE+tau; + } else { /* d=1 */ + a0 = -ONE/h; + a1 = ONE/h; + } + N_VLinearSum(a0, interp->yold, a1, interp->ynew, yout); + break; + + case(2): /* quadratic interpolant */ + if (d == 0) { + a[0] = tau2; + a[1] = ONE - tau2; + a[2] = h*(tau2 + tau); + } else if (d == 1) { + a[0] = TWO*tau/h; + a[1] = -TWO*tau/h; + a[2] = (ONE + TWO*tau); + } else { /* d == 2 */ + a[0] = TWO/h/h; + a[1] = -TWO/h/h; + a[2] = TWO/h; + } + X[0] = interp->yold; + X[1] = interp->ynew; + X[2] = interp->fnew; + retval = N_VLinearCombination(3, a, X, yout); + if (retval != 0) return(ARK_VECTOROP_ERR); + break; + + case(3): /* cubic interpolant */ + if (d == 0) { + a[0] = THREE*tau2 + TWO*tau3; + a[1] = ONE - THREE*tau2 - TWO*tau3; + a[2] = h*(tau2 + tau3); + a[3] = h*(tau + TWO*tau2 + tau3); + } else if (d == 1) { + a[0] = SIX*(tau + tau2)/h; + a[1] = -SIX*(tau + tau2)/h; + a[2] = TWO*tau + THREE*tau2; + a[3] = ONE + FOUR*tau + THREE*tau2; + } else if (d == 2) { + a[0] = SIX*(ONE + TWO*tau)/h2; + a[1] = -SIX*(ONE + TWO*tau)/h2; + a[2] = (TWO + SIX*tau)/h; + a[3] = (FOUR + SIX*tau)/h; + } else { /* d == 3 */ + a[0] = TWELVE/h3; + a[1] = -TWELVE/h3; + a[2] = SIX/h2; + a[3] = SIX/h2; + } + X[0] = interp->yold; + X[1] = interp->ynew; + X[2] = interp->fold; + X[3] = interp->fnew; + retval = N_VLinearCombination(4, a, X, yout); + if (retval != 0) return(ARK_VECTOROP_ERR); + break; + + case(4): /* quartic interpolant */ + + /* first, evaluate cubic interpolant at tau=-1/3 */ + tval = -ONE/THREE; + retval = arkInterpEvaluate(arkode_mem, interp, tval, 0, 3, yout); + 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); + if (retval != 0) return(ARK_RHSFUNC_FAIL); + + /* evaluate desired function */ + if (d == 0) { + a[0] = -SIX*tau2 - RCONST(16.0)*tau3 - RCONST(9.0)*tau4; + a[1] = ONE + SIX*tau2 + RCONST(16.0)*tau3 + RCONST(9.0)*tau4; + a[2] = h*FOURTH*(-FIVE*tau2 - RCONST(14.0)*tau3 - RCONST(9.0)*tau4); + a[3] = h*(tau + TWO*tau2 + tau3); + a[4] = h*RCONST(27.0)*FOURTH*(-tau4 - TWO*tau3 - tau2); + } else if (d == 1) { + a[0] = (-TWELVE*tau - RCONST(48.0)*tau2 - RCONST(36.0)*tau3)/h; + a[1] = (TWELVE*tau + RCONST(48.0)*tau2 + RCONST(36.0)*tau3)/h; + a[2] = HALF*(-FIVE*tau - RCONST(21.0)*tau2 - RCONST(18.0)*tau3); + a[3] = (ONE + FOUR*tau + THREE*tau2); + a[4] = -RCONST(27.0)*HALF*(TWO*tau3 + THREE*tau2 + tau); + } else if (d == 2) { + a[0] = (-TWELVE - RCONST(96.0)*tau - RCONST(108.0)*tau2)/h2; + a[1] = (TWELVE + RCONST(96.0)*tau + RCONST(108.0)*tau2)/h2; + a[2] = (-FIVE*HALF - RCONST(21.0)*tau - RCONST(27.0)*tau2)/h; + a[3] = (FOUR + SIX*tau)/h; + a[4] = (-RCONST(27.0)*HALF - RCONST(81.0)*tau - RCONST(81.0)*tau2)/h; + } else if (d == 3) { + a[0] = (-RCONST(96.0) - RCONST(216.0)*tau)/h3; + a[1] = (RCONST(96.0) + RCONST(216.0)*tau)/h3; + a[2] = (-RCONST(21.0) - RCONST(54.0)*tau)/h2; + a[3] = SIX/h2; + a[4] = (-RCONST(81.0) - RCONST(162.0)*tau)/h2; + } else { /* d == 4 */ + a[0] = -RCONST(216.0)/h4; + a[1] = RCONST(216.0)/h4; + a[2] = -RCONST(54.0)/h3; + 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; + retval = N_VLinearCombination(5, a, X, yout); + if (retval != 0) return(ARK_VECTOROP_ERR); + break; + + case(5): /* quintic interpolant */ + + /* first, evaluate quartic interpolant at tau=-1/3 */ + tval = -ONE/THREE; + retval = arkInterpEvaluate(arkode_mem, interp, tval, 0, 4, yout); + 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); + if (retval != 0) return(ARK_RHSFUNC_FAIL); + + /* third, evaluate quartic interpolant at tau=-2/3 */ + tval = -TWO/THREE; + retval = arkInterpEvaluate(arkode_mem, interp, tval, 0, 4, yout); + 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); + if (retval != 0) return(ARK_RHSFUNC_FAIL); + + /* evaluate desired function */ + if (d == 0) { + a[0] = RCONST(54.0)*tau5 + RCONST(135.0)*tau4 + RCONST(110.0)*tau3 + RCONST(30.0)*tau2; + a[1] = ONE - a[0]; + a[2] = h/FOUR*(RCONST(27.0)*tau5 + RCONST(63.0)*tau4 + RCONST(49.0)*tau3 + RCONST(13.0)*tau2); + a[3] = h/FOUR*(RCONST(27.0)*tau5 + RCONST(72.0)*tau4 + RCONST(67.0)*tau3 + RCONST(26.0)*tau2 + FOUR*tau); + a[4] = h/FOUR*(RCONST(81.0)*tau5 + RCONST(189.0)*tau4 + RCONST(135.0)*tau3 + RCONST(27.0)*tau2); + a[5] = h/FOUR*(RCONST(81.0)*tau5 + RCONST(216.0)*tau4 + RCONST(189.0)*tau3 + RCONST(54.0)*tau2); + } else if (d == 1) { + a[0] = (RCONST(270.0)*tau4 + RCONST(540.0)*tau3 + RCONST(330.0)*tau2 + RCONST(60.0)*tau)/h; + a[1] = -a[0]; + a[2] = (RCONST(135.0)*tau4 + RCONST(252.0)*tau3 + RCONST(147.0)*tau2 + RCONST(26.0)*tau)/FOUR; + a[3] = (RCONST(135.0)*tau4 + RCONST(288.0)*tau3 + RCONST(201.0)*tau2 + RCONST(52.0)*tau + FOUR)/FOUR; + a[4] = (RCONST(405.0)*tau4 + RCONST(4.0)*189*tau3 + RCONST(405.0)*tau2 + RCONST(54.0)*tau)/FOUR; + a[5] = (RCONST(405.0)*tau4 + RCONST(864.0)*tau3 + RCONST(567.0)*tau2 + RCONST(108.0)*tau)/FOUR; + } else if (d == 2) { + a[0] = (RCONST(1080.0)*tau3 + RCONST(1620.0)*tau2 + RCONST(660.0)*tau + RCONST(60.0))/h2; + a[1] = -a[0]; + a[2] = (RCONST(270.0)*tau3 + RCONST(378.0)*tau2 + RCONST(147.0)*tau + RCONST(13.0))/(TWO*h); + a[3] = (RCONST(270.0)*tau3 + RCONST(432.0)*tau2 + RCONST(201.0)*tau + RCONST(26.0))/(TWO*h); + a[4] = (RCONST(810.0)*tau3 + RCONST(1134.0)*tau2 + RCONST(405.0)*tau + RCONST(27.0))/(TWO*h); + a[5] = (RCONST(810.0)*tau3 + RCONST(1296.0)*tau2 + RCONST(567.0)*tau + RCONST(54.0))/(TWO*h); + } else if (d == 3) { + a[0] = (RCONST(3240.0)*tau2 + RCONST(3240.0)*tau + RCONST(660.0))/h3; + a[1] = -a[0]; + a[2] = (RCONST(810.0)*tau2 + RCONST(756.0)*tau + RCONST(147.0))/(TWO*h2); + a[3] = (RCONST(810.0)*tau2 + RCONST(864.0)*tau + RCONST(201.0))/(TWO*h2); + a[4] = (RCONST(2430.0)*tau2 + RCONST(2268.0)*tau + RCONST(405.0))/(TWO*h2); + a[5] = (RCONST(2430.0)*tau2 + RCONST(2592.0)*tau + RCONST(567.0))/(TWO*h2); + } else if (d == 4) { + a[0] = (RCONST(6480.0)*tau + RCONST(3240.0))/h4; + a[1] = -a[0]; + a[2] = (RCONST(810.0)*tau + RCONST(378.0))/h3; + a[3] = (RCONST(810.0)*tau + RCONST(432.0))/h3; + a[4] = (RCONST(2430.0)*tau + RCONST(1134.0))/h3; + a[5] = (RCONST(2430.0)*tau + RCONST(1296.0))/h3; + } else { /* d == 5 */ + a[0] = RCONST(6480.0)/h5; + a[1] = -a[0]; + a[2] = RCONST(810.0)/h4; + a[3] = a[2]; + 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; + retval = N_VLinearCombination(6, a, X, yout); + if (retval != 0) return(ARK_VECTOROP_ERR); + break; + + default: + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", "arkInterpEvaluate", + "Illegal polynomial order"); + return (ARK_ILL_INPUT); + } + + return(ARK_SUCCESS); +} + + +/*=============================================================== + EOF + ===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_interp_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_interp_impl.h new file mode 100644 index 0000000..fc9a6ac --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_interp_impl.h @@ -0,0 +1,89 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * Implementation header file for ARKode's temporal interpolation + * utility. + *--------------------------------------------------------------*/ + +#ifndef _ARKODE_INTERP_IMPL_H +#define _ARKODE_INTERP_IMPL_H + +#include <stdarg.h> +#include <arkode/arkode.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*=============================================================== + 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 */ + + +/*=============================================================== + ARKode 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 { + + 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 */ + N_Vector ynew; /* y at end of last successful step */ + N_Vector fa; /* f(t,y) used in higher-order interpolation */ + 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 */ + +} *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); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_io.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_io.c new file mode 100644 index 0000000..8c2a466 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_io.c @@ -0,0 +1,907 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 the optional input and + * output functions for the ARKode infrastructure; these routines + * should not be called directly by the user; instead they are + * provided as utility routines for ARKode time-step modules + * to use. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "arkode_impl.h" +#include <sundials/sundials_math.h> +#include <sundials/sundials_types.h> + +#if defined(SUNDIALS_EXTENDED_PRECISION) +#define RSYM "Lg" +#else +#define RSYM "g" +#endif + + +/*=============================================================== + ARKode optional input utility functions + ===============================================================*/ + +/*--------------------------------------------------------------- + arkSetDefaults: + + Resets all optional inputs to ARKode default values. Does not + 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). + ---------------------------------------------------------------*/ +int arkSetDefaults(ARKodeMem ark_mem) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSetDefaults", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + + /* 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) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSetDenseOrder", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + + /* set user-provided value, or default, depending on argument */ + if (dord < 0) { + ark_mem->dense_q = QDENSE_DEF; + } else { + ark_mem->dense_q = dord; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetErrHandlerFn: + + Specifies the error handler function + ---------------------------------------------------------------*/ +int arkSetErrHandlerFn(ARKodeMem ark_mem, ARKErrHandlerFn ehfun, + void *eh_data) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSetErrHandlerFn", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + + /* set user-provided values, or defaults, depending on argument */ + if (ehfun == NULL) { + ark_mem->ehfun = arkErrHandler; + ark_mem->eh_data = ark_mem; + } else { + ark_mem->ehfun = ehfun; + ark_mem->eh_data = eh_data; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetErrFile: + + Specifies the FILE pointer for output (NULL means no messages) + ---------------------------------------------------------------*/ +int arkSetErrFile(ARKodeMem ark_mem, FILE *errfp) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSetErrFile", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem->errfp = errfp; + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetUserData: + + Specifies the user data pointer for f + ---------------------------------------------------------------*/ +int arkSetUserData(ARKodeMem ark_mem, void *user_data) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSetUserData", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem->user_data = user_data; + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetDiagnostics: + + Specifies to enable solver diagnostics, and specifies the FILE + pointer for output (diagfp==NULL disables output) + ---------------------------------------------------------------*/ +int arkSetDiagnostics(ARKodeMem ark_mem, FILE *diagfp) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSetDiagnostics", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + + ark_mem->diagfp = diagfp; + if (diagfp != NULL) { + ark_mem->report = SUNTRUE; + } else { + ark_mem->report = SUNFALSE; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetMaxNumSteps: + + Specifies the maximum number of integration steps + ---------------------------------------------------------------*/ +int arkSetMaxNumSteps(ARKodeMem ark_mem, long int mxsteps) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSetMaxNumSteps", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + + /* Passing mxsteps=0 sets the default. Passing mxsteps<0 disables the test. */ + if (mxsteps == 0) + ark_mem->mxstep = MXSTEP_DEFAULT; + else + ark_mem->mxstep = mxsteps; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetMaxHnilWarns: + + Specifies the maximum number of warnings for small h + ---------------------------------------------------------------*/ +int arkSetMaxHnilWarns(ARKodeMem ark_mem, int mxhnil) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSetMaxHnilWarns", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + + /* Passing mxhnil=0 sets the default, otherwise use input. */ + if (mxhnil == 0) { + ark_mem->mxhnil = 10; + } else { + ark_mem->mxhnil = mxhnil; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetInitStep: + + Specifies the initial step size + ---------------------------------------------------------------*/ +int arkSetInitStep(ARKodeMem ark_mem, realtype hin) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSetInitStep", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + + /* Passing hin=0 sets the default, otherwise use input. */ + if (hin == ZERO) { + ark_mem->hin = ZERO; + } else { + ark_mem->hin = hin; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetMinStep: + + Specifies the minimum step size + ---------------------------------------------------------------*/ +int arkSetMinStep(ARKodeMem ark_mem, realtype hmin) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSetMinStep", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + + /* Passing a value <= 0 sets hmax = infinity */ + if (hmin <= ZERO) { + ark_mem->hmin = ZERO; + return(ARK_SUCCESS); + } + + /* check that hmin and hmax are agreeable */ + if (hmin * ark_mem->hmax_inv > ONE) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkSetMinStep", MSG_ARK_BAD_HMIN_HMAX); + return(ARK_ILL_INPUT); + } + + /* set the value */ + ark_mem->hmin = hmin; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetMaxStep: + + Specifies the maximum step size + ---------------------------------------------------------------*/ +int arkSetMaxStep(ARKodeMem ark_mem, realtype hmax) +{ + realtype hmax_inv; + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSetMaxStep", MSG_ARK_NO_MEM); + return (ARK_MEM_NULL); + } + + /* Passing a value <= 0 sets hmax = infinity */ + if (hmax <= ZERO) { + ark_mem->hmax_inv = ZERO; + return(ARK_SUCCESS); + } + + /* check that hmax and hmin are agreeable */ + hmax_inv = ONE/hmax; + if (hmax_inv * ark_mem->hmin > ONE) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkSetMaxStep", MSG_ARK_BAD_HMIN_HMAX); + return(ARK_ILL_INPUT); + } + + /* set the value */ + ark_mem->hmax_inv = hmax_inv; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetStopTime: + + Specifies the time beyond which the integration is not to proceed. + ---------------------------------------------------------------*/ +int arkSetStopTime(ARKodeMem ark_mem, realtype tstop) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSetStopTime", MSG_ARK_NO_MEM); + return (ARK_MEM_NULL); + } + + /* If ARKode was called at least once, test if tstop is legal + (i.e. if it was not already passed). + If arkSetStopTime is called before the first call to ARKode, + tstop will be checked in ARKode. */ + if (ark_mem->nst > 0) { + if ( (tstop - ark_mem->tcur) * ark_mem->h < ZERO ) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkSetStopTime", MSG_ARK_BAD_TSTOP, + tstop, ark_mem->tcur); + return(ARK_ILL_INPUT); + } + } + + ark_mem->tstop = tstop; + ark_mem->tstopset = SUNTRUE; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetFixedStep: + + Specifies to use a fixed time step size instead of performing + any form of temporal adaptivity. ARKode 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, ARKode 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 arkSetFixedStep(ARKodeMem ark_mem, realtype hfixed) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSetFixedStep", MSG_ARK_NO_MEM); + return (ARK_MEM_NULL); + } + + /* set ark_mem entry */ + if (hfixed != ZERO) { + ark_mem->fixedstep = SUNTRUE; + ark_mem->hin = hfixed; + } else { + ark_mem->fixedstep = SUNFALSE; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetRootDirection: + + Specifies the direction of zero-crossings to be monitored. + The default is to monitor both crossings. + ---------------------------------------------------------------*/ +int arkSetRootDirection(ARKodeMem ark_mem, int *rootdir) +{ + ARKodeRootMem ark_root_mem; + int i; + + if (ark_mem == NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSetRootDirection", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + if (ark_mem->root_mem == NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode", + "arkSetRootDirection", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_root_mem = (ARKodeRootMem) ark_mem->root_mem; + + if (ark_root_mem->nrtfn == 0) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkSetRootDirection", MSG_ARK_NO_ROOT); + return(ARK_ILL_INPUT); + } + + for(i=0; i<ark_root_mem->nrtfn; i++) + ark_root_mem->rootdir[i] = rootdir[i]; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkSetNoInactiveRootWarn: + + Disables issuing a warning if some root function appears + to be identically zero at the beginning of the integration + ---------------------------------------------------------------*/ +int arkSetNoInactiveRootWarn(ARKodeMem ark_mem) +{ + ARKodeRootMem ark_root_mem; + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSetNoInactiveRootWarn", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + 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); +} + + +/*--------------------------------------------------------------- + arkSetPostprocessStepFn: + + 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 arkSetPostprocessStepFn(ARKodeMem ark_mem, + ARKPostProcessStepFn ProcessStep) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkSetPostprocessStepFn", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + + /* NULL argument sets default, otherwise set inputs */ + ark_mem->ProcessStep = ProcessStep; + return(ARK_SUCCESS); +} + + +/*=============================================================== + ARKode optional output utility functions + ===============================================================*/ + +/*--------------------------------------------------------------- + arkGetNumSteps: + + Returns the current number of integration steps + ---------------------------------------------------------------*/ +int arkGetNumSteps(ARKodeMem ark_mem, long int *nsteps) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkGetNumSteps", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + *nsteps = ark_mem->nst; + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkGetActualInitStep: + + Returns the step size used on the first step + ---------------------------------------------------------------*/ +int arkGetActualInitStep(ARKodeMem ark_mem, realtype *hinused) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkGetActualInitStep", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + *hinused = ark_mem->h0u; + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkGetLastStep: + + Returns the step size used on the last successful step + ---------------------------------------------------------------*/ +int arkGetLastStep(ARKodeMem ark_mem, realtype *hlast) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkGetLastStep", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + *hlast = ark_mem->hold; + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkGetCurrentStep: + + Returns the step size to be attempted on the next step + ---------------------------------------------------------------*/ +int arkGetCurrentStep(ARKodeMem ark_mem, realtype *hcur) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkGetCurrentStep", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + *hcur = ark_mem->next_h; + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkGetCurrentTime: + + Returns the current value of the independent variable + ---------------------------------------------------------------*/ +int arkGetCurrentTime(ARKodeMem ark_mem, realtype *tcur) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkGetCurrentTime", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + *tcur = ark_mem->tcur; + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkGetTolScaleFactor: + + Returns a suggested factor for scaling tolerances + ---------------------------------------------------------------*/ +int arkGetTolScaleFactor(ARKodeMem ark_mem, realtype *tolsfact) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkGetTolScaleFactor", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + *tolsfact = ark_mem->tolsf; + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkGetErrWeights: + + This routine returns the current error weight vector. + ---------------------------------------------------------------*/ +int arkGetErrWeights(ARKodeMem ark_mem, N_Vector eweight) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkGetErrWeights", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + N_VScale(ONE, ark_mem->ewt, eweight); + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkGetResWeights: + + This routine returns the current residual weight vector. + ---------------------------------------------------------------*/ +int arkGetResWeights(ARKodeMem ark_mem, N_Vector rweight) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkGetResWeights", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + N_VScale(ONE, ark_mem->rwt, rweight); + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkGetWorkSpace: + + Returns integrator work space requirements + ---------------------------------------------------------------*/ +int arkGetWorkSpace(ARKodeMem ark_mem, long int *lenrw, long int *leniw) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkGetWorkSpace", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + *leniw = ark_mem->liw; + *lenrw = ark_mem->lrw; + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkGetNumGEvals: + + Returns the current number of calls to g (for rootfinding) + ---------------------------------------------------------------*/ +int arkGetNumGEvals(ARKodeMem ark_mem, long int *ngevals) +{ + ARKodeRootMem ark_root_mem; + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkGetNumGEvals", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + 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); +} + + +/*--------------------------------------------------------------- + arkGetRootInfo: + + Returns pointer to array rootsfound showing roots found + ---------------------------------------------------------------*/ +int arkGetRootInfo(ARKodeMem ark_mem, int *rootsfound) +{ + int i; + ARKodeRootMem ark_root_mem; + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkGetRootInfo", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + 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; i<ark_root_mem->nrtfn; i++) + rootsfound[i] = ark_root_mem->iroots[i]; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkGetStepStats: + + Returns step statistics + ---------------------------------------------------------------*/ +int arkGetStepStats(ARKodeMem ark_mem, long int *nsteps, + realtype *hinused, realtype *hlast, + realtype *hcur, realtype *tcur) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkGetStepStats", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + *nsteps = ark_mem->nst; + *hinused = ark_mem->h0u; + *hlast = ark_mem->hold; + *hcur = ark_mem->next_h; + *tcur = ark_mem->tcur; + return(ARK_SUCCESS); +} + + +/*-----------------------------------------------------------------*/ + +char *arkGetReturnFlagName(long int flag) +{ + char *name; + name = (char *)malloc(24*sizeof(char)); + + switch(flag) { + case ARK_SUCCESS: + sprintf(name,"ARK_SUCCESS"); + break; + case ARK_TSTOP_RETURN: + sprintf(name,"ARK_TSTOP_RETURN"); + break; + case ARK_ROOT_RETURN: + sprintf(name,"ARK_ROOT_RETURN"); + break; + case ARK_TOO_MUCH_WORK: + sprintf(name,"ARK_TOO_MUCH_WORK"); + break; + case ARK_TOO_MUCH_ACC: + sprintf(name,"ARK_TOO_MUCH_ACC"); + break; + case ARK_ERR_FAILURE: + sprintf(name,"ARK_ERR_FAILURE"); + break; + case ARK_CONV_FAILURE: + sprintf(name,"ARK_CONV_FAILURE"); + break; + case ARK_LINIT_FAIL: + sprintf(name,"ARK_LINIT_FAIL"); + break; + case ARK_LSETUP_FAIL: + sprintf(name,"ARK_LSETUP_FAIL"); + break; + case ARK_LSOLVE_FAIL: + sprintf(name,"ARK_LSOLVE_FAIL"); + break; + case ARK_RHSFUNC_FAIL: + sprintf(name,"ARK_RHSFUNC_FAIL"); + break; + case ARK_FIRST_RHSFUNC_ERR: + sprintf(name,"ARK_FIRST_RHSFUNC_ERR"); + break; + case ARK_REPTD_RHSFUNC_ERR: + sprintf(name,"ARK_REPTD_RHSFUNC_ERR"); + break; + case ARK_UNREC_RHSFUNC_ERR: + sprintf(name,"ARK_UNREC_RHSFUNC_ERR"); + break; + case ARK_RTFUNC_FAIL: + sprintf(name,"ARK_RTFUNC_FAIL"); + break; + case ARK_LFREE_FAIL: + sprintf(name,"ARK_LFREE_FAIL"); + break; + case ARK_MASSINIT_FAIL: + sprintf(name,"ARK_MASSINIT_FAIL"); + break; + case ARK_MASSSETUP_FAIL: + sprintf(name,"ARK_MASSSETUP_FAIL"); + break; + case ARK_MASSSOLVE_FAIL: + sprintf(name,"ARK_MASSSOLVE_FAIL"); + break; + case ARK_MASSFREE_FAIL: + sprintf(name,"ARK_MASSFREE_FAIL"); + break; + case ARK_MASSMULT_FAIL: + sprintf(name,"ARK_MASSMULT_FAIL"); + break; + case ARK_MEM_FAIL: + sprintf(name,"ARK_MEM_FAIL"); + break; + case ARK_MEM_NULL: + sprintf(name,"ARK_MEM_NULL"); + break; + case ARK_ILL_INPUT: + sprintf(name,"ARK_ILL_INPUT"); + break; + case ARK_NO_MALLOC: + sprintf(name,"ARK_NO_MALLOC"); + break; + case ARK_BAD_K: + sprintf(name,"ARK_BAD_K"); + break; + case ARK_BAD_T: + sprintf(name,"ARK_BAD_T"); + break; + case ARK_BAD_DKY: + sprintf(name,"ARK_BAD_DKY"); + break; + case ARK_TOO_CLOSE: + sprintf(name,"ARK_TOO_CLOSE"); + break; + case ARK_POSTPROCESS_FAIL: + sprintf(name,"ARK_POSTPROCESS_FAIL"); + break; + case ARK_VECTOROP_ERR: + sprintf(name,"ARK_VECTOROP_ERR"); + break; + case ARK_NLS_INIT_FAIL: + sprintf(name,"ARK_NLS_INIT_FAIL"); + break; + case ARK_NLS_SETUP_FAIL: + sprintf(name,"ARK_NLS_SETUP_FAIL"); + break; + case ARK_NLS_OP_ERR: + sprintf(name,"ARK_NLS_OP_ERR"); + break; + case ARK_INNERSTEP_FAIL: + sprintf(name,"ARK_INNERSTEP_FAIL"); + break; + default: + sprintf(name,"NONE"); + } + + return(name); +} + + + +/*=============================================================== + ARKode parameter output utility routine + ===============================================================*/ + +/*--------------------------------------------------------------- + arkodeWriteParameters: + + Outputs all solver parameters to the provided file pointer. + ---------------------------------------------------------------*/ +int arkWriteParameters(ARKodeMem ark_mem, FILE *fp) +{ + if (ark_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkWriteParameters", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + + /* 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) + fprintf(fp, " Maximum step size = %" RSYM"\n",ONE/ark_mem->hmax_inv); + if (ark_mem->fixedstep) + fprintf(fp, " Fixed time-stepping enabled\n"); + if (ark_mem->itol == ARK_WF) { + fprintf(fp, " User provided error weight function\n"); + } else { + fprintf(fp, " Solver relative tolerance = %" RSYM"\n", ark_mem->reltol); + if (ark_mem->itol == ARK_SS) { + fprintf(fp, " Solver absolute tolerance = %" RSYM"\n", ark_mem->Sabstol); + } else { + fprintf(fp, " Vector-valued solver absolute tolerance\n"); + } + } + if (!ark_mem->rwt_is_ewt) { + if (ark_mem->ritol == ARK_WF) { + fprintf(fp, " User provided residual weight function\n"); + } else { + if (ark_mem->ritol == ARK_SS) { + fprintf(fp, " Absolute residual tolerance = %" RSYM"\n", ark_mem->SRabstol); + } else { + fprintf(fp, " Vector-valued residual absolute tolerance\n"); + } + } + } + if (ark_mem->hin != ZERO) + fprintf(fp, " Initial step size = %" RSYM"\n",ark_mem->hin); + fprintf(fp, "\n"); + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + EOF + ---------------------------------------------------------------*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_ls.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_ls.c new file mode 100644 index 0000000..6508c22 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_ls.c @@ -0,0 +1,2766 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * Implementation file for ARKode's linear solver interface. + *---------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "arkode_impl.h" +#include "arkode_ls_impl.h" +#include <sundials/sundials_math.h> +#include <sunmatrix/sunmatrix_band.h> +#include <sunmatrix/sunmatrix_dense.h> +#include <sunmatrix/sunmatrix_sparse.h> + +#if defined(SUNDIALS_EXTENDED_PRECISION) +#define RSYM ".32Lg" +#else +#define RSYM ".16g" +#endif + +/* constants */ +#define MIN_INC_MULT RCONST(1000.0) +#define MAX_DQITERS 3 /* max. # of attempts to recover in DQ J*v */ +#define ZERO RCONST(0.0) +#define PT25 RCONST(0.25) +#define ONE RCONST(1.0) + + +/*=============================================================== + ARKLS utility routines (called by time-stepper modules) + ===============================================================*/ + +/*--------------------------------------------------------------- + arkLSSetLinearSolver specifies the linear solver. + ---------------------------------------------------------------*/ +int arkLSSetLinearSolver(void *arkode_mem, SUNLinearSolver LS, + SUNMatrix A) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + int retval, LSType; + + /* Return immediately if either arkode_mem or LS inputs are NULL */ + if (arkode_mem == NULL) { + arkProcessError(NULL, ARKLS_MEM_NULL, "ARKLS", + "arkLSSetLinearSolver", MSG_LS_ARKMEM_NULL); + return(ARKLS_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + + if (LS == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", + "arkLSSetLinearSolver", + "LS must be non-NULL"); + return(ARKLS_ILL_INPUT); + } + + /* 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) ) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", + "arkLSSetLinearSolver", + "LS object is missing a required operation"); + return(ARKLS_ILL_INPUT); + } + + /* Test if vector is compatible with LS interface */ + if ( (ark_mem->tempv1->ops->nvconst == NULL) || + (ark_mem->tempv1->ops->nvdotprod == 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)) { + 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) || + (ark_mem->step_getlinmem == NULL) || + (ark_mem->step_getimplicitrhs == NULL) || + (ark_mem->step_getgammas == NULL) ) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", + "arkLSSetLinearSolver", + "Missing time step module or associated routines"); + return(ARKLS_ILL_INPUT); + } + + /* Allocate memory for ARKLsMemRec */ + arkls_mem = NULL; + arkls_mem = (ARKLsMem) malloc(sizeof(struct ARKLsMemRec)); + if (arkls_mem == NULL) { + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKLS", + "arkLSSetLinearSolver", MSG_LS_MEM_FAIL); + return(ARKLS_MEM_FAIL); + } + memset(arkls_mem, 0, sizeof(struct ARKLsMemRec)); + + /* set SUNLinearSolver pointer */ + arkls_mem->LS = LS; + + /* Set defaults for Jacobian-related fields */ + if (A != NULL) { + arkls_mem->jacDQ = SUNTRUE; + arkls_mem->jac = arkLsDQJac; + arkls_mem->J_data = ark_mem; + } else { + arkls_mem->jacDQ = SUNFALSE; + 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; + + /* Set defaults for preconditioner-related fields */ + arkls_mem->pset = NULL; + arkls_mem->psolve = NULL; + arkls_mem->pfree = NULL; + arkls_mem->P_data = ark_mem->user_data; + + /* Initialize counters */ + arkLsInitializeCounters(arkls_mem); + + /* Set default values for the rest of the LS parameters */ + arkls_mem->msbj = ARKLS_MSBJ; + arkls_mem->jbad = SUNTRUE; + arkls_mem->eplifac = ARKLS_EPLIN; + arkls_mem->last_flag = ARKLS_SUCCESS; + + /* If LS supports ATimes, attach ARKLs routine */ + if (LS->ops->setatimes) { + retval = SUNLinSolSetATimes(LS, ark_mem, arkLsATimes); + if (retval != SUNLS_SUCCESS) { + arkProcessError(ark_mem, ARKLS_SUNLS_FAIL, "ARKLS", + "arkLSSetLinearSolver", + "Error in calling SUNLinSolSetATimes"); + free(arkls_mem); arkls_mem = NULL; + return(ARKLS_SUNLS_FAIL); + } + } + + /* If LS supports preconditioning, initialize pset/psol to NULL */ + if (LS->ops->setpreconditioner) { + retval = SUNLinSolSetPreconditioner(LS, ark_mem, NULL, NULL); + if (retval != SUNLS_SUCCESS) { + arkProcessError(ark_mem, ARKLS_SUNLS_FAIL, "ARKLS", + "arkLSSetLinearSolver", + "Error in calling SUNLinSolSetPreconditioner"); + free(arkls_mem); arkls_mem = NULL; + return(ARKLS_SUNLS_FAIL); + } + } + + /* When using a non-NULL SUNMatrix object, store pointer to A and create saved_J */ + 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); + } + } + + /* Allocate memory for ytemp and x */ + arkls_mem->ytemp = N_VClone(ark_mem->tempv1); + 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); + } + + arkls_mem->x = N_VClone(ark_mem->tempv1); + if (arkls_mem->x == NULL) { + 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) ); + } + + /* Attach ARKLs interface to time stepper module */ + retval = ark_mem->step_attachlinsol(arkode_mem, arkLsInitialize, + arkLsSetup, arkLsSolve, + arkLsFree, 2, 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); + } + + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSSetMassLinearSolver specifies the iterative mass-matrix + linear solver and user-supplied routine to perform the + mass-matrix-vector product. + ---------------------------------------------------------------*/ +int arkLSSetMassLinearSolver(void *arkode_mem, SUNLinearSolver LS, + SUNMatrix M, booleantype time_dep) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + int retval, LSType; + + /* Return immediately if either arkode_mem or LS inputs are NULL */ + if (arkode_mem == NULL) { + arkProcessError(NULL, ARKLS_MEM_NULL, "ARKLS", + "arkLSSetMassLinearSolver", + MSG_LS_ARKMEM_NULL); + return(ARKLS_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + + if (LS == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", + "arkLSSetMassLinearSolver", + "LS must be non-NULL"); + return(ARKLS_ILL_INPUT); + } + + /* 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) ) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", + "arkLSSetMassLinearSolver", + "LS object is missing a required operation"); + return(ARKLS_ILL_INPUT); + } + + /* Test if vector is compatible with LS interface */ + if ( (ark_mem->tempv1->ops->nvconst == NULL) || + (ark_mem->tempv1->ops->nvdotprod == 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)) { + 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 */ + if ( (ark_mem->step_attachmasssol == NULL) || + (ark_mem->step_getmassmem == NULL) ) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", + "arkLSSetMassLinearSolver", + "Missing time step module or associated routines"); + return(ARKLS_ILL_INPUT); + } + + /* Allocate memory for ARKLsMemRec */ + arkls_mem = NULL; + arkls_mem = (ARKLsMassMem) malloc(sizeof(struct ARKLsMassMemRec)); + if (arkls_mem == NULL) { + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKLS", + "arkLSSetMassLinearSolver", MSG_LS_MEM_FAIL); + return(ARKLS_MEM_FAIL); + } + memset(arkls_mem, 0, sizeof(struct ARKLsMassMemRec)); + + /* set SUNLinearSolver pointer; flag indicating time-dependence */ + arkls_mem->LS = LS; + arkls_mem->time_dependent = time_dep; + + /* Set mass-matrix routines to NULL */ + arkls_mem->mass = NULL; + arkls_mem->mtsetup = NULL; + arkls_mem->mtimes = NULL; + arkls_mem->mt_data = NULL; + + /* Set defaults for preconditioner-related fields */ + arkls_mem->pset = NULL; + arkls_mem->psolve = NULL; + arkls_mem->pfree = NULL; + arkls_mem->P_data = ark_mem->user_data; + + /* Initialize counters */ + arkLsInitializeMassCounters(arkls_mem); + + /* Set default values for the rest of the LS parameters */ + arkls_mem->eplifac = ARKLS_EPLIN; + arkls_mem->last_flag = ARKLS_SUCCESS; + + /* If LS supports ATimes, attach ARKLs routine */ + if (LS->ops->setatimes) { + retval = SUNLinSolSetATimes(LS, ark_mem, NULL); + if (retval != SUNLS_SUCCESS) { + arkProcessError(ark_mem, ARKLS_SUNLS_FAIL, "ARKLS", + "arkLSSetMassLinearSolver", + "Error in calling SUNLinSolSetATimes"); + free(arkls_mem); arkls_mem = NULL; + return(ARKLS_SUNLS_FAIL); + } + } + + /* If LS supports preconditioning, initialize pset/psol to NULL */ + if (LS->ops->setpreconditioner) { + retval = SUNLinSolSetPreconditioner(LS, ark_mem, NULL, NULL); + if (retval != SUNLS_SUCCESS) { + arkProcessError(ark_mem, ARKLS_SUNLS_FAIL, "ARKLS", + "arkLSSetMassLinearSolver", + "Error in calling SUNLinSolSetPreconditioner"); + free(arkls_mem); arkls_mem = NULL; + return(ARKLS_SUNLS_FAIL); + } + } + + /* When using a non-NULL SUNMatrix object, store pointer to M and create M_lu */ + if (M != NULL) { + arkls_mem->M = M; + arkls_mem->M_lu = SUNMatClone(M); + if (arkls_mem->M_lu == NULL) { + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKLS", + "arkLSSetMassLinearSolver", MSG_LS_MEM_FAIL); + free(arkls_mem); arkls_mem = NULL; + return(ARKLS_MEM_FAIL); + } + } + + /* Allocate memory for x */ + arkls_mem->x = N_VClone(ark_mem->tempv1); + if (arkls_mem->x == NULL) { + arkProcessError(ark_mem, ARKLS_MEM_FAIL, "ARKLS", + "arkLSSetMassLinearSolver", MSG_LS_MEM_FAIL); + SUNMatDestroy(arkls_mem->M_lu); + 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->x); + arkls_mem->sqrtN = SUNRsqrt( N_VDotProd(arkls_mem->x, + 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); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, retval, "ARKLS", "arkLSSetMassLinearSolver", + "Failed to attach to time stepper module"); + N_VDestroy(arkls_mem->x); + SUNMatDestroy(arkls_mem->M_lu); + free(arkls_mem); arkls_mem = NULL; + return(retval); + } + + return(ARKLS_SUCCESS); +} + + +/*=============================================================== + Optional input/output (called by time-stepper modules) + ===============================================================*/ + +/*--------------------------------------------------------------- + arkLSSetJacFn specifies the Jacobian function. + ---------------------------------------------------------------*/ +int arkLSSetJacFn(void *arkode_mem, ARKLsJacFn jac) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + int retval; + + /* access ARKLsMem structure */ + retval = arkLs_AccessLMem(arkode_mem, "arkLSSetJacFn", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* return with failure if jac cannot be used */ + if ((jac != NULL) && (arkls_mem->A == NULL)) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLSSetJacFn", + "Jacobian routine cannot be supplied for NULL SUNMatrix"); + return(ARKLS_ILL_INPUT); + } + + /* set Jacobian routine pointer, and update relevant flags */ + if (jac != NULL) { + arkls_mem->jacDQ = SUNFALSE; + arkls_mem->jac = jac; + arkls_mem->J_data = ark_mem->user_data; + } else { + arkls_mem->jacDQ = SUNTRUE; + arkls_mem->jac = arkLsDQJac; + arkls_mem->J_data = ark_mem; + } + + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSSetMassFn specifies the mass matrix function. + ---------------------------------------------------------------*/ +int arkLSSetMassFn(void *arkode_mem, ARKLsMassFn mass) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + int retval; + + /* access ARKLsMassMem structure */ + retval = arkLs_AccessMassMem(arkode_mem, "arkLSSetMassFn", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* return with failure if mass cannot be used */ + if (mass == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLSSetMassFn", + "Mass-matrix routine must be non-NULL"); + return(ARKLS_ILL_INPUT); + } + if (arkls_mem->M == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLSSetMassFn", + "Mass-matrix routine cannot be supplied for NULL SUNMatrix"); + return(ARKLS_ILL_INPUT); + } + + /* set mass matrix routine pointer and return */ + arkls_mem->mass = mass; + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSSetEpsLin specifies the nonlinear -> linear tolerance + scale factor. + ---------------------------------------------------------------*/ +int arkLSSetEpsLin(void *arkode_mem, realtype eplifac) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + int retval; + + /* access ARKLsMem structure; store input and return */ + retval = arkLs_AccessLMem(arkode_mem, "arkLSSetEpsLin", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + arkls_mem->eplifac = (eplifac <= ZERO) ? ARKLS_EPLIN : eplifac; + + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSSetMaxStepsBetweenJac specifies the maximum number of + time steps to wait before recomputing the Jacobian matrix + and/or preconditioner. + ---------------------------------------------------------------*/ +int arkLSSetMaxStepsBetweenJac(void *arkode_mem, long int msbj) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + int retval; + + /* access ARKLsMem structure; store input and return */ + retval = arkLs_AccessLMem(arkode_mem, "arkLSSetMaxStepsBetweenJac", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + arkls_mem->msbj = (msbj <= ZERO) ? ARKLS_MSBJ : msbj; + + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSSetPreconditioner specifies the user-supplied + preconditioner setup and solve routines. + ---------------------------------------------------------------*/ +int arkLSSetPreconditioner(void *arkode_mem, + ARKLsPrecSetupFn psetup, + ARKLsPrecSolveFn psolve) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + PSetupFn arkls_psetup; + PSolveFn arkls_psolve; + int retval; + + /* access ARKLsMem structure */ + retval = arkLs_AccessLMem(arkode_mem, "arkLSSetPreconditioner", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* issue error if LS object does not allow user-supplied preconditioning */ + if (arkls_mem->LS->ops->setpreconditioner == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", + "arkLSSetPreconditioner", + "SUNLinearSolver object does not support user-supplied preconditioning"); + return(ARKLS_ILL_INPUT); + } + + /* store function pointers for user-supplied routines */ + arkls_mem->pset = psetup; + arkls_mem->psolve = psolve; + + /* notify linear solver to call ARKLs interface routines */ + arkls_psetup = (psetup == NULL) ? NULL : arkLsPSetup; + arkls_psolve = (psolve == NULL) ? NULL : arkLsPSolve; + retval = SUNLinSolSetPreconditioner(arkls_mem->LS, ark_mem, + arkls_psetup, arkls_psolve); + if (retval != SUNLS_SUCCESS) { + arkProcessError(ark_mem, ARKLS_SUNLS_FAIL, "ARKLS", + "arkLSSetPreconditioner", + "Error in calling SUNLinSolSetPreconditioner"); + return(ARKLS_SUNLS_FAIL); + } + + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSSetJacTimes specifies the user-supplied Jacobian-vector + product setup and multiply routines. + ---------------------------------------------------------------*/ +int arkLSSetJacTimes(void *arkode_mem, + ARKLsJacTimesSetupFn jtsetup, + ARKLsJacTimesVecFn jtimes) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + int retval; + + /* access ARKLsMem structure */ + retval = arkLs_AccessLMem(arkode_mem, "arkLSSetJacTimes", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* issue error if LS object does not allow user-supplied ATimes */ + if (arkls_mem->LS->ops->setatimes == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", + "arkLSSetJacTimes", + "SUNLinearSolver object does not support user-supplied ATimes routine"); + return(ARKLS_ILL_INPUT); + } + + /* store function pointers for user-supplied routines in ARKLs + interface (NULL jtimes implies use of DQ default) */ + if (jtimes != NULL) { + arkls_mem->jtimesDQ = SUNFALSE; + arkls_mem->jtsetup = jtsetup; + arkls_mem->jtimes = jtimes; + arkls_mem->Jt_data = ark_mem->user_data; + } else { + arkls_mem->jtimesDQ = SUNTRUE; + arkls_mem->jtsetup = NULL; + arkls_mem->jtimes = arkLsDQJtimes; + arkls_mem->Jt_data = ark_mem; + } + + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSGetWorkSpace returns the length of workspace allocated for + the ARKLS linear solver interface. + ---------------------------------------------------------------*/ +int arkLSGetWorkSpace(void *arkode_mem, long int *lenrw, + long int *leniw) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + sunindextype lrw1, liw1; + long int lrw, liw; + int retval; + + /* access ARKLsMem structure */ + retval = arkLs_AccessLMem(arkode_mem, "arkLSGetWorkSpace", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* start with fixed sizes plus vector/matrix pointers */ + *lenrw = 3; + *leniw = 30; + + /* add NVector sizes */ + if (arkls_mem->x->ops->nvspace) { + N_VSpace(arkls_mem->x, &lrw1, &liw1); + *lenrw += 2*lrw1; + *leniw += 2*liw1; + } + + /* add SUNMatrix size (only account for the one owned by Ls interface) */ + if (arkls_mem->savedJ) + if (arkls_mem->savedJ->ops->space) { + retval = SUNMatSpace(arkls_mem->savedJ, &lrw, &liw); + if (retval == 0) { + *lenrw += lrw; + *leniw += liw; + } + } + + /* add LS sizes */ + if (arkls_mem->LS->ops->space) { + retval = SUNLinSolSpace(arkls_mem->LS, &lrw, &liw); + if (retval == SUNLS_SUCCESS) { + *lenrw += lrw; + *leniw += liw; + } + } + + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSGetNumJacEvals returns the number of Jacobian evaluations + ---------------------------------------------------------------*/ +int arkLSGetNumJacEvals(void *arkode_mem, long int *njevals) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + int retval; + + /* access ARKLsMem structure; set output value and return */ + retval = arkLs_AccessLMem(arkode_mem, "arkLSGetNumJacEvals", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + *njevals = arkls_mem->nje; + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSGetNumRhsEvals returns the number of calls to the ODE + function needed for the DQ Jacobian approximation or J*v product + approximation. + ---------------------------------------------------------------*/ +int arkLSGetNumRhsEvals(void *arkode_mem, long int *nfevalsLS) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + int retval; + + /* access ARKLsMem structure; set output value and return */ + retval = arkLs_AccessLMem(arkode_mem, "arkLSGetNumRhsEvals", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + *nfevalsLS = arkls_mem->nfeDQ; + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSGetNumPrecEvals returns the number of calls to the + user- or ARKode-supplied preconditioner setup routine. + ---------------------------------------------------------------*/ +int arkLSGetNumPrecEvals(void *arkode_mem, long int *npevals) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + int retval; + + /* access ARKLsMem structure; set output value and return */ + retval = arkLs_AccessLMem(arkode_mem, "arkLSGetNumPrecEvals", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + *npevals = arkls_mem->npe; + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSGetNumPrecSolves returns the number of calls to the + user- or ARKode-supplied preconditioner solve routine. + ---------------------------------------------------------------*/ +int arkLSGetNumPrecSolves(void *arkode_mem, long int *npsolves) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + int retval; + + /* access ARKLsMem structure; set output value and return */ + retval = arkLs_AccessLMem(arkode_mem, "arkLSGetNumPrecSolves", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + *npsolves = arkls_mem->nps; + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSGetNumLinIters returns the number of linear iterations + (if accessible from the LS object). + ---------------------------------------------------------------*/ +int arkLSGetNumLinIters(void *arkode_mem, long int *nliters) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + int retval; + + /* access ARKLsMem structure; set output value and return */ + retval = arkLs_AccessLMem(arkode_mem, "arkLSGetNumLinIters", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + *nliters = arkls_mem->nli; + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSGetNumConvFails returns the number of linear solver + convergence failures (as reported by the LS object). + ---------------------------------------------------------------*/ +int arkLSGetNumConvFails(void *arkode_mem, long int *nlcfails) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + int retval; + + /* access ARKLsMem structure; set output value and return */ + retval = arkLs_AccessLMem(arkode_mem, "arkLSGetNumConvFails", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + *nlcfails = arkls_mem->ncfl; + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSGetNumJTSetupEvals returns the number of calls to the + user-supplied Jacobian-vector product setup routine. + ---------------------------------------------------------------*/ +int arkLSGetNumJTSetupEvals(void *arkode_mem, long int *njtsetups) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + int retval; + + /* access ARKLsMem structure; set output value and return */ + retval = arkLs_AccessLMem(arkode_mem, "arkLSGetNumJTSetupEvals", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + *njtsetups = arkls_mem->njtsetup; + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSGetNumJtimesEvals returns the number of calls to the + Jacobian-vector product multiply routine. + ---------------------------------------------------------------*/ +int arkLSGetNumJtimesEvals(void *arkode_mem, long int *njvevals) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + int retval; + + /* access ARKLsMem structure; set output value and return */ + retval = arkLs_AccessLMem(arkode_mem, "arkLSGetNumJtimesEvals", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + *njvevals = arkls_mem->njtimes; + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSGetLastFlag returns the last flag set in a ARKLS + function. + ---------------------------------------------------------------*/ +int arkLSGetLastFlag(void *arkode_mem, long int *flag) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + int retval; + + /* access ARKLsMem structure; set output value and return */ + retval = arkLs_AccessLMem(arkode_mem, "arkLSGetLastFlag", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + *flag = arkls_mem->last_flag; + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSGetReturnFlagName translates from the integer error code + returned by an ARKLs routine to the corresponding string + equivalent for that flag + ---------------------------------------------------------------*/ +char *arkLSGetReturnFlagName(long int flag) +{ + char *name = (char *)malloc(30*sizeof(char)); + + switch(flag) { + case ARKLS_SUCCESS: + sprintf(name,"ARKLS_SUCCESS"); + break; + case ARKLS_MEM_NULL: + sprintf(name,"ARKLS_MEM_NULL"); + break; + case ARKLS_LMEM_NULL: + sprintf(name,"ARKLS_LMEM_NULL"); + break; + case ARKLS_ILL_INPUT: + sprintf(name,"ARKLS_ILL_INPUT"); + break; + case ARKLS_MEM_FAIL: + sprintf(name,"ARKLS_MEM_FAIL"); + break; + case ARKLS_MASSMEM_NULL: + sprintf(name,"ARKLS_MASSMEM_NULL"); + break; + case ARKLS_JACFUNC_UNRECVR: + sprintf(name,"ARKLS_JACFUNC_UNRECVR"); + break; + case ARKLS_JACFUNC_RECVR: + sprintf(name,"ARKLS_JACFUNC_RECVR"); + break; + case ARKLS_MASSFUNC_UNRECVR: + sprintf(name,"ARKLS_MASSFUNC_UNRECVR"); + break; + case ARKLS_MASSFUNC_RECVR: + sprintf(name,"ARKLS_MASSFUNC_RECVR"); + break; + case ARKLS_SUNMAT_FAIL: + sprintf(name,"ARKLS_SUNMAT_FAIL"); + break; + case ARKLS_SUNLS_FAIL: + sprintf(name,"ARKLS_SUNLS_FAIL"); + break; + default: + sprintf(name,"NONE"); + } + + return(name); +} + + +/*--------------------------------------------------------------- + arkLSSetMassEpsLin specifies the nonlinear -> linear tolerance + scale factor for mass matrix linear systems. + ---------------------------------------------------------------*/ +int arkLSSetMassEpsLin(void *arkode_mem, realtype eplifac) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + int retval; + + /* access ARKLsMassMem structure; store input and return */ + retval = arkLs_AccessMassMem(arkode_mem, "arkLSSetMassEpsLin", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + arkls_mem->eplifac = (eplifac <= ZERO) ? ARKLS_EPLIN : eplifac; + + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSSetMassPreconditioner specifies the user-supplied + preconditioner setup and solve routines. + ---------------------------------------------------------------*/ +int arkLSSetMassPreconditioner(void *arkode_mem, + ARKLsMassPrecSetupFn psetup, + ARKLsMassPrecSolveFn psolve) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + PSetupFn arkls_mpsetup; + PSolveFn arkls_mpsolve; + int retval; + + /* access ARKLsMassMem structure */ + retval = arkLs_AccessMassMem(arkode_mem, "arkLSSetMassPreconditioner", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* issue error if LS object does not allow user-supplied preconditioning */ + if (arkls_mem->LS->ops->setpreconditioner == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", + "arkLSSetMassPreconditioner", + "SUNLinearSolver object does not support user-supplied preconditioning"); + return(ARKLS_ILL_INPUT); + } + + /* store function pointers for user-supplied routines in ARKLs interface */ + arkls_mem->pset = psetup; + arkls_mem->psolve = psolve; + + /* notify linear solver to call ARKLs interface routines */ + arkls_mpsetup = (psetup == NULL) ? NULL : arkLsMPSetup; + arkls_mpsolve = (psolve == NULL) ? NULL : arkLsMPSolve; + retval = SUNLinSolSetPreconditioner(arkls_mem->LS, ark_mem, + arkls_mpsetup, arkls_mpsolve); + if (retval != SUNLS_SUCCESS) { + arkProcessError(ark_mem, ARKLS_SUNLS_FAIL, "ARKLS", + "arkLSSetMassPreconditioner", + "Error in calling SUNLinSolSetPreconditioner"); + return(ARKLS_SUNLS_FAIL); + } + + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSSetMassTimes specifies the user-supplied mass + matrix-vector product setup and multiply routines. + ---------------------------------------------------------------*/ +int arkLSSetMassTimes(void *arkode_mem, + ARKLsMassTimesSetupFn mtsetup, + ARKLsMassTimesVecFn mtimes, + void *mtimes_data) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + int retval; + + /* access ARKLsMassMem structure */ + retval = arkLs_AccessMassMem(arkode_mem, "arkLSSetMassTimes", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* issue error if mtimes function is unusable */ + if (mtimes == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", + "arkLSSetMassTimes", + "non-NULL mtimes function must be supplied"); + return(ARKLS_ILL_INPUT); + } + + /* issue error if LS object does not allow user-supplied ATimes */ + if (arkls_mem->LS->ops->setatimes == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", + "arkLSSetMassTimes", + "SUNLinearSolver object does not support user-supplied ATimes routine"); + return(ARKLS_ILL_INPUT); + } + + /* store pointers for user-supplied routines and data structure + in ARKLs interface */ + arkls_mem->mtsetup = mtsetup; + arkls_mem->mtimes = mtimes; + arkls_mem->mt_data = mtimes_data; + + /* notify linear solver to call ARKLs interface routine */ + retval = SUNLinSolSetATimes(arkls_mem->LS, ark_mem, arkLsMTimes); + if (retval != SUNLS_SUCCESS) { + arkProcessError(ark_mem, ARKLS_SUNLS_FAIL, "ARKLS", + "arkLSSetMassTimes", + "Error in calling SUNLinSolSetATimes"); + return(ARKLS_SUNLS_FAIL); + } + + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSGetMassWorkSpace + ---------------------------------------------------------------*/ +int arkLSGetMassWorkSpace(void *arkode_mem, long int *lenrw, + long int *leniw) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + sunindextype lrw1, liw1; + long int lrw, liw; + int retval; + + /* access ARKLsMassMem structure */ + retval = arkLs_AccessMassMem(arkode_mem, "arkLSGetMassWorkSpace", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* start with fixed sizes plus vector/matrix pointers */ + *lenrw = 2; + *leniw = 23; + + /* add NVector sizes */ + if (ark_mem->tempv1->ops->nvspace) { + N_VSpace(ark_mem->tempv1, &lrw1, &liw1); + *lenrw += lrw1; + *leniw += liw1; + } + + /* add SUNMatrix size (only account for the one owned by Ls interface) */ + if (arkls_mem->M_lu) + if (arkls_mem->M_lu->ops->space) { + retval = SUNMatSpace(arkls_mem->M_lu, &lrw, &liw); + if (retval == 0) { + *lenrw += lrw; + *leniw += liw; + } + } + + /* add LS sizes */ + if (arkls_mem->LS->ops->space) { + retval = SUNLinSolSpace(arkls_mem->LS, &lrw, &liw); + if (retval == SUNLS_SUCCESS) { + *lenrw += lrw; + *leniw += liw; + } + } + + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSGetNumMassSetups returns the number of mass matrix + solver 'setup' calls + ---------------------------------------------------------------*/ +int arkLSGetNumMassSetups(void *arkode_mem, long int *nmsetups) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + int retval; + + /* access ARKLsMassMem structure; set output value and return */ + retval = arkLs_AccessMassMem(arkode_mem, "arkLSGetNumMassSetups", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + *nmsetups = arkls_mem->nmsetups; + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSGetNumMassMult returns the number of calls to the user- + supplied or internal mass matrix-vector product multiply routine. + ---------------------------------------------------------------*/ +int arkLSGetNumMassMult(void *arkode_mem, long int *nmvevals) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + int retval; + + /* access ARKLsMassMem structure; set output value and return */ + retval = arkLs_AccessMassMem(arkode_mem, "arkLSGetNumMassMult", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + *nmvevals = arkls_mem->nmtimes; + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSGetNumMassSolves returns the number of mass matrix + solver 'solve' calls + ---------------------------------------------------------------*/ +int arkLSGetNumMassSolves(void *arkode_mem, long int *nmsolves) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + int retval; + + /* access ARKLsMassMem structure; set output value and return */ + retval = arkLs_AccessMassMem(arkode_mem, "arkLSGetNumMassSolves", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + *nmsolves = arkls_mem->nmsolves; + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSGetNumMassPrecEvals returns the number of calls to the + user- or ARKode-supplied preconditioner setup routine. + ---------------------------------------------------------------*/ +int arkLSGetNumMassPrecEvals(void *arkode_mem, long int *npevals) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + int retval; + + /* access ARKLsMassMem structure; set output value and return */ + retval = arkLs_AccessMassMem(arkode_mem, "arkLSGetNumMassPrecEvals", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + *npevals = arkls_mem->npe; + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSGetNumMassPrecSolves returns the number of calls to the + user- or ARKode-supplied preconditioner solve routine. + ---------------------------------------------------------------*/ +int arkLSGetNumMassPrecSolves(void *arkode_mem, long int *npsolves) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + int retval; + + /* access ARKLsMassMem structure; set output value and return */ + retval = arkLs_AccessMassMem(arkode_mem, "arkLSGetNumMassPrecSolves", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + *npsolves = arkls_mem->nps; + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSGetNumMassIters returns the number of mass matrix solver + linear iterations (if accessible from the LS object). + ---------------------------------------------------------------*/ +int arkLSGetNumMassIters(void *arkode_mem, long int *nmiters) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + int retval; + + /* access ARKLsMassMem structure; set output value and return */ + retval = arkLs_AccessMassMem(arkode_mem, "arkLSGetNumMassIters", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + *nmiters = arkls_mem->nli; + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSGetNumMassConvFails returns the number of linear solver + convergence failures (as reported by the LS object). + ---------------------------------------------------------------*/ +int arkLSGetNumMassConvFails(void *arkode_mem, long int *nmcfails) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + int retval; + + /* access ARKLsMassMem structure; set output value and return */ + retval = arkLs_AccessMassMem(arkode_mem, "arkLSGetNumMassConvFails", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + *nmcfails = arkls_mem->ncfl; + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSGetNumMTSetups returns the number of calls to the + user-supplied mass matrix-vector product setup routine. + ---------------------------------------------------------------*/ +int arkLSGetNumMTSetups(void *arkode_mem, long int *nmtsetups) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + int retval; + + /* access ARKLsMassMem structure; set output value and return */ + retval = arkLs_AccessMassMem(arkode_mem, "arkLSGetNumMTSetups", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + *nmtsetups = arkls_mem->nmtsetup; + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLSGetLastMassFlag returns the last flag set in a ARKLS + function. + ---------------------------------------------------------------*/ +int arkLSGetLastMassFlag(void *arkode_mem, long int *flag) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + int retval; + + /* access ARKLsMassMem structure; set output value and return */ + retval = arkLs_AccessMassMem(arkode_mem, "arkLSGetLastMassFlag", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + *flag = arkls_mem->last_flag; + return(ARKLS_SUCCESS); +} + + +/*=============================================================== + ARKLS Private functions + ===============================================================*/ + +/*--------------------------------------------------------------- + arkLsATimes: + + This routine generates the matrix-vector product z = Av, where + A = M - gamma*J. The product M*v is obtained either by calling + the mtimes routine or by just using v (if M=I). The product + J*v is obtained by calling the jtimes routine. It is then scaled + by -gamma and added to M*v to obtain A*v. The return value is + the same as the values returned by jtimes and mtimes -- + 0 if successful, nonzero otherwise. + ---------------------------------------------------------------*/ +int arkLsATimes(void *arkode_mem, N_Vector v, N_Vector z) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + void* ark_step_massmem; + int retval; + realtype gamma, gamrat; + booleantype dgamma_fail, *jcur; + + /* access ARKLsMem structure */ + retval = arkLs_AccessLMem(arkode_mem, "arkLsATimes", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* Access mass matrix solver (if it exists) */ + ark_step_massmem = NULL; + if (ark_mem->step_getmassmem != NULL) + ark_step_massmem = ark_mem->step_getmassmem(arkode_mem); + + /* get gamma values from time step module */ + retval = ark_mem->step_getgammas(arkode_mem, &gamma, &gamrat, + &jcur, &dgamma_fail); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, retval, "ARKLS", "arkLsATimes", + "An error occurred in ark_step_getgammas"); + return(retval); + } + + /* call Jacobian-times-vector product routine + (either user-supplied or internal DQ) */ + retval = arkls_mem->jtimes(v, z, + arkls_mem->tcur, + arkls_mem->ycur, + arkls_mem->fcur, + arkls_mem->Jt_data, + arkls_mem->ytemp); + arkls_mem->njtimes++; + if (retval != 0) return(retval); + + /* Compute mass matrix vector product and add to result */ + if (ark_step_massmem != NULL) { + retval = arkLsMTimes(arkode_mem, v, arkls_mem->ytemp); + if (retval != 0) return(retval); + N_VLinearSum(ONE, arkls_mem->ytemp, -gamma, z, z); + } else { + N_VLinearSum(ONE, v, -gamma, z, z); + } + + return(0); +} + +/*--------------------------------------------------------------- + arkLsPSetup: + + This routine interfaces between the generic iterative linear + solvers and the user's psetup routine. It passes to psetup all + required state information from arkode_mem. Its return value + is the same as that returned by psetup. Note that the generic + iterative linear solvers guarantee that arkLsPSetup will only + be called in the case that the user's psetup routine is non-NULL. + ---------------------------------------------------------------*/ +int arkLsPSetup(void *arkode_mem) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + realtype gamma, gamrat; + booleantype dgamma_fail, *jcur; + int retval; + + /* access ARKLsMem structure */ + retval = arkLs_AccessLMem(arkode_mem, "arkLsPSetup", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* get gamma values from time step module */ + retval = ark_mem->step_getgammas(arkode_mem, &gamma, &gamrat, + &jcur, &dgamma_fail); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, retval, "ARKLS", "arkLsPSetup", + "An error occurred in ark_step_getgammas"); + return(retval); + } + + /* Call user pset routine to update preconditioner and possibly + reset jcur (pass !jbad as update suggestion) */ + retval = arkls_mem->pset(arkls_mem->tcur, + arkls_mem->ycur, + arkls_mem->fcur, + !(arkls_mem->jbad), + jcur, gamma, + arkls_mem->P_data); + return(retval); +} + +/*--------------------------------------------------------------- + arkLsPSolve: + + This routine interfaces between the generic SUNLinSolSolve + routine and the user's psolve routine. It passes to psolve all + required state information from arkode_mem. Its return value + is the same as that returned by psolve. Note that the generic + SUNLinSol solver guarantees that arkLsPSolve will not be + called in the case in which preconditioning is not done. This + is the only case in which the user's psolve routine is allowed + to be NULL. + ---------------------------------------------------------------*/ +int arkLsPSolve(void *arkode_mem, N_Vector r, N_Vector z, + realtype tol, int lr) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + realtype gamma, gamrat; + booleantype dgamma_fail, *jcur; + int retval; + + /* access ARKLsMem structure */ + retval = arkLs_AccessLMem(arkode_mem, "arkLsPSolve", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* get gamma values from time step module */ + retval = ark_mem->step_getgammas(arkode_mem, &gamma, &gamrat, + &jcur, &dgamma_fail); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, retval, "ARKLS", "arkLsPSolve", + "An error occurred in ark_step_getgammas"); + return(retval); + } + + /* call the user-supplied psolve routine, and accumulate count */ + retval = arkls_mem->psolve(arkls_mem->tcur, + arkls_mem->ycur, + arkls_mem->fcur, r, z, + gamma, tol, lr, + arkls_mem->P_data); + arkls_mem->nps++; + return(retval); +} + +/*--------------------------------------------------------------- + arkLsMTimes: + + This routine generates the matrix-vector product z = Mv, where + M is the system mass matrix, by calling the user-supplied mtimes + routine. The return value is the same as the value returned + by mtimes -- 0 if successful, nonzero otherwise. + ---------------------------------------------------------------*/ +int arkLsMTimes(void *arkode_mem, N_Vector v, N_Vector z) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + int retval; + + /* access ARKLsMassMem structure */ + retval = arkLs_AccessMassMem(arkode_mem, "arkLsMTimes", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* perform multiply by either calling the user-supplied routine + (default), or asking the SUNMatrix to do the multiply */ + retval = -1; + if (arkls_mem->mtimes) { + + /* call user-supplied mtimes routine and increment counter */ + retval = arkls_mem->mtimes(v, z, ark_mem->tcur, + arkls_mem->mt_data); + + } else if (arkls_mem->M) { + + if (arkls_mem->M->ops->matvec) + retval = SUNMatMatvec(arkls_mem->M, v, z); + + } + + if (retval == 0) { + arkls_mem->nmtimes++; + } else { + arkProcessError(ark_mem, retval, "ARKLS", "arkLsMTimes", + "Missing mass matrix-vector product routine"); + } + return(retval); +} + + +/*--------------------------------------------------------------- + arkLsMPSetup: + + This routine interfaces between the generic linear solver and + the user's mass matrix psetup routine. It passes to psetup all + required state information from arkode_mem. Its return value + is the same as that returned by psetup. Note that the generic + linear solvers guarantee that arkLsMPSetup will only be + called if the user's psetup routine is non-NULL. + ---------------------------------------------------------------*/ +int arkLsMPSetup(void *arkode_mem) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + int retval; + + /* access ARKLsMassMem structure */ + retval = arkLs_AccessMassMem(arkode_mem, "arkLsMPSetup", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* only proceed if the mass matrix is time-independent or if + pset has not been called previously */ + if (!arkls_mem->time_dependent && arkls_mem->npe) + return(0); + + /* call user-supplied pset routine and increment counter */ + retval = arkls_mem->pset(ark_mem->tcur, arkls_mem->P_data); + arkls_mem->npe++; + return(retval); +} + + +/*--------------------------------------------------------------- + arkLsMPSolve: + + This routine interfaces between the generic LS routine and the + user's mass matrix psolve routine. It passes to psolve all + required state information from arkode_mem. Its return value is + the same as that returned by psolve. Note that the generic + solver guarantees that arkLsMPSolve will not be called in the + case in which preconditioning is not done. This is the only case + in which the user's psolve routine is allowed to be NULL. + ---------------------------------------------------------------*/ +int arkLsMPSolve(void *arkode_mem, N_Vector r, N_Vector z, + realtype tol, int lr) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + int retval; + + /* access ARKLsMassMem structure */ + retval = arkLs_AccessMassMem(arkode_mem, "arkLsMPSolve", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* call the user-supplied psolve routine, and accumulate count */ + retval = arkls_mem->psolve(ark_mem->tcur, r, z, tol, + lr, arkls_mem->P_data); + arkls_mem->nps++; + return(retval); +} + + +/*--------------------------------------------------------------- + arkLsDQJac: + + This routine is a wrapper for the Dense and Band + implementations of the difference quotient Jacobian + approximation routines. + ---------------------------------------------------------------*/ +int arkLsDQJac(realtype t, N_Vector y, N_Vector fy, + SUNMatrix Jac, void *arkode_mem, N_Vector tmp1, + N_Vector tmp2, N_Vector tmp3) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + ARKRhsFn fi; + int retval; + + /* access ARKLsMem structure */ + retval = arkLs_AccessLMem(arkode_mem, "arkLsDQJac", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* verify that Jac is non-NULL */ + if (Jac == NULL) { + arkProcessError(ark_mem, ARKLS_LMEM_NULL, "ARKLS", + "arkLsDQJac", "SUNMatrix is NULL"); + return(ARKLS_LMEM_NULL); + } + + /* Access implicit RHS function */ + fi = ark_mem->step_getimplicitrhs((void*) ark_mem); + if (fi == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", + "arkLsDQJac", + "Time step module is missing implicit RHS fcn"); + return(ARKLS_ILL_INPUT); + } + + /* Verify that N_Vector supports required routines */ + if (ark_mem->tempv1->ops->nvcloneempty == NULL || + ark_mem->tempv1->ops->nvwrmsnorm == NULL || + ark_mem->tempv1->ops->nvlinearsum == NULL || + ark_mem->tempv1->ops->nvdestroy == NULL || + ark_mem->tempv1->ops->nvscale == NULL || + ark_mem->tempv1->ops->nvgetarraypointer == NULL || + ark_mem->tempv1->ops->nvsetarraypointer == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", + "arkLsDQJac", MSG_LS_BAD_NVECTOR); + return(ARKLS_ILL_INPUT); + } + + /* Call the matrix-structure-specific DQ approximation routine */ + if (SUNMatGetID(Jac) == SUNMATRIX_DENSE) { + retval = arkLsDenseDQJac(t, y, fy, Jac, ark_mem, arkls_mem, + fi, tmp1); + } else if (SUNMatGetID(Jac) == SUNMATRIX_BAND) { + retval = arkLsBandDQJac(t, y, fy, Jac, ark_mem, arkls_mem, + fi, tmp1, tmp2); + } else { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLsDQJac", + "arkLsDQJac not implemented for this SUNMatrix type!"); + retval = ARKLS_ILL_INPUT; + } + return(retval); +} + +/*--------------------------------------------------------------- + arkLsDenseDQJac: + + This routine generates a dense difference quotient approximation + to the Jacobian of f(t,y). It assumes a dense SUNMatrix input + (stored column-wise, and that elements within each column are + contiguous). The address of the jth column of J is obtained via + the function SUNDenseMatrix_Column() and this pointer is + associated with an N_Vector using the + N_VGetArrayPointer/N_VSetArrayPointer functions. Finally, the + actual computation of the jth column of the Jacobian is done + with a call to N_VLinearSum. + ---------------------------------------------------------------*/ +int arkLsDenseDQJac(realtype t, N_Vector y, N_Vector fy, + SUNMatrix Jac, ARKodeMem ark_mem, + ARKLsMem arkls_mem, ARKRhsFn fi, + N_Vector tmp1) +{ + realtype fnorm, minInc, inc, inc_inv, yjsaved, srur; + realtype *y_data, *ewt_data; + N_Vector ftemp, jthCol; + sunindextype j, N; + int retval = 0; + + /* access matrix dimension */ + N = SUNDenseMatrix_Rows(Jac); + + /* Rename work vector for readibility */ + ftemp = tmp1; + + /* Create an empty vector for matrix column calculations */ + jthCol = N_VCloneEmpty(tmp1); + + /* Obtain pointers to the data for ewt, y */ + ewt_data = N_VGetArrayPointer(ark_mem->ewt); + y_data = N_VGetArrayPointer(y); + + /* Set minimum increment based on uround and norm of f */ + srur = SUNRsqrt(ark_mem->uround); + fnorm = N_VWrmsNorm(fy, ark_mem->rwt); + minInc = (fnorm != ZERO) ? + (MIN_INC_MULT * SUNRabs(ark_mem->h) * ark_mem->uround * N * fnorm) : ONE; + + for (j = 0; j < N; j++) { + + /* Generate the jth col of J(tn,y) */ + N_VSetArrayPointer(SUNDenseMatrix_Column(Jac,j), jthCol); + + yjsaved = y_data[j]; + inc = SUNMAX(srur*SUNRabs(yjsaved), minInc/ewt_data[j]); + y_data[j] += inc; + + retval = fi(t, y, ftemp, ark_mem->user_data); + arkls_mem->nfeDQ++; + if (retval != 0) break; + + y_data[j] = yjsaved; + + inc_inv = ONE/inc; + N_VLinearSum(inc_inv, ftemp, -inc_inv, fy, jthCol); + + } + + /* Destroy jthCol vector */ + N_VSetArrayPointer(NULL, jthCol); /* SHOULDN'T BE NEEDED */ + N_VDestroy(jthCol); + + return(retval); +} + + +/*--------------------------------------------------------------- + arkLsBandDQJac: + + This routine generates a banded difference quotient approximation + to the Jacobian of f(t,y). It assumes a band SUNMatrix input + (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 function SUNBandMatrix_Column() and to + write a simple for loop to set each of the elements of a column + in succession. + ---------------------------------------------------------------*/ +int arkLsBandDQJac(realtype t, N_Vector y, N_Vector fy, + SUNMatrix Jac, ARKodeMem ark_mem, + ARKLsMem arkls_mem, ARKRhsFn fi, + N_Vector tmp1, N_Vector tmp2) +{ + N_Vector ftemp, ytemp; + realtype fnorm, minInc, inc, inc_inv, srur; + realtype *col_j, *ewt_data, *fy_data, *ftemp_data, *y_data, *ytemp_data; + sunindextype group, i, j, width, ngroups, i1, i2; + sunindextype N, mupper, mlower; + int retval = 0; + + /* access matrix dimensions */ + N = SUNBandMatrix_Columns(Jac); + mupper = SUNBandMatrix_UpperBandwidth(Jac); + mlower = SUNBandMatrix_LowerBandwidth(Jac); + + /* Rename work vectors for use as temporary values of y and f */ + ftemp = tmp1; + ytemp = tmp2; + + /* Obtain pointers to the data for ewt, fy, ftemp, y, ytemp */ + 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); + + /* Load ytemp with y = predicted y vector */ + N_VScale(ONE, y, ytemp); + + /* Set minimum increment based on uround and norm of f */ + srur = SUNRsqrt(ark_mem->uround); + fnorm = N_VWrmsNorm(fy, ark_mem->rwt); + minInc = (fnorm != ZERO) ? + (MIN_INC_MULT * SUNRabs(ark_mem->h) * ark_mem->uround * N * fnorm) : ONE; + + /* Set bandwidth and number of column groups for band differencing */ + width = mlower + mupper + 1; + ngroups = SUNMIN(width, N); + + /* Loop over column groups. */ + for (group=1; group <= ngroups; group++) { + + /* 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]); + ytemp_data[j] += inc; + } + + /* Evaluate f with incremented y */ + retval = fi(ark_mem->tcur, ytemp, ftemp, ark_mem->user_data); + arkls_mem->nfeDQ++; + if (retval != 0) break; + + /* Restore ytemp, then form and load difference quotients */ + for (j=group-1; j < N; j+=width) { + ytemp_data[j] = y_data[j]; + col_j = SUNBandMatrix_Column(Jac, j); + inc = SUNMAX(srur*SUNRabs(y_data[j]), minInc/ewt_data[j]); + inc_inv = ONE/inc; + i1 = SUNMAX(0, j-mupper); + i2 = SUNMIN(j+mlower, N-1); + for (i=i1; i <= i2; i++) + SM_COLUMN_ELEMENT_B(col_j,i,j) = inc_inv * (ftemp_data[i] - fy_data[i]); + } + } + + return(retval); +} + + +/*--------------------------------------------------------------- + arkLsDQJtimes: + + This routine generates a difference quotient approximation to + the Jacobian-vector product fi_y(t,y) * v. The approximation is + Jv = [fi(y + v*sig) - fi(y)]/sig, where sig = 1 / ||v||_WRMS, + i.e. the WRMS norm of v*sig is 1. + ---------------------------------------------------------------*/ +int arkLsDQJtimes(N_Vector v, N_Vector Jv, realtype t, + N_Vector y, N_Vector fy, void *arkode_mem, + N_Vector work) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + ARKRhsFn fi; + realtype sig, siginv; + int iter, retval; + + /* access ARKLsMem structure */ + retval = arkLs_AccessLMem(arkode_mem, "arkLsDQJtimes", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* Initialize perturbation to 1/||v|| */ + sig = ONE/N_VWrmsNorm(v, ark_mem->ewt); + + /* Access implicit RHS function */ + fi = ark_mem->step_getimplicitrhs(arkode_mem); + if (fi == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", + "arkLsDQJtimes", + "Time step module is missing implicit RHS fcn"); + return(ARKLS_ILL_INPUT); + } + + for (iter=0; iter<MAX_DQITERS; iter++) { + + /* Set work = y + sig*v */ + N_VLinearSum(sig, v, ONE, y, work); + + /* Set Jv = f(tn, y+sig*v) */ + retval = fi(t, work, Jv, ark_mem->user_data); + arkls_mem->nfeDQ++; + if (retval == 0) break; + if (retval < 0) return(-1); + + /* If fi failed recoverably, shrink sig and retry */ + sig *= PT25; + + } + + /* If retval still isn't 0, return with a recoverable failure */ + if (retval > 0) return(+1); + + /* Replace Jv by (Jv - fy)/sig */ + siginv = ONE/sig; + N_VLinearSum(siginv, Jv, -siginv, fy, Jv); + + return(0); +} + + +/*--------------------------------------------------------------- + arkLsInitialize performs remaining initializations specific + to the iterative linear solver interface (and solver itself) + ---------------------------------------------------------------*/ +int arkLsInitialize(void* arkode_mem) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + ARKLsMassMem arkls_massmem; + int retval; + + /* access ARKLsMem structure */ + retval = arkLs_AccessLMem(arkode_mem, "arkLsInitialize", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* access ARKLsMassMem (if applicable) */ + arkls_massmem = NULL; + if (ark_mem->step_getmassmem != NULL) + if (ark_mem->step_getmassmem(arkode_mem) != NULL) { + retval = arkLs_AccessMassMem(arkode_mem, "arkLsInitialize", + &ark_mem, &arkls_massmem); + if (retval != ARK_SUCCESS) return(retval); + } + + + /* Test for valid combinations of matrix & Jacobian routines: */ + 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; + + } else if (arkls_mem->jacDQ) { + + /* 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) { + + 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 { + + /* 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; + } + + + /* Test for valid combination of system matrix and mass matrix (if applicable) */ + if (arkls_massmem) { + + /* A and M must both be NULL or non-NULL */ + if ( (arkls_mem->A==NULL) ^ (arkls_massmem->M==NULL) ) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLsInitialize", + "Cannot combine NULL and non-NULL System and mass matrices"); + arkls_mem->last_flag = ARKLS_ILL_INPUT; + return(ARKLS_ILL_INPUT); + } + + /* If A is non-NULL, A and M must have matching types (if accessible) */ + if (arkls_mem->A) { + retval = 0; + if ((arkls_mem->A->ops->getid==NULL) ^ (arkls_massmem->M->ops->getid==NULL)) + retval++; + if (arkls_mem->A->ops->getid) + if (SUNMatGetID(arkls_mem->A) != SUNMatGetID(arkls_massmem->M)) + retval++; + if (retval) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLsInitialize", + "System and mass matrices have incompatible types"); + arkls_mem->last_flag = ARKLS_ILL_INPUT; + return(ARKLS_ILL_INPUT); + } + } + + /* initialize mass matrix linear solver */ + retval = arkLsMassInitialize(arkode_mem); + if (retval != ARKLS_SUCCESS) { + arkls_mem->last_flag = retval; + return(retval); + } + } + + /* reset counters */ + arkLsInitializeCounters(arkls_mem); + + /* Set Jacobian-vector product 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 + not need to be called, so set the lsetup function to NULL (if possible) */ + if ( (arkls_mem->A == NULL) && + (arkls_mem->pset == NULL) && + (ark_mem->step_disablelsetup != NULL) ) + ark_mem->step_disablelsetup(arkode_mem); + + /* Call LS initialize routine, and return result */ + arkls_mem->last_flag = SUNLinSolInitialize(arkls_mem->LS); + return(arkls_mem->last_flag); +} + + +/*--------------------------------------------------------------- + arkLsSetup conditionally calls the LS 'setup' routine. + + When using a SUNMatrix object, this determines whether + to update a Jacobian matrix (or use a stored version), based + on heuristics regarding previous convergence issues, the number + of time steps since it was last updated, etc.; it then creates + the system matrix from this, the 'gamma' factor and the + mass/identity matrix, + A = M-gamma*J. + + This routine then calls the LS 'setup' routine with A. + ---------------------------------------------------------------*/ +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; + realtype gamma, gamrat; + booleantype dgamma_fail, *jcur; + int retval; + + /* access ARKLsMem structure */ + retval = arkLs_AccessLMem(arkode_mem, "arkLsInitialize", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* Set ARKLs time and N_Vector pointers to current time, + solution and rhs */ + arkls_mem->tcur = tpred; + arkls_mem->ycur = ypred; + arkls_mem->fcur = fpred; + + /* get gamma values from time step module */ + 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", + "An error occurred in ark_step_getgammas"); + return(arkls_mem->last_flag); + } + + /* Use nst, gamma/gammap, and convfail to set J/P eval. flag jok; + Note: the "ARK_FAIL_BAD_J" test is asking whether the nonlinear + solver converged due to a bad system Jacobian AND our gamma was + fine, indicating that the J and/or P were invalid */ + arkls_mem->jbad = (ark_mem->nst == 0) || + (ark_mem->nst > arkls_mem->nstlj + arkls_mem->msbj) || + ((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) { + + *jcurPtr = arkls_mem->jbad; + + } else { + + /* If jbad = SUNFALSE, use saved copy of J */ + if (!arkls_mem->jbad) { + + *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); + } + + /* If jbad = SUNTRUE, clear out J and call jac routine for new value */ + } else { + + 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); + } + + /* Perform linear combination A = M-gamma*A */ + retval = SUNMatScaleAdd(-gamma, arkls_mem->A, arkls_massmem->M); + + /* 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); + } + + } + + /* Call LS setup routine -- the LS may call arkLsPSetup, who will + pass the heuristic suggestions above to the user code(s) */ + arkls_mem->last_flag = SUNLinSolSetup(arkls_mem->LS, arkls_mem->A); + + /* If the SUNMatrix was NULL, update heuristics flags */ + if (arkls_mem->A == NULL) { + + /* If user set jcur to SUNTRUE, increment npe and save nst value */ + if (*jcurPtr) { + arkls_mem->npe++; + arkls_mem->nstlj = ark_mem->nst; + } + + /* Update jcurPtr flag if we suggested an update */ + if (arkls_mem->jbad) *jcurPtr = SUNTRUE; + } + + return(arkls_mem->last_flag); +} + +/*--------------------------------------------------------------- + arkLsSolve: interfaces between ARKode and the generic + SUNLinearSolver object LS, by setting the appropriate tolerance + and scaling vectors, calling the solver, and accumulating + statistics from the solve for use/reporting by ARKode. + + When using a non-NULL SUNMatrix, this will additionally scale + the solution appropriately when gamrat != 1. + ---------------------------------------------------------------*/ +int arkLsSolve(void* arkode_mem, N_Vector b, realtype tnow, + N_Vector ynow, N_Vector fnow, realtype eRNrm, int mnewt) +{ + realtype bnorm, resnorm; + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + realtype gamma, gamrat, delta, deltar, ewt_mean; + booleantype dgamma_fail, *jcur; + int nli_inc, nps_inc, retval, LSType; + + /* access ARKLsMem structure */ + retval = arkLs_AccessLMem(arkode_mem, "arkLsSolve", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* Set scalar tcur and vectors ycur and fcur for use by the + Atimes and Psolve interface routines */ + arkls_mem->tcur = 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) ) { + deltar = arkls_mem->eplifac * eRNrm; + bnorm = N_VWrmsNorm(b, ark_mem->rwt); + if (bnorm <= deltar) { + if (mnewt > 0) N_VConst(ZERO, b); + arkls_mem->last_flag = ARKLS_SUCCESS; + return(arkls_mem->last_flag); + } + delta = deltar * arkls_mem->sqrtN; + } else { + delta = 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); + if (retval != SUNLS_SUCCESS) { + arkProcessError(ark_mem, ARKLS_SUNLS_FAIL, "ARKLS", "arkLsSolve", + "Error in call to SUNLinSolSetScalingVectors"); + arkls_mem->last_flag = ARKLS_SUNLS_FAIL; + return(arkls_mem->last_flag); + } + + /* 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)), + || 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) ) { + + ewt_mean = SUNRsqrt( N_VDotProd(ark_mem->ewt, ark_mem->ewt) ) / arkls_mem->sqrtN; + delta /= ewt_mean; + + } + + /* Store previous nps value in nps_inc */ + nps_inc = arkls_mem->nps; + + /* If a user-provided jtsetup routine is supplied, call that here */ + if (arkls_mem->jtsetup) { + arkls_mem->last_flag = arkls_mem->jtsetup(tnow, ynow, fnow, + arkls_mem->Jt_data); + arkls_mem->njtsetup++; + if (arkls_mem->last_flag) { + arkProcessError(ark_mem, retval, "ARKLS", + "arkLsSolve", MSG_LS_JTSETUP_FAILED); + return(arkls_mem->last_flag); + } + } + + /* Call solver, and copy x to b */ + retval = SUNLinSolSolve(arkls_mem->LS, arkls_mem->A, + arkls_mem->x, b, delta); + N_VScale(ONE, arkls_mem->x, b); + + /* 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) ) { + arkls_mem->last_flag = ark_mem->step_getgammas(arkode_mem, &gamma, &gamrat, + &jcur, &dgamma_fail); + if (arkls_mem->last_flag != ARK_SUCCESS) { + arkProcessError(ark_mem, arkls_mem->last_flag, "ARKLS", "arkLsSolve", + "An error occurred in ark_step_getgammas"); + return(arkls_mem->last_flag); + } + if (gamrat != ONE) N_VScale(TWO/(ONE + gamrat), b, b); + } + + /* Retrieve statistics from iterative linear solvers */ + resnorm = ZERO; + nli_inc = 0; + if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || + (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { + if (arkls_mem->LS->ops->resnorm) + resnorm = SUNLinSolResNorm(arkls_mem->LS); + if (arkls_mem->LS->ops->numiters) + nli_inc = SUNLinSolNumIters(arkls_mem->LS); + } + + /* Increment counters nli and ncfl */ + arkls_mem->nli += nli_inc; + if (retval != SUNLS_SUCCESS) arkls_mem->ncfl++; + + /* 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); + + /* Interpret solver return value */ + arkls_mem->last_flag = retval; + + switch(retval) { + + case SUNLS_SUCCESS: + return(0); + break; + case SUNLS_RES_REDUCED: + /* allow reduction but not solution on first nonlinear iteration, + otherwise return with a recoverable failure */ + if (mnewt == 0) return(0); + else return(1); + break; + case SUNLS_CONV_FAIL: + case SUNLS_ATIMES_FAIL_REC: + case SUNLS_PSOLVE_FAIL_REC: + case SUNLS_PACKAGE_FAIL_REC: + case SUNLS_QRFACT_FAIL: + case SUNLS_LUFACT_FAIL: + return(1); + break; + case SUNLS_MEM_NULL: + case SUNLS_ILL_INPUT: + case SUNLS_MEM_FAIL: + case SUNLS_GS_FAIL: + case SUNLS_QRSOL_FAIL: + return(-1); + break; + case SUNLS_PACKAGE_FAIL_UNREC: + arkProcessError(ark_mem, SUNLS_PACKAGE_FAIL_UNREC, "ARKLS", + "arkLsSolve", + "Failure in SUNLinSol external package"); + return(-1); + break; + case SUNLS_ATIMES_FAIL_UNREC: + arkProcessError(ark_mem, SUNLS_ATIMES_FAIL_UNREC, "ARKLS", + "arkLsSolve", MSG_LS_JTIMES_FAILED); + return(-1); + break; + case SUNLS_PSOLVE_FAIL_UNREC: + arkProcessError(ark_mem, SUNLS_PSOLVE_FAIL_UNREC, "ARKLS", + "arkLsSolve", MSG_LS_PSOLVE_FAILED); + return(-1); + break; + } + + return(0); +} + + +/*--------------------------------------------------------------- + arkLsFree frees memory associates with the ARKLs system + solver interface. + ---------------------------------------------------------------*/ +int arkLsFree(void* arkode_mem) +{ + ARKodeMem ark_mem; + ARKLsMem arkls_mem; + void* ark_step_lmem; + + /* Return immediately if ARKodeMem, ARKLsMem are NULL */ + if (arkode_mem == NULL) return (ARKLS_SUCCESS); + ark_mem = (ARKodeMem) arkode_mem; + ark_step_lmem = ark_mem->step_getlinmem(arkode_mem); + if (ark_step_lmem == NULL) return(ARKLS_SUCCESS); + arkls_mem = (ARKLsMem) ark_step_lmem; + + /* Free N_Vector memory */ + if (arkls_mem->ytemp) { + N_VDestroy(arkls_mem->ytemp); + arkls_mem->ytemp = NULL; + } + if (arkls_mem->x) { + N_VDestroy(arkls_mem->x); + arkls_mem->x = NULL; + } + + /* Free savedJ memory */ + if (arkls_mem->savedJ) { + SUNMatDestroy(arkls_mem->savedJ); + arkls_mem->savedJ = NULL; + } + + /* Nullify other N_Vector pointers */ + arkls_mem->ycur = NULL; + arkls_mem->fcur = NULL; + + /* Nullify other SUNMatrix pointer */ + arkls_mem->A = NULL; + + /* Free preconditioner memory (if applicable) */ + if (arkls_mem->pfree) arkls_mem->pfree(ark_mem); + + /* free ARKLs interface structure */ + free(arkls_mem); + + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLsMassInitialize performs remaining initializations specific + to the iterative linear solver interface (and solver itself) + ---------------------------------------------------------------*/ +int arkLsMassInitialize(void *arkode_mem) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + int retval; + + /* access ARKLsMassMem structure */ + retval = arkLs_AccessMassMem(arkode_mem, "arkLsMassInitialize", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* reset counters */ + arkLsInitializeMassCounters(arkls_mem); + + /* perform checks for mass matrix constructor or mass matrix-vector product routine exist */ + if (arkls_mem->M == NULL) { + if (arkls_mem->mtimes == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", "arkLsMassInitialize", + "Missing user-provided mass matrix-vector product routine"); + arkls_mem->last_flag = ARKLS_ILL_INPUT; + return(arkls_mem->last_flag); + } + } else { + if (arkls_mem->mass == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", + "arkLsMassInitialize", + "Missing user-provided mass-matrix routine"); + arkls_mem->last_flag = ARKLS_ILL_INPUT; + return(arkls_mem->last_flag); + } + } + + /* ensure that a mass matrix solver exists */ + if (arkls_mem->LS == NULL) { + arkProcessError(ark_mem, ARKLS_ILL_INPUT, "ARKLS", + "arkLsMassInitialize", + "Missing SUNLinearSolver object"); + arkls_mem->last_flag = ARKLS_ILL_INPUT; + return(arkls_mem->last_flag); + } + + /* if M is NULL and neither pset or mtsetup are present, then + arkLsMassSetup does not need to be called, so set the + msetup function to NULL */ + if ( (arkls_mem->M == NULL) && + (arkls_mem->pset == NULL) && + (arkls_mem->mtsetup == NULL) && + (ark_mem->step_disablemsetup != NULL) ) + ark_mem->step_disablemsetup(arkode_mem); + + /* Call LS initialize routine */ + arkls_mem->last_flag = SUNLinSolInitialize(arkls_mem->LS); + return(arkls_mem->last_flag); +} + + +/*--------------------------------------------------------------- + arkLsMassSetup calls the LS 'setup' routine. + ---------------------------------------------------------------*/ +int arkLsMassSetup(void *arkode_mem, N_Vector vtemp1, + N_Vector vtemp2, N_Vector vtemp3) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + booleantype call_mtsetup, call_lssetup; + int retval; + + /* access ARKLsMassMem structure */ + retval = arkLs_AccessMassMem(arkode_mem, "arkLsMassSetup", + &ark_mem, &arkls_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* Determine whether to call user-provided mtsetup routine */ + call_mtsetup = SUNFALSE; + if ( (arkls_mem->mtsetup) && + (arkls_mem->time_dependent || (!arkls_mem->nmtsetup)) ) + call_mtsetup = SUNTRUE; + + /* call user-provided mtsetup routine if applicable */ + if (call_mtsetup) { + arkls_mem->last_flag = arkls_mem->mtsetup(ark_mem->tcur, + arkls_mem->mt_data); + arkls_mem->nmtsetup++; + if (arkls_mem->last_flag != 0) { + arkProcessError(ark_mem, arkls_mem->last_flag, "ARKLS", + "arkLsMassSetup", MSG_LS_MTSETUP_FAILED); + return(arkls_mem->last_flag); + } + } + + + /* 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); + + } else { + + /*** matrix-based ***/ + + /* If mass matrix is not time dependent, and if it has been set up + previously, just reuse existing M and M_lu */ + if (!arkls_mem->time_dependent && arkls_mem->nmsetups) { + arkls_mem->last_flag = ARKLS_SUCCESS; + 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); + } + + retval = arkls_mem->mass(ark_mem->tcur, arkls_mem->M, + ark_mem->user_data, + vtemp1, vtemp2, vtemp3); + if (retval < 0) { + arkProcessError(ark_mem, ARKLS_MASSFUNC_UNRECVR, "ARKLS", + "arkLsMassSetup", MSG_LS_MASSFUNC_FAILED); + arkls_mem->last_flag = ARKLS_MASSFUNC_UNRECVR; + return(-1); + } + if (retval > 0) { + arkls_mem->last_flag = ARKLS_MASSFUNC_RECVR; + return(1); + } + + /* Copy M into M_lu for factorization */ + retval = SUNMatCopy(arkls_mem->M, arkls_mem->M_lu); + 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); + } + + /* signal call to LS setup routine */ + call_lssetup = SUNTRUE; + + } + + /* 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); +} + + +/*--------------------------------------------------------------- + arkLsMassSolve: interfaces between ARKode and the generic + SUNLinearSolver object LS, by setting the appropriate tolerance + and scaling vectors, calling the solver, and accumulating + statistics from the solve for use/reporting by ARKode. + ---------------------------------------------------------------*/ +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; + + /* 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) ) { + delta = arkls_mem->eplifac * nlscoef * arkls_mem->sqrtN; + } else { + delta = ZERO; + } + + /* Set initial guess x = 0 for 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); + if (retval != SUNLS_SUCCESS) { + arkProcessError(ark_mem, ARKLS_SUNLS_FAIL, "ARKLS", "arkLsMassSolve", + "Error in call to SUNLinSolSetScalingVectors"); + arkls_mem->last_flag = ARKLS_SUNLS_FAIL; + return(arkls_mem->last_flag); + } + + /* If solver is iterative and does not support scaling vectors, update the + tolerance in an attempt to account for rwt vector. We make the + following assumptions: + 1. rwt_i = rwt_mean, for i=0,...,n-1 (i.e. the solution 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} (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 = ||rwt||_2 / sqrt(n), and scale + the desired tolerance accordingly. */ + } else if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || + (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { + + rwt_mean = SUNRsqrt( N_VDotProd(ark_mem->rwt, ark_mem->rwt) ) / arkls_mem->sqrtN; + delta /= rwt_mean; + + } + + /* Store previous nps value in nps_inc */ + nps_inc = arkls_mem->nps; + + /* Call solver, copy x to b, and increment mass solver counter */ + retval = SUNLinSolSolve(arkls_mem->LS, arkls_mem->M_lu, + arkls_mem->x, b, delta); + N_VScale(ONE, arkls_mem->x, b); + arkls_mem->nmsolves++; + + /* Retrieve statistics from iterative linear solvers */ + resnorm = ZERO; + nli_inc = 0; + if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || + (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { + if (arkls_mem->LS->ops->resnorm) + resnorm = SUNLinSolResNorm(arkls_mem->LS); + if (arkls_mem->LS->ops->numiters) + nli_inc = SUNLinSolNumIters(arkls_mem->LS); + } + + /* Increment counters nli and ncfl */ + arkls_mem->nli += nli_inc; + if (retval != SUNLS_SUCCESS) arkls_mem->ncfl++; + + /* 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); + + /* Interpret solver return value */ + arkls_mem->last_flag = retval; + + switch(retval) { + + case SUNLS_SUCCESS: + return(0); + break; + case SUNLS_RES_REDUCED: + case SUNLS_CONV_FAIL: + case SUNLS_ATIMES_FAIL_REC: + case SUNLS_PSOLVE_FAIL_REC: + case SUNLS_PACKAGE_FAIL_REC: + case SUNLS_QRFACT_FAIL: + case SUNLS_LUFACT_FAIL: + return(1); + break; + case SUNLS_MEM_NULL: + case SUNLS_ILL_INPUT: + case SUNLS_MEM_FAIL: + case SUNLS_GS_FAIL: + case SUNLS_QRSOL_FAIL: + return(-1); + break; + case SUNLS_PACKAGE_FAIL_UNREC: + arkProcessError(ark_mem, SUNLS_PACKAGE_FAIL_UNREC, "ARKLS", + "arkLsMassSolve", + "Failure in SUNLinSol external package"); + return(-1); + break; + case SUNLS_ATIMES_FAIL_UNREC: + arkProcessError(ark_mem, SUNLS_ATIMES_FAIL_UNREC, "ARKLS", + "arkLsMassSolve", MSG_LS_MTIMES_FAILED); + return(-1); + break; + case SUNLS_PSOLVE_FAIL_UNREC: + arkProcessError(ark_mem, SUNLS_PSOLVE_FAIL_UNREC, "ARKLS", + "arkLsMassSolve", MSG_LS_PSOLVE_FAILED); + return(-1); + break; + } + + return(0); +} + + +/*--------------------------------------------------------------- + arkLsMassFree frees memory associates with the ARKLs mass + matrix solver interface. + ---------------------------------------------------------------*/ +int arkLsMassFree(void *arkode_mem) +{ + ARKodeMem ark_mem; + ARKLsMassMem arkls_mem; + void* ark_step_massmem; + + /* Return immediately if ARKodeMem, ARKLsMassMem are NULL */ + if (arkode_mem == NULL) return (ARKLS_SUCCESS); + ark_mem = (ARKodeMem) arkode_mem; + ark_step_massmem = ark_mem->step_getmassmem(arkode_mem); + if (ark_step_massmem == NULL) return(ARKLS_SUCCESS); + arkls_mem = (ARKLsMassMem) ark_step_massmem; + + /* detach ARKLs interface routines from LS object (ignore return values) */ + if (arkls_mem->LS->ops->setatimes) + SUNLinSolSetATimes(arkls_mem->LS, NULL, NULL); + + if (arkls_mem->LS->ops->setpreconditioner) + SUNLinSolSetPreconditioner(arkls_mem->LS, NULL, NULL, NULL); + + /* Free N_Vector memory */ + if (arkls_mem->x) { + N_VDestroy(arkls_mem->x); + arkls_mem->x = NULL; + } + + /* Free M_lu memory */ + if (arkls_mem->M_lu) { + SUNMatDestroy(arkls_mem->M_lu); + arkls_mem->M_lu = NULL; + } + + /* Nullify other N_Vector pointers */ + arkls_mem->ycur = NULL; + + /* Nullify other SUNMatrix pointer */ + arkls_mem->M = NULL; + + /* Free preconditioner memory (if applicable) */ + if (arkls_mem->pfree) + arkls_mem->pfree(ark_mem); + + /* free ARKLs interface structure */ + free(arkls_mem); + + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkLsInitializeCounters and arkLsInitializeMassCounters: + + These routines reset all counters from an ARKLsMem or + ARKLsMassMem structure. + ---------------------------------------------------------------*/ +int arkLsInitializeCounters(ARKLsMem arkls_mem) +{ + arkls_mem->nje = 0; + arkls_mem->nfeDQ = 0; + arkls_mem->nstlj = 0; + arkls_mem->npe = 0; + arkls_mem->nli = 0; + arkls_mem->nps = 0; + arkls_mem->ncfl = 0; + arkls_mem->njtsetup = 0; + arkls_mem->njtimes = 0; + return(0); +} + +int arkLsInitializeMassCounters(ARKLsMassMem arkls_mem) +{ + arkls_mem->nmsetups = 0; + arkls_mem->nmsolves = 0; + arkls_mem->nmtsetup = 0; + arkls_mem->nmtimes = 0; + arkls_mem->npe = 0; + arkls_mem->nli = 0; + arkls_mem->nps = 0; + arkls_mem->ncfl = 0; + return(0); +} + + +/*--------------------------------------------------------------- + arkLs_AccessLMem and arkLs_AccessMassMem: + + Shortcut routines to unpack ark_mem, ls_mem and mass_mem + structures from void* pointer. If any is missing it returns + ARKLS_MEM_NULL, ARKLS_LMEM_NULL or ARKLS_MASSMEM_NULL. + ---------------------------------------------------------------*/ +int arkLs_AccessLMem(void* arkode_mem, const char *fname, + ARKodeMem *ark_mem, ARKLsMem *arkls_mem) +{ + void* ark_step_lmem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARKLS_MEM_NULL, "ARKLS", + fname, MSG_LS_ARKMEM_NULL); + return(ARKLS_MEM_NULL); + } + *ark_mem = (ARKodeMem) arkode_mem; + ark_step_lmem = (*ark_mem)->step_getlinmem(arkode_mem); + if (ark_step_lmem==NULL) { + arkProcessError(*ark_mem, ARKLS_LMEM_NULL, "ARKLS", + fname, MSG_LS_LMEM_NULL); + return(ARKLS_LMEM_NULL); + } + *arkls_mem = (ARKLsMem) ark_step_lmem; + return(ARKLS_SUCCESS); +} + +int arkLs_AccessMassMem(void* arkode_mem, const char *fname, + ARKodeMem *ark_mem, ARKLsMassMem *arkls_mem) +{ + void* ark_step_massmem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARKLS_MEM_NULL, "ARKLS", + fname, MSG_LS_ARKMEM_NULL); + return(ARKLS_MEM_NULL); + } + *ark_mem = (ARKodeMem) arkode_mem; + ark_step_massmem = (*ark_mem)->step_getmassmem(arkode_mem); + if (ark_step_massmem==NULL) { + arkProcessError(*ark_mem, ARKLS_MASSMEM_NULL, "ARKLS", + fname, MSG_LS_MASSMEM_NULL); + return(ARKLS_MASSMEM_NULL); + } + *arkls_mem = (ARKLsMassMem) ark_step_massmem; + return(ARKLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + EOF + ---------------------------------------------------------------*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_ls_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_ls_impl.h new file mode 100644 index 0000000..568f6f1 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_ls_impl.h @@ -0,0 +1,303 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * Implementation header file for ARKode's linear solver interface. + *--------------------------------------------------------------*/ + +#ifndef _ARKLS_IMPL_H +#define _ARKLS_IMPL_H + +#include <arkode/arkode_ls.h> +#include "arkode_impl.h" + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*--------------------------------------------------------------- + ARKLS solver constants: + + ARKLS_MSBJ default maximum number of steps between Jacobian / + preconditioner evaluations + + ARKLS_EPLIN default value for factor by which the tolerance + on the nonlinear iteration is multiplied to get + a tolerance on the linear iteration + ---------------------------------------------------------------*/ +#define ARKLS_MSBJ 50 +#define ARKLS_EPLIN RCONST(0.05) + + +/*--------------------------------------------------------------- + Types: ARKLsMemRec, ARKLsMem + + The type ARKLsMem is pointer to a ARKLsMemRec. + ---------------------------------------------------------------*/ +typedef struct ARKLsMemRec { + + /* 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 */ + + /* Iterative solver tolerance */ + realtype sqrtN; /* sqrt(N) */ + realtype eplifac; /* nonlinear -> linear tol scaling factor */ + + /* Linear solver, matrix and vector objects/pointers */ + SUNLinearSolver LS; /* generic linear solver object */ + SUNMatrix A; /* A = M - gamma * df/dy */ + SUNMatrix savedJ; /* savedJ = old Jacobian */ + N_Vector ytemp; /* temp vector passed to jtimes and psolve */ + N_Vector x; /* solution vector used by SUNLinearSolver */ + N_Vector ycur; /* ptr to current y vector in ARKLs solve */ + N_Vector fcur; /* ptr to current fcur = fI(tcur, ycur) */ + + /* Statistics and associated parameters */ + long int msbj; /* max num steps between jac/pset calls */ + realtype tcur; /* 'time' for current ARKLs solve */ + long int nje; /* no. of calls to jac */ + long int nfeDQ; /* no. of calls to f due to DQ Jacobian or J*v + approximations */ + long int nstlj; /* value of nst at the last jac/pset call */ + long int npe; /* npe = total number of pset calls */ + long int nli; /* nli = total number of linear iterations */ + long int nps; /* nps = total number of psolve calls */ + long int ncfl; /* ncfl = total number of convergence failures */ + long int njtsetup; /* njtsetup = total number of calls to jtsetup */ + long int njtimes; /* njtimes = total number of calls to jtimes */ + + /* Preconditioner computation + (a) user-provided: + - P_data == user_data + - 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 */ + ARKLsPrecSetupFn pset; + ARKLsPrecSolveFn psolve; + int (*pfree)(ARKodeMem ark_mem); + void *P_data; + + /* Jacobian times vector computation + (a) jtimes function provided by the user: + - Jt_data == user_data + - jtimesDQ == SUNFALSE + (b) internal jtimes + - Jt_data == arkode_mem + - jtimesDQ == SUNTRUE */ + booleantype jtimesDQ; + ARKLsJacTimesSetupFn jtsetup; + ARKLsJacTimesVecFn jtimes; + void *Jt_data; + + long int last_flag; /* last error flag returned by any function */ + +} *ARKLsMem; + + +/*--------------------------------------------------------------- + Types: ARKLsMassMemRec, ARKLsMassMem + + The type ARKLsMassMem is pointer to a ARKLsMassMemRec. + ---------------------------------------------------------------*/ +typedef struct ARKLsMassMemRec { + + /* 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 */ + + /* Iterative solver tolerance */ + 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 */ + + /* 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 */ + + /* Preconditioner computation + (a) user-provided: + - P_data == user_data + - 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 */ + ARKLsMassPrecSetupFn pset; + ARKLsMassPrecSolveFn psolve; + int (*pfree)(ARKodeMem ark_mem); + void *P_data; + + /* Mass matrix times vector setup and product routines, data */ + ARKLsMassTimesSetupFn mtsetup; + ARKLsMassTimesVecFn mtimes; + void *mt_data; + + long int last_flag; /* last error flag returned by any function */ + +} *ARKLsMassMem; + + +/*--------------------------------------------------------------- + Prototypes of internal functions + ---------------------------------------------------------------*/ + +/* Interface routines called by system SUNLinearSolver */ +int arkLsATimes(void* arkode_mem, N_Vector v, N_Vector z); +int arkLsPSetup(void* arkode_mem); +int arkLsPSolve(void* arkode_mem, N_Vector r, N_Vector z, + realtype tol, int lr); + +/* Interface routines called by mass SUNLinearSolver */ +int arkLsMTimes(void* arkode_mem, N_Vector v, N_Vector z); +int arkLsMPSetup(void* arkode_mem); +int arkLsMPSolve(void* arkode_mem, N_Vector r, N_Vector z, + realtype tol, int lr); + +/* Difference quotient approximation for Jac times vector */ +int arkLsDQJtimes(N_Vector v, N_Vector Jv, realtype t, + N_Vector y, N_Vector fy, void* data, + N_Vector work); + +/* Difference-quotient Jacobian approximation routines */ +int arkLsDQJac(realtype t, N_Vector y, N_Vector fy, + SUNMatrix Jac, void* data, N_Vector tmp1, + N_Vector tmp2, N_Vector tmp3); +int arkLsDenseDQJac(realtype t, N_Vector y, N_Vector fy, + SUNMatrix Jac, ARKodeMem ark_mem, + ARKLsMem arkls_mem, ARKRhsFn fi, N_Vector tmp1); +int arkLsBandDQJac(realtype t, N_Vector y, N_Vector fy, + SUNMatrix Jac, ARKodeMem ark_mem, + ARKLsMem arkls_mem, ARKRhsFn fi, + N_Vector tmp1, N_Vector tmp2); + +/* Generic linit/lsetup/lsolve/lfree interface routines for ARKode to call */ +int arkLsInitialize(void* arkode_mem); + +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); + +int arkLsSolve(void* arkode_mem, N_Vector b, realtype tcur, + N_Vector ycur, N_Vector fcur, realtype eRnrm, int mnewt); + +int arkLsFree(void* arkode_mem); + +/* Generic minit/msetup/mmult/msolve/mfree routines for ARKode to call */ +int arkLsMassInitialize(void* arkode_mem); + +int arkLsMassSetup(void* arkode_mem, N_Vector vtemp1, + N_Vector vtemp2, N_Vector vtemp3); + +int arkLsMassMult(void* arkode_mem, N_Vector v, N_Vector Mv); + +int arkLsMassSolve(void* arkode_mem, N_Vector b, realtype nlscoef); + +int arkLsMassFree(void* arkode_mem); + +/* Auxilliary functions */ +int arkLsInitializeCounters(ARKLsMem arkls_mem); + +int arkLsInitializeMassCounters(ARKLsMassMem arkls_mem); + +int arkLs_AccessLMem(void* arkode_mem, const char* fname, + ARKodeMem* ark_mem, ARKLsMem* arkls_mem); + +int arkLs_AccessMassMem(void* arkode_mem, const char* fname, + ARKodeMem* ark_mem, ARKLsMassMem* arkls_mem); + +/* Set/get routines called by time-stepper module */ +int arkLSSetLinearSolver(void* arkode_mem, SUNLinearSolver LS, SUNMatrix A); + +int arkLSSetMassLinearSolver(void* arkode_mem, SUNLinearSolver LS, + SUNMatrix M, booleantype time_dep); + +int arkLSSetJacFn(void* arkode_mem, ARKLsJacFn jac); +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 arkLSSetPreconditioner(void* arkode_mem, ARKLsPrecSetupFn psetup, + ARKLsPrecSolveFn psolve); +int arkLSSetMassPreconditioner(void* arkode_mem, ARKLsMassPrecSetupFn psetup, + ARKLsMassPrecSolveFn psolve); +int arkLSSetJacTimes(void* arkode_mem, ARKLsJacTimesSetupFn jtsetup, + ARKLsJacTimesVecFn jtimes); +int arkLSSetMassTimes(void* arkode_mem, ARKLsMassTimesSetupFn msetup, + ARKLsMassTimesVecFn mtimes, void* mtimes_data); + +int arkLSGetWorkSpace(void* arkode_mem, long int* lenrwLS, long int* leniwLS); +int arkLSGetNumJacEvals(void* arkode_mem, long int* njevals); +int arkLSGetNumPrecEvals(void* arkode_mem, long int* npevals); +int arkLSGetNumPrecSolves(void* arkode_mem, long int* npsolves); +int arkLSGetNumLinIters(void* arkode_mem, long int* nliters); +int arkLSGetNumConvFails(void* arkode_mem, long int* nlcfails); +int arkLSGetNumJTSetupEvals(void* arkode_mem, long int* njtsetups); +int arkLSGetNumJtimesEvals(void* arkode_mem, long int* njvevals); +int arkLSGetNumRhsEvals(void* arkode_mem, long int* nfevalsLS); +int arkLSGetLastFlag(void* arkode_mem, long int* flag); + +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 arkLSGetNumMassSolves(void* arkode_mem, long int* nmsolves); +int arkLSGetNumMassPrecEvals(void* arkode_mem, long int* nmpevals); +int arkLSGetNumMassPrecSolves(void* arkode_mem, long int* nmpsolves); +int arkLSGetNumMassIters(void* arkode_mem, long int* nmiters); +int arkLSGetNumMassConvFails(void* arkode_mem, long int* nmcfails); +int arkLSGetNumMTSetups(void* arkode_mem, long int* nmtsetups); +int arkLSGetLastMassFlag(void* arkode_mem, long int* flag); + +char* arkLSGetReturnFlagName(long int flag); + +/*--------------------------------------------------------------- + Error Messages + ---------------------------------------------------------------*/ +#define MSG_LS_ARKMEM_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_LSTYPE "Incompatible linear solver type." +#define MSG_LS_LMEM_NULL "Linear solver memory is NULL." +#define MSG_LS_MASSMEM_NULL "Mass matrix solver memory is NULL." +#define MSG_LS_BAD_SIZES "Illegal bandwidth parameter(s). Must have 0 <= ml, mu <= N-1." + +#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." +#define MSG_LS_JTSETUP_FAILED "The Jacobian x vector setup routine failed in an unrecoverable manner." +#define MSG_LS_JTIMES_FAILED "The Jacobian x vector routine failed in an unrecoverable manner." +#define MSG_LS_MTSETUP_FAILED "The mass matrix x vector setup routine failed in an unrecoverable manner." +#define MSG_LS_MTIMES_FAILED "The mass matrix x vector routine failed in an unrecoverable manner." + +#define MSG_LS_JACFUNC_FAILED "The Jacobian routine failed in an unrecoverable manner." +#define MSG_LS_MASSFUNC_FAILED "The mass matrix routine failed in an unrecoverable manner." +#define MSG_LS_SUNMAT_FAILED "A SUNMatrix routine failed in an unrecoverable manner." + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_mristep.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_mristep.c new file mode 100644 index 0000000..a66838d --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_mristep.c @@ -0,0 +1,1146 @@ +/* ----------------------------------------------------------------------------- + * 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 is the implementation file for ARKode's MRI time stepper module. + * ---------------------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "arkode_impl.h" +#include "arkode_mristep_impl.h" +#include <sundials/sundials_math.h> + +#if defined(SUNDIALS_EXTENDED_PRECISION) +#define RSYM ".32Lg" +#else +#define RSYM ".16g" +#endif + +#define NO_DEBUG_OUTPUT +/* #define DEBUG_OUTPUT */ +#ifdef DEBUG_OUTPUT +#include <nvector/nvector_serial.h> +#endif + +/* constants */ +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + + + +/*=============================================================== + MRIStep Exported functions -- Required + ===============================================================*/ + +void* MRIStepCreate(ARKRhsFn fs, ARKRhsFn ff, realtype t0, N_Vector y0) +{ + 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; + + /* Initialize all the counters */ + step_mem->nfs = 0; + step_mem->nff = 0; + + /* 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"); + 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); + } + + return((void *)ark_mem); +} + + +/*--------------------------------------------------------------- + MRIStepResize: + + This routine resizes the memory within the MRIStep module. + It first resizes the main ARKode infrastructure memory, and + then resizes its own data. + ---------------------------------------------------------------*/ +int MRIStepResize(void *arkode_mem, N_Vector y0, realtype t0, + ARKVecResizeFn resize, void *resize_data) +{ + ARKodeMem ark_mem; + ARKodeMRIStepMem step_mem; + sunindextype lrw1, liw1, lrw_diff, liw_diff; + int retval, i, flag; + + /* access ARKodeMRIStepMem structure */ + retval = mriStep_AccessStepMem(arkode_mem, "MRIStepResize", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* Determing change in vector sizes */ + lrw1 = liw1 = 0; + if (y0->ops->nvspace != NULL) + N_VSpace(y0, &lrw1, &liw1); + lrw_diff = lrw1 - ark_mem->lrw1; + liw_diff = liw1 - ark_mem->liw1; + ark_mem->lrw1 = lrw1; + ark_mem->liw1 = liw1; + + /* resize ARKode infrastructure memory (use hscale = 1.0) */ + flag = arkResize(ark_mem, y0, RCONST(1.0), t0, resize, resize_data); + if (flag != ARK_SUCCESS) { + arkProcessError(ark_mem, flag, "ARKode::MRIStep", "MRIStepResize", + "Unable to resize main ARKode infrastructure"); + 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 RHS vectors */ + for (i=0; i<step_mem->stages; i++) { + retval = arkResizeVec(ark_mem, resize, resize_data, lrw_diff, + 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); +} + + +/*--------------------------------------------------------------- + MRIStepReInit: + + This routine re-initializes the MRIStep module to solve a new + problem of the same size as was previously solved. + ---------------------------------------------------------------*/ +int MRIStepReInit(void* arkode_mem, ARKRhsFn fs, ARKRhsFn ff, + realtype t0, N_Vector y0) +{ + ARKodeMem ark_mem; + ARKodeMRIStepMem step_mem; + int retval; + + /* access ARKodeMRIStepMem structure */ + retval = mriStep_AccessStepMem(arkode_mem, "MRIStepReInit", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* Check that fs and ff are supplied */ + if (fs == NULL || ff == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::MRIStep", + "MRIStepReInit", MSG_ARK_NULL_F); + return(ARK_ILL_INPUT); + } + + /* Check for legal input parameters */ + if (y0 == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::MRIStep", + "MRIStepReInit", MSG_ARK_NULL_Y0); + return(ARK_ILL_INPUT); + } + + /* ReInitialize main ARKode infrastructure */ + retval = arkReInit(arkode_mem, t0, y0); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, retval, "ARKode::MRIStep", "MRIStepReInit", + "Unable to initialize main ARKode infrastructure"); + return(retval); + } + + /* 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); + } + + /* Initialize the saved return value for the inner stepper */ + step_mem->inner_retval = ARK_SUCCESS; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + MRIStepRootInit: + + Initialize (attach) a rootfinding problem to the stepper + (wrappers for general ARKode utility routine) + ---------------------------------------------------------------*/ +int MRIStepRootInit(void *arkode_mem, int nrtfn, ARKRootFn g) +{ + /* unpack ark_mem, call arkRootInit, and return */ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::MRIStep", + "MRIStepRootInit", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + return(arkRootInit(ark_mem, nrtfn, g)); +} + + +/*--------------------------------------------------------------- + MRIStepEvolve: + + This is the main time-integration driver (wrappers for general + ARKode utility routine) + ---------------------------------------------------------------*/ +int MRIStepEvolve(void *arkode_mem, realtype tout, N_Vector yout, + realtype *tret, int itask) +{ + /* unpack ark_mem, call arkEvolve, and return */ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::MRIStep", + "MRIStepEvolve", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + return(arkEvolve(ark_mem, tout, yout, tret, itask)); +} + + +/*--------------------------------------------------------------- + MRIStepGetDky: + + This returns interpolated output of the solution or its + derivatives over the most-recently-computed step (wrapper for + generic ARKode utility routine) + ---------------------------------------------------------------*/ +int MRIStepGetDky(void *arkode_mem, realtype t, int k, N_Vector dky) +{ + /* unpack ark_mem, call arkGetDky, and return */ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::MRIStep", + "MRIStepGetDky", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + return(arkGetDky(ark_mem, t, k, dky)); +} + + +/*--------------------------------------------------------------- + MRIStepFree frees all MRIStep memory, and then calls an ARKode + utility routine to free the ARKode infrastructure memory. + ---------------------------------------------------------------*/ +void MRIStepFree(void **arkode_mem) +{ + int j; + sunindextype Bliw, Blrw; + ARKodeMem ark_mem; + ARKodeMRIStepMem step_mem; + + /* nothing to do if arkode_mem is already NULL */ + if (*arkode_mem == NULL) return; + + /* conditional frees on non-NULL MRIStep module */ + ark_mem = (ARKodeMem) (*arkode_mem); + if (ark_mem->step_mem != NULL) { + + step_mem = (ARKodeMRIStepMem) ark_mem->step_mem; + + /* free the Butcher table */ + if (step_mem->B != NULL) { + ARKodeButcherTable_Space(step_mem->B, &Bliw, &Blrw); + ARKodeButcherTable_Free(step_mem->B); + step_mem->B = NULL; + ark_mem->liw -= Bliw; + 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 RHS vectors */ + if (step_mem->F != NULL) { + for(j=0; j<step_mem->stages; j++) + arkFreeVec(ark_mem, &step_mem->F[j]); + free(step_mem->F); + step_mem->F = NULL; + ark_mem->liw -= step_mem->stages; + } + + /* free the reusable arrays for fused vector interface */ + if (step_mem->cvals != NULL) { + free(step_mem->cvals); + step_mem->cvals = NULL; + ark_mem->lrw -= (step_mem->stages + 1); + } + if (step_mem->Xvecs != NULL) { + free(step_mem->Xvecs); + step_mem->Xvecs = NULL; + 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; + } + + /* free memory for overall ARKode infrastructure */ + arkFree(arkode_mem); +} + + +/*--------------------------------------------------------------- + MRIStepPrintMem: + + This routine outputs the memory from the MRIStep structure and + the main ARKode infrastructure to a specified file pointer + (useful when debugging). + ---------------------------------------------------------------*/ +void MRIStepPrintMem(void* arkode_mem, FILE* outfile) +{ + ARKodeMem ark_mem; + ARKodeMRIStepMem step_mem; + int retval; + + /* access ARKodeMRIStepMem structure */ + retval = mriStep_AccessStepMem(arkode_mem, "MRIStepPrintMem", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return; + + /* output data from main ARKode infrastructure */ + fprintf(outfile,"MRIStep Slow Stepper Mem:\n"); + arkPrintMem(ark_mem, outfile); + + /* output integer quantities */ + fprintf(outfile,"MRIStep: q = %i\n", step_mem->q); + fprintf(outfile,"MRIStep: p = %i\n", step_mem->p); + fprintf(outfile,"MRIStep: stages = %i\n", step_mem->stages); + + /* 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"); + ARKodeButcherTable_Write(step_mem->B, outfile); + +#ifdef DEBUG_OUTPUT + /* output vector quantities */ + for (i=0; i<step_mem->stages; i++) { + fprintf(outfile,"MRIStep: F[%i]:\n", i); + N_VPrint_Serial(step_mem->F[i]); + } +#endif + + /* Print inner stepper memory */ + fprintf(outfile,"MRIStep Fast Stepper Mem:\n"); + ARKStepPrintMem(step_mem->inner_arkode_mem, outfile); +} + + + +/*=============================================================== + MRIStep Private functions + ===============================================================*/ + +/*--------------------------------------------------------------- + Interface routines supplied to ARKode + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + mriStep_Init: + + 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). + + With init_type == 0, this routine: + - sets/checks the ARK Butcher tables to be used + - allocates any memory that depends on the number of ARK + stages, method order, or solver options + + With init_type == 1, this routine does nothing. + ---------------------------------------------------------------*/ +int mriStep_Init(void* arkode_mem, int init_type) +{ + ARKodeMem ark_mem; + ARKodeMRIStepMem step_mem; + 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 */ + if (!ark_mem->fixedstep) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::MRIStep", "mriStep_Init", + "Adaptive time stepping is not currently supported"); + return(ARK_ILL_INPUT); + } + + /* Create Butcher table (if not already set) */ + retval = mriStep_SetButcherTable(ark_mem); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::MRIStep", "mriStep_Init", + "Could not create Butcher table"); + return(ARK_ILL_INPUT); + } + + /* Check that Butcher table is OK */ + retval = mriStep_CheckButcherTable(ark_mem); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::MRIStep", + "mriStep_Init", "Error in Butcher table"); + return(ARK_ILL_INPUT); + } + + /* note Butcher table space requirements */ + ARKodeButcherTable_Space(step_mem->B, &Bliw, &Blrw); + ark_mem->liw += Bliw; + ark_mem->lrw += Blrw; + + /* Allocate MRI RHS vector memory, update storage requirements */ + /* Allocate F[0] ... F[stages-1] if needed */ + if (step_mem->F == NULL) + step_mem->F = (N_Vector *) calloc(step_mem->stages, sizeof(N_Vector)); + for (j=0; j<step_mem->stages; j++) { + if (!arkAllocVec(ark_mem, ark_mem->ewt, &(step_mem->F[j]))) + return(ARK_MEM_FAIL); + } + ark_mem->liw += step_mem->stages; /* pointers */ + + /* Allocate reusable arrays for fused vector interface */ + if (step_mem->cvals == NULL) { + step_mem->cvals = (realtype *) calloc(step_mem->stages+1, sizeof(realtype)); + if (step_mem->cvals == NULL) return(ARK_MEM_FAIL); + ark_mem->lrw += (step_mem->stages + 1); + } + if (step_mem->Xvecs == NULL) { + step_mem->Xvecs = (N_Vector *) calloc(step_mem->stages+1, sizeof(N_Vector)); + if (step_mem->Xvecs == NULL) return(ARK_MEM_FAIL); + ark_mem->liw += (step_mem->stages + 1); /* pointers */ + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + mriStep_FullRHS: + + This is just a wrapper to call the user-supplied RHS functions, + f(t,y) = fs(t,y) + ff(t,y). + + This will be called in one of three 'modes': + 0 -> called at the beginning of a simulation + 1 -> called at the end of a successful step + 2 -> called elsewhere (e.g. for dense output) + + If it is called in mode 0, we store the vectors f(t,y) in F[0] + for possible reuse in the first stage of the subsequent time step. + + If it is called in mode 1, we reevauate f(t,y). At this time no + checks are made to see if the method coefficient support copying + vectors F[stages] to fill f instead of calling f(). + + Mode 2 is only called for dense output in-between steps, so we + strive to store the intermediate parts so that they do not + interfere with the other two modes. + ---------------------------------------------------------------*/ +int mriStep_FullRHS(void* arkode_mem, realtype t, + N_Vector y, N_Vector f, int mode) +{ + ARKodeMem ark_mem; + ARKodeMRIStepMem step_mem; + int retval; + + /* access ARKodeMRIStepMem structure */ + retval = mriStep_AccessStepMem(arkode_mem, "mriStep_FullRHS", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* perform RHS functions contingent on 'mode' argument */ + switch(mode) { + + /* Mode 0: called at the beginning of a simulation + Store the vector fs(t,y) in F[0] for possible reuse + in the first stage of the subsequent time step */ + case 0: + + /* call fs */ + retval = step_mem->fs(t, y, step_mem->F[0], ark_mem->user_data); + step_mem->nfs++; + if (retval != 0) { + arkProcessError(ark_mem, ARK_RHSFUNC_FAIL, "ARKode::MRIStep", + "mriStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); + return(ARK_RHSFUNC_FAIL); + } + + /* call ff */ + retval = step_mem->ff(t, y, f, ark_mem->user_data); + step_mem->nff++; + if (retval != 0) { + arkProcessError(ark_mem, ARK_RHSFUNC_FAIL, "ARKode::MRIStep", + "mriStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); + return(ARK_RHSFUNC_FAIL); + } + + /* combine RHS vectors into output */ + N_VLinearSum(ONE, step_mem->F[0], ONE, f, f); + + break; + + + /* Mode 1: called at the end of a successful step + This always recomputes the full RHS (i.e., this is the + same as case 0). */ + case 1: + + /* call fs */ + retval = step_mem->fs(t, y, step_mem->F[0], ark_mem->user_data); + step_mem->nfs++; + if (retval != 0) { + arkProcessError(ark_mem, ARK_RHSFUNC_FAIL, "ARKode::MRIStep", + "mriStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); + return(ARK_RHSFUNC_FAIL); + } + + /* call ff */ + retval = step_mem->ff(t, y, f, ark_mem->user_data); + step_mem->nff++; + if (retval != 0) { + arkProcessError(ark_mem, ARK_RHSFUNC_FAIL, "ARKode::MRIStep", + "mriStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); + return(ARK_RHSFUNC_FAIL); + } + + /* combine RHS vectors into output */ + N_VLinearSum(ONE, step_mem->F[0], ONE, f, f); + + break; + + /* Mode 2: called for dense output in-between steps + store the intermediate calculations in such a way as to not + interfere with the other two modes */ + default: + + /* call fs */ + retval = step_mem->fs(t, y, ark_mem->tempv2, ark_mem->user_data); + step_mem->nfs++; + if (retval != 0) { + arkProcessError(ark_mem, ARK_RHSFUNC_FAIL, "ARKode::MRIStep", + "mriStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); + return(ARK_RHSFUNC_FAIL); + } + + /* call ff */ + retval = step_mem->ff(t, y, f, ark_mem->user_data); + step_mem->nff++; + if (retval != 0) { + arkProcessError(ark_mem, ARK_RHSFUNC_FAIL, "ARKode::MRIStep", + "mriStep_FullRHS", MSG_ARK_RHSFUNC_FAILED, t); + return(ARK_RHSFUNC_FAIL); + } + + /* combine RHS vectors into output */ + N_VLinearSum(ONE, ark_mem->tempv2, ONE, f, f); + + break; + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + 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. + ---------------------------------------------------------------*/ +int mriStep_TakeStep(void* arkode_mem) +{ + realtype dsm, tspan, hi, rcdiff, tret; + int retval, is, eflag, js, nvec, nstep; + realtype* cvals; + N_Vector* Xvecs; + ARKodeMem ark_mem; + ARKodeMRIStepMem step_mem; + + /* access ARKodeMRIStepMem 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; is<step_mem->stages; is++) { + + /* 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); +#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; js<is; js++) { + cvals[js] = rcdiff * (step_mem->B->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); + + /* 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("RHS:\n"); + N_VPrint_Serial(step_mem->F[is]); +#endif + + } /* loop over stages */ + + /* Compute time step solution */ + + /* 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; js<step_mem->stages; 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++; + } + + 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); + + /* 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); + + /* 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); + } + + /* 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); + +#ifdef DEBUG_OUTPUT + printf("error estimate = %"RSYM"\n", dsm); + printf("updated solution:\n"); + N_VPrint_Serial(ark_mem->ycur); +#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); + +#ifdef DEBUG_OUTPUT + printf("error test flag = %i\n", eflag); +#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 = mriStep_PrepareNextStep(ark_mem, dsm); + if (retval != ARK_SUCCESS) return(retval); + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + Internal utility routines + ---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + mriStep_AccessStepMem: + + Shortcut routine to unpack ark_mem and step_mem structures from + void* pointer. If either is missing it returns ARK_MEM_NULL. + ---------------------------------------------------------------*/ +int mriStep_AccessStepMem(void* arkode_mem, const char *fname, + ARKodeMem *ark_mem, ARKodeMRIStepMem *step_mem) +{ + + /* access ARKodeMem structure */ + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::MRIStep", + fname, MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + *ark_mem = (ARKodeMem) arkode_mem; + if ((*ark_mem)->step_mem==NULL) { + arkProcessError(*ark_mem, ARK_MEM_NULL, "ARKode::MRIStep", + fname, MSG_MRISTEP_NO_MEM); + return(ARK_MEM_NULL); + } + *step_mem = (ARKodeMRIStepMem) (*ark_mem)->step_mem; + return(ARK_SUCCESS); +} + + + +/*--------------------------------------------------------------- + mriStep_CheckNVector: + + This routine checks if all required vector operations are + present. If any of them is missing it returns SUNFALSE. + ---------------------------------------------------------------*/ +booleantype mriStep_CheckNVector(N_Vector tmpl) +{ + if ( (tmpl->ops->nvclone == NULL) || + (tmpl->ops->nvdestroy == NULL) || + (tmpl->ops->nvlinearsum == NULL) || + (tmpl->ops->nvconst == NULL) || + (tmpl->ops->nvscale == NULL) || + (tmpl->ops->nvwrmsnorm == NULL) ) + return(SUNFALSE); + return(SUNTRUE); +} + + +/*--------------------------------------------------------------- + mriStep_SetButcherTable + + This routine determines the MRI method to use, based on the + desired accuracy. + ---------------------------------------------------------------*/ +int mriStep_SetButcherTable(ARKodeMem ark_mem) +{ + int istable, iftable, retval; + ARKodeMRIStepMem step_mem; + + /* access ARKodeMRIStepMem structure */ + if (ark_mem->step_mem==NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::MRIStep", + "mriStep_SetButcherTable", MSG_MRISTEP_NO_MEM); + return(ARK_MEM_NULL); + } + step_mem = (ARKodeMRIStepMem) ark_mem->step_mem; + + /* if table has already been specified, just return */ + if (step_mem->B != NULL) + return(ARK_SUCCESS); + + /* initialize table number to illegal values */ + istable = -1; + + /* select method based on order */ + switch (step_mem->q) { + case(3): + istable = DEFAULT_MRI_STABLE_3; + iftable = DEFAULT_MRI_FTABLE_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; + break; + } + + if (istable > -1) + step_mem->B = ARKodeButcherTable_LoadERK(istable); + + /* set [redundant] stored values for stage numbers and method orders */ + if (step_mem->B != NULL) { + step_mem->stages = step_mem->B->stages; + step_mem->q = step_mem->B->q; + 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); +} + + +/*--------------------------------------------------------------- + mriStep_CheckButcherTable + + This routine runs through the outer Butcher table to ensure + that it meets all necessary requirements, including: + strictly lower-triangular (ERK) + method order q > 0 (all) + stages > 0 (all) + + Returns ARK_SUCCESS if tables pass, ARK_ILL_INPUT otherwise. + ---------------------------------------------------------------*/ +int mriStep_CheckButcherTable(ARKodeMem ark_mem) +{ + int i, j; + booleantype okay; + ARKodeMRIStepMem step_mem; + realtype tol = RCONST(1.0e-12); + + /* access ARKodeMRIStepMem structure */ + if (ark_mem->step_mem==NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::MRIStep", + "mriStep_CheckButcherTable", MSG_MRISTEP_NO_MEM); + return(ARK_MEM_NULL); + } + step_mem = (ARKodeMRIStepMem) ark_mem->step_mem; + + /* check that stages > 0 */ + if (step_mem->stages < 1) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::MRIStep", + "mriStep_CheckButcherTable", + "stages < 1!"); + return(ARK_ILL_INPUT); + } + + /* check that method order q > 0 */ + if (step_mem->q < 1) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::MRIStep", + "mriStep_CheckButcherTable", + "method order < 1!"); + return(ARK_ILL_INPUT); + } + + /* check that embedding order p > 0 */ + if ((step_mem->p < 1) && (!ark_mem->fixedstep)) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::MRIStep", + "mriStep_CheckButcherTable", + "embedding order < 1!"); + return(ARK_ILL_INPUT); + } + + /* check that MRI table is strictly lower triangular */ + okay = SUNTRUE; + for (i=0; i<step_mem->stages; i++) + for (j=i; j<step_mem->stages; j++) + if (SUNRabs(step_mem->B->A[i][j]) > tol) + okay = SUNFALSE; + if (!okay) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::MRIStep", + "mriStep_CheckButcherTable", + "As Butcher table is implicit!"); + return(ARK_ILL_INPUT); + } + + /* check that stages times are unique and ordered */ + okay = SUNTRUE; + for (i=1; i<step_mem->stages; i++) { + if (SUNRabs(step_mem->B->c[i] - step_mem->B->c[i-1]) < tol) + okay = SUNFALSE; + else if (step_mem->B->c[i] - step_mem->B->c[i-1] < ZERO) + okay = SUNFALSE; + } + if (!okay) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::MRIStep", + "mriStep_CheckButcherTable", + "Stage times must be unique and ordered."); + return(ARK_ILL_INPUT); + } + + /* check that the last stage is not at or beyond the final time */ + okay = SUNTRUE; + if (SUNRabs(ONE - step_mem->B->c[step_mem->stages-1]) < tol) + okay = SUNFALSE; + else if (ONE - step_mem->B->c[step_mem->stages-1] < ZERO) + okay = SUNFALSE; + + if (!okay) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode::MRIStep", + "mriStep_CheckButcherTable", + "Final stage time must be less than 1."); + return(ARK_ILL_INPUT); + } + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + 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. + ---------------------------------------------------------------*/ +int mriStep_PrepareNextStep(ARKodeMem ark_mem, realtype dsm) +{ + /* 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); + } + + /* Set hprime value for next step size */ + ark_mem->hprime = ark_mem->h * ark_mem->eta; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + Routines for inner stepper + ---------------------------------------------------------------*/ + +int mriStep_InnerRhsFn(realtype t, N_Vector y, N_Vector ydot, + void *user_data) +{ + ARKodeMem ark_mem; + ARKodeMRIStepMem step_mem; + int retval; + + /* access outer integrator memory */ + ark_mem = (ARKodeMem) user_data; + step_mem = (ARKodeMRIStepMem) ark_mem->step_mem; + + /* call user fast RHS function */ + retval = step_mem->ff(t, y, ydot, ark_mem->user_data); + if (retval != 0) return(retval); + + /* add contribution from the outer integrator */ + N_VLinearSum(ONE, step_mem->forcing, ONE, ydot, ydot); + + /* successfully computed RHS */ + return(0); +} + +/*=============================================================== + EOF + ===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_mristep_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_mristep_impl.h new file mode 100644 index 0000000..5b405a1 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_mristep_impl.h @@ -0,0 +1,106 @@ +/* ----------------------------------------------------------------------------- + * 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 + * ----------------------------------------------------------------------------- + * Implementation header file for ARKode's MRI time stepper module. + * ---------------------------------------------------------------------------*/ + +#ifndef _ARKODE_MRISTEP_IMPL_H +#define _ARKODE_MRISTEP_IMPL_H + +#include <arkode/arkode_mristep.h> +#include "arkode_impl.h" +#include "arkode/arkode_arkstep.h" + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*=============================================================== + 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. + ---------------------------------------------------------------*/ +typedef struct ARKodeMRIStepMemRec { + + /* MRI problem specification */ + ARKRhsFn fs; /* y' = fs(t,y) + ff(t,y) */ + ARKRhsFn ff; + + /* Outer RK method storage and parameters */ + N_Vector *F; /* slow RHS at each stage */ + int q; /* method order */ + int p; /* embedding order */ + int stages; /* number of stages */ + 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 */ + + /* Counters */ + long int nfs; /* num fe calls */ + long int nff; /* num fe calls */ + + /* Reusable arrays for fused vector operations */ + realtype* cvals; + N_Vector* Xvecs; + +} *ARKodeMRIStepMem; + + + +/*=============================================================== + MRI time step module private function prototypes + ===============================================================*/ + +/* 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); + +/* Internal utility routines */ +int mriStep_AccessStepMem(void* arkode_mem, const char *fname, + ARKodeMem *ark_mem, ARKodeMRIStepMem *step_mem); +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); + +/* Internal inner stepper routines */ +int mriStep_InnerRhsFn(realtype t, N_Vector y, N_Vector ydot, void *user_data); + +/*=============================================================== + Reusable MRIStep Error Messages + ===============================================================*/ + +/* Initialization and I/O error messages */ +#define MSG_MRISTEP_NO_MEM "Time step module memory is NULL." + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_mristep_io.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_mristep_io.c new file mode 100644 index 0000000..cced0b6 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_mristep_io.c @@ -0,0 +1,768 @@ +/* ----------------------------------------------------------------------------- + * 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 is the implementation file for the optional input and output functions + * for the ARKode MRIStep time stepper module. + * ---------------------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "arkode_mristep_impl.h" +#include <sundials/sundials_math.h> +#include <sundials/sundials_types.h> + +#if defined(SUNDIALS_EXTENDED_PRECISION) +#define RSYM "Lg" +#else +#define RSYM "g" +#endif + + +/*=============================================================== + MRIStep Optional input functions (wrappers for generic ARKode + utility routines) + ===============================================================*/ + +/*--------------------------------------------------------------- + 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 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. + ---------------------------------------------------------------*/ +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)); +} + + +/*=============================================================== + MRIStep Optional output functions (wrappers for generic ARKode + utility routines) + ===============================================================*/ + +/*--------------------------------------------------------------- + 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) +{ + ARKodeMem ark_mem; + if (arkode_mem==NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode::MRIStep", + "MRIStepGetCurrentTime", 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); + } + 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)); +} + +/*--------------------------------------------------------------- + MRIStepGetReturnFlagName: translates from return flags IDs to + names + ---------------------------------------------------------------*/ +char *MRIStepGetReturnFlagName(long int flag) +{ return(arkGetReturnFlagName(flag)); } + + + +/*=============================================================== + MRIStep optional input functions -- stepper-specific + ===============================================================*/ + +/*--------------------------------------------------------------- + MRIStepSetDefaults: + + Resets all MRIStep optional inputs to their default values. + Does not change problem-defining function pointers or + user_data pointer. + ---------------------------------------------------------------*/ +int MRIStepSetDefaults(void* arkode_mem) +{ + 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 default values for integrator optional inputs */ + step_mem->q = 3; /* method order */ + step_mem->p = 0; /* embedding order */ + 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: + + 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 retval; + ARKodeMem ark_mem; + ARKodeMRIStepMem step_mem; + + /* access ARKodeMRIStepMem structure */ + retval = mriStep_AccessStepMem(arkode_mem, "MRIStepSetTable", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* check for illegal inputs */ + if ((Bs == NULL) && (Bf == NULL)) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::MRIStep", + "MRIStepSetTables", MSG_ARK_NO_MEM); + 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; + + /* set the relevant parameters */ + step_mem->stages = Bs->stages; + step_mem->q = Bs->q; + step_mem->p = 0; /* assume fixed stepping */ + + /* copy the table in step memory */ + step_mem->B = ARKodeButcherTable_Copy(Bs); + 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); +} + + +/*--------------------------------------------------------------- + MRIStepSetTableNum: + + Specifies to use pre-existing Butcher tables for the problem, + 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) +{ + ARKodeMem ark_mem; + ARKodeMRIStepMem step_mem; + int retval; + + /* access ARKodeMRIStepMem structure */ + retval = mriStep_AccessStepMem(arkode_mem, "MRIStepSetTableNum", + &ark_mem, &step_mem); + 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 ) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::MRIStep", + "MRIStepSetTableNum", + "Illegal MRI 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(istable); + if (step_mem->B == NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::MRIStep", + "MRIStepSetTableNum", + "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; + + /* 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); +} + + +/*=============================================================== + MRIStep optional output functions -- stepper-specific + ===============================================================*/ + +/*--------------------------------------------------------------- + MRIStepGetLastInnerStepFlag: + + Returns the last return value from the inner stepper. + ---------------------------------------------------------------*/ +int MRIStepGetLastInnerStepFlag(void *arkode_mem, int *flag) +{ + ARKodeMem ark_mem; + ARKodeMRIStepMem step_mem; + int retval; + + /* access ARKodeMRIStepMem structure */ + retval = mriStep_AccessStepMem(arkode_mem, "MRIStepGetLastInnerStepFlag", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* get the last return value from the inner stepper */ + *flag = step_mem->inner_retval; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + MRIStepGetNumRhsEvals: + + Returns the current number of calls to fs and ff + ---------------------------------------------------------------*/ +int MRIStepGetNumRhsEvals(void *arkode_mem, long int *nfs_evals, + long int *nff_evals) +{ + ARKodeMem ark_mem; + ARKodeMRIStepMem step_mem; + int retval; + long int tmp; + + /* access ARKodeMRIStepMem structure */ + retval = mriStep_AccessStepMem(arkode_mem, "MRIStepGetNumRhsEvals", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* 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); +} + + +/*--------------------------------------------------------------- + MRIStepGetCurrentButcherTables: + + Sets pointers to the slow and fast Butcher tables currently in + use. + ---------------------------------------------------------------*/ +int MRIStepGetCurrentButcherTables(void *arkode_mem, + ARKodeButcherTable *Bs, + ARKodeButcherTable *Bf) +{ + 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); + + return(ARK_SUCCESS); +} + + +/*=============================================================== + MRIStep parameter output + ===============================================================*/ + +/*--------------------------------------------------------------- + MRIStepWriteParameters: + + Outputs all solver parameters to the provided file pointer. + ---------------------------------------------------------------*/ +int MRIStepWriteParameters(void *arkode_mem, FILE *fp) +{ + ARKodeMem ark_mem; + ARKodeMRIStepMem step_mem; + int retval; + + /* access ARKodeMRIStepMem structure */ + retval = mriStep_AccessStepMem(arkode_mem, "MRIStepWriteParameters", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* output ARKode infrastructure parameters first */ + retval = arkWriteParameters(arkode_mem, fp); + if (retval != ARK_SUCCESS) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::MRIStep", + "MRIStepWriteParameters", + "Error writing ARKode infrastructure parameters"); + 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); +} + + +/*--------------------------------------------------------------- + MRIStepWriteButcher: + + Outputs Butcher tables to the provided file pointer. + ---------------------------------------------------------------*/ +int MRIStepWriteButcher(void *arkode_mem, FILE *fp) +{ + ARKodeMem ark_mem; + ARKodeMRIStepMem step_mem; + ARKodeButcherTable Bfi, Bfe; + int retval; + + /* access ARKodeMRIStepMem structure */ + retval = mriStep_AccessStepMem(arkode_mem, "MRIStepWriteButcher", + &ark_mem, &step_mem); + if (retval != ARK_SUCCESS) return(retval); + + /* check that Butcher table is non-NULL (otherwise report error) */ + if (step_mem->B == NULL) { + arkProcessError(ark_mem, ARK_MEM_NULL, "ARKode::MRIStep", + "MRIStepWriteButcher", "Butcher table memory is NULL"); + return(ARK_MEM_NULL); + } + + /* wrie outer Butcher table */ + fprintf(fp, "\nMRIStep Butcher tables:\n"); + if (step_mem->B != NULL) { + fprintf(fp, " Slow Butcher table (stages = %i):\n", step_mem->stages); + ARKodeButcherTable_Write(step_mem->B, 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); +} + + +/*--------------------------------------------------------------- + EOF + ---------------------------------------------------------------*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_root.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_root.c new file mode 100644 index 0000000..8131c14 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_root.c @@ -0,0 +1,790 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 ARKode's root-finding (in + * time) utility. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> + +#include "arkode_impl.h" +#include <sundials/sundials_math.h> +#include <sundials/sundials_types.h> + +#if defined(SUNDIALS_EXTENDED_PRECISION) +#define RSYM ".32Lg" +#else +#define RSYM ".16g" +#endif + + + +/*--------------------------------------------------------------- + arkRootInit: + + arkRootInit initializes a rootfinding problem to be solved + during the integration of the ODE system. It loads the root + function pointer and the number of root functions, and allocates + workspace memory. The return value is ARK_SUCCESS = 0 if no + errors occurred, or a negative value otherwise. + ---------------------------------------------------------------*/ +int arkRootInit(ARKodeMem ark_mem, int nrtfn, ARKRootFn g) +{ + int i, nrt; + + /* Check ark_mem pointer */ + if (ark_mem == NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkRootInit", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + nrt = (nrtfn < 0) ? 0 : nrtfn; + + /* If unallocated, allocate rootfinding structure, set defaults, update space */ + if (ark_mem->root_mem == NULL) { + ark_mem->root_mem = (ARKodeRootMem) malloc(sizeof(struct ARKodeRootMemRec)); + if (ark_mem->root_mem == NULL) { + arkProcessError(ark_mem, 0, "ARKode", "arkRootInit", + 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->lrw += ARK_ROOT_LRW; + ark_mem->liw += ARK_ROOT_LIW; + } + + /* If rerunning arkRootInit() with a different number of root + functions (changing number of gfun components), then free + currently held memory resources */ + if ((nrt != ark_mem->root_mem->nrtfn) && (ark_mem->root_mem->nrtfn > 0)) { + free(ark_mem->root_mem->glo); ark_mem->root_mem->glo = NULL; + free(ark_mem->root_mem->ghi); ark_mem->root_mem->ghi = NULL; + free(ark_mem->root_mem->grout); ark_mem->root_mem->grout = NULL; + free(ark_mem->root_mem->iroots); ark_mem->root_mem->iroots = NULL; + free(ark_mem->root_mem->rootdir); ark_mem->root_mem->rootdir = NULL; + free(ark_mem->root_mem->gactive); ark_mem->root_mem->gactive = NULL; + + ark_mem->lrw -= 3 * (ark_mem->root_mem->nrtfn); + ark_mem->liw -= 3 * (ark_mem->root_mem->nrtfn); + } + + /* If arkRootInit() was called with nrtfn == 0, then set + nrtfn to zero and gfun to NULL before returning */ + if (nrt == 0) { + ark_mem->root_mem->nrtfn = nrt; + ark_mem->root_mem->gfun = NULL; + return(ARK_SUCCESS); + } + + /* If rerunning arkRootInit() with the same number of root + functions (not changing number of gfun components), then + check if the root function argument has changed */ + /* If g != NULL then return as currently reserved memory + resources will suffice */ + if (nrt == ark_mem->root_mem->nrtfn) { + if (g != ark_mem->root_mem->gfun) { + if (g == NULL) { + free(ark_mem->root_mem->glo); ark_mem->root_mem->glo = NULL; + free(ark_mem->root_mem->ghi); ark_mem->root_mem->ghi = NULL; + free(ark_mem->root_mem->grout); ark_mem->root_mem->grout = NULL; + free(ark_mem->root_mem->iroots); ark_mem->root_mem->iroots = NULL; + free(ark_mem->root_mem->rootdir); ark_mem->root_mem->rootdir = NULL; + free(ark_mem->root_mem->gactive); ark_mem->root_mem->gactive = NULL; + + ark_mem->lrw -= 3*nrt; + ark_mem->liw -= 3*nrt; + + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkRootInit", MSG_ARK_NULL_G); + return(ARK_ILL_INPUT); + } + else { + ark_mem->root_mem->gfun = g; + return(ARK_SUCCESS); + } + } + else return(ARK_SUCCESS); + } + + /* Set variable values in ARKode memory block */ + ark_mem->root_mem->nrtfn = nrt; + if (g == NULL) { + arkProcessError(ark_mem, ARK_ILL_INPUT, "ARKode", + "arkRootInit", MSG_ARK_NULL_G); + return(ARK_ILL_INPUT); + } + else ark_mem->root_mem->gfun = g; + + /* Allocate necessary memory and return */ + ark_mem->root_mem->glo = NULL; + ark_mem->root_mem->glo = (realtype *) malloc(nrt*sizeof(realtype)); + if (ark_mem->root_mem->glo == NULL) { + arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode", + "arkRootInit", MSG_ARK_MEM_FAIL); + return(ARK_MEM_FAIL); + } + ark_mem->root_mem->ghi = NULL; + ark_mem->root_mem->ghi = (realtype *) malloc(nrt*sizeof(realtype)); + if (ark_mem->root_mem->ghi == NULL) { + free(ark_mem->root_mem->glo); ark_mem->root_mem->glo = NULL; + arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode", + "arkRootInit", MSG_ARK_MEM_FAIL); + return(ARK_MEM_FAIL); + } + ark_mem->root_mem->grout = NULL; + ark_mem->root_mem->grout = (realtype *) malloc(nrt*sizeof(realtype)); + if (ark_mem->root_mem->grout == NULL) { + free(ark_mem->root_mem->glo); ark_mem->root_mem->glo = NULL; + free(ark_mem->root_mem->ghi); ark_mem->root_mem->ghi = NULL; + arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode", + "arkRootInit", MSG_ARK_MEM_FAIL); + return(ARK_MEM_FAIL); + } + ark_mem->root_mem->iroots = NULL; + ark_mem->root_mem->iroots = (int *) malloc(nrt*sizeof(int)); + if (ark_mem->root_mem->iroots == NULL) { + free(ark_mem->root_mem->glo); ark_mem->root_mem->glo = NULL; + free(ark_mem->root_mem->ghi); ark_mem->root_mem->ghi = NULL; + free(ark_mem->root_mem->grout); ark_mem->root_mem->grout = NULL; + arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode", + "arkRootInit", MSG_ARK_MEM_FAIL); + return(ARK_MEM_FAIL); + } + ark_mem->root_mem->rootdir = NULL; + ark_mem->root_mem->rootdir = (int *) malloc(nrt*sizeof(int)); + if (ark_mem->root_mem->rootdir == NULL) { + free(ark_mem->root_mem->glo); ark_mem->root_mem->glo = NULL; + free(ark_mem->root_mem->ghi); ark_mem->root_mem->ghi = NULL; + free(ark_mem->root_mem->grout); ark_mem->root_mem->grout = NULL; + free(ark_mem->root_mem->iroots); ark_mem->root_mem->iroots = NULL; + arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKode", + "arkRootInit", MSG_ARK_MEM_FAIL); + return(ARK_MEM_FAIL); + } + ark_mem->root_mem->gactive = NULL; + ark_mem->root_mem->gactive = (booleantype *) malloc(nrt*sizeof(booleantype)); + if (ark_mem->root_mem->gactive == NULL) { + free(ark_mem->root_mem->glo); ark_mem->root_mem->glo = NULL; + free(ark_mem->root_mem->ghi); ark_mem->root_mem->ghi = NULL; + free(ark_mem->root_mem->grout); ark_mem->root_mem->grout = NULL; + free(ark_mem->root_mem->iroots); ark_mem->root_mem->iroots = NULL; + free(ark_mem->root_mem->rootdir); ark_mem->root_mem->rootdir = NULL; + arkProcessError(ark_mem, ARK_MEM_FAIL, "ARKodeS", + "arkRootInit", MSG_ARK_MEM_FAIL); + return(ARK_MEM_FAIL); + } + + /* Set default values for rootdir (both directions) */ + for(i=0; i<nrt; i++) ark_mem->root_mem->rootdir[i] = 0; + + /* Set default values for gactive (all active) */ + for(i=0; i<nrt; i++) ark_mem->root_mem->gactive[i] = SUNTRUE; + + ark_mem->lrw += 3*nrt; + ark_mem->liw += 3*nrt; + + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkRootFree + + This routine frees all memory associated with ARKode's + rootfinding module. + ---------------------------------------------------------------*/ +int arkRootFree(void* arkode_mem) +{ + ARKodeMem ark_mem; + if (arkode_mem == NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkRootFree", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + if (ark_mem->root_mem != NULL) { + if (ark_mem->root_mem->nrtfn > 0) { + free(ark_mem->root_mem->glo); ark_mem->root_mem->glo = NULL; + free(ark_mem->root_mem->ghi); ark_mem->root_mem->ghi = NULL; + free(ark_mem->root_mem->grout); ark_mem->root_mem->grout = NULL; + free(ark_mem->root_mem->iroots); ark_mem->root_mem->iroots = NULL; + free(ark_mem->root_mem->rootdir); ark_mem->root_mem->rootdir = NULL; + free(ark_mem->root_mem->gactive); ark_mem->root_mem->gactive = NULL; + ark_mem->lrw -= 3*ark_mem->root_mem->nrtfn; + ark_mem->liw -= 3*ark_mem->root_mem->nrtfn; + } + free(ark_mem->root_mem); + ark_mem->lrw -= ARK_ROOT_LRW; + ark_mem->liw -= ARK_ROOT_LIW; + } + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkPrintRootMem + + This routine outputs the root-finding memory structure to a + specified file pointer. + ---------------------------------------------------------------*/ +int arkPrintRootMem(void* arkode_mem, FILE *outfile) +{ + int i; + ARKodeMem ark_mem; + if (arkode_mem == NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkPrintRootMem", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + if (ark_mem->root_mem != NULL) { + fprintf(outfile, "ark_nrtfn = %i\n", ark_mem->root_mem->nrtfn); + fprintf(outfile, "ark_nge = %li\n", ark_mem->root_mem->nge); + if (ark_mem->root_mem->iroots != NULL) + for (i=0; i<ark_mem->root_mem->nrtfn; i++) + fprintf(outfile, "ark_iroots[%i] = %i\n", i, ark_mem->root_mem->iroots[i]); + if (ark_mem->root_mem->rootdir != NULL) + for (i=0; i<ark_mem->root_mem->nrtfn; i++) + fprintf(outfile, "ark_rootdir[%i] = %i\n", i, ark_mem->root_mem->rootdir[i]); + fprintf(outfile, "ark_taskc = %i\n", ark_mem->root_mem->taskc); + fprintf(outfile, "ark_irfnd = %i\n", ark_mem->root_mem->irfnd); + fprintf(outfile, "ark_mxgnull = %i\n", ark_mem->root_mem->mxgnull); + if (ark_mem->root_mem->gactive != NULL) + for (i=0; i<ark_mem->root_mem->nrtfn; i++) + fprintf(outfile, "ark_gactive[%i] = %i\n", i, ark_mem->root_mem->gactive[i]); + fprintf(outfile, "ark_tlo = %"RSYM"\n", ark_mem->root_mem->tlo); + fprintf(outfile, "ark_thi = %"RSYM"\n", ark_mem->root_mem->thi); + fprintf(outfile, "ark_trout = %"RSYM"\n", ark_mem->root_mem->trout); + if (ark_mem->root_mem->glo != NULL) + for (i=0; i<ark_mem->root_mem->nrtfn; i++) + fprintf(outfile, "ark_glo[%i] = %"RSYM"\n", i, ark_mem->root_mem->glo[i]); + if (ark_mem->root_mem->ghi != NULL) + for (i=0; i<ark_mem->root_mem->nrtfn; i++) + fprintf(outfile, "ark_ghi[%i] = %"RSYM"\n", i, ark_mem->root_mem->ghi[i]); + if (ark_mem->root_mem->grout != NULL) + for (i=0; i<ark_mem->root_mem->nrtfn; i++) + fprintf(outfile, "ark_grout[%i] = %"RSYM"\n", i, ark_mem->root_mem->grout[i]); + fprintf(outfile, "ark_toutc = %"RSYM"\n", ark_mem->root_mem->toutc); + fprintf(outfile, "ark_ttol = %"RSYM"\n", ark_mem->root_mem->ttol); + } + return(ARK_SUCCESS); +} + + + +/*--------------------------------------------------------------- + arkRootCheck1 + + This routine completes the initialization of rootfinding memory + information, and checks whether g has a zero both at and very near + the initial point of the IVP. + + This routine returns an int equal to: + ARK_RTFUNC_FAIL < 0 if the g function failed, or + ARK_SUCCESS = 0 otherwise. + ---------------------------------------------------------------*/ +int arkRootCheck1(void* arkode_mem) +{ + int i, retval; + realtype smallh, hratio, tplus; + booleantype zroot; + ARKodeMem ark_mem; + ARKodeRootMem rootmem; + if (arkode_mem == NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkRootCheck1", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + rootmem = ark_mem->root_mem; + + for (i = 0; i < rootmem->nrtfn; i++) + rootmem->iroots[i] = 0; + rootmem->tlo = ark_mem->tcur; + rootmem->ttol = (SUNRabs(ark_mem->tcur) + + SUNRabs(ark_mem->h))*ark_mem->uround*HUND; + + /* 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->nge = 1; + if (retval != 0) return(ARK_RTFUNC_FAIL); + + zroot = SUNFALSE; + for (i = 0; i < rootmem->nrtfn; i++) { + if (SUNRabs(rootmem->glo[i]) == ZERO) { + zroot = SUNTRUE; + rootmem->gactive[i] = SUNFALSE; + } + } + if (!zroot) return(ARK_SUCCESS); + + /* Some g_i is zero at t0; look at g at t0+(small increment). */ + 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); + retval = rootmem->gfun(tplus, ark_mem->ycur, rootmem->ghi, + ark_mem->user_data); + rootmem->nge++; + if (retval != 0) return(ARK_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 < rootmem->nrtfn; i++) { + if (!rootmem->gactive[i] && SUNRabs(rootmem->ghi[i]) != ZERO) { + rootmem->gactive[i] = SUNTRUE; + rootmem->glo[i] = rootmem->ghi[i]; + } + } + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkRootCheck2 + + This routine checks for exact zeros of g at the last root found, + if the last return was a root. It then checks for a close pair of + zeros (an error condition), and for a new root at a nearby point. + The array glo = g(tlo) at the left endpoint of the search interval + is adjusted if necessary to assure that all g_i are nonzero + there, before returning to do a root search in the interval. + + On entry, tlo = tretlast is the last value of tret returned by + ARKode. This may be the previous tn, the previous tout value, or + the last root location. + + This routine returns an int equal to: + ARK_RTFUNC_FAIL < 0 if the g function failed, or + CLOSERT = 3 if a close pair of zeros was found, or + RTFOUND = 1 if a new zero of g was found near tlo, or + ARK_SUCCESS = 0 otherwise. + ---------------------------------------------------------------*/ +int arkRootCheck2(void* arkode_mem) +{ + int i, retval; + realtype smallh, tplus; + booleantype zroot; + ARKodeMem ark_mem; + ARKodeRootMem rootmem; + if (arkode_mem == NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkRootCheck2", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + rootmem = ark_mem->root_mem; + + /* return if no roots in previous step */ + if (rootmem->irfnd == 0) return(ARK_SUCCESS); + + /* Set ark_ycur = y(tlo) */ + (void) arkGetDky(ark_mem, rootmem->tlo, 0, ark_mem->ycur); + + /* Evaluate root-finding function: glo = g(tlo, y(tlo)) */ + retval = rootmem->gfun(rootmem->tlo, ark_mem->ycur, + rootmem->glo, ark_mem->user_data); + rootmem->nge++; + if (retval != 0) return(ARK_RTFUNC_FAIL); + + /* reset root-finding flags (overall, and for specific eqns) */ + zroot = SUNFALSE; + for (i = 0; i < rootmem->nrtfn; i++) + rootmem->iroots[i] = 0; + + /* for all active roots, check if glo_i == 0 to mark roots found */ + for (i = 0; i < rootmem->nrtfn; i++) { + if (!rootmem->gactive[i]) continue; + if (SUNRabs(rootmem->glo[i]) == ZERO) { + zroot = SUNTRUE; + rootmem->iroots[i] = 1; + } + } + if (!zroot) return(ARK_SUCCESS); /* return if no roots */ + + /* One or more g_i has a zero at tlo. Check g at tlo+smallh. */ + /* set time tolerance */ + rootmem->ttol = (SUNRabs(ark_mem->tcur) + + SUNRabs(ark_mem->h))*ark_mem->uround*HUND; + /* set tplus = tlo + smallh */ + smallh = (ark_mem->h > ZERO) ? rootmem->ttol : -rootmem->ttol; + tplus = rootmem->tlo + smallh; + /* 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); + } 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->nge++; + if (retval != 0) return(ARK_RTFUNC_FAIL); + + /* Check for close roots (error return), for a new zero at tlo+smallh, + and for a g_i that changed from zero to nonzero. */ + zroot = SUNFALSE; + for (i = 0; i < rootmem->nrtfn; i++) { + if (!rootmem->gactive[i]) continue; + if (SUNRabs(rootmem->ghi[i]) == ZERO) { + if (rootmem->iroots[i] == 1) return(CLOSERT); + zroot = SUNTRUE; + rootmem->iroots[i] = 1; + } else { + if (rootmem->iroots[i] == 1) + rootmem->glo[i] = rootmem->ghi[i]; + } + } + if (zroot) return(RTFOUND); + return(ARK_SUCCESS); +} + + +/*--------------------------------------------------------------- + arkRootCheck3 + + This routine interfaces to arkRootfind to look for a root of g + between tlo and either tn or tout, whichever comes first. + Only roots beyond tlo in the direction of integration are sought. + + This routine returns an int equal to: + ARK_RTFUNC_FAIL < 0 if the g function failed, or + RTFOUND = 1 if a root of g was found, or + ARK_SUCCESS = 0 otherwise. + ---------------------------------------------------------------*/ +int arkRootCheck3(void* arkode_mem) +{ + int i, retval, ier; + ARKodeMem ark_mem; + ARKodeRootMem rootmem; + if (arkode_mem == NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkRootCheck3", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + rootmem = ark_mem->root_mem; + + /* Set thi = tn or tout, whichever comes first; set y = y(thi). */ + if (rootmem->taskc == ARK_ONE_STEP) { + rootmem->thi = ark_mem->tcur; + N_VScale(ONE, ark_mem->yn, ark_mem->ycur); + } + if (rootmem->taskc == ARK_NORMAL) { + if ( (rootmem->toutc - ark_mem->tcur)*ark_mem->h >= ZERO) { + rootmem->thi = ark_mem->tcur; + N_VScale(ONE, ark_mem->yn, ark_mem->ycur); + } else { + rootmem->thi = rootmem->toutc; + (void) arkGetDky(ark_mem, rootmem->thi, 0, ark_mem->ycur); + } + } + + /* 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->nge++; + if (retval != 0) return(ARK_RTFUNC_FAIL); + + rootmem->ttol = (SUNRabs(ark_mem->tcur) + + SUNRabs(ark_mem->h))*ark_mem->uround*HUND; + ier = arkRootfind(ark_mem); + if (ier == ARK_RTFUNC_FAIL) return(ARK_RTFUNC_FAIL); + for(i=0; i<rootmem->nrtfn; i++) { + if (!rootmem->gactive[i] && rootmem->grout[i] != ZERO) + rootmem->gactive[i] = SUNTRUE; + } + rootmem->tlo = rootmem->trout; + for (i = 0; i < rootmem->nrtfn; i++) + rootmem->glo[i] = rootmem->grout[i]; + + /* If no root found, return ARK_SUCCESS. */ + if (ier == ARK_SUCCESS) return(ARK_SUCCESS); + + /* If a root was found, interpolate to get y(trout) and return. */ + (void) arkGetDky(ark_mem, rootmem->trout, 0, ark_mem->ycur); + return(RTFOUND); +} + + +/*--------------------------------------------------------------- + arkRootfind + + This routine solves for a root of g(t) between tlo and thi, if + one exists. Only roots of odd multiplicity (i.e. with a change + of sign in one of the g_i), or exact zeros, are found. + Here the sign of tlo - thi is arbitrary, but if multiple roots + are found, the one closest to tlo is returned. + + The method used is the Illinois algorithm, a modified secant method. + Reference: Kathie L. Hiebert and Lawrence F. Shampine, Implicitly + Defined Output Points for Solutions of ODEs, Sandia National + Laboratory Report SAND80-0180, February 1980. + + This routine uses the following parameters for communication: + + nrtfn = number of functions g_i, or number of components of + the vector-valued function g(t). Input only. + + gfun = user-defined function for g(t). Its form is + (void) gfun(t, y, gt, user_data) + + rootdir = in array specifying the direction of zero-crossings. + If rootdir[i] > 0, search for roots of g_i only if + g_i is increasing; if rootdir[i] < 0, search for + roots of g_i only if g_i is decreasing; otherwise + always search for roots of g_i. + + gactive = array specifying whether a component of g should + or should not be monitored. gactive[i] is initially + 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 + corresponding g function moves away from 0.0. + + nge = cumulative counter for gfun calls. + + ttol = a convergence tolerance for trout. Input only. + When a root at trout is found, it is located only to + within a tolerance of ttol. Typically, ttol should + be set to a value on the order of + 100 * UROUND * max (SUNRabs(tlo), SUNRabs(thi)) + where UROUND is the unit roundoff of the machine. + + tlo, thi = endpoints of the interval in which roots are sought. + On input, and must be distinct, but tlo - thi may + be of either sign. The direction of integration is + assumed to be from tlo to thi. On return, tlo and thi + are the endpoints of the final relevant interval. + + glo, ghi = arrays of length nrtfn containing the vectors g(tlo) + and g(thi) respectively. Input and output. On input, + none of the glo[i] should be zero. + + trout = root location, if a root was found, or thi if not. + Output only. If a root was found other than an exact + zero of g, trout is the endpoint thi of the final + interval bracketing the root, with size at most ttol. + + grout = array of length nrtfn containing g(trout) on return. + + iroots = int array of length nrtfn with root information. + Output only. If a root was found, iroots indicates + which components g_i have a root at trout. For + i = 0, ..., nrtfn-1, iroots[i] = 1 if g_i has a root + and g_i is increasing, iroots[i] = -1 if g_i has a + root and g_i is decreasing, and iroots[i] = 0 if g_i + has no roots or g_i varies in the direction opposite + to that indicated by rootdir[i]. + + This routine returns an int equal to: + ARK_RTFUNC_FAIL < 0 if the g function failed, or + RTFOUND = 1 if a root of g was found, or + ARK_SUCCESS = 0 otherwise. + ---------------------------------------------------------------*/ +int arkRootfind(void* arkode_mem) +{ + realtype alpha, tmid, gfrac, maxfrac, fracint, fracsub; + int i, retval, imax, side, sideprev; + booleantype zroot, sgnchg; + ARKodeMem ark_mem; + ARKodeRootMem rootmem; + if (arkode_mem == NULL) { + arkProcessError(NULL, ARK_MEM_NULL, "ARKode", + "arkRootfind", MSG_ARK_NO_MEM); + return(ARK_MEM_NULL); + } + ark_mem = (ARKodeMem) arkode_mem; + rootmem = ark_mem->root_mem; + + imax = 0; + + /* First check for change in sign in ghi or for a zero in ghi. */ + maxfrac = ZERO; + zroot = SUNFALSE; + sgnchg = SUNFALSE; + for (i = 0; i < rootmem->nrtfn; i++) { + if (!rootmem->gactive[i]) continue; + if (SUNRabs(rootmem->ghi[i]) == ZERO) { + if (rootmem->rootdir[i]*rootmem->glo[i] <= ZERO) { + zroot = SUNTRUE; + } + } else { + if ( (rootmem->glo[i]*rootmem->ghi[i] < ZERO) && + (rootmem->rootdir[i]*rootmem->glo[i] <= ZERO) ) { + gfrac = SUNRabs(rootmem->ghi[i]/(rootmem->ghi[i] - rootmem->glo[i])); + if (gfrac > maxfrac) { + sgnchg = SUNTRUE; + maxfrac = gfrac; + imax = i; + } + } + } + } + + /* If no sign change was found, reset trout and grout. Then return + ARK_SUCCESS if no zero was found, or set iroots and return RTFOUND. */ + if (!sgnchg) { + rootmem->trout = rootmem->thi; + for (i = 0; i < rootmem->nrtfn; i++) + rootmem->grout[i] = rootmem->ghi[i]; + if (!zroot) return(ARK_SUCCESS); + for (i = 0; i < rootmem->nrtfn; i++) { + rootmem->iroots[i] = 0; + if (!rootmem->gactive[i]) continue; + if (SUNRabs(rootmem->ghi[i]) == ZERO) + rootmem->iroots[i] = rootmem->glo[i] > 0 ? -1:1; + } + return(RTFOUND); + } + + /* Initialize alpha to avoid compiler warning */ + alpha = 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(rootmem->thi - rootmem->tlo) <= rootmem->ttol) break; + + /* Set weight alpha. + On the first two passes, set alpha = 1. Thereafter, reset alpha + 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 alpha = 1. + If the sides were the same, then double alpha (if high side), + or halve alpha (if low side). + The next guess tmid is the secant method value if alpha = 1, but + is closer to tlo if alpha < 1, and closer to thi if alpha > 1. */ + if (sideprev == side) { + alpha = (side == 2) ? alpha*TWO : alpha*HALF; + } else { + alpha = 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 = rootmem->thi - (rootmem->thi - rootmem->tlo) * + rootmem->ghi[imax]/(rootmem->ghi[imax] - alpha*rootmem->glo[imax]); + if (SUNRabs(tmid - rootmem->tlo) < HALF*rootmem->ttol) { + fracint = SUNRabs(rootmem->thi - rootmem->tlo)/rootmem->ttol; + fracsub = (fracint > FIVE) ? TENTH : HALF/fracint; + tmid = rootmem->tlo + fracsub*(rootmem->thi - rootmem->tlo); + } + if (SUNRabs(rootmem->thi - tmid) < HALF*rootmem->ttol) { + fracint = SUNRabs(rootmem->thi - rootmem->tlo)/rootmem->ttol; + fracsub = (fracint > FIVE) ? TENTH : HALF/fracint; + tmid = rootmem->thi - fracsub*(rootmem->thi - rootmem->tlo); + } + + (void) arkGetDky(ark_mem, tmid, 0, ark_mem->ycur); + retval = rootmem->gfun(tmid, ark_mem->ycur, rootmem->grout, + ark_mem->user_data); + rootmem->nge++; + if (retval != 0) return(ARK_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 < rootmem->nrtfn; i++) { + if (!rootmem->gactive[i]) continue; + if (SUNRabs(rootmem->grout[i]) == ZERO) { + if (rootmem->rootdir[i]*rootmem->glo[i] <= ZERO) { + zroot = SUNTRUE; + } + } else { + if ( (rootmem->glo[i]*rootmem->grout[i] < ZERO) && + (rootmem->rootdir[i]*rootmem->glo[i] <= ZERO) ) { + gfrac = SUNRabs(rootmem->grout[i]/(rootmem->grout[i] - rootmem->glo[i])); + if (gfrac > maxfrac) { + sgnchg = SUNTRUE; + maxfrac = gfrac; + imax = i; + } + } + } + } + if (sgnchg) { + /* Sign change found in (tlo,tmid); replace thi with tmid. */ + rootmem->thi = tmid; + for (i = 0; i < rootmem->nrtfn; i++) + rootmem->ghi[i] = rootmem->grout[i]; + side = 1; + /* Stop at root thi if converged; otherwise loop. */ + if (SUNRabs(rootmem->thi - rootmem->tlo) <= rootmem->ttol) break; + continue; /* Return to looping point. */ + } + + if (zroot) { + /* No sign change in (tlo,tmid), but g = 0 at tmid; return root tmid. */ + rootmem->thi = tmid; + for (i = 0; i < rootmem->nrtfn; i++) + rootmem->ghi[i] = rootmem->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. */ + rootmem->tlo = tmid; + for (i = 0; i < rootmem->nrtfn; i++) + rootmem->glo[i] = rootmem->grout[i]; + side = 2; + /* Stop at root thi if converged; otherwise loop back. */ + if (SUNRabs(rootmem->thi - rootmem->tlo) <= rootmem->ttol) + break; + + } /* End of root-search loop */ + + /* Reset trout and grout, set iroots, and return RTFOUND. */ + rootmem->trout = rootmem->thi; + for (i = 0; i < rootmem->nrtfn; i++) { + rootmem->grout[i] = rootmem->ghi[i]; + rootmem->iroots[i] = 0; + if (!rootmem->gactive[i]) continue; + if ( (SUNRabs(rootmem->ghi[i]) == ZERO) && + (rootmem->rootdir[i]*rootmem->glo[i] <= ZERO) ) + rootmem->iroots[i] = rootmem->glo[i] > 0 ? -1:1; + if ( (rootmem->glo[i]*rootmem->ghi[i] < ZERO) && + (rootmem->rootdir[i]*rootmem->glo[i] <= ZERO) ) + rootmem->iroots[i] = rootmem->glo[i] > 0 ? -1:1; + } + return(RTFOUND); +} + + +/*=============================================================== + EOF + ===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_root_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_root_impl.h new file mode 100644 index 0000000..69b6170 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/arkode_root_impl.h @@ -0,0 +1,86 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * Implementation header file for ARKode's root-finding (in time) + * utility. + *--------------------------------------------------------------*/ + +#ifndef _ARKODE_ROOT_IMPL_H +#define _ARKODE_ROOT_IMPL_H + +#include <stdarg.h> +#include <arkode/arkode.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*=============================================================== + ARKode Root-finding constants + ===============================================================*/ + +#define ARK_ROOT_LRW 5 +#define ARK_ROOT_LIW 12 /* int, ptr, etc */ + +/*=============================================================== + ARKode Root-finding Data Structure + ===============================================================*/ + +/*--------------------------------------------------------------- + Types : struct ARKodeRootMemRec, ARKodeRootMem + ----------------------------------------------------------------- + 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 { + + ARKRootFn gfun; /* function g for roots sought */ + int nrtfn; /* number of components of g */ + int *iroots; /* array for root information */ + int *rootdir; /* array specifying direction of zero-crossing */ + realtype tlo; /* nearest endpoint of interval in root search */ + realtype thi; /* farthest endpoint of interval in root search */ + realtype trout; /* t value returned by rootfinding routine */ + realtype *glo; /* saved array of g values at t = tlo */ + realtype *ghi; /* saved array of g values at t = thi */ + realtype *grout; /* array of g values at t = trout */ + realtype toutc; /* copy of tout (if NORMAL mode) */ + realtype ttol; /* tolerance on root location */ + int taskc; /* copy of parameter itask */ + int irfnd; /* flag showing whether last step had a root */ + long int nge; /* counter for g evaluations */ + booleantype *gactive; /* array with active/inactive event functions */ + int mxgnull; /* num. warning messages about possible g==0 */ + +} *ARKodeRootMem; + + +/*=============================================================== + ARKode Root-finding Routines +===============================================================*/ + +int arkRootFree(void* arkode_mem); +int arkPrintRootMem(void* arkode_mem, FILE *outfile); +int arkRootCheck1(void* arkode_mem); +int arkRootCheck2(void* arkode_mem); +int arkRootCheck3(void* arkode_mem); +int arkRootfind(void* arkode_mem); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkadapt.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkadapt.c new file mode 100644 index 0000000..09a8300 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkadapt.c @@ -0,0 +1,78 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * Fortran/C interface routines for ARKODE, for the case of a + * user-supplied step adaptivity routine. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "farkode.h" +#include "arkode_impl.h" + +/*=============================================================*/ + +/* Prototype of the Fortran routine */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FARK_ADAPT(realtype *Y, realtype *T, realtype *H1, + realtype *H2, realtype *H3, realtype *E1, + realtype *E2, realtype *E3, int *Q, int *P, + realtype *HNEW, long int *IPAR, + realtype *RPAR, int *IER); + +#ifdef __cplusplus +} +#endif + +/*=============================================================*/ + +/* Fortran interface to C routine ARKStepSetAdaptivityFn; see + farkode.h for further information */ +void FARK_ADAPTSET(int *flag, int *ier) +{ + if (*flag == 0) { + *ier = ARKStepSetAdaptivityFn(ARK_arkodemem, NULL, NULL); + } else { + *ier = ARKStepSetAdaptivityFn(ARK_arkodemem, FARKAdapt, + ARK_arkodemem); + } + return; +} + +/*=============================================================*/ + +/* C interface to user-supplied fortran routine FARKADAPT; see + farkode.h for further information */ +int FARKAdapt(N_Vector y, realtype t, realtype h1, realtype h2, + realtype h3, realtype e1, realtype e2, realtype e3, + int q, int p, realtype *hnew, void *user_data) +{ + int ier = 0; + realtype *ydata; + FARKUserData ARK_userdata; + + ydata = N_VGetArrayPointer(y); + ARK_userdata = (FARKUserData) user_data; + + FARK_ADAPT(ydata, &t, &h1, &h2, &h3, &e1, &e2, &e3, &q, &p, hnew, + ARK_userdata->ipar, ARK_userdata->rpar, &ier); + return(ier); +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkband.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkband.c new file mode 100644 index 0000000..0247b73 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkband.c @@ -0,0 +1,96 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * Fortran/C interface routines for ARKODE/ARKLS, for the case + * of a user-supplied Jacobian approximation routine. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "farkode.h" +#include "arkode_impl.h" +#include <arkode/arkode_arkstep.h> +#include <sunmatrix/sunmatrix_band.h> + + +/*=============================================================*/ + +/* Prototype of the Fortran routine */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FARK_BJAC(long int *N, long int *MU, + long int *ML, long int *EBAND, + realtype *T, realtype *Y, realtype *FY, + realtype *BJAC, realtype *H, + long int *IPAR, realtype *RPAR, + realtype *V1, realtype *V2, + realtype *V3, int *IER); + +#ifdef __cplusplus +} +#endif + +/*=============================================================*/ + +/* Fortran interface routine to ARKStepSetJacFn; see farkode.h + for further details */ +void FARK_BANDSETJAC(int *flag, int *ier) +{ + if (*flag == 0) { + *ier = ARKStepSetJacFn(ARK_arkodemem, NULL); + } else { + *ier = ARKStepSetJacFn(ARK_arkodemem, FARKBandJac); + } + return; +} + +/*=============================================================*/ + +/* C interface to user-supplied Fortran subroutine FARKBJAC; see + farkode.h for further details */ +int FARKBandJac(realtype t, N_Vector y, N_Vector fy, SUNMatrix J, + void *user_data, N_Vector vtemp1, N_Vector vtemp2, + N_Vector vtemp3) +{ + realtype *ydata, *fydata, *jacdata, *v1data, *v2data, *v3data; + realtype h; + long int N, mupper, mlower, smu, eband; + FARKUserData ARK_userdata; + int ier = 0; + + ARKStepGetLastStep(ARK_arkodemem, &h); + ydata = N_VGetArrayPointer(y); + fydata = N_VGetArrayPointer(fy); + v1data = N_VGetArrayPointer(vtemp1); + v2data = N_VGetArrayPointer(vtemp2); + v3data = N_VGetArrayPointer(vtemp3); + N = SUNBandMatrix_Columns(J); + mupper = SUNBandMatrix_UpperBandwidth(J); + mlower = SUNBandMatrix_LowerBandwidth(J); + smu = SUNBandMatrix_StoredUpperBandwidth(J); + eband = smu + mlower + 1; + jacdata = SUNBandMatrix_Column(J,0) - mupper; + ARK_userdata = (FARKUserData) user_data; + + FARK_BJAC(&N, &mupper, &mlower, &eband, &t, ydata, fydata, + jacdata, &h, ARK_userdata->ipar, ARK_userdata->rpar, + v1data, v2data, v3data, &ier); + return(ier); +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkbandmass.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkbandmass.c new file mode 100644 index 0000000..38bdd50 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkbandmass.c @@ -0,0 +1,85 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * Fortran/C interface routines for ARKODE/ARKLS, for the case + * of a user-supplied mass-matrix approximation routine. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "farkode.h" +#include "arkode_impl.h" +#include <arkode/arkode_arkstep.h> +#include <sunmatrix/sunmatrix_band.h> + + +/*=============================================================*/ + +/* Prototype of the Fortran routine */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FARK_BMASS(long int *N, long int *MU, + long int *ML, long int *EBAND, + realtype *T, realtype *BMASS, + long int *IPAR, realtype *RPAR, + realtype *V1, realtype *V2, realtype *V3, + int *IER); + +#ifdef __cplusplus +} +#endif + +/*=============================================================*/ + +/* Fortran interface routine to ARKStepSetMassFn; see farkode.h + for further details */ +void FARK_BANDSETMASS(int *ier) +{ + *ier = ARKStepSetMassFn(ARK_arkodemem, FARKBandMass); +} + +/*=============================================================*/ + +/* C interface to user-supplied Fortran subroutine FARKBMASS; see + farkode.h for further details */ +int FARKBandMass(realtype t, SUNMatrix M, void *user_data, + N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3) +{ + int ier; + realtype *massdata, *v1data, *v2data, *v3data; + long int N, mupper, mlower, smu, eband; + FARKUserData ARK_userdata; + + v1data = N_VGetArrayPointer(vtemp1); + v2data = N_VGetArrayPointer(vtemp2); + v3data = N_VGetArrayPointer(vtemp3); + N = SUNBandMatrix_Columns(M); + mupper = SUNBandMatrix_UpperBandwidth(M); + mlower = SUNBandMatrix_LowerBandwidth(M); + smu = SUNBandMatrix_StoredUpperBandwidth(M); + eband = smu + mlower + 1; + massdata = SUNBandMatrix_Column(M,0) - mupper; + ARK_userdata = (FARKUserData) user_data; + + FARK_BMASS(&N, &mupper, &mlower, &eband, &t, massdata, + ARK_userdata->ipar, ARK_userdata->rpar, v1data, + v2data, v3data, &ier); + return(ier); +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkbbd.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkbbd.c new file mode 100644 index 0000000..9bf7c0d --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkbbd.c @@ -0,0 +1,133 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 module contains the routines necessary to interface with + * the ARKBBDPRE module and user-supplied Fortran routines. + * The routines here call the generically named routines and + * providea standard interface to the C code of the ARKBBDPRE + * package. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "farkode.h" +#include "farkbbd.h" +#include <arkode/arkode_bbdpre.h> + +/*=============================================================*/ + +/* Prototypes of the Fortran routines */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FARK_GLOCFN(long int *NLOC, realtype *T, + realtype *YLOC, realtype *GLOC, + long int *IPAR, realtype *RPAR, + int *ier); + extern void FARK_COMMFN(long int *NLOC, realtype *T, + realtype *Y, long int *IPAR, + realtype *RPAR, int *ier); + +#ifdef __cplusplus +} +#endif + +/*=============================================================*/ + +/* Fortran interface to C routine ARKBBDPrecInit; see farkbbd.h + for further details. */ +void FARK_BBDINIT(long int *Nloc, long int *mudq, + long int *mldq, long int *mu, + long int *ml, realtype* dqrely, + int *ier) +{ + /* 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, + (ARKLocalFn) FARKgloc, + (ARKCommFn) FARKcfn); + return; +} + +/*=============================================================*/ + +/* Fortran interface to C routine ARKBBDPrecReInit; see farkbbd.h + for further details. */ +void FARK_BBDREINIT(long int *mudq, long int *mldq, + realtype* dqrely, int *ier) +{ + *ier = ARKBBDPrecReInit(ARK_arkodemem, *mudq, *mldq, *dqrely); + return; +} + +/*=============================================================*/ + +/* C interface to user-supplied Fortran routine FARKGLOCFN; see + farkbbd.h for further details. */ +int FARKgloc(long int Nloc, realtype t, N_Vector yloc, + N_Vector gloc, void *user_data) +{ + realtype *yloc_data, *gloc_data; + FARKUserData ARK_userdata; + int ier = 0; + + /* Initialize all pointers to NULL */ + yloc_data = gloc_data = NULL; + + yloc_data = N_VGetArrayPointer(yloc); + gloc_data = N_VGetArrayPointer(gloc); + ARK_userdata = (FARKUserData) user_data; + + FARK_GLOCFN(&Nloc, &t, yloc_data, gloc_data, + ARK_userdata->ipar, ARK_userdata->rpar, &ier); + return(ier); +} + +/*=============================================================*/ + +/* C interface to user-supplied Fortran routine FARKCOMMFN; see + farkbbd.h for further details. */ +int FARKcfn(long int Nloc, realtype t, N_Vector y, void *user_data) +{ + realtype *yloc; + FARKUserData ARK_userdata; + int ier = 0; + + /* Initialize all pointers to NULL */ + yloc = NULL; + + yloc = N_VGetArrayPointer(y); + ARK_userdata = (FARKUserData) user_data; + FARK_COMMFN(&Nloc, &t, yloc, ARK_userdata->ipar, + ARK_userdata->rpar, &ier); + return(ier); +} + +/*=============================================================*/ + +/* Fortran interface to C routines ARKBBDPrecGetWorkSpace and + ARKBBDPrecGetNumGfnEvals; see farkbbd.h for further details */ +void FARK_BBDOPT(long int *lenrwbbd, long int *leniwbbd, + long int *ngebbd) +{ + ARKBBDPrecGetWorkSpace(ARK_arkodemem, lenrwbbd, leniwbbd); + ARKBBDPrecGetNumGfnEvals(ARK_arkodemem, ngebbd); + return; +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkbbd.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkbbd.h new file mode 100644 index 0000000..65dd522 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkbbd.h @@ -0,0 +1,83 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 Fortran interface include file for the BBD + * preconditioner (ARKBBDPRE) + *--------------------------------------------------------------*/ + +/*=============================================================== + FARKBBD Interface Package + + The FARKBBD Interface Package is a package of C functions which, + together with the FARKODE Interface Package, support the use of + the ARKODE solver and MPI-parallel N_Vector module, along with + the ARKBBDPRE preconditioner module, for the solution of ODE + systems in a mixed Fortran/C setting. We refer the reader to + the main ARKode documentation PDF and HTML) for information on + usage of the FARKBBD interfce. + ===============================================================*/ + +#ifndef _FARKBBD_H +#define _FARKBBD_H + +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_types.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* header files */ +/* Definitions of interface function names */ +#if defined(SUNDIALS_F77_FUNC) + +#define FARK_BBDINIT SUNDIALS_F77_FUNC(farkbbdinit, FARKBBDINIT) +#define FARK_BBDREINIT SUNDIALS_F77_FUNC(farkbbdreinit, FARKBBDREINIT) +#define FARK_BBDOPT SUNDIALS_F77_FUNC(farkbbdopt, FARKBBDOPT) +#define FARK_GLOCFN SUNDIALS_F77_FUNC(farkglocfn, FARKGLOCFN) +#define FARK_COMMFN SUNDIALS_F77_FUNC(farkcommfn, FARKCOMMFN) + +#else + +#define FARK_BBDINIT farkbbdinit_ +#define FARK_BBDREINIT farkbbdreinit_ +#define FARK_BBDOPT farkbbdopt_ +#define FARK_GLOCFN farkglocfn_ +#define FARK_COMMFN farkcommfn_ + +#endif + +/* Prototypes of exported functions */ +void FARK_BBDINIT(long int *Nloc, long int *mudq, + long int *mldq, long int *mu, + long int *ml, realtype* dqrely, int *ier); +void FARK_BBDREINIT(long int *mudq, long int *mldq, + realtype* dqrely, int *ier); +void FARK_BBDOPT(long int *lenrwbbd, long int *leniwbbd, + long int *ngebbd); + +/* Prototypes: Functions Called by the ARKBBDPRE Module */ +int FARKgloc(long int Nloc, realtype t, N_Vector yloc, + N_Vector gloc, void *user_data); +int FARKcfn(long int Nloc, realtype t, N_Vector y, + void *user_data); + +#ifdef __cplusplus +} +#endif + +#endif + +/*=============================================================== + EOF + ===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkbp.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkbp.c new file mode 100644 index 0000000..fbb7aac --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkbp.c @@ -0,0 +1,51 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 module contains the routines necessary to interface with + * the ARKBANDPRE module and user-supplied Fortran routines. The + * routines here call the generically named routines and provide + * a standard interface to the C code of the ARKBANDPRE package. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "farkode.h" +#include "farkbp.h" +#include <arkode/arkode_bandpre.h> + +/*=============================================================*/ + +/* Fortran interface to C routine ARKBandPrecInit; see farkbp.h + for additional information */ +void FARK_BPINIT(long int *N, long int *mu, + long int *ml, int *ier) +{ + *ier = ARKBandPrecInit(ARK_arkodemem, *N, *mu, *ml); + return; +} + +/*=============================================================*/ + +/* Fortran interface to C routines ARKBandPrecGetWorkSpace and + ARKBandPrecGetNumRhsEvals; see farkbp.h for additional + information */ +void FARK_BPOPT(long int *lenrwbp, long int *leniwbp, long int *nfebp) +{ + ARKBandPrecGetWorkSpace(ARK_arkodemem, lenrwbp, leniwbp); + ARKBandPrecGetNumRhsEvals(ARK_arkodemem, nfebp); + return; +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkbp.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkbp.h new file mode 100644 index 0000000..2781725 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkbp.h @@ -0,0 +1,71 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 Fortran interface include file for the BAND + * preconditioner (ARKBANDPRE). + *--------------------------------------------------------------*/ + +/*=============================================================== + FARKBP Interface Package + + The FARKBP Interface Package is a package of C functions which, + together with the FARKODE Interface Package, support the use of + the ARKODE solver and serial, OpenMP or PThreads vector module + with the ARKBANDPRE preconditioner module, for the solution of + ODE systems in a mixed Fortran/C setting. We refer the reader to + the main ARKode documentation PDF and HTML) for information on + usage of the FARKBBD interfce. + ===============================================================*/ + +#ifndef _FARKBP_H +#define _FARKBP_H + +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_types.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* header files */ +/* Definitions of interface function names */ +#if defined(SUNDIALS_F77_FUNC) + +#define FARK_BPINIT SUNDIALS_F77_FUNC(farkbpinit, FARKBPINIT) +#define FARK_BPOPT SUNDIALS_F77_FUNC(farkbpopt, FARKBPOPT) + +#else + +#define FARK_BPINIT farkbpinit_ +#define FARK_BPOPT farkbpopt_ + +#endif + +/* Prototypes of exported function */ +void FARK_BPINIT(long int *N, + long int *mu, + long int *ml, + int *ier); +void FARK_BPOPT(long int *lenrwbp, + long int *leniwbp, + long int *nfebp); + +#ifdef __cplusplus +} +#endif + +#endif + +/*=============================================================== + EOF + ===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkdense.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkdense.c new file mode 100644 index 0000000..d551895 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkdense.c @@ -0,0 +1,92 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * Fortran/C interface routines for ARKODE/ARKLS, for the case + * of a user-supplied Jacobian approximation routine. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "farkode.h" +#include "arkode_impl.h" +#include <arkode/arkode_arkstep.h> +#include <sunmatrix/sunmatrix_dense.h> + +/*=============================================================*/ + +/* Prototype of the Fortran routine */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FARK_DJAC(long int *N, realtype *T, realtype *Y, + realtype *FY, realtype *DJAC, + realtype *H, long int *IPAR, + realtype *RPAR, realtype *V1, + realtype *V2, realtype *V3, int *ier); + +#ifdef __cplusplus +} +#endif + +/*=============================================================*/ + +/* Fortran interface to C routine ARKStepSetJacFn; see + farkode.h for additional information */ +void FARK_DENSESETJAC(int *flag, int *ier) +{ + if (*flag == 0) { + *ier = ARKStepSetJacFn(ARK_arkodemem, NULL); + } else { + *ier = ARKStepSetJacFn(ARK_arkodemem, FARKDenseJac); + } + return; +} + +/*=============================================================*/ + +/* C interface to user-supplied Fortran routine FARKDJAC; see + farkode.h for additional information */ +int FARKDenseJac(realtype t, N_Vector y, N_Vector fy, SUNMatrix J, + void *user_data, N_Vector vtemp1, N_Vector vtemp2, + N_Vector vtemp3) +{ + realtype *ydata, *fydata, *jacdata, *v1data, *v2data, *v3data; + realtype h; + long int N; + FARKUserData ARK_userdata; + int ier = 0; + + /* Initialize all pointers to NULL */ + ydata = fydata = jacdata = v1data = v2data = v3data = NULL; + + ARKStepGetLastStep(ARK_arkodemem, &h); + ydata = N_VGetArrayPointer(y); + fydata = N_VGetArrayPointer(fy); + v1data = N_VGetArrayPointer(vtemp1); + v2data = N_VGetArrayPointer(vtemp2); + v3data = N_VGetArrayPointer(vtemp3); + N = SUNDenseMatrix_Columns(J); + jacdata = SUNDenseMatrix_Column(J,0); + ARK_userdata = (FARKUserData) user_data; + + FARK_DJAC(&N, &t, ydata, fydata, jacdata, &h, + ARK_userdata->ipar, ARK_userdata->rpar, v1data, + v2data, v3data, &ier); + return(ier); +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkdensemass.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkdensemass.c new file mode 100644 index 0000000..7aea9b6 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkdensemass.c @@ -0,0 +1,77 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * Fortran/C interface routines for ARKODE/ARKLS, for the case + * of a user-supplied mass-matrix approximation routine. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "farkode.h" +#include "arkode_impl.h" +#include <arkode/arkode_arkstep.h> +#include <sunmatrix/sunmatrix_dense.h> + +/*=============================================================*/ + +/* Prototype of the Fortran routine */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FARK_DMASS(long int *N, realtype *T, + realtype *DMASS, long int *IPAR, + realtype *RPAR, realtype *V1, + realtype *V2, realtype *V3, int *ier); + +#ifdef __cplusplus +} +#endif + +/*=============================================================*/ + +/* Fortran interface routine to ARKStepSetMassFn; see + farkode.h for further details */ +void FARK_DENSESETMASS(int *ier) +{ + *ier = ARKStepSetMassFn(ARK_arkodemem, FARKDenseMass); +} + +/*=============================================================*/ + +/* C interface to user-supplied Fortran routine FARKDMASS; see + farkode.h for additional information */ +int FARKDenseMass(realtype t, SUNMatrix M, void *user_data, + N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3) +{ + int ier; + realtype *massdata, *v1data, *v2data, *v3data; + long int N; + FARKUserData ARK_userdata; + + v1data = N_VGetArrayPointer(vtemp1); + v2data = N_VGetArrayPointer(vtemp2); + v3data = N_VGetArrayPointer(vtemp3); + N = SUNDenseMatrix_Columns(M); + massdata = SUNDenseMatrix_Column(M,0); + ARK_userdata = (FARKUserData) user_data; + + FARK_DMASS(&N, &t, massdata, ARK_userdata->ipar, ARK_userdata->rpar, + v1data, v2data, v3data, &ier); + return(ier); +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkewt.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkewt.c new file mode 100644 index 0000000..4dc0395 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkewt.c @@ -0,0 +1,72 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * Fortran/C interface routines for ARKODE, for the case of a + * user-supplied error weight calculation routine. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "farkode.h" +#include "arkode_impl.h" + +/*=============================================================*/ + +/* Prototype of the Fortran routine */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FARK_EWT(realtype *Y, realtype *EWT, + long int *IPAR, realtype *RPAR, + int *IER); + +#ifdef __cplusplus +} +#endif + +/*=============================================================*/ + +/* Fortran interface to C routine ARKStepWFtolerances; see + farkode.h for further information */ +void FARK_EWTSET(int *flag, int *ier) +{ + if (*flag != 0) { + *ier = ARKStepWFtolerances(ARK_arkodemem, FARKEwt); + } + return; +} + +/*=============================================================*/ + +/* C interface to user-supplied fortran routine FARKEWT; see + farkode.h for further information */ +int FARKEwt(N_Vector y, N_Vector ewt, void *user_data) +{ + int ier = 0; + realtype *ydata, *ewtdata; + FARKUserData ARK_userdata; + + ydata = N_VGetArrayPointer(y); + ewtdata = N_VGetArrayPointer(ewt); + ARK_userdata = (FARKUserData) user_data; + + FARK_EWT(ydata, ewtdata, ARK_userdata->ipar, + ARK_userdata->rpar, &ier); + return(ier); +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkexpstab.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkexpstab.c new file mode 100644 index 0000000..e7fa37e --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkexpstab.c @@ -0,0 +1,73 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * Fortran/C interface routines for ARKODE, for the case of a + * user-supplied explicit stability routine. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "farkode.h" +#include "arkode_impl.h" + +/*=============================================================*/ + +/* Prototype of the Fortran routine */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FARK_EXPSTAB(realtype *Y, realtype *T, realtype *HSTAB, + long int *IPAR, realtype *RPAR, int *IER); + +#ifdef __cplusplus +} +#endif + +/*=============================================================*/ + +/* Fortran interface to C routine ARKStepSetStabilityFn; see + farkode.h for further information */ +void FARK_EXPSTABSET(int *flag, int *ier) +{ + if (*flag == 0) { + *ier = ARKStepSetStabilityFn(ARK_arkodemem, NULL, NULL); + } else { + *ier = ARKStepSetStabilityFn(ARK_arkodemem, FARKExpStab, + ARK_arkodemem); + } + return; +} + +/*=============================================================*/ + +/* C interface to user-supplied fortran routine FARKEXPSTAB; see + farkode.h for further information */ +int FARKExpStab(N_Vector y, realtype t, realtype *hstab, void *udata) +{ + int ier = 0; + realtype *ydata; + FARKUserData ARK_userdata; + + ydata = N_VGetArrayPointer(y); + ARK_userdata = (FARKUserData) udata; + + FARK_EXPSTAB(ydata, &t, hstab, ARK_userdata->ipar, + ARK_userdata->rpar, &ier); + return(ier); +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkjtimes.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkjtimes.c new file mode 100644 index 0000000..a4b07d5 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkjtimes.c @@ -0,0 +1,121 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * The C functions FARKJTSetup and FARKJtimes are to interface + * between the ARKLS module and the user-supplied Jacobian-vector + * product routines FARKJTSETUP and FARKJTIMES. Note use of the + * generic names FARK_JTSETUP and FARK_JTIMES in the code below. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "farkode.h" +#include "arkode_impl.h" +#include <arkode/arkode_arkstep.h> + +/*=============================================================*/ + +/* Prototype of the Fortran routine */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FARK_JTSETUP(realtype *T, realtype *Y, realtype *FY, + realtype *H, long int *IPAR, + realtype *RPAR, int *IER); + + extern void FARK_JTIMES(realtype *V, realtype *JV, realtype *T, + realtype *Y, realtype *FY, realtype *H, + long int *IPAR, realtype *RPAR, + realtype *WRK, int *IER); + +#ifdef __cplusplus +} +#endif + +/*=============================================================*/ + +/* ---DEPRECATED--- + Fortran interface to C routine ARKStepSetJacTimes; see + farkode.h for further information */ +void FARK_SPILSSETJAC(int *flag, int *ier) +{ FARK_LSSETJAC(flag,ier); } + +/* Fortran interface to C routine ARKStepSetJacTimes; see + farkode.h for further information */ +void FARK_LSSETJAC(int *flag, int *ier) +{ + if (*flag == 0) { + *ier = ARKStepSetJacTimes(ARK_arkodemem, NULL, NULL); + } else { + *ier = ARKStepSetJacTimes(ARK_arkodemem, FARKJTSetup, FARKJtimes); + } + return; +} + +/*=============================================================*/ + +/* C interface to user-supplied Fortran routine FARKJTSETUP; see + farkode.h for further information */ +int FARKJTSetup(realtype t, N_Vector y, N_Vector fy, void *user_data) +{ + realtype *ydata, *fydata; + realtype h; + FARKUserData ARK_userdata; + int ier = 0; + + /* Initialize all pointers to NULL */ + ydata = fydata = NULL; + + ARKStepGetLastStep(ARK_arkodemem, &h); + ydata = N_VGetArrayPointer(y); + fydata = N_VGetArrayPointer(fy); + ARK_userdata = (FARKUserData) user_data; + + FARK_JTSETUP(&t, ydata, fydata, &h, ARK_userdata->ipar, + ARK_userdata->rpar, &ier); + return(ier); +} + +/* C interface to user-supplied Fortran routine FARKJTIMES; see + farkode.h for further information */ +int FARKJtimes(N_Vector v, N_Vector Jv, realtype t, N_Vector y, + N_Vector fy, void *user_data, N_Vector work) +{ + realtype *vdata, *Jvdata, *ydata, *fydata, *wkdata; + realtype h; + FARKUserData ARK_userdata; + int ier = 0; + + /* Initialize all pointers to NULL */ + vdata = Jvdata = ydata = fydata = wkdata = NULL; + + ARKStepGetLastStep(ARK_arkodemem, &h); + + vdata = N_VGetArrayPointer(v); + Jvdata = N_VGetArrayPointer(Jv); + ydata = N_VGetArrayPointer(y); + fydata = N_VGetArrayPointer(fy); + wkdata = N_VGetArrayPointer(work); + + ARK_userdata = (FARKUserData) user_data; + + FARK_JTIMES(vdata, Jvdata, &t, ydata, fydata, &h, ARK_userdata->ipar, + ARK_userdata->rpar, wkdata, &ier); + return(ier); +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkmasspreco.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkmasspreco.c new file mode 100644 index 0000000..3f78949 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkmasspreco.c @@ -0,0 +1,102 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * The C function FARKPSet is to interface between the ARKLSMASS + * module and the user-supplied mass matrix preconditioner + * setup/solve routines FARKPSET and FARKPSOL. Note the use of + * the generic names FARK_PSET and FARK_PSOL in the code below. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "farkode.h" +#include "arkode_impl.h" +#include <arkode/arkode_arkstep.h> + +/*=============================================================*/ + +/* Prototype of the Fortran routines */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FARK_MASSPSET(realtype *T, long int *IPAR, + realtype *RPAR, int *IER); + extern void FARK_MASSPSOL(realtype *T, realtype *R, realtype *Z, + realtype *DELTA, int *LR, long int *IPAR, + realtype *RPAR, int *IER); + +#ifdef __cplusplus +} +#endif + +/*=============================================================*/ + +/* ---DEPRECATED--- + Fortran interface to C routine ARKStepSetMassPreconditioner; see + farkode.h for further details */ +void FARK_SPILSSETMASSPREC(int *flag, int *ier) +{ FARK_LSSETMASSPREC(flag, ier); } + +/* Fortran interface to C routine ARKStepSetMassPreconditioner; see + farkode.h for further details */ +void FARK_LSSETMASSPREC(int *flag, int *ier) +{ + if (*flag == 0) { + *ier = ARKStepSetMassPreconditioner(ARK_arkodemem, NULL, NULL); + } else { + *ier = ARKStepSetMassPreconditioner(ARK_arkodemem, + FARKMassPSet, FARKMassPSol); + } + return; +} + +/*=============================================================*/ + +/* C interface to user-supplied Fortran routine FARKMASSPSET; see + farkode.h for further details */ +int FARKMassPSet(realtype t, void *user_data) +{ + int ier = 0; + FARKUserData ARK_userdata; + ARK_userdata = (FARKUserData) user_data; + FARK_MASSPSET(&t, ARK_userdata->ipar, ARK_userdata->rpar, &ier); + return(ier); +} + + +/*=============================================================*/ + +/* C interface to user-supplied Fortran routine FARKMASSPSOL; see + farkode.h for further details */ +int FARKMassPSol(realtype t, N_Vector r, N_Vector z, realtype delta, + int lr, void *user_data) +{ + int ier = 0; + realtype *rdata, *zdata; + FARKUserData ARK_userdata; + + rdata = N_VGetArrayPointer(r); + zdata = N_VGetArrayPointer(z); + ARK_userdata = (FARKUserData) user_data; + + FARK_MASSPSOL(&t, rdata, zdata, &delta, &lr, ARK_userdata->ipar, + ARK_userdata->rpar, &ier); + return(ier); +} + + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkmtimes.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkmtimes.c new file mode 100644 index 0000000..2a2a8a2 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkmtimes.c @@ -0,0 +1,93 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * The C functions FARKMTSetup and FARKMtimes are to interface + * between the ARKLS and ARKLSMASS modules and the user-supplied + * mass-matrix-vector setup/product routines FARKMTSETUP and + * FARKJTIMES. Note the use of the generic names FARK_MTSETUP + * and FARK_MTIMES in the code below. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "farkode.h" +#include "arkode_impl.h" +#include <arkode/arkode_arkstep.h> + +/*=============================================================*/ + +/* Prototype of the Fortran routine */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FARK_MTSETUP(realtype *T, long int *IPAR, + realtype *RPAR, int *IER); + extern void FARK_MTIMES(realtype *V, realtype *MV, realtype *T, + long int *IPAR, realtype *RPAR, int *IER); + +#ifdef __cplusplus +} +#endif + +/*=============================================================*/ + +/* ---DEPRECATED--- + Fortran interface to C routine ARKStepSetMassTimes; see + farkode.h for further information */ +void FARK_SPILSSETMASS(int *ier) +{ FARK_LSSETMASS(ier); } + +/* Fortran interface to C routine ARKStepSetMassTimes; see + farkode.h for further information */ +void FARK_LSSETMASS(int *ier) +{ + ARKodeMem ark_mem; + ark_mem = (ARKodeMem) ARK_arkodemem; + *ier = ARKStepSetMassTimes(ARK_arkodemem, FARKMTSetup, + FARKMtimes, ark_mem->user_data); +} + +/*=============================================================*/ + +/* C interface to user-supplied Fortran routine FARKMTSETUP; see + farkode.h for further information */ +int FARKMTSetup(realtype t, void *user_data) +{ + FARKUserData ARK_userdata; + int ier = 0; + ARK_userdata = (FARKUserData) user_data; + FARK_MTSETUP(&t, ARK_userdata->ipar, ARK_userdata->rpar, &ier); + return(ier); +} + +/* C interface to user-supplied Fortran routine FARKMTIMES; see + farkode.h for further information */ +int FARKMtimes(N_Vector v, N_Vector Mv, realtype t, void *user_data) +{ + realtype *vdata, *Mvdata; + FARKUserData ARK_userdata; + int ier = 0; + + vdata = N_VGetArrayPointer(v); + Mvdata = N_VGetArrayPointer(Mv); + ARK_userdata = (FARKUserData) user_data; + FARK_MTIMES(vdata, Mvdata, &t, ARK_userdata->ipar, + ARK_userdata->rpar, &ier); + return(ier); +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farknulllinsol.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farknulllinsol.c new file mode 100644 index 0000000..e7b9d98 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farknulllinsol.c @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * File that provides globally-defined, but NULL-valued, + * SUNLinearSolver objects, to ensure that F2C_ARKODE_linsol and + * F2C_ARKODE_mass_sol are defined for cases when no linear + * solver object is linked in with the main executable. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "farkode.h" +#include "arkode_impl.h" + +/*=============================================================*/ + +/* Define global matrix variables */ + +SUNLinearSolver F2C_ARKODE_linsol; +SUNLinearSolver F2C_ARKODE_mass_sol; + +/*=============================================================*/ + +/* C routine that is called when solving an explicit problem */ +void FARKNullLinsol() +{ + F2C_ARKODE_linsol = NULL; + F2C_ARKODE_mass_sol = NULL; +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farknullmatrix.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farknullmatrix.c new file mode 100644 index 0000000..36fc016 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farknullmatrix.c @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * File that provides globally-defined, but NULL-valued, + * SUNMatrix objects, to ensure that F2C_ARKODE_matrix and + * F2C_ARKODE_mass_matrix are defined for cases when no matrix + * object is linked in with the main executable. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "farkode.h" +#include "arkode_impl.h" + +/*=============================================================*/ + +/* Define global matrix variables */ + +SUNMatrix F2C_ARKODE_matrix; +SUNMatrix F2C_ARKODE_mass_matrix; + +/*=============================================================*/ + +/* C routine that is called when solving an explicit problem, or + when using matrix-free linear solvers */ +void FARKNullMatrix() +{ + F2C_ARKODE_matrix = NULL; + F2C_ARKODE_mass_matrix = NULL; +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farknullnonlinsol.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farknullnonlinsol.c new file mode 100644 index 0000000..1097f91 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farknullnonlinsol.c @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * File that provides a globally-defined, but NULL-valued, + * SUNNonlinearSolver object, to ensure that F2C_ARKODE_nonlinsol + * isdefined for cases when no Fortran-defined nonlinear solver + * object is linked in with the main executable. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "farkode.h" +#include "arkode_impl.h" + +/*=============================================================*/ + +/* Define global variable */ + +SUNNonlinearSolver F2C_ARKODE_nonlinsol; + +/*=============================================================*/ + +/* C routine that is called when solving an explicit problem */ +void FARKNullNonlinsol() +{ + F2C_ARKODE_nonlinsol = NULL; +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkode.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkode.c new file mode 100644 index 0000000..be0f6f9 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkode.c @@ -0,0 +1,881 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 the Fortran interface to + * the ARKODE package. See farkode.h for usage. + * NOTE: some routines are necessarily stored elsewhere to avoid + * linking problems. Therefore, see also the other C files in + * this folder for all of the available options. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "farkode.h" +#include "arkode_impl.h" +#include <sundials/sundials_matrix.h> +#include <arkode/arkode_ls.h> +#include <arkode/arkode_arkstep.h> + +/*=============================================================*/ + +/* Constants and default values (in case of illegal inputs) */ +#define ABSTOL RCONST(1.0e-9) +#define RELTOL RCONST(1.0e-4) +#define ZERO RCONST(0.0) + +/*=============================================================*/ + +/* Definitions for global variables shared between Fortran/C + interface routines */ +void *ARK_arkodemem; +long int *ARK_iout; +realtype *ARK_rout; +int ARK_nrtfn; +int ARK_ls; +int ARK_mass_ls; + +/*=============================================================*/ + +/* Prototypes of the Fortran routines */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FARK_IMP_FUN(realtype *T, realtype *Y, realtype *YDOT, + long int *IPAR, realtype *RPAR, int *IER); + extern void FARK_EXP_FUN(realtype *T, realtype *Y, realtype *YDOT, + long int *IPAR, realtype *RPAR, int *IER); + +#ifdef __cplusplus +} +#endif + +/*=============================================================*/ + +/* Fortran interface routine to initialize ARKStep memory + structure; functions as an all-in-one interface to the C + routines ARKStepCreate, ARKStepSetUserData, and + ARKStepSStolerances (or ARKStepSVtolerances); see farkode.h + for further details */ +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) { + + N_Vector Vatol; + FARKUserData ARK_userdata; + realtype reltol, abstol; + + *ier = 0; + + /* Check for required vector operations */ + if(F2C_ARKODE_vec->ops->nvgetarraypointer == NULL) { + *ier = -1; + fprintf(stderr, "Error: getarraypointer vector operation is not implemented.\n\n"); + return; + } + if(F2C_ARKODE_vec->ops->nvsetarraypointer == NULL) { + *ier = -1; + fprintf(stderr, "Error: setarraypointer vector operation is not implemented.\n\n"); + return; + } + if(F2C_ARKODE_vec->ops->nvcloneempty == NULL) { + *ier = -1; + fprintf(stderr, "Error: cloneempty vector operation is not implemented.\n\n"); + return; + } + + /* Initialize all pointers to NULL */ + ARK_arkodemem = NULL; + Vatol = NULL; + + /* initialize global constants to disable each option */ + ARK_nrtfn = 0; + ARK_ls = SUNFALSE; + ARK_mass_ls = SUNFALSE; + + /* Set data in F2C_ARKODE_vec to y0 */ + N_VSetArrayPointer(y0, F2C_ARKODE_vec); + + /* Call ARKStepCreate based on imex argument */ + switch (*imex) { + case 0: /* purely implicit */ + ARK_arkodemem = ARKStepCreate(NULL, FARKfi, *t0, F2C_ARKODE_vec); + break; + case 1: /* purely explicit */ + ARK_arkodemem = ARKStepCreate(FARKfe, NULL, *t0, F2C_ARKODE_vec); + FARKNullMatrix(); + FARKNullLinsol(); + FARKNullNonlinsol(); + break; + case 2: /* imex */ + ARK_arkodemem = ARKStepCreate(FARKfe, FARKfi, *t0, F2C_ARKODE_vec); + break; + } + if (ARK_arkodemem == NULL) { + *ier = -1; + return; + } + + /* Set and attach user data */ + ARK_userdata = NULL; + ARK_userdata = (FARKUserData) malloc(sizeof *ARK_userdata); + if (ARK_userdata == NULL) { + *ier = -1; + return; + } + ARK_userdata->rpar = rpar; + ARK_userdata->ipar = ipar; + *ier = ARKStepSetUserData(ARK_arkodemem, ARK_userdata); + if(*ier != ARK_SUCCESS) { + free(ARK_userdata); ARK_userdata = NULL; + *ier = -1; + return; + } + + /* Reset data pointers */ + N_VSetArrayPointer(NULL, F2C_ARKODE_vec); + + /* Set tolerances -- if <= 0, keep as defaults */ + reltol = RELTOL; + abstol = ABSTOL; + if (*rtol > ZERO) reltol = *rtol; + switch (*iatol) { + case 1: + if (*atol > ZERO) abstol = *atol; + *ier = ARKStepSStolerances(ARK_arkodemem, reltol, abstol); + break; + case 2: + Vatol = N_VCloneEmpty(F2C_ARKODE_vec); + if (Vatol == NULL) { + free(ARK_userdata); + ARK_userdata = NULL; + *ier = -1; + return; + } + N_VSetArrayPointer(atol, Vatol); + if (N_VMin(Vatol) <= ZERO) N_VConst(abstol, Vatol); + *ier = ARKStepSVtolerances(ARK_arkodemem, reltol, Vatol); + N_VDestroy(Vatol); + break; + } + + /* On failure, exit */ + if(*ier != ARK_SUCCESS) { + free(ARK_userdata); + ARK_userdata = NULL; + *ier = -1; + return; + } + + /* store pointers to optional output arrays in global vars */ + ARK_iout = iout; + ARK_rout = rout; + + /* Store the unit roundoff in rout for user access */ + ARK_rout[5] = UNIT_ROUNDOFF; + + return; +} + +/*=============================================================*/ + +/* Fortran interface routine to re-initialize ARKStep memory + structure; functions as an all-in-one interface to the C + routines ARKStepReInit and ARKStepSStolerances (or + ARKStepSVtolerances); see farkode.h for further details */ +void FARK_REINIT(realtype *t0, realtype *y0, int *imex, int *iatol, + realtype *rtol, realtype *atol, int *ier) { + + N_Vector Vatol; + realtype reltol, abstol; + *ier = 0; + + /* Initialize all pointers to NULL */ + Vatol = NULL; + + /* Set data in F2C_ARKODE_vec to y0 */ + N_VSetArrayPointer(y0, F2C_ARKODE_vec); + + /* Call ARKStepReInit based on imex argument */ + switch (*imex) { + case 0: /* purely implicit */ + *ier = ARKStepReInit(ARK_arkodemem, NULL, FARKfi, + *t0, F2C_ARKODE_vec); + break; + case 1: /* purely explicit */ + *ier = ARKStepReInit(ARK_arkodemem, FARKfe, NULL, + *t0, F2C_ARKODE_vec); + break; + case 2: /* imex */ + *ier = ARKStepReInit(ARK_arkodemem, FARKfe, FARKfi, + *t0, F2C_ARKODE_vec); + break; + } + + /* Reset data pointers */ + N_VSetArrayPointer(NULL, F2C_ARKODE_vec); + + /* On failure, exit */ + if (*ier != ARK_SUCCESS) { + *ier = -1; + return; + } + + /* Set tolerances */ + reltol = RELTOL; + abstol = ABSTOL; + if (*rtol > ZERO) reltol = *rtol; + switch (*iatol) { + case 1: + if (*atol > ZERO) abstol = *atol; + *ier = ARKStepSStolerances(ARK_arkodemem, reltol, abstol); + break; + case 2: + Vatol = N_VCloneEmpty(F2C_ARKODE_vec); + if (Vatol == NULL) { + *ier = -1; + return; + } + N_VSetArrayPointer(atol, Vatol); + if (N_VMin(Vatol) <= ZERO) N_VConst(abstol, Vatol); + *ier = ARKStepSVtolerances(ARK_arkodemem, reltol, Vatol); + N_VDestroy(Vatol); + break; + } + + /* On failure, exit */ + if (*ier != ARK_SUCCESS) { + *ier = -1; + return; + } + + return; +} + +/*=============================================================*/ + +/* Fortran interface routine to re-initialize ARKStep memory + structure for a problem with a new size but similar time + scale; functions as an all-in-one interface to the C + routines ARKStepResize (and potentially ARKStepSVtolerances); + see farkode.h for further details */ +void FARK_RESIZE(realtype *t0, realtype *y0, realtype *hscale, + int *itol, realtype *rtol, realtype *atol, int *ier) { + + *ier = 0; + + /* Set data in F2C_ARKODE_vec to y0 */ + N_VSetArrayPointer(y0, F2C_ARKODE_vec); + + /* Call ARKStepResize (currently does not allow Fortran + user-supplied vector resize function) */ + *ier = ARKStepResize(ARK_arkodemem, F2C_ARKODE_vec, *hscale, + *t0, NULL, NULL); + + /* Reset data pointer */ + N_VSetArrayPointer(NULL, F2C_ARKODE_vec); + + /* On failure, exit */ + if (*ier != ARK_SUCCESS) { + *ier = -1; + return; + } + + /* Set tolerances, based on itol argument */ + if (*itol) { + N_Vector Vatol = NULL; + Vatol = N_VCloneEmpty(F2C_ARKODE_vec); + if (Vatol == NULL) { + *ier = -1; + return; + } + N_VSetArrayPointer(atol, Vatol); + *ier = ARKStepSVtolerances(ARK_arkodemem, *rtol, Vatol); + N_VDestroy(Vatol); + } + + return; +} + +/*=============================================================*/ + +/* Fortran interface to C routine ARKStepSetDefaults; see + farkode.h for further details */ +void FARK_SETDEFAULTS(int *ier) { + *ier += ARKStepSetDefaults(ARK_arkodemem); + return; +} + +/*=============================================================*/ + +/* Fortran interface to C "set" routines having integer + arguments; see farkode.h for further details */ +void FARK_SETIIN(char key_name[], long int *ival, int *ier) { + if (!strncmp(key_name, "ORDER", 5)) + *ier = ARKStepSetOrder(ARK_arkodemem, (int) *ival); + else if (!strncmp(key_name, "DENSE_ORDER", 11)) + *ier = ARKStepSetDenseOrder(ARK_arkodemem, (int) *ival); + else if (!strncmp(key_name, "LINEAR", 6)) + *ier = ARKStepSetLinear(ARK_arkodemem, (int) *ival); + else if (!strncmp(key_name, "NONLINEAR", 9)) + *ier = ARKStepSetNonlinear(ARK_arkodemem); + else if (!strncmp(key_name, "EXPLICIT", 8)) + *ier = ARKStepSetExplicit(ARK_arkodemem); + else if (!strncmp(key_name, "IMPLICIT", 8)) + *ier = ARKStepSetImplicit(ARK_arkodemem); + else if (!strncmp(key_name, "IMEX", 4)) + *ier = ARKStepSetImEx(ARK_arkodemem); + else if (!strncmp(key_name, "IRK_TABLE_NUM", 13)) + *ier = ARKStepSetTableNum(ARK_arkodemem, (int) *ival, -1); + else if (!strncmp(key_name, "ERK_TABLE_NUM", 13)) + *ier = ARKStepSetTableNum(ARK_arkodemem, -1, (int) *ival); + else if (!strncmp(key_name, "ARK_TABLE_NUM", 13)) + *ier = ARKStepSetTableNum(ARK_arkodemem, (int) ival[0], (int) ival[1]); + else if (!strncmp(key_name, "MAX_NSTEPS", 10)) + *ier = ARKStepSetMaxNumSteps(ARK_arkodemem, (long int) *ival); + else if (!strncmp(key_name, "HNIL_WARNS", 10)) + *ier = ARKStepSetMaxHnilWarns(ARK_arkodemem, (int) *ival); + else if (!strncmp(key_name, "PREDICT_METHOD", 14)) + *ier = ARKStepSetPredictorMethod(ARK_arkodemem, (int) *ival); + else if (!strncmp(key_name, "MAX_ERRFAIL", 11)) + *ier = ARKStepSetMaxErrTestFails(ARK_arkodemem, (int) *ival); + else if (!strncmp(key_name, "MAX_CONVFAIL", 12)) + *ier = ARKStepSetMaxConvFails(ARK_arkodemem, (int) *ival); + else if (!strncmp(key_name, "MAX_NITERS", 10)) + *ier = ARKStepSetMaxNonlinIters(ARK_arkodemem, (int) *ival); + else if (!strncmp(key_name, "ADAPT_SMALL_NEF", 15)) + *ier = ARKStepSetSmallNumEFails(ARK_arkodemem, (int) *ival); + else if (!strncmp(key_name, "LSETUP_MSBP", 11)) + *ier = ARKStepSetMaxStepsBetweenLSet(ARK_arkodemem, (int) *ival); + else { + *ier = -99; + fprintf(stderr, "FARKSETIIN: Unrecognized key.\n\n"); + } + return; +} + +/*=============================================================*/ + +/* Fortran interface to C "set" routines having real + arguments; see farkode.h for further details */ +void FARK_SETRIN(char key_name[], realtype *rval, int *ier) { + if (!strncmp(key_name, "INIT_STEP", 9)) + *ier = ARKStepSetInitStep(ARK_arkodemem, *rval); + else if (!strncmp(key_name, "MAX_STEP", 8)) + *ier = ARKStepSetMaxStep(ARK_arkodemem, *rval); + else if (!strncmp(key_name, "MIN_STEP", 8)) + *ier = ARKStepSetMinStep(ARK_arkodemem, *rval); + else if (!strncmp(key_name, "STOP_TIME", 9)) + *ier = ARKStepSetStopTime(ARK_arkodemem, *rval); + else if (!strncmp(key_name, "NLCONV_COEF", 11)) + *ier = ARKStepSetNonlinConvCoef(ARK_arkodemem, *rval); + else if (!strncmp(key_name, "ADAPT_CFL", 9)) + *ier = ARKStepSetCFLFraction(ARK_arkodemem, *rval); + else if (!strncmp(key_name, "ADAPT_SAFETY", 12)) + *ier = ARKStepSetSafetyFactor(ARK_arkodemem, *rval); + else if (!strncmp(key_name, "ADAPT_BIAS", 10)) + *ier = ARKStepSetErrorBias(ARK_arkodemem, *rval); + else if (!strncmp(key_name, "ADAPT_GROWTH", 12)) + *ier = ARKStepSetMaxGrowth(ARK_arkodemem, *rval); + else if (!strncmp(key_name, "ADAPT_BOUNDS", 12)) + *ier = ARKStepSetFixedStepBounds(ARK_arkodemem, rval[0], rval[1]); + else if (!strncmp(key_name, "ADAPT_ETAMX1", 12)) + *ier = ARKStepSetMaxFirstGrowth(ARK_arkodemem, *rval); + else if (!strncmp(key_name, "ADAPT_ETAMXF", 12)) + *ier = ARKStepSetMaxEFailGrowth(ARK_arkodemem, *rval); + else if (!strncmp(key_name, "ADAPT_ETACF", 11)) + *ier = ARKStepSetMaxCFailGrowth(ARK_arkodemem, *rval); + else if (!strncmp(key_name, "NONLIN_CRDOWN", 11)) + *ier = ARKStepSetNonlinCRDown(ARK_arkodemem, *rval); + else if (!strncmp(key_name, "NONLIN_RDIV", 9)) + *ier = ARKStepSetNonlinRDiv(ARK_arkodemem, *rval); + else if (!strncmp(key_name, "LSETUP_DGMAX", 12)) + *ier = ARKStepSetDeltaGammaMax(ARK_arkodemem, *rval); + else if (!strncmp(key_name, "FIXED_STEP", 10)) + *ier = ARKStepSetFixedStep(ARK_arkodemem, *rval); + else { + *ier = -99; + fprintf(stderr, "FARKSETRIN: Unrecognized key: %s\n\n",key_name); + } + return; +} + +/*=============================================================*/ + +/* Fortran interface to C routine ARKStepSetAdaptivityMethod; + see farkode.h for further details */ +void FARK_SETADAPTMETHOD(int *imethod, int *idefault, int *ipq, + realtype *params, int *ier) { + + *ier = ARKStepSetAdaptivityMethod(ARK_arkodemem, *imethod, + *idefault, *ipq, params); + return; +} + +/*=============================================================*/ + +/* Fortran interface to C routine ARKStepSetTables; see + farkode.h for further details */ +void FARK_SETERKTABLE(int *s, int *q, int *p, realtype *c, realtype *A, + realtype *b, realtype *b2, int *ier) { + ARKodeButcherTable Be; + Be = ARKodeButcherTable_Create(*s, *q, *p, c, A, b, b2); + *ier = ARKStepSetTables(ARK_arkodemem, *q, *p, NULL, Be); + ARKodeButcherTable_Free(Be); + return; +} + +/*=============================================================*/ + +/* Fortran interface to C routine ARKStepSetTables; see + farkode.h for further details */ +void FARK_SETIRKTABLE(int *s, int *q, int *p, realtype *c, realtype *A, + realtype *b, realtype *b2, int *ier) { + ARKodeButcherTable Bi; + Bi = ARKodeButcherTable_Create(*s, *q, *p, c, A, b, b2); + *ier = ARKStepSetTables(ARK_arkodemem, *q, *p, Bi, NULL); + ARKodeButcherTable_Free(Bi); + return; +} + +/*=============================================================*/ + +/* Fortran interface to C routine ARKStepSetTables; see + farkode.h for further details */ +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) { + ARKodeButcherTable Bi, Be; + Bi = ARKodeButcherTable_Create(*s, *q, *p, ci, Ai, bi, b2i); + Be = ARKodeButcherTable_Create(*s, *q, *p, ce, Ae, be, b2e); + *ier = ARKStepSetTables(ARK_arkodemem, *q, *p, Bi, Be); + ARKodeButcherTable_Free(Bi); + ARKodeButcherTable_Free(Be); + return; +} + +/*=============================================================*/ + +/* Fortran interface routine to set residual tolerance + scalar/array; functions as an all-in-one interface to the C + routines ARKStepResStolerance and ARKStepResVtolerance; + see farkode.h for further details */ +void FARK_SETRESTOLERANCE(int *itol, realtype *atol, int *ier) { + + N_Vector Vatol; + realtype abstol; + + *ier = 0; + + /* Set tolerance, based on itol argument */ + abstol = ABSTOL; + switch (*itol) { + case 1: + if (*atol > ZERO) abstol = *atol; + *ier = ARKStepResStolerance(ARK_arkodemem, abstol); + break; + case 2: + Vatol = NULL; + Vatol = N_VCloneEmpty(F2C_ARKODE_vec); + if (Vatol == NULL) { + *ier = -1; + return; + } + N_VSetArrayPointer(atol, Vatol); + if (N_VMin(Vatol) <= ZERO) N_VConst(abstol, Vatol); + *ier = ARKStepResVtolerance(ARK_arkodemem, Vatol); + N_VDestroy(Vatol); + break; + } + + return; +} + +/*=============================================================*/ + +/* Fortran interface to C routine ARKStepSetDiagnostics; see + farkode.h for further details */ +void FARK_SETDIAGNOSTICS(char fname[], int *flen, int *ier) { + char *filename=NULL; + FILE *DFID=NULL; + int i; + + /* copy fname into array of specified length */ + filename = (char *) malloc((*flen)*sizeof(char)); + for (i=0; i<*flen; i++) filename[i] = fname[i]; + + /* open diagnostics output file */ + DFID = fopen(filename,"w"); + if (DFID == NULL) { + *ier = 1; + return; + } + *ier = ARKStepSetDiagnostics(ARK_arkodemem, DFID); + free(filename); + return; +} + +/*=============================================================*/ + +/* Fortran routine to close diagnostics output file; see farkode.h + for further details */ +void FARK_STOPDIAGNOSTICS(int *ier) { + ARKodeMem ark_mem; + if (ARK_arkodemem == NULL) { + *ier = 1; + return; + } + ark_mem = (ARKodeMem) ARK_arkodemem; + + if (ark_mem->diagfp == NULL) { + *ier = 1; + return; + } + *ier = fclose(ark_mem->diagfp); + return; +} + +/*=============================================================*/ + +/* Fortran interface to C routine ARKStepSetNonlinearSolver */ +void FARK_NLSINIT(int *ier) { + if ( (ARK_arkodemem == NULL) || (F2C_ARKODE_nonlinsol == NULL) ) { + *ier = -1; + return; + } + *ier = ARKStepSetNonlinearSolver(ARK_arkodemem, F2C_ARKODE_nonlinsol); + return; +} + +/*=============================================================*/ + +/* ---DEPRECATED--- + Fortran interface to C routine ARKStepSetLinearSolver; see + farkode.h for further details */ +void FARK_DLSINIT(int *ier) +{ FARK_LSINIT(ier); } + +/* ---DEPRECATED--- + Fortran interface to C routine ARKStepSetMassLinearSolver; see + farkode.h for further details */ +void FARK_DLSMASSINIT(int *time_dep, int *ier) +{ FARK_LSMASSINIT(time_dep, ier); } + +/*=============================================================*/ + +/* ---DEPRECATED--- + Fortran interface to C routine ARKStepSetLinearSolver; see + farkode.h for further details */ +void FARK_SPILSINIT(int *ier) +{ FARK_LSINIT(ier); } + +/* ---DEPRECATED--- + Fortran interface to C routine ARKStepSetMassLinearSolver; see + farkode.h for further details */ +void FARK_SPILSMASSINIT(int *time_dep, int *ier) +{ FARK_LSMASSINIT(time_dep, ier); } + +/*=============================================================*/ + +/* ---DEPRECATED--- + Fortran interfaces to C "set" routines for the ARKStep linear + solver; see farkode.h for further details */ +void FARK_SPILSSETEPSLIN(realtype *eplifac, int *ier) +{ FARK_LSSETEPSLIN(eplifac, ier); } + +void FARK_SPILSSETMASSEPSLIN(realtype *eplifac, int *ier) +{ FARK_LSSETMASSEPSLIN(eplifac, ier); } + +/*=============================================================*/ + +/* Fortran interface to C routine ARKStepSetLinearSolver; see + farkode.h for further details */ +void FARK_LSINIT(int *ier) { + if ( (ARK_arkodemem == NULL) || (F2C_ARKODE_linsol == NULL) ) { + *ier = -1; + return; + } + *ier = ARKStepSetLinearSolver(ARK_arkodemem, F2C_ARKODE_linsol, + F2C_ARKODE_matrix); + ARK_ls = SUNTRUE; + return; +} + +/* Fortran interface to C routine ARKStepSetMassLinearSolver; see + farkode.h for further details */ +void FARK_LSMASSINIT(int *time_dep, int *ier) { + if ( (ARK_arkodemem == NULL) || (F2C_ARKODE_mass_sol == NULL) ) { + *ier = -1; + return; + } + *ier = ARKStepSetMassLinearSolver(ARK_arkodemem, + F2C_ARKODE_mass_sol, + F2C_ARKODE_mass_matrix, + *time_dep); + ARK_mass_ls = SUNTRUE; + return; +} + +/*=============================================================*/ + +/* Fortran interfaces to C "set" routines for the ARKStep linear + solver; see farkode.h for further details */ +void FARK_LSSETEPSLIN(realtype *eplifac, int *ier) +{ *ier = ARKStepSetEpsLin(ARK_arkodemem, *eplifac); } + +void FARK_LSSETMASSEPSLIN(realtype *eplifac, int *ier) +{ *ier = ARKStepSetMassEpsLin(ARK_arkodemem, *eplifac); } + +/*=============================================================*/ + +/* Fortran interface to C routine ARKStepEvolve (the main integrator) + and optional output routines ARKStepGet*; see farkode.h for + further details */ +void FARK_ARKODE(realtype *tout, realtype *t, realtype *y, + int *itask, int *ier) { + + /* attach user solution array to solver memory */ + N_VSetArrayPointer(y, F2C_ARKODE_vec); + + /* call ARKStepEvolve solver */ + *ier = ARKStepEvolve(ARK_arkodemem, *tout, F2C_ARKODE_vec, t, *itask); + + /* detach user solution array from solver memory */ + N_VSetArrayPointer(NULL, F2C_ARKODE_vec); + + /* Load optional outputs in iout & rout */ + ARKStepGetWorkSpace(ARK_arkodemem, + &ARK_iout[0], /* LENRW */ + &ARK_iout[1]); /* LENIW */ + ARKStepGetStepStats(ARK_arkodemem, + &ARK_iout[2], /* NST */ + &ARK_rout[0], /* H0U */ + &ARK_rout[1], /* HU */ + &ARK_rout[2], /* HCUR */ + &ARK_rout[3]); /* TCUR */ + ARKStepGetTimestepperStats(ARK_arkodemem, + &ARK_iout[3], /* NST_STB */ + &ARK_iout[4], /* NST_ACC */ + &ARK_iout[5], /* NST_ATT */ + &ARK_iout[6], /* NFE */ + &ARK_iout[7], /* NFI */ + &ARK_iout[8], /* NSETUPS */ + &ARK_iout[9]); /* NETF */ + ARKStepGetTolScaleFactor(ARK_arkodemem, + &ARK_rout[4]); /* TOLSFAC */ + ARKStepGetNonlinSolvStats(ARK_arkodemem, + &ARK_iout[10], /* NNI */ + &ARK_iout[11]); /* NCFN */ + + /* If root finding is on, load those outputs as well */ + if (ARK_nrtfn != 0) + ARKStepGetNumGEvals(ARK_arkodemem, &ARK_iout[12]); /* NGE */ + + /* Attach linear solver outputs */ + if (ARK_ls) { + ARKStepGetLinWorkSpace(ARK_arkodemem, &ARK_iout[13], &ARK_iout[14]); /* LENRWLS, LENIWLS */ + ARKStepGetLastLinFlag(ARK_arkodemem, &ARK_iout[15]); /* LSTF */ + ARKStepGetNumLinRhsEvals(ARK_arkodemem, &ARK_iout[16]); /* NFELS */ + ARKStepGetNumJacEvals(ARK_arkodemem, &ARK_iout[17]); /* NJE */ + ARKStepGetNumJTSetupEvals(ARK_arkodemem, &ARK_iout[18]); /* NJTS */ + ARKStepGetNumJtimesEvals(ARK_arkodemem, &ARK_iout[19]); /* NJTV */ + ARKStepGetNumPrecEvals(ARK_arkodemem, &ARK_iout[20]); /* NPE */ + ARKStepGetNumPrecSolves(ARK_arkodemem, &ARK_iout[21]); /* NPS */ + 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 */ + ARKStepGetLastMassFlag(ARK_arkodemem, &ARK_iout[26]); /* LSTMF */ + ARKStepGetNumMassSetups(ARK_arkodemem, &ARK_iout[27]); /* NMSET */ + ARKStepGetNumMassSolves(ARK_arkodemem, &ARK_iout[28]); /* NMSOL */ + ARKStepGetNumMTSetups(ARK_arkodemem, &ARK_iout[29]); /* NMTSET */ + ARKStepGetNumMassMult(ARK_arkodemem, &ARK_iout[30]); /* NMMUL */ + ARKStepGetNumMassPrecEvals(ARK_arkodemem, &ARK_iout[31]); /* NMPE */ + ARKStepGetNumMassPrecSolves(ARK_arkodemem, &ARK_iout[32]); /* NMPS */ + ARKStepGetNumMassIters(ARK_arkodemem, &ARK_iout[33]); /* NMLI */ + ARKStepGetNumMassConvFails(ARK_arkodemem, &ARK_iout[34]); /* NMCFL */ + } + return; +} + +/*=============================================================*/ + +/* Fortran interface to C routine ARKStepGetDky; see farkode.h + for further details */ +void FARK_DKY(realtype *t, int *k, realtype *dky, int *ier) { + + /* store pointer existing F2C_ARKODE_vec data array */ + realtype *f2c_data = N_VGetArrayPointer(F2C_ARKODE_vec); + + /* attach output data array to F2C_ARKODE_vec */ + N_VSetArrayPointer(dky, F2C_ARKODE_vec); + + /* call ARKStepGetDky */ + *ier = 0; + *ier = ARKStepGetDky(ARK_arkodemem, *t, *k, F2C_ARKODE_vec); + + /* reattach F2C_ARKODE_vec to previous data array */ + N_VSetArrayPointer(f2c_data, F2C_ARKODE_vec); + return; +} + +/*=============================================================*/ + +/* Fortran interface to C routine ARKStepGetErrWeights; see + farkode.h for further details */ +void FARK_GETERRWEIGHTS(realtype *eweight, int *ier) { + + /* store pointer existing F2C_ARKODE_vec data array */ + realtype *f2c_data = N_VGetArrayPointer(F2C_ARKODE_vec); + + /* attach output data array to F2C_ARKODE_vec */ + N_VSetArrayPointer(eweight, F2C_ARKODE_vec); + + /* call ARKStepGetErrWeights */ + *ier = 0; + *ier = ARKStepGetErrWeights(ARK_arkodemem, F2C_ARKODE_vec); + + /* reattach F2C_ARKODE_vec to previous data array */ + N_VSetArrayPointer(f2c_data, F2C_ARKODE_vec); + return; +} + +/*=============================================================*/ + +/* Fortran interface to C routine ARKStepGetResWeights; see + farkode.h for further details */ +void FARK_GETRESWEIGHTS(realtype *rweight, int *ier) { + + /* store pointer existing F2C_ARKODE_vec data array */ + realtype *f2c_data = N_VGetArrayPointer(F2C_ARKODE_vec); + + /* attach output data array to F2C_ARKODE_vec */ + N_VSetArrayPointer(rweight, F2C_ARKODE_vec); + + /* call ARKStepGetResWeights */ + *ier = 0; + *ier = ARKStepGetResWeights(ARK_arkodemem, F2C_ARKODE_vec); + + /* reattach F2C_ARKODE_vec to previous data array */ + N_VSetArrayPointer(f2c_data, F2C_ARKODE_vec); + return; +} + +/*=============================================================*/ + +/* Fortran interface to C routine ARKStepGetEstLocalErrors; see + farkode.h for further details */ +void FARK_GETESTLOCALERR(realtype *ele, int *ier) { + + /* store pointer existing F2C_ARKODE_vec data array */ + realtype *f2c_data = N_VGetArrayPointer(F2C_ARKODE_vec); + + /* attach output data array to F2C_ARKODE_vec */ + N_VSetArrayPointer(ele, F2C_ARKODE_vec); + + /* call ARKStepGetEstLocalErrors */ + *ier = 0; + *ier = ARKStepGetEstLocalErrors(ARK_arkodemem, F2C_ARKODE_vec); + + /* reattach F2C_ARKODE_vec to previous data array */ + N_VSetArrayPointer(f2c_data, F2C_ARKODE_vec); + return; +} + +/*=============================================================*/ + +/* Fortran interface to C routine ARKStepFree; see farkode.h for + further details */ +void FARK_FREE() { + + ARKodeMem ark_mem; + ark_mem = (ARKodeMem) ARK_arkodemem; + + /* free user_data structure */ + if (ark_mem->user_data) + free(ark_mem->user_data); + ark_mem->user_data = NULL; + + /* free main integrator memory structure (internally + frees time step module, rootfinding, interpolation structures) */ + ARKStepFree(&ARK_arkodemem); + + /* free interface vector / matrices / linear solvers */ + N_VSetArrayPointer(NULL, F2C_ARKODE_vec); + N_VDestroy(F2C_ARKODE_vec); + if (F2C_ARKODE_matrix) + SUNMatDestroy(F2C_ARKODE_matrix); + if (F2C_ARKODE_mass_matrix) + SUNMatDestroy(F2C_ARKODE_mass_matrix); + if (F2C_ARKODE_linsol) + SUNLinSolFree(F2C_ARKODE_linsol); + if (F2C_ARKODE_mass_sol) + SUNLinSolFree(F2C_ARKODE_mass_sol); + return; +} + +/*=============================================================*/ + +/* Fortran interface to C routineARKStepWriteParameters; see + farkode.h for further details */ +void FARK_WRITEPARAMETERS(int *ier) { + *ier += ARKStepWriteParameters(ARK_arkodemem, stdout); + return; +} + +/*=============================================================*/ + +/* C interface to user-supplied FORTRAN function FARKEFUN; see + farkode.h for further details */ +int FARKfe(realtype t, N_Vector y, N_Vector ydot, void *user_data) { + + int ier; + realtype *ydata, *dydata; + FARKUserData ARK_userdata; + ydata = N_VGetArrayPointer(y); + dydata = N_VGetArrayPointer(ydot); + ARK_userdata = (FARKUserData) user_data; + + FARK_EXP_FUN(&t, ydata, dydata, ARK_userdata->ipar, + ARK_userdata->rpar, &ier); + return(ier); +} + +/*=============================================================*/ + +/* C interface to user-supplied FORTRAN function FARKIFUN; see + farkode.h for further details */ +int FARKfi(realtype t, N_Vector y, N_Vector ydot, void *user_data) { + + int ier; + realtype *ydata, *dydata; + FARKUserData ARK_userdata; + ydata = N_VGetArrayPointer(y); + dydata = N_VGetArrayPointer(ydot); + ARK_userdata = (FARKUserData) user_data; + + FARK_IMP_FUN(&t, ydata, dydata, ARK_userdata->ipar, + ARK_userdata->rpar, &ier); + return(ier); +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkode.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkode.h new file mode 100644 index 0000000..02eb14f --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkode.h @@ -0,0 +1,404 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 header file for FARKODE, the Fortran interface to + * the ARKODE package. + *--------------------------------------------------------------*/ + +/*=============================================================== + 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 + implementation. + + 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 + FARKODE documentation has been removed from this file. + ===============================================================*/ + +#ifndef _FARKODE_H +#define _FARKODE_H + +/* header files */ +#include <arkode/arkode.h> +#include <arkode/arkode_arkstep.h> +#include <sundials/sundials_linearsolver.h> /* definition of type SUNLinearSolver */ +#include <sundials/sundials_matrix.h> /* definition of type SUNMatrix */ +#include <sundials/sundials_nvector.h> /* definition of type N_Vector */ +#include <sundials/sundials_types.h> /* definition of type realtype */ + +/*=============================================================*/ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* Definitions of interface function names */ +#if defined(SUNDIALS_F77_FUNC) + +#define FARK_IMP_FUN SUNDIALS_F77_FUNC(farkifun, FARKIFUN) +#define FARK_EXP_FUN SUNDIALS_F77_FUNC(farkefun, FARKEFUN) +#define FARK_MALLOC SUNDIALS_F77_FUNC(farkmalloc, FARKMALLOC) +#define FARK_REINIT SUNDIALS_F77_FUNC(farkreinit, FARKREINIT) +#define FARK_RESIZE SUNDIALS_F77_FUNC(farkresize, FARKRESIZE) +#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_SETADAPTMETHOD SUNDIALS_F77_FUNC(farksetadaptivitymethod, FARKSETADAPTIVITYMETHOD) +#define FARK_SETERKTABLE SUNDIALS_F77_FUNC(farkseterktable, FARKSETERKTABLE) +#define FARK_SETIRKTABLE SUNDIALS_F77_FUNC(farksetirktable, FARKSETIRKTABLE) +#define FARK_SETARKTABLES SUNDIALS_F77_FUNC(farksetarktables, FARKSETARKTABLES) +#define FARK_SETRESTOLERANCE SUNDIALS_F77_FUNC(farksetrestolerance, FARKSETRESTOLERANCE) +#define FARK_SETDIAGNOSTICS SUNDIALS_F77_FUNC(farksetdiagnostics, FARKSETDIAGNOSTICS) +#define FARK_STOPDIAGNOSTICS SUNDIALS_F77_FUNC(farkstopdiagnostics, FARKSTOPDIAGNOSTICS) +#define FARK_NLSINIT SUNDIALS_F77_FUNC(farknlsinit, FARKNLSINIT) +#define FARK_LSINIT SUNDIALS_F77_FUNC(farklsinit, FARKLSINIT) +#define FARK_LSSETEPSLIN SUNDIALS_F77_FUNC(farklssetepslin, FARKLSSETEPSLIN) +#define FARK_LSMASSINIT SUNDIALS_F77_FUNC(farklsmassinit, FARKLSMASSINIT) +#define FARK_LSSETMASSEPSLIN SUNDIALS_F77_FUNC(farklssetmassepslin, FARKLSSETMASSEPSLIN) +#define FARK_ARKODE SUNDIALS_F77_FUNC(farkode, FARKODE) +#define FARK_DKY SUNDIALS_F77_FUNC(farkdky, FARKDKY) +#define FARK_GETERRWEIGHTS SUNDIALS_F77_FUNC(farkgeterrweights, FARKGETERRWEIGHTS) +#define FARK_GETRESWEIGHTS SUNDIALS_F77_FUNC(farkgetresweights, FARKGETRESWEIGHTS) +#define FARK_GETESTLOCALERR SUNDIALS_F77_FUNC(farkgetestlocalerr, FARKGETESTLOCALERR) +#define FARK_FREE SUNDIALS_F77_FUNC(farkfree, FARKFREE) +#define FARK_WRITEPARAMETERS SUNDIALS_F77_FUNC(farkwriteparameters, FARKWRITEPARAMETERS) + +#define FARK_DENSESETJAC SUNDIALS_F77_FUNC(farkdensesetjac, FARKDENSESETJAC) +#define FARK_DJAC SUNDIALS_F77_FUNC(farkdjac, FARKDJAC) + +#define FARK_BANDSETJAC SUNDIALS_F77_FUNC(farkbandsetjac, FARKBANDSETJAC) +#define FARK_BJAC SUNDIALS_F77_FUNC(farkbjac, FARKBJAC) + +#define FARK_SPARSESETJAC SUNDIALS_F77_FUNC(farksparsesetjac, FARKSPARSESETJAC) +#define FARK_SPJAC SUNDIALS_F77_FUNC(farkspjac, FARKSPJAC) + +#define FARK_DENSESETMASS SUNDIALS_F77_FUNC(farkdensesetmass, FARKDENSESETMASS) +#define FARK_DMASS SUNDIALS_F77_FUNC(farkdmass, FARKDMASS) + +#define FARK_BANDSETMASS SUNDIALS_F77_FUNC(farkbandsetmass, FARKBANDSETMASS) +#define FARK_BMASS SUNDIALS_F77_FUNC(farkbmass, FARKBMASS) + +#define FARK_SPARSESETMASS SUNDIALS_F77_FUNC(farksparsesetmass, FARKSPARSESETMASS) +#define FARK_SPMASS SUNDIALS_F77_FUNC(farkspmass, FARKSPMASS) + +#define FARK_LSSETJAC SUNDIALS_F77_FUNC(farklssetjac, FARKLSSETJAC) +#define FARK_JTSETUP SUNDIALS_F77_FUNC(farkjtsetup, FARKJTSETUP) +#define FARK_JTIMES SUNDIALS_F77_FUNC(farkjtimes, FARKJTIMES) + +#define FARK_LSSETPREC SUNDIALS_F77_FUNC(farklssetprec, FARKLSSETPREC) +#define FARK_PSOL SUNDIALS_F77_FUNC(farkpsol, FARKPSOL) +#define FARK_PSET SUNDIALS_F77_FUNC(farkpset, FARKPSET) + +#define FARK_LSSETMASS SUNDIALS_F77_FUNC(farklssetmass, FARKLSSETMASS) +#define FARK_MTSETUP SUNDIALS_F77_FUNC(farkmtsetup, FARKMTSETUP) +#define FARK_MTIMES SUNDIALS_F77_FUNC(farkmtimes, FARKMTIMES) + +#define FARK_LSSETMASSPREC SUNDIALS_F77_FUNC(farklssetmassprec, FARKLSSETMASSPREC) +#define FARK_MASSPSOL SUNDIALS_F77_FUNC(farkmasspsol, FARKMASSPSOL) +#define FARK_MASSPSET SUNDIALS_F77_FUNC(farkmasspset, FARKMASSPSET) + +#define FARK_EWTSET SUNDIALS_F77_FUNC(farkewtset, FARKEWTSET) +#define FARK_EWT SUNDIALS_F77_FUNC(farkewt, FARKEWT) + +#define FARK_ADAPTSET SUNDIALS_F77_FUNC(farkadaptset, FARKADAPTSET) +#define FARK_ADAPT SUNDIALS_F77_FUNC(farkadapt, FARKADAPT) + +#define FARK_EXPSTABSET SUNDIALS_F77_FUNC(farkexpstabset, FARKEXPSTABSET) +#define FARK_EXPSTAB SUNDIALS_F77_FUNC(farkexpstab, FARKEXPSTAB) + +/*---DEPRECATED---*/ +#define FARK_DLSINIT SUNDIALS_F77_FUNC(farkdlsinit, FARKDLSINIT) +#define FARK_DLSMASSINIT SUNDIALS_F77_FUNC(farkdlsmassinit, FARKDLSMASSINIT) +#define FARK_SPILSINIT SUNDIALS_F77_FUNC(farkspilsinit, FARKSPILSINIT) +#define FARK_SPILSSETEPSLIN SUNDIALS_F77_FUNC(farkspilssetepslin, FARKSPILSSETEPSLIN) +#define FARK_SPILSMASSINIT SUNDIALS_F77_FUNC(farkspilsmassinit, FARKSPILSMASSINIT) +#define FARK_SPILSSETMASSEPSLIN SUNDIALS_F77_FUNC(farkspilssetmassepslin, FARKSPILSSETMASSEPSLIN) +#define FARK_SPILSSETJAC SUNDIALS_F77_FUNC(farkspilssetjac, FARKSPILSSETJAC) +#define FARK_SPILSSETPREC SUNDIALS_F77_FUNC(farkspilssetprec, FARKSPILSSETPREC) +#define FARK_SPILSSETMASS SUNDIALS_F77_FUNC(farkspilssetmass, FARKSPILSSETMASS) +#define FARK_SPILSSETMASSPREC SUNDIALS_F77_FUNC(farkspilssetmassprec, FARKSPILSSETMASSPREC) +/*----------------*/ + +#else + +#define FARK_IMP_FUN farkifun_ +#define FARK_EXP_FUN farkefun_ +#define FARK_MALLOC farkmalloc_ +#define FARK_REINIT farkreinit_ +#define FARK_RESIZE farkresize_ +#define FARK_SETDEFAULTS farksetdefaults_ +#define FARK_SETIIN farksetiin_ +#define FARK_SETRIN farksetrin_ +#define FARK_SETADAPTMETHOD farksetadaptivitymethod_ +#define FARK_SETERKTABLE farkseterktable_ +#define FARK_SETIRKTABLE farksetirktable_ +#define FARK_SETARKTABLES farksetarktables_ +#define FARK_SETRESTOLERANCE farksetrestolerance_ +#define FARK_SETDIAGNOSTICS farksetdiagnostics_ +#define FARK_STOPDIAGNOSTICS farkstopdiagnostics_ +#define FARK_NLSINIT farknlsinit_ +#define FARK_LSINIT farklsinit_ +#define FARK_LSSETEPSLIN farklssetepslin_ +#define FARK_LSMASSINIT farklsmassinit_ +#define FARK_LSSETMASSEPSLIN farklssetmassepslin_ +#define FARK_ARKODE farkode_ +#define FARK_DKY farkdky_ +#define FARK_GETERRWEIGHTS farkgeterrweights_ +#define FARK_GETRESWEIGHTS farkgetresweights_ +#define FARK_GETESTLOCALERR farkgetestlocalerr_ +#define FARK_FREE farkfree_ +#define FARK_WRITEPARAMETERS farkwriteparameters_ + +#define FARK_DENSESETJAC farkdensesetjac_ +#define FARK_DJAC farkdjac_ + +#define FARK_BANDSETJAC farkbandsetjac_ +#define FARK_BJAC farkbjac_ + +#define FARK_SPARSESETJAC farksparsesetjac_ +#define FARK_SPJAC farkspjac_ + +#define FARK_DENSESETMASS farkdensesetmass_ +#define FARK_DMASS farkdmass_ + +#define FARK_BANDSETMASS farkbandsetmass_ +#define FARK_BMASS farkbmass_ + +#define FARK_SPARSESETMASS farksparsesetmass_ +#define FARK_SPMASS farkspmass_ + +#define FARK_LSSETJAC farklssetjac_ +#define FARK_JTSETUP farkjtsetup_ +#define FARK_JTIMES farkjtimes_ + +#define FARK_LSSETPREC farklssetprec_ +#define FARK_PSOL farkpsol_ +#define FARK_PSET farkpset_ + +#define FARK_LSSETMASS farklssetmass_ +#define FARK_MTSETUP farkmtsetup_ +#define FARK_MTIMES farkmtimes_ + +#define FARK_LSSETMASSPREC farklssetmassprec_ +#define FARK_MASSPSOL farkmasspsol_ +#define FARK_MASSPSET farkmasspset_ + +#define FARK_EWTSET farkewtset_ +#define FARK_EWT farkewt_ + +#define FARK_ADAPTSET farkadaptset_ +#define FARK_ADAPT farkadapt_ + +#define FARK_EXPSTABSET farkexpstabset_ +#define FARK_EXPSTAB farkexpstab_ + +/*---DEPRECATED---*/ +#define FARK_DLSINIT farkdlsinit_ +#define FARK_DLSMASSINIT farkdlsmassinit_ +#define FARK_SPILSINIT farkspilsinit_ +#define FARK_SPILSSETEPSLIN farkspilssetepslin_ +#define FARK_SPILSMASSINIT farkspilsmassinit_ +#define FARK_SPILSSETMASSEPSLIN farkspilssetmassepslin_ +#define FARK_SPILSSETJAC farkspilssetjac_ +#define FARK_SPILSSETPREC farkspilssetprec_ +#define FARK_SPILSSETMASS farkspilssetmass_ +#define FARK_SPILSSETMASSPREC farkspilssetmassprec_ +/*----------------*/ + +#endif + + /* Type for user data */ + typedef struct { + realtype *rpar; + long int *ipar; + } *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, + long int *ipar, realtype *rpar, int *ier); + + void FARK_REINIT(realtype *t0, realtype *y0, int *imex, + int *iatol, realtype *rtol, realtype *atol, + int *ier); + + void FARK_RESIZE(realtype *t0, realtype *y0, realtype *hscale, + int *itol, realtype *rtol, realtype *atol, int *ier); + + 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_SETADAPTMETHOD(int *imethod, int *idefault, int *ipq, + realtype *params, int *ier); + + 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, + realtype *b2e, int *ier); + + void FARK_SETRESTOLERANCE(int *itol, realtype *atol, int *ier); + void FARK_SETDIAGNOSTICS(char fname[], int *flen, int *ier); + 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, + int *itask, int *ier); + void FARK_DKY(realtype *t, int *k, realtype *dky, int *ier); + + void FARK_GETERRWEIGHTS(realtype *eweight, int *ier); + void FARK_GETRESWEIGHTS(realtype *rweight, int *ier); + void FARK_GETESTLOCALERR(realtype *ele, int *ier); + + void FARK_FREE(void); + + void FARK_WRITEPARAMETERS(int *ier); + + void FARK_DENSESETJAC(int *flag, int *ier); + void FARK_BANDSETJAC(int *flag, int *ier); + void FARK_SPARSESETJAC(int *ier); + + void FARK_DENSESETMASS(int *ier); + void FARK_BANDSETMASS(int *ier); + void FARK_SPARSESETMASS(int *ier); + + void FARK_LSSETJAC(int *flag, int *ier); + void FARK_LSSETPREC(int *flag, int *ier); + void FARK_LSSETMASS(int *ier); + void FARK_LSSETMASSPREC(int *flag, int *ier); + + void FARK_EWTSET(int *flag, int *ier); + void FARK_ADAPTSET(int *flag, int *ier); + void FARK_EXPSTABSET(int *flag, int *ier); + +/*---DEPRECATED---*/ + void FARK_DLSINIT(int *ier); + void FARK_DLSMASSINIT(int *time_dep, int *ier); + void FARK_SPILSINIT(int *ier); + void FARK_SPILSSETEPSLIN(realtype *eplifac, int *ier); + void FARK_SPILSMASSINIT(int *time_dep, int *ier); + void FARK_SPILSSETMASSEPSLIN(realtype *eplifac, int *ier); + void FARK_SPILSSETJAC(int *flag, int *ier); + void FARK_SPILSSETPREC(int *flag, int *ier); + void FARK_SPILSSETMASS(int *ier); + 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, + 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, + N_Vector vtemp2, N_Vector vtemp3); + + + 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, + N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3); + + 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, + void *user_data); + + 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, + 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); + + int FARKAdapt(N_Vector y, realtype t, realtype h1, realtype h2, + realtype h3, realtype e1, realtype e2, realtype e3, + int q, int p, realtype *hnew, void *user_data); + + int FARKExpStab(N_Vector y, realtype t, realtype *hstab, void *user_data); + + void FARKNullMatrix(); + void FARKNullLinsol(); + void FARKNullNonlinsol(); + + /* 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; + extern SUNMatrix F2C_ARKODE_matrix; + extern SUNMatrix F2C_ARKODE_mass_matrix; + extern SUNLinearSolver F2C_ARKODE_linsol; + extern SUNLinearSolver F2C_ARKODE_mass_sol; + extern SUNNonlinearSolver F2C_ARKODE_nonlinsol; + + /* items defined in farkode.c */ + extern void *ARK_arkodemem; + extern long int *ARK_iout; + extern realtype *ARK_rout; + extern int ARK_nrtfn; + extern booleantype ARK_ls; + extern booleantype ARK_mass_ls; + +#ifdef __cplusplus +} +#endif + +#endif + +/*=============================================================== + EOF + ===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkpreco.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkpreco.c new file mode 100644 index 0000000..32da995 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkpreco.c @@ -0,0 +1,118 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * The C functions FARKPSet and FARKPSol are to interface between + * the ARKLS module and the user-supplied preconditioner + * setup/solve routines FARKPSET and FARKPSOL. Note the use of + * the generic names FARK_PSET and FARK_PSOL in the code below. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "farkode.h" +#include "arkode_impl.h" +#include <arkode/arkode_arkstep.h> + +/*=============================================================*/ + +/* Prototype of the Fortran routines */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FARK_PSET(realtype *T, realtype *Y, realtype *FY, + booleantype *JOK, booleantype *JCUR, + realtype *GAMMA, realtype *H, + long int *IPAR, realtype *RPAR, int *IER); + extern void FARK_PSOL(realtype *T, realtype *Y, realtype *FY, + realtype *R, realtype *Z, + realtype *GAMMA, realtype *DELTA, + int *LR, long int *IPAR, realtype *RPAR, + int *IER); + +#ifdef __cplusplus +} +#endif + +/*=============================================================*/ + +/* ---DEPRECATED--- + Fortran interface to C routine ARKStepSetPreconditioner; see + farkode.h for further details */ +void FARK_SPILSSETPREC(int *flag, int *ier) +{ FARK_LSSETPREC(flag, ier); } + +/* Fortran interface to C routine ARKStepSetPreconditioner; see + farkode.h for further details */ +void FARK_LSSETPREC(int *flag, int *ier) +{ + if (*flag == 0) { + *ier = ARKStepSetPreconditioner(ARK_arkodemem, NULL, NULL); + } else { + *ier = ARKStepSetPreconditioner(ARK_arkodemem, + FARKPSet, FARKPSol); + } + return; +} + +/*=============================================================*/ + +/* C interface to user-supplied Fortran routine FARKPSET; see + farkode.h for further details */ +int FARKPSet(realtype t, N_Vector y, N_Vector fy, + booleantype jok, booleantype *jcurPtr, + realtype gamma, void *user_data) +{ + int ier = 0; + realtype *ydata, *fydata; + realtype h; + FARKUserData ARK_userdata; + + ARKStepGetLastStep(ARK_arkodemem, &h); + ydata = N_VGetArrayPointer(y); + fydata = N_VGetArrayPointer(fy); + ARK_userdata = (FARKUserData) user_data; + + FARK_PSET(&t, ydata, fydata, &jok, jcurPtr, &gamma, &h, + ARK_userdata->ipar, ARK_userdata->rpar, &ier); + return(ier); +} + + +/*=============================================================*/ + +/* C interface to user-supplied Fortran routine FARKPSOL; see + farkode.h for further details */ +int FARKPSol(realtype t, N_Vector y, N_Vector fy, N_Vector r, + N_Vector z, realtype gamma, realtype delta, + int lr, void *user_data) +{ + int ier = 0; + realtype *ydata, *fydata, *rdata, *zdata; + FARKUserData ARK_userdata; + + ydata = N_VGetArrayPointer(y); + fydata = N_VGetArrayPointer(fy); + rdata = N_VGetArrayPointer(r); + zdata = N_VGetArrayPointer(z); + ARK_userdata = (FARKUserData) user_data; + + FARK_PSOL(&t, ydata, fydata, rdata, zdata, &gamma, &delta, &lr, + ARK_userdata->ipar, ARK_userdata->rpar, &ier); + return(ier); +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkroot.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkroot.c new file mode 100644 index 0000000..b44235a --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkroot.c @@ -0,0 +1,93 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * The FARKROOT module contains the routines necessary to use + * the rootfinding feature of the ARKODE module and to interface + * with the user-supplied Fortran subroutine. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "farkode.h" +#include "farkroot.h" +#include "arkode_impl.h" + +/*=============================================================*/ + +/* Prototype of the Fortran routine */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + extern void FARK_ROOTFN(realtype *T, realtype *Y, + realtype *G, long int *IPAR, + realtype *RPAR, int *ier); + +#ifdef __cplusplus +} +#endif + +/*=============================================================*/ + +/* Fortran interface to C routine ARKStepRootInit; see farkroot.h + for further information. */ +void FARK_ROOTINIT(int *nrtfn, int *ier) +{ + *ier = ARKStepRootInit(ARK_arkodemem, *nrtfn, + (ARKRootFn) FARKrootfunc); + ARK_nrtfn = *nrtfn; + return; +} + +/*=============================================================*/ + +/* Fortran interface to C routine ARKStepGetRootInfo; see + farkroot.h for further information. */ +void FARK_ROOTINFO(int *nrtfn, int *info, int *ier) +{ + *ier = ARKStepGetRootInfo(ARK_arkodemem, info); + return; +} + +/*=============================================================*/ + +/* Fortran interface to C routine ARKStepRootInit, used to free + existing memory resources; see farkroot.h for further + information. */ +void FARK_ROOTFREE(void) +{ + ARKStepRootInit(ARK_arkodemem, 0, NULL); + return; +} + +/*=============================================================*/ + +/* C interface to user-supplied routine FARKROOTFN; see + farkroot.h for further information. */ +int FARKrootfunc(realtype t, N_Vector y, + realtype *gout, void *user_data) +{ + int ier; + realtype *ydata; + FARKUserData ARK_userdata; + + ydata = N_VGetArrayPointer(y); + ARK_userdata = (FARKUserData) user_data; + FARK_ROOTFN(&t, ydata, gout, ARK_userdata->ipar, + ARK_userdata->rpar, &ier); + return(ier); +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkroot.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkroot.h new file mode 100644 index 0000000..a6f1f91 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farkroot.h @@ -0,0 +1,71 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 Fortran interface include file for the rootfinding + * feature of ARKODE. + *--------------------------------------------------------------*/ + +/*=============================================================== + FARKROOT Interface Package + + The FARKROOT interface package allows programs written in + FORTRAN to use the rootfinding features of the ARKODE solver + module. We refer the reader to the main ARKode documentation + (PDF and HTML) for usage information. + ===============================================================*/ + +#ifndef _FARKROOT_H +#define _FARKROOT_H + +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_types.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* Definitions of interface function names */ +#if defined(SUNDIALS_F77_FUNC) + +#define FARK_ROOTINIT SUNDIALS_F77_FUNC(farkrootinit, FARKROOTINIT) +#define FARK_ROOTINFO SUNDIALS_F77_FUNC(farkrootinfo, FARKROOTINFO) +#define FARK_ROOTFREE SUNDIALS_F77_FUNC(farkrootfree, FARKROOTFREE) +#define FARK_ROOTFN SUNDIALS_F77_FUNC(farkrootfn, FARKROOTFN) + +#else + +#define FARK_ROOTINIT farkrootinit_ +#define FARK_ROOTINFO farkrootinfo_ +#define FARK_ROOTFREE farkrootfree_ +#define FARK_ROOTFN farkrootfn_ + +#endif + +/* Prototypes of exported function */ +void FARK_ROOTINIT(int *nrtfn, int *ier); +void FARK_ROOTINFO(int *nrtfn, int *info, int *ier); +void FARK_ROOTFREE(void); + +/* Prototype of function called by ARKODE module */ +int FARKrootfunc(realtype t, N_Vector y, + realtype *gout, void *user_data); + +#ifdef __cplusplus +} +#endif + +#endif + +/*=============================================================== + EOF + ===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farksparse.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farksparse.c new file mode 100644 index 0000000..8be2124 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farksparse.c @@ -0,0 +1,99 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * Fortran/C interface routines for ARKODE/ARKLS, for the case + * of a user-supplied sparse Jacobian routine. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "farkode.h" +#include "arkode_impl.h" +#include <arkode/arkode_arkstep.h> +#include <sunmatrix/sunmatrix_sparse.h> + +/*=============================================================*/ + +/* Prototype of the Fortran routine */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + + extern void FARK_SPJAC(realtype *T, realtype *Y, + realtype *FY, long int *N, + long int *NNZ, realtype *JDATA, + sunindextype *JRVALS, sunindextype *JCPTRS, + realtype *H, long int *IPAR, + realtype *RPAR, realtype *V1, + realtype *V2, realtype *V3, + int *ier); + +#ifdef __cplusplus +} +#endif + +/*=============================================================*/ + +/* Fortran interface to C routine ARKStepSetJacFn; see + farkode.h for further information */ +void FARK_SPARSESETJAC(int *ier) +{ +#if defined(SUNDIALS_INT32_T) + arkProcessError((ARKodeMem) ARK_arkodemem, ARK_ILL_INPUT, "ARKODE", + "FARKSPARSESETJAC", + "Sparse Fortran users must configure SUNDIALS with 64-bit integers."); + *ier = 1; +#else + *ier = ARKStepSetJacFn(ARK_arkodemem, FARKSparseJac); +#endif +} + +/*=============================================================*/ + +/* C interface to user-supplied Fortran routine FARKSPJAC; see + farkode.h for additional information */ +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 ier; + realtype *ydata, *fydata, *v1data, *v2data, *v3data, *Jdata; + realtype h; + long int NP, NNZ; + sunindextype *indexvals, *indexptrs; + FARKUserData ARK_userdata; + + ARKStepGetLastStep(ARK_arkodemem, &h); + ydata = N_VGetArrayPointer(y); + fydata = N_VGetArrayPointer(fy); + v1data = N_VGetArrayPointer(vtemp1); + v2data = N_VGetArrayPointer(vtemp2); + v3data = N_VGetArrayPointer(vtemp3); + ARK_userdata = (FARKUserData) user_data; + NP = SUNSparseMatrix_NP(J); + NNZ = SUNSparseMatrix_NNZ(J); + Jdata = SUNSparseMatrix_Data(J); + indexvals = SUNSparseMatrix_IndexValues(J); + indexptrs = SUNSparseMatrix_IndexPointers(J); + + FARK_SPJAC(&t, ydata, fydata, &NP, &NNZ, Jdata, indexvals, + indexptrs, &h, ARK_userdata->ipar, ARK_userdata->rpar, + v1data, v2data, v3data, &ier); + return(ier); +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farksparsemass.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farksparsemass.c new file mode 100644 index 0000000..6075c52 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/arkode/fcmix/farksparsemass.c @@ -0,0 +1,84 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * Fortran/C interface routines for ARKODE/ARKLS, for the case + * of a user-supplied mass-matrix approximation routine. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "farkode.h" +#include "arkode_impl.h" +#include <arkode/arkode_arkstep.h> +#include <sunmatrix/sunmatrix_sparse.h> + +/*=============================================================*/ + +/* Prototype of the Fortran routine */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FARK_SPMASS(realtype *T, long int *N, + long int *NNZ, realtype *MDATA, + sunindextype *MRVALS, sunindextype *MCPTRS, + long int *IPAR, realtype *RPAR, + realtype *V1, realtype *V2, realtype *V3, + int *ier); + +#ifdef __cplusplus +} +#endif + +/*=============================================================*/ + +/* Fortran interface to C routine ARKSlsSetMassFn; see + farkode.h for further information */ +void FARK_SPARSESETMASS(int *ier) +{ + *ier = ARKStepSetMassFn(ARK_arkodemem, FARKSparseMass); +} + +/*=============================================================*/ + +/* C interface to user-supplied Fortran routine FARKSPMASS; see + farkode.h for additional information */ +int FARKSparseMass(realtype t, SUNMatrix MassMat, void *user_data, + N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3) +{ + int ier; + realtype *v1data, *v2data, *v3data, *Mdata; + FARKUserData ARK_userdata; + long int NP, NNZ; + sunindextype *indexvals, *indexptrs; + + v1data = N_VGetArrayPointer(vtemp1); + v2data = N_VGetArrayPointer(vtemp2); + v3data = N_VGetArrayPointer(vtemp3); + NP = SUNSparseMatrix_NP(MassMat); + NNZ = SUNSparseMatrix_NNZ(MassMat); + Mdata = SUNSparseMatrix_Data(MassMat); + indexvals = SUNSparseMatrix_IndexValues(MassMat); + indexptrs = SUNSparseMatrix_IndexPointers(MassMat); + ARK_userdata = (FARKUserData) user_data; + + FARK_SPMASS(&t, &NP, &NNZ, Mdata, indexvals, indexptrs, + ARK_userdata->ipar, ARK_userdata->rpar, v1data, + v2data, v3data, &ier); + return(ier); +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode.c new file mode 100644 index 0000000..1bdc4aa --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode.c @@ -0,0 +1,4093 @@ +/* + * ----------------------------------------------------------------- + * $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 + * 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 main CVODE integrator. + * It is independent of the CVODE linear solver in use. + * ----------------------------------------------------------------- + */ + +/*=================================================================*/ +/* Import Header Files */ +/*=================================================================*/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> + +#include "cvode_impl.h" +#include <sundials/sundials_math.h> +#include <sundials/sundials_types.h> +#include "sunnonlinsol/sunnonlinsol_newton.h" + +/*=================================================================*/ +/* 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 + * ---------------------------------------------------------- + * + * cvHin return values: + * CV_SUCCESS + * CV_RHSFUNC_FAIL + * CV_TOO_CLOSE + * + * cvStep control constants: + * DO_ERROR_TEST + * PREDICT_AGAIN + * + * cvStep return values: + * CV_SUCCESS, + * CV_LSETUP_FAIL, CV_LSOLVE_FAIL, + * CV_RHSFUNC_FAIL, CV_RTFUNC_FAIL + * CV_CONV_FAILURE, CV_ERR_FAILURE, + * CV_FIRST_RHSFUNC_ERR + * + * cvNls input nflag values: + * FIRST_CALL + * PREV_CONV_FAIL + * PREV_ERR_FAIL + * + * cvNls return values: + * CV_SUCCESS, + * CV_LSETUP_FAIL, CV_LSOLVE_FAIL, CV_RHSFUNC_FAIL, + * CONV_FAIL, RHSFUNC_RECVR + * + * cvNewtonIteration return values: + * CV_SUCCESS, + * CV_LSOLVE_FAIL, CV_RHSFUNC_FAIL + * CONV_FAIL, RHSFUNC_RECVR, + * TRY_AGAIN + * + */ + +#define DO_ERROR_TEST +2 +#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 + +/* + * Control constants for lower-level rootfinding functions + * ------------------------------------------------------- + * + * cvRcheck1 return values: + * CV_SUCCESS, + * CV_RTFUNC_FAIL, + * cvRcheck2 return values: + * CV_SUCCESS + * CV_RTFUNC_FAIL, + * CLOSERT + * RTFOUND + * cvRcheck3 return values: + * CV_SUCCESS + * CV_RTFUNC_FAIL, + * RTFOUND + * cvRootfind return values: + * CV_SUCCESS + * CV_RTFUNC_FAIL, + * RTFOUND + */ + +#define RTFOUND +1 +#define CLOSERT +3 + +/* + * Control constants for tolerances + * -------------------------------- + */ + +#define CV_NN 0 +#define CV_SS 1 +#define CV_SV 2 +#define CV_WF 3 + +/* + * Algorithmic constants + * --------------------- + * + * CVodeGetDky and cvStep + * + * FUZZ_FACTOR + * + * cvHin + * + * HLB_FACTOR + * HUB_FACTOR + * H_BIAS + * MAX_ITERS + * + * CVodeCreate + * + * CORTES + * + * cvStep + * + * THRESH + * ETAMX1 + * ETAMX2 + * ETAMX3 + * ETAMXF + * ETAMIN + * ETACF + * ADDON + * BIAS1 + * BIAS2 + * BIAS3 + * ONEPSM + * + * 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 + * SMALL_NEF if an error failure occurs and SMALL_NEF <= nef <= MXNEF1, then + * reset eta = SUNMIN(eta, ETAMXF) + * LONG_WAIT number of steps to wait before considering an order change when + * q==1 and MXNEF1 error test failures have occurred + * + * cvNls + * + * DGMAX iter == CV_NEWTON, |gamma/gammap-1| > DGMAX => call lsetup + * MSBP max no. of steps between lsetup calls + * + */ + + +#define FUZZ_FACTOR RCONST(100.0) + +#define HLB_FACTOR RCONST(100.0) +#define HUB_FACTOR RCONST(0.1) +#define H_BIAS HALF +#define MAX_ITERS 4 + +#define CORTES RCONST(0.1) + +#define THRESH RCONST(1.5) +#define ETAMX1 RCONST(10000.0) +#define ETAMX2 RCONST(10.0) +#define ETAMX3 RCONST(10.0) +#define ETAMXF RCONST(0.2) +#define ETAMIN RCONST(0.1) +#define ETACF RCONST(0.25) +#define ADDON RCONST(0.000001) +#define BIAS1 RCONST(6.0) +#define BIAS2 RCONST(6.0) +#define BIAS3 RCONST(10.0) +#define ONEPSM RCONST(1.000001) + +#define SMALL_NST 10 +#define MXNCF 10 +#define MXNEF 7 +#define MXNEF1 3 +#define SMALL_NEF 2 +#define LONG_WAIT 10 + +#define DGMAX RCONST(0.3) +#define MSBP 20 + +/*=================================================================*/ +/* Private Helper Functions Prototypes */ +/*=================================================================*/ + +static booleantype cvCheckNvector(N_Vector tmpl); + +static int cvInitialSetup(CVodeMem cv_mem); + +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); + +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); + +static int cvStep(CVodeMem cv_mem); + +static int cvSLdet(CVodeMem cv_mem); + +static void cvAdjustParams(CVodeMem cv_mem); +static void cvAdjustOrder(CVodeMem cv_mem, int deltaq); +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[]); +static void cvAdamsFinish(CVodeMem cv_mem, realtype m[], realtype M[], realtype hsum); +static realtype cvAltSum(int iend, realtype a[], int k); +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); + +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); + +static int cvDoErrorTest(CVodeMem cv_mem, int *nflagPtr, + realtype saved_t, int *nefPtr, realtype *dsmPtr); + +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); + +static int cvHandleFailure(CVodeMem cv_mem,int flag); + +static int cvRcheck1(CVodeMem cv_mem); +static int cvRcheck2(CVodeMem cv_mem); +static int cvRcheck3(CVodeMem cv_mem); +static int cvRootfind(CVodeMem cv_mem); + +/* + * ================================================================= + * EXPORTED FUNCTIONS IMPLEMENTATION + * ================================================================= + */ + +/* + * CVodeCreate + * + * CVodeCreate creates an internal memory block for a problem to + * be solved by CVODE. + * 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) +{ + int maxord; + CVodeMem cv_mem; + + /* Test inputs */ + + if ((lmm != CV_ADAMS) && (lmm != CV_BDF)) { + cvProcessError(NULL, 0, "CVODE", "CVodeCreate", MSGCV_BAD_LMM); + return(NULL); + } + + cv_mem = NULL; + cv_mem = (CVodeMem) malloc(sizeof(struct CVodeMemRec)); + if (cv_mem == NULL) { + cvProcessError(NULL, 0, "CVODE", "CVodeCreate", MSGCV_CVMEM_FAIL); + return(NULL); + } + + /* Zero out cv_mem */ + memset(cv_mem, 0, sizeof(struct CVodeMemRec)); + + maxord = (lmm == CV_ADAMS) ? ADAMS_Q_MAX : BDF_Q_MAX; + + /* 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_constraints = NULL; + cv_mem->cv_constraintsSet = SUNFALSE; + + /* Initialize root finding variables */ + + cv_mem->cv_glo = NULL; + cv_mem->cv_ghi = NULL; + cv_mem->cv_grout = NULL; + cv_mem->cv_iroots = NULL; + cv_mem->cv_rootdir = NULL; + cv_mem->cv_gfun = NULL; + cv_mem->cv_nrtfn = 0; + cv_mem->cv_gactive = NULL; + cv_mem->cv_mxgnull = 1; + + /* Set the saved value qmax_alloc */ + + cv_mem->cv_qmax_alloc = maxord; + + /* Initialize lrw and liw */ + + cv_mem->cv_lrw = 58 + 2*L_MAX + NUM_TESTS; + cv_mem->cv_liw = 40; + + /* No mallocs have been done yet */ + + cv_mem->cv_VabstolMallocDone = SUNFALSE; + cv_mem->cv_MallocDone = SUNFALSE; + cv_mem->cv_constraintsMallocDone = SUNFALSE; + + /* Initialize nonlinear solver variables */ + cv_mem->NLS = NULL; + cv_mem->ownNLS = SUNFALSE; + + /* Return pointer to CVODE memory block */ + + return((void *)cv_mem); +} + +/*-----------------------------------------------------------------*/ + +/* + * 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 + * errfp and an error flag is returned. Otherwise, it returns CV_SUCCESS + */ + +int CVodeInit(void *cvode_mem, CVRhsFn f, realtype t0, N_Vector y0) +{ + CVodeMem cv_mem; + booleantype nvectorOK, allocOK; + sunindextype lrw1, liw1; + int i,k, retval; + SUNNonlinearSolver NLS; + + /* Check cvode_mem */ + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeInit", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Check for legal input parameters */ + + if (y0==NULL) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeInit", MSGCV_NULL_Y0); + return(CV_ILL_INPUT); + } + + if (f == NULL) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeInit", MSGCV_NULL_F); + return(CV_ILL_INPUT); + } + + /* Test if all required vector operations are implemented */ + + nvectorOK = cvCheckNvector(y0); + if(!nvectorOK) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeInit", MSGCV_BAD_NVECTOR); + return(CV_ILL_INPUT); + } + + /* Set space requirements for one N_Vector */ + + if (y0->ops->nvspace != NULL) { + N_VSpace(y0, &lrw1, &liw1); + } else { + lrw1 = 0; + liw1 = 0; + } + cv_mem->cv_lrw1 = lrw1; + cv_mem->cv_liw1 = liw1; + + /* Allocate the vectors (using y0 as a template) */ + + allocOK = cvAllocVectors(cv_mem, y0); + if (!allocOK) { + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODE", "CVodeInit", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + /* create a Newton nonlinear solver object by default */ + NLS = SUNNonlinSol_Newton(y0); + + /* check that nonlinear solver is non-NULL */ + if (NLS == NULL) { + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODE", "CVodeInit", MSGCV_MEM_FAIL); + cvFreeVectors(cv_mem); + return(CV_MEM_FAIL); + } + + /* attach the nonlinear solver to the CVODE memory */ + retval = CVodeSetNonlinearSolver(cv_mem, NLS); + + /* check that the nonlinear solver was successfully attached */ + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, retval, "CVODE", "CVodeInit", + "Setting the nonlinear solver failed"); + cvFreeVectors(cv_mem); + SUNNonlinSolFree(NLS); + return(CV_MEM_FAIL); + } + + /* set ownership flag */ + cv_mem->ownNLS = SUNTRUE; + + /* All error checking is complete at this point */ + + /* Copy the input parameters into CVODE state */ + + cv_mem->cv_f = f; + cv_mem->cv_tn = t0; + + /* Set step parameters */ + + cv_mem->cv_q = 1; + cv_mem->cv_L = 2; + 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; + + /* Set the linear solver addresses to NULL. + (We check != NULL later, in CVode, if using CV_NEWTON.) */ + + cv_mem->cv_linit = NULL; + cv_mem->cv_lsetup = NULL; + cv_mem->cv_lsolve = NULL; + cv_mem->cv_lfree = NULL; + cv_mem->cv_lmem = NULL; + + /* 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; + cv_mem->cv_nfe = 0; + cv_mem->cv_ncfn = 0; + cv_mem->cv_netf = 0; + cv_mem->cv_nni = 0; + cv_mem->cv_nsetups = 0; + cv_mem->cv_nhnil = 0; + cv_mem->cv_nstlp = 0; + cv_mem->cv_nscon = 0; + cv_mem->cv_nge = 0; + + cv_mem->cv_irfnd = 0; + + /* Initialize other integrator optional outputs */ + + cv_mem->cv_h0u = ZERO; + cv_mem->cv_next_h = ZERO; + cv_mem->cv_next_q = 0; + + /* Initialize Stablilty Limit Detection data */ + /* NOTE: We do this even if stab lim det was not + turned on yet. This way, the user can turn it + on at any time */ + + cv_mem->cv_nor = 0; + for (i = 1; i <= 5; i++) + for (k = 1; k <= 3; k++) + cv_mem->cv_ssdat[i-1][k-1] = ZERO; + + /* Problem has been successfully initialized */ + + cv_mem->cv_MallocDone = SUNTRUE; + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +/* + * CVodeReInit + * + * CVodeReInit re-initializes CVODE's memory for a problem, assuming + * it has already been allocated in a prior CVodeInit call. + * 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. + */ + +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, "CVODE", "CVodeReInit", 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, "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); + return(CV_ILL_INPUT); + } + + /* Copy the input parameters into CVODE state */ + + cv_mem->cv_tn = t0; + + /* Set step parameters */ + + cv_mem->cv_q = 1; + cv_mem->cv_L = 2; + 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; + + /* 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; + cv_mem->cv_nfe = 0; + cv_mem->cv_ncfn = 0; + cv_mem->cv_netf = 0; + cv_mem->cv_nni = 0; + cv_mem->cv_nsetups = 0; + cv_mem->cv_nhnil = 0; + cv_mem->cv_nstlp = 0; + cv_mem->cv_nscon = 0; + cv_mem->cv_nge = 0; + + cv_mem->cv_irfnd = 0; + + /* Initialize other integrator optional outputs */ + + cv_mem->cv_h0u = ZERO; + cv_mem->cv_next_h = ZERO; + cv_mem->cv_next_q = 0; + + /* Initialize Stablilty Limit Detection data */ + + cv_mem->cv_nor = 0; + for (i = 1; i <= 5; i++) + for (k = 1; k <= 3; k++) + cv_mem->cv_ssdat[i-1][k-1] = ZERO; + + /* Problem has been successfully re-initialized */ + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +/* + * CVodeSStolerances + * CVodeSVtolerances + * CVodeWFtolerances + * + * These functions specify the integration tolerances. One of them + * MUST be called before the first call to CVode. + * + * CVodeSStolerances specifies scalar relative and absolute tolerances. + * CVodeSVtolerances specifies scalar relative tolerance and a vector + * 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. + */ + +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); + 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); + return(CV_NO_MALLOC); + } + + /* Check inputs */ + + if (reltol < ZERO) { + 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); + return(CV_ILL_INPUT); + } + + /* Copy tolerances into memory */ + + cv_mem->cv_reltol = reltol; + cv_mem->cv_Sabstol = abstol; + + cv_mem->cv_itol = CV_SS; + + cv_mem->cv_user_efun = SUNFALSE; + cv_mem->cv_efun = cvEwtSet; + cv_mem->cv_e_data = NULL; /* will be set to cvode_mem in InitialSetup */ + + return(CV_SUCCESS); +} + + +int CVodeSVtolerances(void *cvode_mem, realtype reltol, N_Vector abstol) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + 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); + return(CV_NO_MALLOC); + } + + /* Check inputs */ + + if (reltol < ZERO) { + 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); + 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; + cv_mem->cv_liw += cv_mem->cv_liw1; + cv_mem->cv_VabstolMallocDone = SUNTRUE; + } + + cv_mem->cv_reltol = reltol; + N_VScale(ONE, abstol, cv_mem->cv_Vabstol); + + cv_mem->cv_itol = CV_SV; + + cv_mem->cv_user_efun = SUNFALSE; + cv_mem->cv_efun = cvEwtSet; + cv_mem->cv_e_data = NULL; /* will be set to cvode_mem in InitialSetup */ + + return(CV_SUCCESS); +} + + +int CVodeWFtolerances(void *cvode_mem, CVEwtFn efun) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + 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); + return(CV_NO_MALLOC); + } + + cv_mem->cv_itol = CV_WF; + + cv_mem->cv_user_efun = SUNTRUE; + cv_mem->cv_efun = efun; + cv_mem->cv_e_data = NULL; /* will be set to user_data in InitialSetup */ + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +/* + * CVodeRootInit + * + * CVodeRootInit initializes a rootfinding problem to be solved + * during the integration of the ODE system. It loads the root + * function pointer and the number of root functions, and allocates + * workspace memory. The return value is CV_SUCCESS = 0 if no errors + * occurred, or a negative value otherwise. + */ + +int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g) +{ + CVodeMem cv_mem; + int i, nrt; + + /* Check cvode_mem pointer */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeRootInit", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + nrt = (nrtfn < 0) ? 0 : nrtfn; + + /* If rerunning CVodeRootInit() with a different number of root + functions (changing number of gfun components), then free + currently held memory resources */ + if ((nrt != cv_mem->cv_nrtfn) && (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_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; + + 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 + zero and cv_gfun to NULL before returning */ + if (nrt == 0) { + cv_mem->cv_nrtfn = nrt; + cv_mem->cv_gfun = NULL; + return(CV_SUCCESS); + } + + /* If rerunning CVodeRootInit() with the same number of root functions + (not changing number of gfun components), then check if the root + function argument has changed */ + /* If g != NULL then return as currently reserved memory resources + will suffice */ + 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_rootdir); cv_mem->cv_rootdir = NULL; + free(cv_mem->cv_gactive); cv_mem->cv_gactive = NULL; + + cv_mem->cv_lrw -= 3*nrt; + cv_mem->cv_liw -= 3*nrt; + + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeRootInit", MSGCV_NULL_G); + return(CV_ILL_INPUT); + } + else { + cv_mem->cv_gfun = g; + return(CV_SUCCESS); + } + } + else return(CV_SUCCESS); + } + + /* 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); + return(CV_ILL_INPUT); + } + else cv_mem->cv_gfun = g; + + /* Allocate necessary memory and return */ + 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); + return(CV_MEM_FAIL); + } + + cv_mem->cv_ghi = NULL; + 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); + return(CV_MEM_FAIL); + } + + cv_mem->cv_grout = NULL; + cv_mem->cv_grout = (realtype *) malloc(nrt*sizeof(realtype)); + 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); + return(CV_MEM_FAIL); + } + + cv_mem->cv_iroots = NULL; + cv_mem->cv_iroots = (int *) malloc(nrt*sizeof(int)); + if (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; + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODE", "CVodeRootInit", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + 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_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); + 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_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; + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeRootInit", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + /* Set default values for rootdir (both directions) */ + for(i=0; i<nrt; i++) cv_mem->cv_rootdir[i] = 0; + + /* Set default values for gactive (all active) */ + for(i=0; i<nrt; i++) cv_mem->cv_gactive[i] = SUNTRUE; + + cv_mem->cv_lrw += 3*nrt; + cv_mem->cv_liw += 3*nrt; + + return(CV_SUCCESS); +} + + +/*-----------------------------------------------------------------*/ + +/* + * CVode + * + * This routine is the main driver of the CVODE package. + * + * It integrates over a time interval defined by the user, by calling + * cvStep to do internal time steps. + * + * The first time that CVode is called for a successfully initialized + * problem, it computes a tentative initial step size h. + * + * CVode supports two modes, specified by itask: CV_NORMAL, CV_ONE_STEP. + * In the CV_NORMAL mode, the solver steps until it reaches or passes tout + * and then interpolates to obtain y(tout). + * In the CV_ONE_STEP mode, it takes one internal step and returns. + */ + +int CVode(void *cvode_mem, realtype tout, N_Vector yout, + realtype *tret, int itask) +{ + CVodeMem cv_mem; + long int nstloc; + int retval, hflag, kflag, istate, ir, ier, irfndp; + int ewtsetOK; + realtype troundoff, tout_hin, rh, nrm; + booleantype inactive_roots; + + /* + * ------------------------------------- + * 1. Check and process inputs + * ------------------------------------- + */ + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "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, "CVODE", "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, "CVODE", "CVode", MSGCV_YOUT_NULL); + return(CV_ILL_INPUT); + } + + /* Check for tret != NULL */ + if (tret == NULL) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "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, "CVODE", "CVode", MSGCV_BAD_ITASK); + return(CV_ILL_INPUT); + } + + if (itask == CV_NORMAL) cv_mem->cv_toutc = tout; + cv_mem->cv_taskc = itask; + + /* + * ---------------------------------------- + * 2. Initializations performed only at + * the first step (nst=0): + * - initial setup + * - initialize Nordsieck history array + * - compute initial step size + * - check for approach to tstop + * - check for approach to a root + * ---------------------------------------- + */ + + if (cv_mem->cv_nst == 0) { + + cv_mem->cv_tretlast = *tret = cv_mem->cv_tn; + + 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. */ + + 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_nfe++; + if (retval < 0) { + cvProcessError(cv_mem, CV_RHSFUNC_FAIL, "CVODE", "CVode", + MSGCV_RHSFUNC_FAILED, cv_mem->cv_tn); + return(CV_RHSFUNC_FAIL); + } + if (retval > 0) { + cvProcessError(cv_mem, CV_FIRST_RHSFUNC_ERR, "CVODE", "CVode", + MSGCV_RHSFUNC_FIRST); + return(CV_FIRST_RHSFUNC_ERR); + } + + /* Test input tstop for legality. */ + + if (cv_mem->cv_tstopset) { + if ( (cv_mem->cv_tstop - cv_mem->cv_tn)*(tout - cv_mem->cv_tn) <= ZERO ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVode", + MSGCV_BAD_TSTOP, cv_mem->cv_tstop, cv_mem->cv_tn); + return(CV_ILL_INPUT); + } + } + + /* 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, "CVODE", "CVode", MSGCV_BAD_H0); + return(CV_ILL_INPUT); + } + 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 ) + tout_hin = cv_mem->cv_tstop; + hflag = cvHin(cv_mem, tout_hin); + if (hflag != CV_SUCCESS) { + istate = cvHandleFailure(cv_mem, hflag); + return(istate); + } + } + rh = SUNRabs(cv_mem->cv_h)*cv_mem->cv_hmax_inv; + if (rh > ONE) cv_mem->cv_h /= rh; + if (SUNRabs(cv_mem->cv_h) < cv_mem->cv_hmin) + cv_mem->cv_h *= cv_mem->cv_hmin/SUNRabs(cv_mem->cv_h); + + /* 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 ) + cv_mem->cv_h = (cv_mem->cv_tstop - cv_mem->cv_tn)*(ONE-FOUR*cv_mem->cv_uround); + } + + /* Scale zn[1] by h.*/ + + cv_mem->cv_hscale = cv_mem->cv_h; + cv_mem->cv_h0u = cv_mem->cv_h; + cv_mem->cv_hprime = cv_mem->cv_h; + + N_VScale(cv_mem->cv_h, cv_mem->cv_zn[1], cv_mem->cv_zn[1]); + + /* Check for zeros of root function g at and near t0. */ + + if (cv_mem->cv_nrtfn > 0) { + + retval = cvRcheck1(cv_mem); + + if (retval == CV_RTFUNC_FAIL) { + cvProcessError(cv_mem, CV_RTFUNC_FAIL, "CVODE", "cvRcheck1", + MSGCV_RTFUNC_FAILED, cv_mem->cv_tn); + return(CV_RTFUNC_FAIL); + } + + } + + } /* end of first call block */ + + /* + * ------------------------------------------------------ + * 3. At following steps, perform stop tests: + * - check for root in last step + * - check if we passed tstop + * - check if we passed tout (NORMAL mode) + * - check if current tn was returned (ONE_STEP mode) + * - check if we are close to tstop + * (adjust step size if needed) + * ------------------------------------------------------- + */ + + if (cv_mem->cv_nst > 0) { + + /* 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)); + + /* 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) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "cvRcheck2", + MSGCV_CLOSE_ROOTS, cv_mem->cv_tlo); + return(CV_ILL_INPUT); + } else if (retval == CV_RTFUNC_FAIL) { + cvProcessError(cv_mem, CV_RTFUNC_FAIL, "CVODE", "cvRcheck2", + MSGCV_RTFUNC_FAILED, cv_mem->cv_tlo); + return(CV_RTFUNC_FAIL); + } else if (retval == RTFOUND) { + 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 ) { + + retval = cvRcheck3(cv_mem); + + if (retval == CV_SUCCESS) { /* no root found */ + cv_mem->cv_irfnd = 0; + if ((irfndp == 1) && (itask == CV_ONE_STEP)) { + cv_mem->cv_tretlast = *tret = cv_mem->cv_tn; + N_VScale(ONE, cv_mem->cv_zn[0], yout); + return(CV_SUCCESS); + } + } else if (retval == RTFOUND) { /* a new root was found */ + cv_mem->cv_irfnd = 1; + 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, "CVODE", "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; + ier = CVodeGetDky(cv_mem, tout, 0, yout); + if (ier != CV_SUCCESS) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVode", + MSGCV_BAD_TOUT, tout); + return(CV_ILL_INPUT); + } + 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 ) { + cv_mem->cv_tretlast = *tret = cv_mem->cv_tn; + 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) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVode", + MSGCV_BAD_TSTOP, cv_mem->cv_tstop, cv_mem->cv_tn); + return(CV_ILL_INPUT); + } + cv_mem->cv_tretlast = *tret = cv_mem->cv_tstop; + 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 */ + + /* + * -------------------------------------------------- + * 4. Looping point for internal steps + * + * 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.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 */ + if (cv_mem->cv_nst > 0) { + + ewtsetOK = cv_mem->cv_efun(cv_mem->cv_zn[0], cv_mem->cv_ewt, cv_mem->cv_e_data); + + if (ewtsetOK != 0) { + + if (cv_mem->cv_itol == CV_WF) + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVode", + MSGCV_EWT_NOW_FAIL, cv_mem->cv_tn); + else + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "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); + break; + + } + } + + /* Check for too many steps */ + if ( (cv_mem->cv_mxstep>0) && (nstloc >= cv_mem->cv_mxstep) ) { + cvProcessError(cv_mem, CV_TOO_MUCH_WORK, "CVODE", "CVode", + MSGCV_MAX_STEPS, cv_mem->cv_tn); + istate = CV_TOO_MUCH_WORK; + cv_mem->cv_tretlast = *tret = cv_mem->cv_tn; + N_VScale(ONE, cv_mem->cv_zn[0], yout); + break; + } + + /* Check for too much accuracy requested */ + nrm = N_VWrmsNorm(cv_mem->cv_zn[0], cv_mem->cv_ewt); + cv_mem->cv_tolsf = cv_mem->cv_uround * nrm; + if (cv_mem->cv_tolsf > ONE) { + cvProcessError(cv_mem, CV_TOO_MUCH_ACC, "CVODE", "CVode", + MSGCV_TOO_MUCH_ACC, cv_mem->cv_tn); + istate = CV_TOO_MUCH_ACC; + cv_mem->cv_tretlast = *tret = cv_mem->cv_tn; + N_VScale(ONE, cv_mem->cv_zn[0], yout); + cv_mem->cv_tolsf *= TWO; + break; + } 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) + 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); + } + + /* Call cvStep to take a step */ + kflag = cvStep(cv_mem); + + /* Process failed step cases, and exit loop */ + if (kflag != CV_SUCCESS) { + istate = cvHandleFailure(cv_mem, kflag); + cv_mem->cv_tretlast = *tret = cv_mem->cv_tn; + N_VScale(ONE, cv_mem->cv_zn[0], yout); + break; + } + + nstloc++; + + /* 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; + cv_mem->cv_tretlast = *tret = cv_mem->cv_tlo; + break; + } else if (retval == CV_RTFUNC_FAIL) { /* g failed */ + cvProcessError(cv_mem, CV_RTFUNC_FAIL, "CVODE", "cvRcheck3", + MSGCV_RTFUNC_FAILED, cv_mem->cv_tlo); + istate = CV_RTFUNC_FAIL; + break; + } + + /* If we are at the end of the first step and we still have + * some event functions that are inactive, issue a warning + * as this may indicate a user error in the implementation + * of the root function. */ + + if (cv_mem->cv_nst==1) { + inactive_roots = SUNFALSE; + for (ir=0; ir<cv_mem->cv_nrtfn; ir++) { + if (!cv_mem->cv_gactive[ir]) { + inactive_roots = SUNTRUE; + break; + } + } + if ((cv_mem->cv_mxgnull > 0) && inactive_roots) { + cvProcessError(cv_mem, CV_WARNING, "CVODES", "CVode", + MSGCV_INACTIVE_ROOTS); + } + } + + } + + /* In NORMAL mode, check if tout reached */ + if ( (itask == CV_NORMAL) && (cv_mem->cv_tn-tout)*cv_mem->cv_h >= ZERO ) { + istate = CV_SUCCESS; + cv_mem->cv_tretlast = *tret = tout; + (void) CVodeGetDky(cv_mem, tout, 0, yout); + cv_mem->cv_next_q = cv_mem->cv_qprime; + cv_mem->cv_next_h = cv_mem->cv_hprime; + break; + } + + /* 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)); + 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; + cv_mem->cv_tstopset = SUNFALSE; + istate = CV_TSTOP_RETURN; + break; + } + + 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; + } + + } + + /* In ONE_STEP mode, copy y and exit loop */ + if (itask == CV_ONE_STEP) { + istate = CV_SUCCESS; + cv_mem->cv_tretlast = *tret = cv_mem->cv_tn; + N_VScale(ONE, cv_mem->cv_zn[0], yout); + cv_mem->cv_next_q = cv_mem->cv_qprime; + cv_mem->cv_next_h = cv_mem->cv_hprime; + break; + } + + } /* end looping for internal steps */ + + return(istate); +} + +/*-----------------------------------------------------------------*/ + +/* + * CVodeGetDky + * + * 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 + * 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. + * + * This function is called by CVode with k = 0 and t = tout, but + * may also be called directly by the user. + */ + +int CVodeGetDky(void *cvode_mem, realtype t, int k, N_Vector dky) +{ + 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, "CVODE", "CVodeGetDky", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + if (dky == NULL) { + cvProcessError(cv_mem, CV_BAD_DKY, "CVODE", "CVodeGetDky", MSGCV_NULL_DKY); + return(CV_BAD_DKY); + } + + if ((k < 0) || (k > cv_mem->cv_q)) { + cvProcessError(cv_mem, CV_BAD_K, "CVODE", "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)); + if (cv_mem->cv_hu < ZERO) tfuzz = -tfuzz; + tp = cv_mem->cv_tn - cv_mem->cv_hu - tfuzz; + tn1 = cv_mem->cv_tn + tfuzz; + if ((t-tp)*(t-tn1) > ZERO) { + cvProcessError(cv_mem, CV_BAD_T, "CVODE", "CVodeGetDky", MSGCV_BAD_T, + t, cv_mem->cv_tn-cv_mem->cv_hu, cv_mem->cv_tn); + 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; + for (i=j; i >= j-k+1; i--) + cv_mem->cv_cvals[nvec] *= i; + for (i=0; i < j-k; i++) + cv_mem->cv_cvals[nvec] *= s; + cv_mem->cv_Xvecs[nvec] = cv_mem->cv_zn[j]; + nvec += 1; + } + ier = N_VLinearCombination(nvec, cv_mem->cv_cvals, cv_mem->cv_Xvecs, dky); + if (ier != CV_SUCCESS) return (CV_VECTOROP_ERR); + + if (k == 0) return(CV_SUCCESS); + r = SUNRpowerI(cv_mem->cv_h,-k); + N_VScale(r, dky, dky); + return(CV_SUCCESS); +} + +/* + * CVodeFree + * + * 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). + */ + +void CVodeFree(void **cvode_mem) +{ + CVodeMem cv_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; + cv_mem->NLS = NULL; + } + + 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_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; + } + + free(*cvode_mem); + *cvode_mem = NULL; +} + +/* + * ================================================================= + * Private Functions Implementation + * ================================================================= + */ + +/* + * cvCheckNvector + * This routine checks if all required vector operations are present. + * If any of them is missing it returns SUNFALSE. + */ + +static booleantype cvCheckNvector(N_Vector tmpl) +{ + if((tmpl->ops->nvclone == NULL) || + (tmpl->ops->nvdestroy == NULL) || + (tmpl->ops->nvlinearsum == NULL) || + (tmpl->ops->nvconst == NULL) || + (tmpl->ops->nvprod == NULL) || + (tmpl->ops->nvdiv == NULL) || + (tmpl->ops->nvscale == NULL) || + (tmpl->ops->nvabs == NULL) || + (tmpl->ops->nvinv == NULL) || + (tmpl->ops->nvaddconst == NULL) || + (tmpl->ops->nvmaxnorm == NULL) || + (tmpl->ops->nvwrmsnorm == NULL) || + (tmpl->ops->nvmin == NULL)) + return(SUNFALSE); + else + return(SUNTRUE); +} + +/* + * cvAllocVectors + * + * This routine allocates the CVODE vectors ewt, acor, tempv, ftemp, and + * zn[0], ..., zn[maxord]. + * 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 + * allocated here. + */ + +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); + + cv_mem->cv_acor = N_VClone(tmpl); + if (cv_mem->cv_acor == NULL) { + N_VDestroy(cv_mem->cv_ewt); + return(SUNFALSE); + } + + cv_mem->cv_tempv = N_VClone(tmpl); + if (cv_mem->cv_tempv == NULL) { + N_VDestroy(cv_mem->cv_ewt); + N_VDestroy(cv_mem->cv_acor); + return(SUNFALSE); + } + + cv_mem->cv_ftemp = N_VClone(tmpl); + if (cv_mem->cv_ftemp == NULL) { + N_VDestroy(cv_mem->cv_tempv); + N_VDestroy(cv_mem->cv_ewt); + N_VDestroy(cv_mem->cv_acor); + return(SUNFALSE); + } + + cv_mem->cv_vtemp1 = N_VClone(tmpl); + if (cv_mem->cv_vtemp1 == NULL) { + N_VDestroy(cv_mem->cv_ftemp); + N_VDestroy(cv_mem->cv_tempv); + N_VDestroy(cv_mem->cv_ewt); + N_VDestroy(cv_mem->cv_acor); + return(SUNFALSE); + } + + cv_mem->cv_vtemp2 = N_VClone(tmpl); + if (cv_mem->cv_vtemp2 == NULL) { + N_VDestroy(cv_mem->cv_vtemp1); + N_VDestroy(cv_mem->cv_ftemp); + N_VDestroy(cv_mem->cv_tempv); + N_VDestroy(cv_mem->cv_ewt); + N_VDestroy(cv_mem->cv_acor); + return(SUNFALSE); + } + + cv_mem->cv_vtemp3 = N_VClone(tmpl); + if (cv_mem->cv_vtemp3 == NULL) { + N_VDestroy(cv_mem->cv_vtemp2); + N_VDestroy(cv_mem->cv_vtemp1); + N_VDestroy(cv_mem->cv_ftemp); + N_VDestroy(cv_mem->cv_tempv); + N_VDestroy(cv_mem->cv_ewt); + N_VDestroy(cv_mem->cv_acor); + return(SUNFALSE); + } + + /* Allocate zn[0] ... zn[qmax] */ + + for (j=0; j <= cv_mem->cv_qmax; j++) { + cv_mem->cv_zn[j] = N_VClone(tmpl); + if (cv_mem->cv_zn[j] == NULL) { + N_VDestroy(cv_mem->cv_ewt); + N_VDestroy(cv_mem->cv_acor); + N_VDestroy(cv_mem->cv_tempv); + N_VDestroy(cv_mem->cv_ftemp); + N_VDestroy(cv_mem->cv_vtemp1); + N_VDestroy(cv_mem->cv_vtemp2); + N_VDestroy(cv_mem->cv_vtemp3); + for (i=0; i < j; i++) N_VDestroy(cv_mem->cv_zn[i]); + return(SUNFALSE); + } + } + + /* Update solver workspace lengths */ + cv_mem->cv_lrw += (cv_mem->cv_qmax + 8)*cv_mem->cv_lrw1; + cv_mem->cv_liw += (cv_mem->cv_qmax + 8)*cv_mem->cv_liw1; + + /* Store the value of qmax used here */ + cv_mem->cv_qmax_alloc = cv_mem->cv_qmax; + + return(SUNTRUE); +} + +/* + * cvFreeVectors + * + * This routine frees the CVODE 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); + N_VDestroy(cv_mem->cv_acor); + N_VDestroy(cv_mem->cv_tempv); + N_VDestroy(cv_mem->cv_ftemp); + N_VDestroy(cv_mem->cv_vtemp1); + N_VDestroy(cv_mem->cv_vtemp2); + N_VDestroy(cv_mem->cv_vtemp3); + for (j=0; j <= maxord; j++) N_VDestroy(cv_mem->cv_zn[j]); + + cv_mem->cv_lrw -= (maxord + 8)*cv_mem->cv_lrw1; + cv_mem->cv_liw -= (maxord + 8)*cv_mem->cv_liw1; + + if (cv_mem->cv_VabstolMallocDone) { + N_VDestroy(cv_mem->cv_Vabstol); + cv_mem->cv_lrw -= cv_mem->cv_lrw1; + cv_mem->cv_liw -= cv_mem->cv_liw1; + } + + if (cv_mem->cv_constraintsMallocDone) { + N_VDestroy(cv_mem->cv_constraints); + cv_mem->cv_lrw -= cv_mem->cv_lrw1; + cv_mem->cv_liw -= cv_mem->cv_liw1; + } +} + +/* + * 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, "CVODE", "cvInitialSetup", MSGCV_NO_TOLS); + 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) { + 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); + 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, "CVODE", "cvInitialSetup", MSGCV_EWT_FAIL); + else + 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) */ + 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); + return(CV_LINIT_FAIL); + } + } + + /* Initialize the nonlinear solver (must occur after linear solver is initialize) 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); + return(CV_NLS_INIT_FAIL); + } + + return(CV_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * PRIVATE FUNCTIONS FOR CVODE + * ----------------------------------------------------------------- + */ + +/* + * cvHin + * + * 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 + * enabled and it is closer to t0=tn than tout). + * If the RHS function fails unrecoverably, cvHin returns CV_RHSFUNC_FAIL. + * If the RHS function fails recoverably too many times and recovery is + * not possible, cvHin returns CV_REPTD_RHSFUNC_ERR. + * 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, + * where ydd = estimated second derivative of y. + * + * We start with an initial estimate equal to the geometric mean of the + * lower and upper bounds on the step size. + * + * 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. + * + * 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 + * still cannot be found, fall back on a previous value if possible, + * or else return CV_REPTD_RHSFUNC_ERR. + * + * Finally, we apply a bias (0.5) and verify that h0 is within bounds. + */ + +static int cvHin(CVodeMem cv_mem, realtype tout) +{ + int retval, sign, count1, count2; + realtype tdiff, tdist, tround, hlb, hub; + realtype hg, hgs, hs, hnew, hrat, h0, yddnrm; + 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 + as first trial value. + Exit with this value if the bounds cross each other. + */ + + hlb = HLB_FACTOR * tround; + hub = cvUpperBoundH0(cv_mem, tdist); + + hg = SUNRsqrt(hlb*hub); + + if (hub < hlb) { + if (sign == -1) cv_mem->cv_h = -hg; + else cv_mem->cv_h = hg; + return(CV_SUCCESS); + } + + /* Outer loop */ + + hs = hg; /* safeguard against 'uninitialized variable' warning */ + + for(count1 = 1; count1 <= MAX_ITERS; count1++) { + + /* Attempts to estimate ydd */ + + hgOK = SUNFALSE; + + for (count2 = 1; count2 <= MAX_ITERS; count2++) { + hgs = hg*sign; + retval = cvYddNorm(cv_mem, hgs, &yddnrm); + /* If f() 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 */ + hg *= POINT2; + } + + /* If f() failed recoverably MAX_ITERS times */ + + if (!hgOK) { + /* Exit if this is the first or second pass. No recovery possible */ + if (count1 <= 2) return(CV_REPTD_RHSFUNC_ERR); + /* We have a fall-back option. The value hs is a previous hnew which + passed through f(). Use it and break */ + hnew = hs; + break; + } + + /* The proposed step size is feasible. Save it. */ + hs = hg; + + /* 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; + + /* After one pass, if ydd seems to be bad, use fall-back value. */ + if ((count1 > 1) && (hrat > TWO)) { + hnew = hg; + break; + } + + /* Send this value back through f() */ + hg = hnew; + + } + + /* Apply bounds, bias factor, and attach sign */ + + h0 = H_BIAS*hnew; + if (h0 < hlb) h0 = hlb; + if (h0 > hub) h0 = hub; + if (sign == -1) h0 = -h0; + cv_mem->cv_h = h0; + + return(CV_SUCCESS); +} + +/* + * cvUpperBoundH0 + * + * This routine sets an upper bound on abs(h0) based on + * tdist = tn - t0 and the values of y[i]/y'[i]. + */ + +static realtype cvUpperBoundH0(CVodeMem cv_mem, realtype tdist) +{ + realtype hub_inv, hub; + N_Vector temp1, temp2; + + /* + * Bound based on |y0|/|y0'| -- 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. + */ + + temp1 = cv_mem->cv_tempv; + temp2 = cv_mem->cv_acor; + + N_VAbs(cv_mem->cv_zn[0], temp2); + cv_mem->cv_efun(cv_mem->cv_zn[0], temp1, cv_mem->cv_e_data); + N_VInv(temp1, temp1); + N_VLinearSum(HUB_FACTOR, temp2, ONE, temp1, temp1); + + N_VAbs(cv_mem->cv_zn[1], temp2); + + N_VDiv(temp2, temp1, temp1); + hub_inv = N_VMaxNorm(temp1); + + /* + * bound based on tdist -- allow at most a step of magnitude + * HUB_FACTOR * tdist + */ + + hub = HUB_FACTOR*tdist; + + /* Use the smaller of the two */ + + if (hub*hub_inv > ONE) hub = ONE/hub_inv; + + return(hub); +} + +/* + * cvYddNorm + * + * This routine computes an estimate of the second derivative of y + * using a difference quotient, and returns its WRMS norm. + */ + +static int cvYddNorm(CVodeMem cv_mem, realtype hg, realtype *yddnrm) +{ + int retval; + + N_VLinearSum(hg, cv_mem->cv_zn[1], ONE, cv_mem->cv_zn[0], cv_mem->cv_y); + retval = cv_mem->cv_f(cv_mem->cv_tn+hg, cv_mem->cv_y, + cv_mem->cv_tempv, cv_mem->cv_user_data); + cv_mem->cv_nfe++; + if (retval < 0) return(CV_RHSFUNC_FAIL); + if (retval > 0) return(RHSFUNC_RECVR); + + 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); + + return(CV_SUCCESS); +} + +/* + * cvStep + * + * 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 cvStep(CVodeMem cv_mem) +{ + realtype saved_t, dsm; + int ncf, nef; + int nflag, kflag, eflag; + + saved_t = cv_mem->cv_tn; + ncf = nef = 0; + nflag = FIRST_CALL; + + if ((cv_mem->cv_nst > 0) && (cv_mem->cv_hprime != cv_mem->cv_h)) + cvAdjustParams(cv_mem); + + /* Looping point for attempts to take a step */ + for(;;) { + + cvPredict(cv_mem); + cvSet(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)*/ + if (kflag == PREDICT_AGAIN) continue; + + /* Return if nonlinear solve failed and recovery not possible. */ + if (kflag != DO_ERROR_TEST) return(kflag); + + /* Perform error test (nflag=CV_SUCCESS) */ + 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; + + /* Return if error test failed and recovery not possible. */ + if (eflag != CV_SUCCESS) return(eflag); + + /* Error test passed (eflag=CV_SUCCESS), break from loop */ + break; + + } + + /* 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); + return(CV_SUCCESS); + +} + +/* + * 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 void cvAdjustParams(CVodeMem cv_mem) +{ + 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); +} + +/* + * 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 void cvAdjustOrder(CVodeMem cv_mem, int deltaq) +{ + 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; + } +} + +/* + * cvAdjustAdams + * + * This routine adjusts the history array on a change of order q by + * deltaq, in the case that lmm == CV_ADAMS. + */ + +static void cvAdjustAdams(CVodeMem cv_mem, int deltaq) +{ + int i, j; + realtype xi, hsum; + + /* 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]); + 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)); + + for (j=2; j < cv_mem->cv_q; j++) + cv_mem->cv_cvals[j-2] = -cv_mem->cv_l[j]; + + if (cv_mem->cv_q > 2) + (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); +} + +/* + * 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 void cvAdjustBDF(CVodeMem cv_mem, int deltaq) +{ + switch(deltaq) { + case 1: + cvIncreaseBDF(cv_mem); + return; + case -1: + cvDecreaseBDF(cv_mem); + return; + } +} + +/* + * 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 void cvIncreaseBDF(CVodeMem cv_mem) +{ + realtype alpha0, alpha1, prod, xi, xiold, hsum, A1; + int i, j; + + 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; + 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); +} + +/* + * cvDecreaseBDF + * + * 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 void cvDecreaseBDF(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]; + } + + for (j=2; j < cv_mem->cv_q; j++) + cv_mem->cv_cvals[j-2] = -cv_mem->cv_l[j]; + + if (cv_mem->cv_q > 2) + (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); +} + +/* + * 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. + */ + +static void cvRescale(CVodeMem cv_mem) +{ + int j; + + 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); + + 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; +} + +/* + * 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. + */ + +static void cvPredict(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]); +} + +/* + * 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 */ +} + +/* + * 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. + */ + +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); +} + +/* + * 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]; + } + 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. + */ + +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]; + + 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; + } + + cv_mem->cv_tq[4] = cv_mem->cv_nlscoef / cv_mem->cv_tq[2]; +} + +/* + * 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). + */ + +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); +} + +/* + * cvSetBDF + * + * 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 cvSetBDF(CVodeMem cv_mem) +{ + 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); +} + +/* + * cvSetTqBDF + * + * This routine sets the test quantity array tq in the case + * lmm == CV_BDF. + */ + +static void cvSetTqBDF(CVodeMem cv_mem, realtype hsum, realtype alpha0, + realtype alpha0_hat, realtype xi_inv, realtype xistar_inv) +{ + 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)); + } + cv_mem->cv_tq[4] = cv_mem->cv_nlscoef / cv_mem->cv_tq[2]; +} + +/* + * cvNls + * + * 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; + + /* 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); + } else { + cv_mem->cv_crate = ONE; + callSetup = SUNFALSE; + } + + /* initial guess for the correction to the predictor */ + N_VConst(ZERO, cv_mem->cv_tempv); + + /* call nonlinear solver setup if it exists */ + if ((cv_mem->NLS)->ops->setup) { + flag = SUNNonlinSolSetup(cv_mem->NLS, cv_mem->cv_tempv, 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, + 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); + + /* 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 (cv_mem->cv_constraintsSet) + flag = cvCheckConstraints(cv_mem); + + return(flag); +} + +/* + * 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 + */ + +static int cvCheckConstraints(CVodeMem cv_mem) +{ + booleantype constraintsPassed; + realtype vnorm; + cv_mem->cv_mm = cv_mem->cv_ftemp; + + /* Get mask vector mm, set where constraints failed */ + + 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); +} + + + +/* + * 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. + * + * 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 + * PREDICT_AGAIN, telling cvStep to reattempt the step. + * + */ + +static int cvHandleNFlag(CVodeMem cv_mem, int *nflagPtr, realtype saved_t, + int *ncfPtr) +{ + int nflag; + + nflag = *nflagPtr; + + if (nflag == CV_SUCCESS) return(DO_ERROR_TEST); + + /* The nonlinear soln. failed; increment ncfn and restore zn */ + cv_mem->cv_ncfn++; + cvRestore(cv_mem, saved_t); + + /* Return if failed unrecoverably */ + if (nflag < 0) return(nflag); + + /* At this point, nflag = SUN_NLS_CONV_RECVR or RHSFUNC_RECVR; increment ncf */ + + (*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 ((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); + } + + /* 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); +} + +/* + * cvRestore + * + * 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 cvRestore(CVodeMem cv_mem, realtype saved_t) +{ + 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]); +} + +/* + * cvDoErrorTest + * + * This routine performs the local error test. + * 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. If f() fails we return either CV_RHSFUNC_FAIL + * or CV_UNREC_RHSFUNC_ERR (no recovery is possible at this stage). + * + * - otherwise, set *nflagPtr to PREV_ERR_FAIL, and return TRY_AGAIN. + * + */ + +static booleantype cvDoErrorTest(CVodeMem cv_mem, int *nflagPtr, + realtype saved_t, int *nefPtr, realtype *dsmPtr) +{ + realtype dsm; + int retval; + + dsm = cv_mem->cv_acnrm * cv_mem->cv_tq[2]; + + /* 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)++; + cv_mem->cv_netf++; + *nflagPtr = PREV_ERR_FAIL; + cvRestore(cv_mem, saved_t); + + /* 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); + + /* Set etamax = 1 to prevent step size increase at end of this step */ + cv_mem->cv_etamax = ONE; + + /* 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 already at order 1, restart: reload zn 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; + + 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]); + + return(TRY_AGAIN); +} + +/* + * ----------------------------------------------------------------- + * Functions called after succesful step + * ----------------------------------------------------------------- + */ + +/* + * cvCompleteStep + * + * 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 cv_mem->cv_tq[5] for a possible order increase. + */ + +static void cvCompleteStep(CVodeMem cv_mem) +{ + int i; + + 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); + 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]); + 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) * 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) * 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; + + 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]); + + } + } +} + +/* + * cvHandleFailure + * + * 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 int cvHandleFailure(CVodeMem cv_mem, int flag) +{ + + /* 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) { + case CV_ERR_FAILURE: + 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); + break; + case CV_LSETUP_FAIL: + 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); + break; + case CV_RHSFUNC_FAIL: + 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); + break; + case CV_REPTD_RHSFUNC_ERR: + 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); + break; + case CV_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); + break; + case SUN_NLS_MEM_NULL: + 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); + break; + case CV_CONSTR_FAIL: + cvProcessError(cv_mem, CV_CONSTR_FAIL, "CVODE", "CVode", MSGCV_FAILED_CONSTR, + cv_mem->cv_tn); + break; + default: + return(CV_SUCCESS); + } + + return(flag); +} + +/* + * ----------------------------------------------------------------- + * Functions for BDF Stability Limit Detection + * ----------------------------------------------------------------- + */ + +/* + * cvBDFStab + * + * This routine handles the BDF Stability Limit Detection Algorithm + * STALD. It is called if lmm = CV_BDF and the SLDET option is on. + * If the order is 3 or more, the required norm data is saved. + * If a decision to reduce order has not already been made, and + * enough data has been saved, cvSLdet is called. If it signals + * a stability limit violation, the order is reduced, and the step + * size is reset accordingly. + */ + +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. */ + + if (cv_mem->cv_q >= 3) { + for (k = 1; k <= 3; k++) + for (i = 5; i >= 2; i--) + cv_mem->cv_ssdat[i][k] = cv_mem->cv_ssdat[i-1][k]; + factorial = 1; + for (i = 1; i <= cv_mem->cv_q-1; i++) factorial *= i; + sq = factorial * cv_mem->cv_q * (cv_mem->cv_q+1) * + 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); + 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, + nscon >= q+5, then call stability limit detection routine. */ + + if ( (cv_mem->cv_q >= 3) && (cv_mem->cv_nscon >= cv_mem->cv_q+5) ) { + ldflag = cvSLdet(cv_mem); + if (ldflag > 3) { + /* A stability limit violation is indicated by + 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 = 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_nor = cv_mem->cv_nor + 1; + } + } + } + else { + /* Otherwise, let order increase happen, and + reset stability limit counter, nscon. */ + cv_mem->cv_nscon = 0; + } +} + +/* + * cvSLdet + * + * 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", + * 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. + * + * Returned values: + * kflag = 1 -> Found stable characteristic root, normal matrix case + * kflag = 2 -> Found stable characteristic root, quartic solution + * kflag = 3 -> Found stable characteristic root, quartic solution, + * with Newton correction + * kflag = 4 -> Found stability violation, normal matrix case + * kflag = 5 -> Found stability violation, quartic solution + * kflag = 6 -> Found stability violation, quartic solution, + * with Newton correction + * + * 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 = -5 -> R value from quartics not consistent. + * kflag = -6 -> No corrected root passes test on qk values + * kflag = -7 -> Trouble solving for sigsq. + * kflag = -8 -> Trouble solving for B, or R via B. + * kflag = -9 -> R via sigsq[k] disagrees with R from data. + */ + +static int cvSLdet(CVodeMem cv_mem) +{ + int i, k, j, it, kmin = 0, kflag = 0; + realtype rat[5][4], rav[4], qkr[4], sigsq[4], smax[4], ssmax[4]; + realtype drr[4], rrc[4],sqmx[4], qjk[4][4], vrat[5], qc[6][4], qco[6][4]; + realtype rr, rrcut, vrrtol, vrrt2, sqtol, rrtol; + 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 ratp, ratm, qfac1, qfac2, bb, rrb; + + /* The following are cutoffs and tolerances used by this routine */ + + rrcut = RCONST(0.98); + vrrtol = RCONST(1.0e-4); + vrrt2 = RCONST(5.0e-4); + sqtol = RCONST(1.0e-3); + rrtol = RCONST(1.0e-2); + + rr = ZERO; + + /* Index k corresponds to the degree of the interpolating polynomial. */ + /* k = 1 -> q-1 */ + /* k = 2 -> q */ + /* k = 3 -> q+1 */ + + /* Index i is a backward-in-time index, i = 1 -> current time, */ + /* i = 2 -> previous step, etc */ + + /* get maxima, minima, and variances, and form quartic coefficients */ + + 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; + return(kflag); + } + smax[k] = smaxk; + ssmax[k] = smaxk*smaxk; + + 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]; + 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]); + + qc[5][k] = cv_mem->cv_ssdat[1][k] * cv_mem->cv_ssdat[3][k] - + cv_mem->cv_ssdat[2][k] * cv_mem->cv_ssdat[2][k]; + qc[4][k] = cv_mem->cv_ssdat[2][k] * cv_mem->cv_ssdat[3][k] - + cv_mem->cv_ssdat[1][k] * cv_mem->cv_ssdat[4][k]; + qc[3][k] = ZERO; + qc[2][k] = cv_mem->cv_ssdat[2][k] * cv_mem->cv_ssdat[5][k] - + cv_mem->cv_ssdat[3][k] * cv_mem->cv_ssdat[4][k]; + 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++) + 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; + return(kflag); + } else { + rr = (rav[1] + rav[2] + rav[3])/THREE; + drrmax = ZERO; + for (k = 1;k<=3;k++) { + adrr = SUNRabs(rav[k] - rr); + drrmax = SUNMAX(drrmax, adrr); + } + if (drrmax > vrrt2) {kflag = -3; return(kflag);} + + kflag = 1; + + /* can compute charactistic root, drop to next section */ + } + + } else { + + /* use the quartics to get rr. */ + + if (SUNRabs(qco[1][1]) < TINY*ssmax[1]) { + kflag = -4; + return(kflag); + } + + tem = qco[1][2]/qco[1][1]; + for (i=2; i<=5; i++) { + qco[i][2] = qco[i][2] - tem*qco[i][1]; + } + + qco[1][2] = ZERO; + tem = qco[1][3]/qco[1][1]; + for (i=2; i<=5; i++) { + qco[i][3] = qco[i][3] - tem*qco[i][1]; + } + qco[1][3] = ZERO; + + if (SUNRabs(qco[2][2]) < TINY*ssmax[2]) { + kflag = -4; + return(kflag); + } + + tem = qco[2][3]/qco[2][2]; + for (i=3; i<=5; i++) { + qco[i][3] = qco[i][3] - tem*qco[i][2]; + } + + if (SUNRabs(qco[4][3]) < TINY*ssmax[3]) { + kflag = -4; + return(kflag); + } + + rr = -qco[5][3]/qco[4][3]; + + if (rr < TINY || rr > HUNDRED) { + kflag = -5; + return(kflag); + } + + for (k=1; k<=3; k++) + qkr[k] = qc[5][k] + rr*(qc[4][k] + rr*rr*(qc[2][k] + rr*qc[1][k])); + + sqmax = ZERO; + for (k=1; k<=3; k++) { + saqk = SUNRabs(qkr[k])/ssmax[k]; + if (saqk > sqmax) sqmax = saqk; + } + + if (sqmax < sqtol) { + kflag = 2; + + /* can compute charactistic root, drop to "given rr,etc" */ + + } else { + + /* do Newton corrections to improve rr. */ + + for (it=1; it<=3; it++) { + for (k=1; k<=3; k++) { + qp = qc[4][k] + rr*rr*(THREE*qc[2][k] + rr*FOUR*qc[1][k]); + 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]; + sqmaxk = ZERO; + for (j=1; j<=3; j++) { + 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; + } + + sqmin = sqmx[1] + ONE; + for (k=1; k<=3; k++) { + if (sqmx[k] < sqmin) { + 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; + } else { + for (j=1; j<=3; j++) { + qkr[j] = qjk[j][kmin]; + } + } + } /* end of Newton correction loop */ + + if (sqmin > sqtol) { + kflag = -6; + return(kflag); + } + } /* end of if (sqmax < sqtol) else */ + } /* end of if (vmin < vrrtol*vrrtol) else, quartics to get rr. */ + + /* 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; + rsc = cv_mem->cv_ssdat[3][k]*rr*rr; + rsd = cv_mem->cv_ssdat[4][k]*rr*rr*rr; + rd1a = rsa - rsb; + rd1b = rsb - rsc; + rd1c = rsc - rsd; + 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; + return(kflag); + } + 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 + * information, and checks whether g has a zero both at and very near + * the initial point of the IVP. + * + * This routine returns an int equal to: + * CV_RTFUNC_FAIL < 0 if the g function failed, or + * CV_SUCCESS = 0 otherwise. + */ + +static int cvRcheck1(CVodeMem cv_mem) +{ + int i, retval; + realtype smallh, hratio, tplus; + booleantype zroot; + + 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; + + /* Evaluate g at initial t and check for zero values. */ + retval = cv_mem->cv_gfun(cv_mem->cv_tlo, cv_mem->cv_zn[0], + cv_mem->cv_glo, cv_mem->cv_user_data); + cv_mem->cv_nge = 1; + if (retval != 0) return(CV_RTFUNC_FAIL); + + zroot = SUNFALSE; + for (i = 0; i < cv_mem->cv_nrtfn; i++) { + if (SUNRabs(cv_mem->cv_glo[i]) == ZERO) { + zroot = SUNTRUE; + cv_mem->cv_gactive[i] = SUNFALSE; + } + } + if (!zroot) return(CV_SUCCESS); + + /* Some g_i is zero at t0; look at g at t0+(small increment). */ + 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); + retval = cv_mem->cv_gfun(tplus, cv_mem->cv_y, + cv_mem->cv_ghi, cv_mem->cv_user_data); + cv_mem->cv_nge++; + if (retval != 0) return(CV_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 < cv_mem->cv_nrtfn; i++) { + if (!cv_mem->cv_gactive[i] && SUNRabs(cv_mem->cv_ghi[i]) != ZERO) { + cv_mem->cv_gactive[i] = SUNTRUE; + cv_mem->cv_glo[i] = cv_mem->cv_ghi[i]; + } + } + return(CV_SUCCESS); +} + +/* + * cvRcheck2 + * + * This routine checks for exact zeros of g at the last root found, + * if the last return was a root. It then checks for a close pair of + * zeros (an error condition), and for a new root at a nearby point. + * The array glo = g(tlo) at the left endpoint of the search interval + * is adjusted if necessary to assure that all g_i are nonzero + * there, before returning to do a root search in the interval. + * + * On entry, tlo = tretlast is the last value of tret returned by + * CVode. This may be the previous tn, the previous tout value, + * or the last root location. + * + * This routine returns an int equal to: + * CV_RTFUNC_FAIL < 0 if the g function failed, or + * CLOSERT = 3 if a close pair of zeros was found, or + * RTFOUND = 1 if a new zero of g was found near tlo, or + * CV_SUCCESS = 0 otherwise. + */ + +static int cvRcheck2(CVodeMem cv_mem) +{ + int i, retval; + realtype smallh, hratio, tplus; + booleantype zroot; + + if (cv_mem->cv_irfnd == 0) return(CV_SUCCESS); + + (void) CVodeGetDky(cv_mem, cv_mem->cv_tlo, 0, cv_mem->cv_y); + retval = cv_mem->cv_gfun(cv_mem->cv_tlo, cv_mem->cv_y, + cv_mem->cv_glo, cv_mem->cv_user_data); + cv_mem->cv_nge++; + 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++) { + if (!cv_mem->cv_gactive[i]) continue; + if (SUNRabs(cv_mem->cv_glo[i]) == ZERO) { + zroot = SUNTRUE; + cv_mem->cv_iroots[i] = 1; + } + } + if (!zroot) return(CV_SUCCESS); + + /* 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; + 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) { + hratio = smallh/cv_mem->cv_h; + N_VLinearSum(ONE, cv_mem->cv_y, hratio, cv_mem->cv_zn[1], cv_mem->cv_y); + } else { + (void) CVodeGetDky(cv_mem, tplus, 0, 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++; + if (retval != 0) return(CV_RTFUNC_FAIL); + + /* Check for close roots (error return), for a new zero at tlo+smallh, + and for a g_i that changed from zero to nonzero. */ + zroot = SUNFALSE; + for (i = 0; i < cv_mem->cv_nrtfn; i++) { + if (!cv_mem->cv_gactive[i]) continue; + if (SUNRabs(cv_mem->cv_ghi[i]) == ZERO) { + if (cv_mem->cv_iroots[i] == 1) return(CLOSERT); + zroot = SUNTRUE; + cv_mem->cv_iroots[i] = 1; + } else { + if (cv_mem->cv_iroots[i] == 1) + cv_mem->cv_glo[i] = cv_mem->cv_ghi[i]; + } + } + if (zroot) return(RTFOUND); + return(CV_SUCCESS); +} + +/* + * cvRcheck3 + * + * This routine interfaces to cvRootfind to look for a root of g + * between tlo and either tn or tout, whichever comes first. + * Only roots beyond tlo in the direction of integration are sought. + * + * This routine returns an int equal to: + * CV_RTFUNC_FAIL < 0 if the g function failed, or + * RTFOUND = 1 if a root of g was found, or + * CV_SUCCESS = 0 otherwise. + */ + +static int cvRcheck3(CVodeMem cv_mem) +{ + int i, ier, retval; + + /* Set thi = tn or tout, whichever comes first; set y = y(thi). */ + if (cv_mem->cv_taskc == CV_ONE_STEP) { + cv_mem->cv_thi = cv_mem->cv_tn; + N_VScale(ONE, cv_mem->cv_zn[0], cv_mem->cv_y); + } + 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; + N_VScale(ONE, cv_mem->cv_zn[0], cv_mem->cv_y); + } else { + cv_mem->cv_thi = cv_mem->cv_toutc; + (void) CVodeGetDky(cv_mem, cv_mem->cv_thi, 0, cv_mem->cv_y); + } + } + + /* Set ghi = g(thi) and call cvRootfind to search (tlo,thi) for roots. */ + retval = cv_mem->cv_gfun(cv_mem->cv_thi, cv_mem->cv_y, + cv_mem->cv_ghi, cv_mem->cv_user_data); + cv_mem->cv_nge++; + 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; + ier = cvRootfind(cv_mem); + if (ier == CV_RTFUNC_FAIL) return(CV_RTFUNC_FAIL); + for(i=0; i<cv_mem->cv_nrtfn; i++) { + if(!cv_mem->cv_gactive[i] && cv_mem->cv_grout[i] != ZERO) + cv_mem->cv_gactive[i] = SUNTRUE; + } + cv_mem->cv_tlo = cv_mem->cv_trout; + 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 (ier == CV_SUCCESS) return(CV_SUCCESS); + + /* If a root was found, interpolate to get y(trout) and return. */ + (void) CVodeGetDky(cv_mem, cv_mem->cv_trout, 0, cv_mem->cv_y); + return(RTFOUND); +} + +/* + * cvRootfind + * + * This routine solves for a root of g(t) between tlo and thi, if + * one exists. Only roots of odd multiplicity (i.e. with a change + * of sign in one of the g_i), or exact zeros, are found. + * Here the sign of tlo - thi is arbitrary, but if multiple roots + * are found, the one closest to tlo is returned. + * + * The method used is the Illinois algorithm, a modified secant method. + * Reference: Kathie L. Hiebert and Lawrence F. Shampine, Implicitly + * Defined Output Points for Solutions of ODEs, Sandia National + * Laboratory Report SAND80-0180, February 1980. + * + * This routine uses the following parameters for communication: + * + * nrtfn = number of functions g_i, or number of components of + * the vector-valued function g(t). Input only. + * + * gfun = user-defined function for g(t). Its form is + * (void) gfun(t, y, gt, user_data) + * + * rootdir = in array specifying the direction of zero-crossings. + * If rootdir[i] > 0, search for roots of g_i only if + * g_i is increasing; if rootdir[i] < 0, search for + * roots of g_i only if g_i is decreasing; otherwise + * always search for roots of g_i. + * + * gactive = array specifying whether a component of g should + * or should not be monitored. gactive[i] is initially + * 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 + * corresponding g function moves away from 0.0. + * + * nge = cumulative counter for gfun calls. + * + * ttol = a convergence tolerance for trout. Input only. + * When a root at trout is found, it is located only to + * within a tolerance of ttol. Typically, ttol should + * be set to a value on the order of + * 100 * UROUND * max (SUNRabs(tlo), SUNRabs(thi)) + * where UROUND is the unit roundoff of the machine. + * + * tlo, thi = endpoints of the interval in which roots are sought. + * On input, these must be distinct, but tlo - thi may + * be of either sign. The direction of integration is + * assumed to be from tlo to thi. On return, tlo and thi + * are the endpoints of the final relevant interval. + * + * glo, ghi = arrays of length nrtfn containing the vectors g(tlo) + * and g(thi) respectively. Input and output. On input, + * none of the glo[i] should be zero. + * + * trout = root location, if a root was found, or thi if not. + * Output only. If a root was found other than an exact + * zero of g, trout is the endpoint thi of the final + * interval bracketing the root, with size at most ttol. + * + * grout = array of length nrtfn containing g(trout) on return. + * + * iroots = int array of length nrtfn with root information. + * Output only. If a root was found, iroots indicates + * which components g_i have a root at trout. For + * i = 0, ..., nrtfn-1, iroots[i] = 1 if g_i has a root + * and g_i is increasing, iroots[i] = -1 if g_i has a + * root and g_i is decreasing, and iroots[i] = 0 if g_i + * has no roots or g_i varies in the direction opposite + * to that indicated by rootdir[i]. + * + * This routine returns an int equal to: + * CV_RTFUNC_FAIL < 0 if the g function failed, or + * RTFOUND = 1 if a root of g was found, or + * CV_SUCCESS = 0 otherwise. + */ + +static int cvRootfind(CVodeMem cv_mem) +{ + realtype alph, tmid, gfrac, maxfrac, fracint, fracsub; + int i, retval, imax, side, sideprev; + booleantype zroot, sgnchg; + + imax = 0; + + /* First check for change in sign in ghi or for a zero in ghi. */ + maxfrac = ZERO; + zroot = SUNFALSE; + sgnchg = SUNFALSE; + for (i = 0; i < cv_mem->cv_nrtfn; i++) { + if(!cv_mem->cv_gactive[i]) continue; + if (SUNRabs(cv_mem->cv_ghi[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_ghi[i] < ZERO) && + (cv_mem->cv_rootdir[i]*cv_mem->cv_glo[i] <= ZERO) ) { + gfrac = SUNRabs(cv_mem->cv_ghi[i]/(cv_mem->cv_ghi[i] - cv_mem->cv_glo[i])); + if (gfrac > maxfrac) { + sgnchg = SUNTRUE; + maxfrac = gfrac; + imax = i; + } + } + } + } + + /* 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. + * 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 (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. + * 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 (N_VMin(cv_mem->cv_tempv) <= ZERO) return(-1); + N_VInv(cv_mem->cv_tempv, weight); + return(0); +} + +/* + * ----------------------------------------------------------------- + * Error message handling functions + * ----------------------------------------------------------------- + */ + +/* + * 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 + * pointed to by cv_ehfun. + */ + +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 + (msgfmt is the last required argument to cvProcessError) */ + + va_start(ap, msgfmt); + + /* Compose the message */ + + vsprintf(msg, msgfmt, ap); + + if (cv_mem == NULL) { /* We write to stderr */ +#ifndef NO_FPRINTF_OUTPUT + fprintf(stderr, "\n[%s ERROR] %s\n ", module, fname); + fprintf(stderr, "%s\n\n", msg); +#endif + + } else { /* We can call ehfun */ + cv_mem->cv_ehfun(error_code, module, fname, msg, cv_mem->cv_eh_data); + } + + /* Finalize argument processing */ + va_end(ap); + + return; +} + +/* + * cvErrHandler is the default error handling function. + * It sends the error message to the stream pointed to by cv_errfp. + */ + +void cvErrHandler(int error_code, const char *module, + const char *function, char *msg, void *data) +{ + CVodeMem cv_mem; + char err_type[10]; + + /* data points to cv_mem here */ + + cv_mem = (CVodeMem) data; + + if (error_code == CV_WARNING) + sprintf(err_type,"WARNING"); + else + sprintf(err_type,"ERROR"); + +#ifndef NO_FPRINTF_OUTPUT + if (cv_mem->cv_errfp!=NULL) { + fprintf(cv_mem->cv_errfp,"\n[%s %s] %s\n",module,err_type,function); + fprintf(cv_mem->cv_errfp," %s\n\n",msg); + } +#endif + + return; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_bandpre.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_bandpre.c new file mode 100644 index 0000000..41194b0 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_bandpre.c @@ -0,0 +1,562 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * Scott D. Cohen, Alan C. Hindmarsh, Radu Serban, + * 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 file contains implementations of the banded difference + * quotient Jacobian-based preconditioner and solver routines for + * use with the CVLS linear solver interface. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "cvode_impl.h" +#include "cvode_bandpre_impl.h" +#include "cvode_ls_impl.h" +#include <sundials/sundials_math.h> + +#define MIN_INC_MULT RCONST(1000.0) +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) +#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, + realtype gamma, void *bp_data); +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); + +/* Prototype for CVBandPrecFree */ +static int CVBandPrecFree(CVodeMem cv_mem); + +/* Prototype for difference quotient Jacobian calculation routine */ +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 + N_VGetArrayPointer exists. + -----------------------------------------------------------------*/ +int CVBandPrecInit(void *cvode_mem, sunindextype N, + sunindextype mu, sunindextype ml) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + CVBandPrecData pdata; + sunindextype mup, mlp, storagemu; + int flag; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVBANDPRE", + "CVBandPrecInit", MSGBP_MEM_NULL); + return(CVLS_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Test if the CVLS linear solver interface has been attached */ + if (cv_mem->cv_lmem == NULL) { + cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVBANDPRE", + "CVBandPrecInit", MSGBP_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + /* Test compatibility of NVECTOR package with the BAND preconditioner */ + if(cv_mem->cv_tempv->ops->nvgetarraypointer == NULL) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVBANDPRE", + "CVBandPrecInit", MSGBP_BAD_NVECTOR); + return(CVLS_ILL_INPUT); + } + + /* Allocate data memory */ + pdata = NULL; + pdata = (CVBandPrecData) malloc(sizeof *pdata); + if (pdata == NULL) { + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBANDPRE", + "CVBandPrecInit", MSGBP_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + + /* Load pointers and bandwidths into pdata block. */ + pdata->cvode_mem = cvode_mem; + pdata->N = N; + pdata->mu = mup = SUNMIN(N-1, SUNMAX(0,mu)); + pdata->ml = mlp = SUNMIN(N-1, SUNMAX(0,ml)); + + /* Initialize nfeBP counter */ + pdata->nfeBP = 0; + + /* Allocate memory for saved banded Jacobian approximation. */ + pdata->savedJ = NULL; + pdata->savedJ = SUNBandMatrixStorage(N, mup, mlp, mup); + if (pdata->savedJ == NULL) { + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBANDPRE", + "CVBandPrecInit", MSGBP_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + + /* Allocate memory for banded preconditioner. */ + storagemu = SUNMIN(N-1, mup+mlp); + pdata->savedP = NULL; + pdata->savedP = SUNBandMatrixStorage(N, mup, mlp, storagemu); + if (pdata->savedP == NULL) { + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBANDPRE", + "CVBandPrecInit", MSGBP_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + + /* Allocate memory for banded linear solver */ + pdata->LS = NULL; + pdata->LS = SUNLinSol_Band(cv_mem->cv_tempv, pdata->savedP); + if (pdata->LS == NULL) { + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBANDPRE", + "CVBandPrecInit", MSGBP_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + + /* allocate memory for temporary N_Vectors */ + pdata->tmp1 = NULL; + pdata->tmp1 = N_VClone(cv_mem->cv_tempv); + if (pdata->tmp1 == NULL) { + SUNLinSolFree(pdata->LS); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBANDPRE", + "CVBandPrecInit", MSGBP_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + pdata->tmp2 = NULL; + pdata->tmp2 = N_VClone(cv_mem->cv_tempv); + if (pdata->tmp2 == NULL) { + SUNLinSolFree(pdata->LS); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + N_VDestroy(pdata->tmp1); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBANDPRE", + "CVBandPrecInit", MSGBP_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + + /* initialize band linear solver object */ + flag = SUNLinSolInitialize(pdata->LS); + if (flag != SUNLS_SUCCESS) { + SUNLinSolFree(pdata->LS); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + N_VDestroy(pdata->tmp1); + N_VDestroy(pdata->tmp2); + free(pdata); pdata = NULL; + 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); + + /* Point to the new P_data field in the LS memory */ + cvls_mem->P_data = pdata; + + /* Attach the pfree function */ + cvls_mem->pfree = CVBandPrecFree; + + /* Attach preconditioner solve and setup functions */ + flag = CVodeSetPreconditioner(cvode_mem, + CVBandPrecSetup, + CVBandPrecSolve); + return(flag); +} + + +int CVBandPrecGetWorkSpace(void *cvode_mem, long int *lenrwBP, + long int *leniwBP) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + CVBandPrecData pdata; + sunindextype lrw1, liw1; + long int lrw, liw; + int flag; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVBANDPRE", + "CVBandPrecGetWorkSpace", MSGBP_MEM_NULL); + return(CVLS_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + if (cv_mem->cv_lmem == NULL) { + cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVBANDPRE", + "CVBandPrecGetWorkSpace", MSGBP_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + if (cvls_mem->P_data == NULL) { + 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 */ + *leniwBP = 4; + *lenrwBP = 0; + if (cv_mem->cv_tempv->ops->nvspace) { + N_VSpace(cv_mem->cv_tempv, &lrw1, &liw1); + *leniwBP += 2*liw1; + *lenrwBP += 2*lrw1; + } + if (pdata->savedJ->ops->space) { + flag = SUNMatSpace(pdata->savedJ, &lrw, &liw); + if (flag != 0) return(-1); + *leniwBP += liw; + *lenrwBP += lrw; + } + if (pdata->savedP->ops->space) { + flag = SUNMatSpace(pdata->savedP, &lrw, &liw); + if (flag != 0) return(-1); + *leniwBP += liw; + *lenrwBP += lrw; + } + if (pdata->LS->ops->space) { + flag = SUNLinSolSpace(pdata->LS, &lrw, &liw); + if (flag != 0) return(-1); + *leniwBP += liw; + *lenrwBP += lrw; + } + + return(CVLS_SUCCESS); +} + + +int CVBandPrecGetNumRhsEvals(void *cvode_mem, long int *nfevalsBP) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + CVBandPrecData pdata; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVBANDPRE", + "CVBandPrecGetNumRhsEvals", MSGBP_MEM_NULL); + return(CVLS_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + if (cv_mem->cv_lmem == NULL) { + cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVBANDPRE", + "CVBandPrecGetNumRhsEvals", MSGBP_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + if (cvls_mem->P_data == NULL) { + cvProcessError(cv_mem, CVLS_PMEM_NULL, "CVBANDPRE", + "CVBandPrecGetNumRhsEvals", MSGBP_PMEM_NULL); + return(CVLS_PMEM_NULL); + } + pdata = (CVBandPrecData) cvls_mem->P_data; + + *nfevalsBP = pdata->nfeBP; + + return(CVLS_SUCCESS); +} + + +/*----------------------------------------------------------------- + CVBandPrecSetup + ----------------------------------------------------------------- + Together CVBandPrecSetup and CVBandPrecSolve use a banded + 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 + from scratch. + jok == SUNTRUE means that Jacobian data from the + previous PrecSetup call will be reused + (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, + 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; + cv_mem = (CVodeMem) pdata->cvode_mem; + + if (jok) { + + /* If jok = SUNTRUE, use saved copy of J. */ + *jcurPtr = SUNFALSE; + retval = SUNMatCopy(pdata->savedJ, pdata->savedP); + if (retval < 0) { + cvProcessError(cv_mem, -1, "CVBANDPRE", + "CVBandPrecSetup", MSGBP_SUNMAT_FAIL); + return(-1); + } + if (retval > 0) { + return(1); + } + + } else { + + /* If jok = SUNFALSE, call CVBandPDQJac for new J value. */ + *jcurPtr = SUNTRUE; + retval = SUNMatZero(pdata->savedJ); + if (retval < 0) { + cvProcessError(cv_mem, -1, "CVBANDPRE", + "CVBandPrecSetup", MSGBP_SUNMAT_FAIL); + return(-1); + } + if (retval > 0) { + return(1); + } + + retval = CVBandPDQJac(pdata, t, y, fy, + pdata->tmp1, pdata->tmp2); + if (retval < 0) { + cvProcessError(cv_mem, -1, "CVBANDPRE", + "CVBandPrecSetup", MSGBP_RHSFUNC_FAILED); + return(-1); + } + if (retval > 0) { + return(1); + } + + retval = SUNMatCopy(pdata->savedJ, pdata->savedP); + if (retval < 0) { + cvProcessError(cv_mem, -1, "CVBANDPRE", + "CVBandPrecSetup", MSGBP_SUNMAT_FAIL); + return(-1); + } + if (retval > 0) { + return(1); + } + + } + + /* Scale and add identity to get savedP = I - gamma*J. */ + retval = SUNMatScaleAddI(-gamma, pdata->savedP); + if (retval) { + 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); +} + + +/*----------------------------------------------------------------- + CVBandPrecSolve + ----------------------------------------------------------------- + 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, + realtype delta, int lr, void *bp_data) +{ + CVBandPrecData pdata; + int retval; + + /* Assume matrix and lpivots have already been allocated. */ + pdata = (CVBandPrecData) bp_data; + + /* Call banded solver object to do the work */ + retval = SUNLinSolSolve(pdata->LS, pdata->savedP, z, r, ZERO); + return(retval); +} + + +static int CVBandPrecFree(CVodeMem cv_mem) +{ + CVLsMem cvls_mem; + CVBandPrecData 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 = (CVBandPrecData) cvls_mem->P_data; + + SUNLinSolFree(pdata->LS); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + N_VDestroy(pdata->tmp1); + N_VDestroy(pdata->tmp2); + + free(pdata); + pdata = NULL; + + return(0); +} + + +/*----------------------------------------------------------------- + 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 + 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 + in succession. + -----------------------------------------------------------------*/ +static int CVBandPDQJac(CVBandPrecData pdata, realtype t, N_Vector y, + N_Vector fy, N_Vector ftemp, N_Vector ytemp) +{ + CVodeMem cv_mem; + 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; + realtype *y_data, *ytemp_data, *cns_data; + int retval; + + cv_mem = (CVodeMem) pdata->cvode_mem; + + /* Obtain pointers to the data for various vectors */ + ewt_data = N_VGetArrayPointer(cv_mem->cv_ewt); + fy_data = N_VGetArrayPointer(fy); + 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); + + /* Load ytemp with y = predicted y vector. */ + N_VScale(ONE, y, ytemp); + + /* Set minimum increment based on uround and norm of f. */ + srur = SUNRsqrt(cv_mem->cv_uround); + fnorm = N_VWrmsNorm(fy, cv_mem->cv_ewt); + minInc = (fnorm != ZERO) ? + (MIN_INC_MULT * SUNRabs(cv_mem->cv_h) * cv_mem->cv_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 (cv_mem->cv_constraints != NULL) { + 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 f with incremented y. */ + retval = cv_mem->cv_f(t, ytemp, ftemp, cv_mem->cv_user_data); + pdata->nfeBP++; + if (retval != 0) return(retval); + + /* 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 (cv_mem->cv_constraints != NULL) { + 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); + for (i=i1; i <= i2; i++) + SM_COLUMN_ELEMENT_B(col_j,i,j) = inc_inv * (ftemp_data[i] - fy_data[i]); + } + } + + return(0); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_bandpre_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_bandpre_impl.h new file mode 100644 index 0000000..be463b1 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_bandpre_impl.h @@ -0,0 +1,75 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * Michael Wittman, 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 + * ----------------------------------------------------------------- + * Implementation header file for the CVBANDPRE module. + * ----------------------------------------------------------------- + */ + +#ifndef _CVBANDPRE_IMPL_H +#define _CVBANDPRE_IMPL_H + +#include <cvode/cvode_bandpre.h> +#include <sunmatrix/sunmatrix_band.h> +#include <sunlinsol/sunlinsol_band.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*----------------------------------------------------------------- + Type: CVBandPrecData + -----------------------------------------------------------------*/ + +typedef struct CVBandPrecDataRec { + + /* Data set by user in CVBandPrecInit */ + sunindextype N; + sunindextype ml, mu; + + /* Data set by CVBandPrecSetup */ + SUNMatrix savedJ; + SUNMatrix savedP; + SUNLinearSolver LS; + N_Vector tmp1; + N_Vector tmp2; + + /* Rhs calls */ + long int nfeBP; + + /* Pointer to cvode_mem */ + void *cvode_mem; + +} *CVBandPrecData; + +/*----------------------------------------------------------------- + CVBANDPRE error messages + -----------------------------------------------------------------*/ + +#define MSGBP_MEM_NULL "Integrator memory is NULL." +#define MSGBP_LMEM_NULL "Linear solver memory is NULL. One of the SPILS linear solvers must be attached." +#define MSGBP_MEM_FAIL "A memory request failed." +#define MSGBP_BAD_NVECTOR "A required vector operation is not implemented." +#define MSGBP_SUNMAT_FAIL "An error arose from a SUNBandMatrix routine." +#define MSGBP_SUNLS_FAIL "An error arose from a SUNBandLinearSolver routine." +#define MSGBP_PMEM_NULL "Band preconditioner memory is NULL. CVBandPrecInit must be called." +#define MSGBP_RHSFUNC_FAILED "The right-hand side routine failed in an unrecoverable manner." + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_bbdpre.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_bbdpre.c new file mode 100644 index 0000000..5ddd701 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_bbdpre.c @@ -0,0 +1,702 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * Michael Wittman, Alan C. Hindmarsh, Radu Serban, 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 file contains implementations of routines for a + * band-block-diagonal preconditioner, i.e. a block-diagonal + * matrix with banded blocks, for use with CVODE, the CVLS linear + * solver interface, and the MPI-parallel implementation of NVECTOR. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "cvode_impl.h" +#include "cvode_bbdpre_impl.h" +#include "cvode_ls_impl.h" +#include <sundials/sundials_math.h> +#include <nvector/nvector_serial.h> + +#define MIN_INC_MULT RCONST(1000.0) +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) +#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, + realtype gamma, void *bbd_data); +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); + +/* Prototype for CVBBDPrecFree */ +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, + N_Vector ytemp, N_Vector gtemp); + +/*----------------------------------------------------------------- + User-Callable Functions: initialization, reinit and free + -----------------------------------------------------------------*/ +int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, + sunindextype mudq, sunindextype mldq, + sunindextype mukeep, sunindextype mlkeep, + realtype dqrely, CVLocalFn gloc, CVCommFn cfn) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + CVBBDPrecData pdata; + sunindextype muk, mlk, storage_mu, lrw1, liw1; + long int lrw, liw; + int flag; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVBBDPRE", + "CVBBDPrecInit", MSGBBD_MEM_NULL); + return(CVLS_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Test if the CVLS linear solver interface has been created */ + if (cv_mem->cv_lmem == NULL) { + cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVBBDPRE", + "CVBBDPrecInit", MSGBBD_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + /* Test compatibility of NVECTOR package with the BBD preconditioner */ + if(cv_mem->cv_tempv->ops->nvgetarraypointer == NULL) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVBBDPRE", + "CVBBDPrecInit", MSGBBD_BAD_NVECTOR); + return(CVLS_ILL_INPUT); + } + + /* Allocate data memory */ + pdata = NULL; + pdata = (CVBBDPrecData) malloc(sizeof *pdata); + if (pdata == NULL) { + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", + "CVBBDPrecInit", MSGBBD_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + + /* Set pointers to gloc and cfn; load half-bandwidths */ + pdata->cvode_mem = cvode_mem; + pdata->gloc = gloc; + pdata->cfn = cfn; + pdata->mudq = SUNMIN(Nlocal-1, SUNMAX(0,mudq)); + pdata->mldq = SUNMIN(Nlocal-1, SUNMAX(0,mldq)); + muk = SUNMIN(Nlocal-1, SUNMAX(0,mukeep)); + mlk = SUNMIN(Nlocal-1, SUNMAX(0,mlkeep)); + pdata->mukeep = muk; + pdata->mlkeep = mlk; + + /* Allocate memory for saved Jacobian */ + pdata->savedJ = SUNBandMatrixStorage(Nlocal, muk, mlk, muk); + if (pdata->savedJ == NULL) { + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", + "CVBBDPrecInit", MSGBBD_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + + /* Allocate memory for preconditioner matrix */ + storage_mu = SUNMIN(Nlocal-1, muk + mlk); + pdata->savedP = NULL; + pdata->savedP = SUNBandMatrixStorage(Nlocal, muk, mlk, storage_mu); + if (pdata->savedP == NULL) { + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", + "CVBBDPrecInit", MSGBBD_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + + /* Allocate memory for temporary N_Vectors */ + pdata->zlocal = NULL; + pdata->zlocal = N_VNewEmpty_Serial(Nlocal); + if (pdata->zlocal == NULL) { + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", + "CVBBDPrecInit", MSGBBD_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + pdata->rlocal = NULL; + pdata->rlocal = N_VNewEmpty_Serial(Nlocal); + if (pdata->rlocal == NULL) { + N_VDestroy(pdata->zlocal); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", + "CVBBDPrecInit", MSGBBD_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + pdata->tmp1 = NULL; + pdata->tmp1 = N_VClone(cv_mem->cv_tempv); + if (pdata->tmp1 == NULL) { + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", + "CVBBDPrecInit", MSGBBD_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + pdata->tmp2 = NULL; + pdata->tmp2 = N_VClone(cv_mem->cv_tempv); + if (pdata->tmp2 == NULL) { + N_VDestroy(pdata->tmp1); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", + "CVBBDPrecInit", MSGBBD_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + pdata->tmp3 = NULL; + pdata->tmp3 = N_VClone(cv_mem->cv_tempv); + if (pdata->tmp3 == NULL) { + N_VDestroy(pdata->tmp1); + N_VDestroy(pdata->tmp2); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", + "CVBBDPrecInit", MSGBBD_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + + /* Allocate memory for banded linear solver */ + pdata->LS = NULL; + pdata->LS = SUNLinSol_Band(pdata->rlocal, pdata->savedP); + if (pdata->LS == NULL) { + N_VDestroy(pdata->tmp1); + N_VDestroy(pdata->tmp2); + N_VDestroy(pdata->tmp3); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVBBDPRE", + "CVBBDPrecInit", MSGBBD_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + + /* initialize band linear solver object */ + flag = SUNLinSolInitialize(pdata->LS); + if (flag != SUNLS_SUCCESS) { + N_VDestroy(pdata->tmp1); + N_VDestroy(pdata->tmp2); + N_VDestroy(pdata->tmp3); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + SUNLinSolFree(pdata->LS); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_SUNLS_FAIL, "CVBBDPRE", + "CVBBDPrecInit", MSGBBD_SUNLS_FAIL); + return(CVLS_SUNLS_FAIL); + } + + /* Set pdata->dqrely based on input dqrely (0 implies default). */ + pdata->dqrely = (dqrely > ZERO) ? + dqrely : SUNRsqrt(cv_mem->cv_uround); + + /* Store Nlocal to be used in CVBBDPrecSetup */ + pdata->n_local = Nlocal; + + /* Set work space sizes and initialize nge */ + pdata->rpwsize = 0; + pdata->ipwsize = 0; + if (cv_mem->cv_tempv->ops->nvspace) { + N_VSpace(cv_mem->cv_tempv, &lrw1, &liw1); + pdata->rpwsize += 3*lrw1; + pdata->ipwsize += 3*liw1; + } + if (pdata->rlocal->ops->nvspace) { + N_VSpace(pdata->rlocal, &lrw1, &liw1); + pdata->rpwsize += 2*lrw1; + pdata->ipwsize += 2*liw1; + } + if (pdata->savedJ->ops->space) { + flag = SUNMatSpace(pdata->savedJ, &lrw, &liw); + pdata->rpwsize += lrw; + pdata->ipwsize += liw; + } + if (pdata->savedP->ops->space) { + flag = SUNMatSpace(pdata->savedP, &lrw, &liw); + pdata->rpwsize += lrw; + pdata->ipwsize += liw; + } + if (pdata->LS->ops->space) { + flag = SUNLinSolSpace(pdata->LS, &lrw, &liw); + pdata->rpwsize += lrw; + pdata->ipwsize += liw; + } + pdata->nge = 0; + + /* make sure P_data is free from any previous allocations */ + if (cvls_mem->pfree) + cvls_mem->pfree(cv_mem); + + /* Point to the new P_data field in the LS memory */ + cvls_mem->P_data = pdata; + + /* Attach the pfree function */ + cvls_mem->pfree = CVBBDPrecFree; + + /* Attach preconditioner solve and setup functions */ + flag = CVodeSetPreconditioner(cvode_mem, + CVBBDPrecSetup, + CVBBDPrecSolve); + return(flag); +} + + +int CVBBDPrecReInit(void *cvode_mem, sunindextype mudq, + sunindextype mldq, realtype dqrely) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + CVBBDPrecData pdata; + sunindextype Nlocal; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVBBDPRE", + "CVBBDPrecReInit", MSGBBD_MEM_NULL); + return(CVLS_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Test if the LS linear solver interface has been created */ + if (cv_mem->cv_lmem == NULL) { + cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVBBDPRE", + "CVBBDPrecReInit", MSGBBD_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + /* Test if the preconditioner data is non-NULL */ + if (cvls_mem->P_data == NULL) { + cvProcessError(cv_mem, CVLS_PMEM_NULL, "CVBBDPRE", + "CVBBDPrecReInit", MSGBBD_PMEM_NULL); + return(CVLS_PMEM_NULL); + } + pdata = (CVBBDPrecData) cvls_mem->P_data; + + /* Load half-bandwidths */ + Nlocal = pdata->n_local; + pdata->mudq = SUNMIN(Nlocal-1, SUNMAX(0,mudq)); + pdata->mldq = SUNMIN(Nlocal-1, SUNMAX(0,mldq)); + + /* Set pdata->dqrely based on input dqrely (0 implies default). */ + pdata->dqrely = (dqrely > ZERO) ? + dqrely : SUNRsqrt(cv_mem->cv_uround); + + /* Re-initialize nge */ + pdata->nge = 0; + + return(CVLS_SUCCESS); +} + + +int CVBBDPrecGetWorkSpace(void *cvode_mem, + long int *lenrwBBDP, + long int *leniwBBDP) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + CVBBDPrecData pdata; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVBBDPRE", + "CVBBDPrecGetWorkSpace", MSGBBD_MEM_NULL); + return(CVLS_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + if (cv_mem->cv_lmem == NULL) { + cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVBBDPRE", + "CVBBDPrecGetWorkSpace", MSGBBD_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + if (cvls_mem->P_data == NULL) { + cvProcessError(cv_mem, CVLS_PMEM_NULL, "CVBBDPRE", + "CVBBDPrecGetWorkSpace", MSGBBD_PMEM_NULL); + return(CVLS_PMEM_NULL); + } + pdata = (CVBBDPrecData) cvls_mem->P_data; + + *lenrwBBDP = pdata->rpwsize; + *leniwBBDP = pdata->ipwsize; + + return(CVLS_SUCCESS); +} + + +int CVBBDPrecGetNumGfnEvals(void *cvode_mem, + long int *ngevalsBBDP) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + CVBBDPrecData pdata; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVBBDPRE", + "CVBBDPrecGetNumGfnEvals", MSGBBD_MEM_NULL); + return(CVLS_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + if (cv_mem->cv_lmem == NULL) { + cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVBBDPRE", + "CVBBDPrecGetNumGfnEvals", MSGBBD_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + if (cvls_mem->P_data == NULL) { + cvProcessError(cv_mem, CVLS_PMEM_NULL, "CVBBDPRE", + "CVBBDPrecGetNumGfnEvals", MSGBBD_PMEM_NULL); + return(CVLS_PMEM_NULL); + } + pdata = (CVBBDPrecData) cvls_mem->P_data; + + *ngevalsBBDP = pdata->nge; + + return(CVLS_SUCCESS); +} + + +/*----------------------------------------------------------------- + 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 + from scratch. + jok == SUNTRUE means that Jacobian data from the + previous cvBBDPrecSetup call can be reused + (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, + realtype gamma, void *bbd_data) +{ + sunindextype ier; + CVBBDPrecData pdata; + CVodeMem cv_mem; + int retval; + + pdata = (CVBBDPrecData) bbd_data; + cv_mem = (CVodeMem) pdata->cvode_mem; + + /* If jok = SUNTRUE, use saved copy of J */ + if (jok) { + *jcurPtr = SUNFALSE; + retval = SUNMatCopy(pdata->savedJ, pdata->savedP); + if (retval < 0) { + cvProcessError(cv_mem, -1, "CVBBDPRE", + "CVBBDPrecSetup", MSGBBD_SUNMAT_FAIL); + return(-1); + } + if (retval > 0) { + return(1); + } + + /* Otherwise call CVBBDDQJac for new J value */ + } else { + + *jcurPtr = SUNTRUE; + retval = SUNMatZero(pdata->savedJ); + if (retval < 0) { + cvProcessError(cv_mem, -1, "CVBBDPRE", + "CVBBDPrecSetup", MSGBBD_SUNMAT_FAIL); + return(-1); + } + if (retval > 0) { + return(1); + } + + retval = CVBBDDQJac(pdata, t, y, pdata->tmp1, + pdata->tmp2, pdata->tmp3); + if (retval < 0) { + cvProcessError(cv_mem, -1, "CVBBDPRE", "CVBBDPrecSetup", + MSGBBD_FUNC_FAILED); + return(-1); + } + if (retval > 0) { + return(1); + } + + retval = SUNMatCopy(pdata->savedJ, pdata->savedP); + if (retval < 0) { + cvProcessError(cv_mem, -1, "CVBBDPRE", + "CVBBDPrecSetup", MSGBBD_SUNMAT_FAIL); + return(-1); + } + if (retval > 0) { + return(1); + } + + } + + /* Scale and add I to get P = I - gamma*J */ + retval = SUNMatScaleAddI(-gamma, pdata->savedP); + if (retval) { + 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); +} + + +/*----------------------------------------------------------------- + Function : CVBBDPrecSolve + ----------------------------------------------------------------- + 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, + realtype gamma, realtype delta, + int lr, void *bbd_data) +{ + int retval; + CVBBDPrecData pdata; + + pdata = (CVBBDPrecData) bbd_data; + + /* 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, + pdata->rlocal, ZERO); + + /* Detach local data arrays from rlocal and zlocal */ + N_VSetArrayPointer(NULL, pdata->rlocal); + N_VSetArrayPointer(NULL, pdata->zlocal); + + return(retval); +} + + +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; + + SUNLinSolFree(pdata->LS); + N_VDestroy(pdata->tmp1); + N_VDestroy(pdata->tmp2); + N_VDestroy(pdata->tmp3); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + + free(pdata); + pdata = NULL; + + return(0); +} + + +/*----------------------------------------------------------------- + Function : CVBBDDQJac + ----------------------------------------------------------------- + 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 + 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 CVBBDDQJac(CVBBDPrecData pdata, realtype t, N_Vector y, + N_Vector gy, N_Vector ytemp, N_Vector gtemp) +{ + CVodeMem cv_mem; + 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; + realtype *ytemp_data, *col_j, *cns_data; + int retval; + + cv_mem = (CVodeMem) pdata->cvode_mem; + + /* Load ytemp with y = predicted solution vector */ + N_VScale(ONE, y, ytemp); + + /* Call cfn and gloc to get base value of g(t,y) */ + if (pdata->cfn != NULL) { + retval = pdata->cfn(pdata->n_local, t, y, cv_mem->cv_user_data); + if (retval != 0) return(retval); + } + + retval = pdata->gloc(pdata->n_local, t, ytemp, gy, + cv_mem->cv_user_data); + pdata->nge++; + if (retval != 0) return(retval); + + /* Obtain pointers to the data for various vectors */ + y_data = N_VGetArrayPointer(y); + gy_data = N_VGetArrayPointer(gy); + ewt_data = N_VGetArrayPointer(cv_mem->cv_ewt); + ytemp_data = N_VGetArrayPointer(ytemp); + gtemp_data = N_VGetArrayPointer(gtemp); + if (cv_mem->cv_constraints != NULL) + cns_data = N_VGetArrayPointer(cv_mem->cv_constraints); + + /* Set minimum increment based on uround and norm of g */ + gnorm = N_VWrmsNorm(gy, cv_mem->cv_ewt); + minInc = (gnorm != ZERO) ? + (MIN_INC_MULT * SUNRabs(cv_mem->cv_h) * + cv_mem->cv_uround * pdata->n_local * gnorm) : ONE; + + /* Set bandwidth and number of column groups for band differencing */ + width = pdata->mldq + pdata->mudq + 1; + ngroups = SUNMIN(width, pdata->n_local); + + /* 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) { + 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, + cv_mem->cv_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]); + + /* Adjust sign(inc) as before. */ + if (cv_mem->cv_constraints != NULL) { + 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); + for (i=i1; i <= i2; i++) + SM_COLUMN_ELEMENT_B(col_j,i,j) = + inc_inv * (gtemp_data[i] - gy_data[i]); + } + } + + return(0); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_bbdpre_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_bbdpre_impl.h new file mode 100644 index 0000000..4bb58d3 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_bbdpre_impl.h @@ -0,0 +1,83 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * Michael Wittman, 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 + * ----------------------------------------------------------------- + * Implementation header file for the CVBBDPRE module. + * ----------------------------------------------------------------- + */ + +#ifndef _CVBBDPRE_IMPL_H +#define _CVBBDPRE_IMPL_H + +#include <cvode/cvode_bbdpre.h> +#include <sunmatrix/sunmatrix_band.h> +#include <sunlinsol/sunlinsol_band.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*----------------------------------------------------------------- + Type: CVBBDPrecData + -----------------------------------------------------------------*/ + +typedef struct CVBBDPrecDataRec { + + /* passed by user to CVBBDPrecInit and used by PrecSetup/PrecSolve */ + sunindextype mudq, mldq, mukeep, mlkeep; + realtype dqrely; + CVLocalFn gloc; + CVCommFn cfn; + + /* set by CVBBDPrecSetup and used by CVBBDPrecSolve */ + SUNMatrix savedJ; + SUNMatrix savedP; + SUNLinearSolver LS; + N_Vector tmp1; + N_Vector tmp2; + N_Vector tmp3; + N_Vector zlocal; + N_Vector rlocal; + + /* set by CVBBDPrecInit and used by CVBBDPrecSetup */ + sunindextype n_local; + + /* available for optional output */ + long int rpwsize; + long int ipwsize; + long int nge; + + /* pointer to cvode_mem */ + void *cvode_mem; + +} *CVBBDPrecData; + +/*----------------------------------------------------------------- + CVBBDPRE error messages + -----------------------------------------------------------------*/ + +#define MSGBBD_MEM_NULL "Integrator memory is NULL." +#define MSGBBD_LMEM_NULL "Linear solver memory is NULL. One of the SPILS linear solvers must be attached." +#define MSGBBD_MEM_FAIL "A memory request failed." +#define MSGBBD_BAD_NVECTOR "A required vector operation is not implemented." +#define MSGBBD_SUNMAT_FAIL "An error arose from a SUNBandMatrix routine." +#define MSGBBD_SUNLS_FAIL "An error arose from a SUNBandLinearSolver routine." +#define MSGBBD_PMEM_NULL "BBD peconditioner memory is NULL. CVBBDPrecInit must be called." +#define MSGBBD_FUNC_FAILED "The gloc or cfn routine failed in an unrecoverable manner." + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_diag.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_diag.c new file mode 100644 index 0000000..72b3555 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_diag.c @@ -0,0 +1,439 @@ +/* + * ----------------------------------------------------------------- + * 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 CVDIAG linear solver. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "cvode_diag_impl.h" +#include "cvode_impl.h" + +/* Other Constants */ + +#define FRACT RCONST(0.1) +#define ONE RCONST(1.0) + +/* CVDIAG linit, lsetup, lsolve, and lfree routines */ + +static int CVDiagInit(CVodeMem cv_mem); + +static int CVDiagSetup(CVodeMem cv_mem, int convfail, N_Vector ypred, + N_Vector fpred, booleantype *jcurPtr, N_Vector vtemp1, + N_Vector vtemp2, N_Vector vtemp3); + +static int CVDiagSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight, + N_Vector ycur, N_Vector fcur); + +static int CVDiagFree(CVodeMem cv_mem); + +/* Readability Replacements */ + +#define lrw1 (cv_mem->cv_lrw1) +#define liw1 (cv_mem->cv_liw1) +#define f (cv_mem->cv_f) +#define uround (cv_mem->cv_uround) +#define tn (cv_mem->cv_tn) +#define h (cv_mem->cv_h) +#define rl1 (cv_mem->cv_rl1) +#define gamma (cv_mem->cv_gamma) +#define ewt (cv_mem->cv_ewt) +#define nfe (cv_mem->cv_nfe) +#define zn (cv_mem->cv_zn) +#define linit (cv_mem->cv_linit) +#define lsetup (cv_mem->cv_lsetup) +#define lsolve (cv_mem->cv_lsolve) +#define lfree (cv_mem->cv_lfree) +#define lmem (cv_mem->cv_lmem) +#define vec_tmpl (cv_mem->cv_tempv) +#define setupNonNull (cv_mem->cv_setupNonNull) + +#define gammasv (cvdiag_mem->di_gammasv) +#define M (cvdiag_mem->di_M) +#define bit (cvdiag_mem->di_bit) +#define bitcomp (cvdiag_mem->di_bitcomp) +#define nfeDI (cvdiag_mem->di_nfeDI) +#define last_flag (cvdiag_mem->di_last_flag) + +/* + * ----------------------------------------------------------------- + * CVDiag + * ----------------------------------------------------------------- + * This routine initializes the memory record and sets various function + * fields specific to the diagonal linear solver module. CVDense first + * calls the existing lfree routine if this is not NULL. Then it sets + * the cv_linit, cv_lsetup, cv_lsolve, cv_lfree fields in (*cvode_mem) + * to be CVDiagInit, CVDiagSetup, CVDiagSolve, and CVDiagFree, + * respectively. It allocates memory for a structure of type + * CVDiagMemRec and sets the cv_lmem field in (*cvode_mem) to the + * address of this structure. It sets setupNonNull in (*cvode_mem) to + * SUNTRUE. Finally, it allocates memory for M, bit, and bitcomp. + * The CVDiag return value is SUCCESS = 0, LMEM_FAIL = -1, or + * LIN_ILL_INPUT=-2. + * ----------------------------------------------------------------- + */ + +int CVDiag(void *cvode_mem) +{ + CVodeMem cv_mem; + CVDiagMem cvdiag_mem; + + /* Return immediately if cvode_mem is NULL */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CVDIAG_MEM_NULL, "CVDIAG", "CVDiag", MSGDG_CVMEM_NULL); + return(CVDIAG_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Check if N_VCompare and N_VInvTest are present */ + if(vec_tmpl->ops->nvcompare == NULL || + vec_tmpl->ops->nvinvtest == NULL) { + cvProcessError(cv_mem, CVDIAG_ILL_INPUT, "CVDIAG", "CVDiag", MSGDG_BAD_NVECTOR); + return(CVDIAG_ILL_INPUT); + } + + if (lfree != NULL) lfree(cv_mem); + + /* Set four main function fields in cv_mem */ + linit = CVDiagInit; + lsetup = CVDiagSetup; + lsolve = CVDiagSolve; + lfree = CVDiagFree; + + /* Get memory for CVDiagMemRec */ + cvdiag_mem = NULL; + cvdiag_mem = (CVDiagMem) malloc(sizeof(CVDiagMemRec)); + if (cvdiag_mem == NULL) { + cvProcessError(cv_mem, CVDIAG_MEM_FAIL, "CVDIAG", "CVDiag", MSGDG_MEM_FAIL); + return(CVDIAG_MEM_FAIL); + } + + last_flag = CVDIAG_SUCCESS; + + + /* Allocate memory for M, bit, and bitcomp */ + + M = N_VClone(vec_tmpl); + if (M == NULL) { + cvProcessError(cv_mem, CVDIAG_MEM_FAIL, "CVDIAG", "CVDiag", MSGDG_MEM_FAIL); + free(cvdiag_mem); cvdiag_mem = NULL; + return(CVDIAG_MEM_FAIL); + } + + bit = N_VClone(vec_tmpl); + if (bit == NULL) { + cvProcessError(cv_mem, CVDIAG_MEM_FAIL, "CVDIAG", "CVDiag", MSGDG_MEM_FAIL); + N_VDestroy(M); + free(cvdiag_mem); cvdiag_mem = NULL; + return(CVDIAG_MEM_FAIL); + } + + bitcomp = N_VClone(vec_tmpl); + if (bitcomp == NULL) { + cvProcessError(cv_mem, CVDIAG_MEM_FAIL, "CVDIAG", "CVDiag", MSGDG_MEM_FAIL); + N_VDestroy(M); + N_VDestroy(bit); + free(cvdiag_mem); cvdiag_mem = NULL; + return(CVDIAG_MEM_FAIL); + } + + /* Attach linear solver memory to integrator memory */ + lmem = cvdiag_mem; + + return(CVDIAG_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * CVDiagGetWorkSpace + * ----------------------------------------------------------------- + */ + +int CVDiagGetWorkSpace(void *cvode_mem, long int *lenrwLS, long int *leniwLS) +{ + CVodeMem cv_mem; + + /* Return immediately if cvode_mem is NULL */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CVDIAG_MEM_NULL, "CVDIAG", "CVDiagGetWorkSpace", MSGDG_CVMEM_NULL); + return(CVDIAG_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + *lenrwLS = 3*lrw1; + *leniwLS = 3*liw1; + + return(CVDIAG_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * CVDiagGetNumRhsEvals + * ----------------------------------------------------------------- + */ + +int CVDiagGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS) +{ + CVodeMem cv_mem; + CVDiagMem cvdiag_mem; + + /* Return immediately if cvode_mem is NULL */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CVDIAG_MEM_NULL, "CVDIAG", "CVDiagGetNumRhsEvals", MSGDG_CVMEM_NULL); + return(CVDIAG_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + if (lmem == NULL) { + cvProcessError(cv_mem, CVDIAG_LMEM_NULL, "CVDIAG", "CVDiagGetNumRhsEvals", MSGDG_LMEM_NULL); + return(CVDIAG_LMEM_NULL); + } + cvdiag_mem = (CVDiagMem) lmem; + + *nfevalsLS = nfeDI; + + return(CVDIAG_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * CVDiagGetLastFlag + * ----------------------------------------------------------------- + */ + +int CVDiagGetLastFlag(void *cvode_mem, long int *flag) +{ + CVodeMem cv_mem; + CVDiagMem cvdiag_mem; + + /* Return immediately if cvode_mem is NULL */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CVDIAG_MEM_NULL, "CVDIAG", "CVDiagGetLastFlag", MSGDG_CVMEM_NULL); + return(CVDIAG_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + if (lmem == NULL) { + cvProcessError(cv_mem, CVDIAG_LMEM_NULL, "CVDIAG", "CVDiagGetLastFlag", MSGDG_LMEM_NULL); + return(CVDIAG_LMEM_NULL); + } + cvdiag_mem = (CVDiagMem) lmem; + + *flag = last_flag; + + return(CVDIAG_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * CVDiagGetReturnFlagName + * ----------------------------------------------------------------- + */ + +char *CVDiagGetReturnFlagName(long int flag) +{ + char *name; + + name = (char *)malloc(30*sizeof(char)); + + switch(flag) { + case CVDIAG_SUCCESS: + sprintf(name,"CVDIAG_SUCCESS"); + break; + case CVDIAG_MEM_NULL: + sprintf(name,"CVDIAG_MEM_NULL"); + break; + case CVDIAG_LMEM_NULL: + sprintf(name,"CVDIAG_LMEM_NULL"); + break; + case CVDIAG_ILL_INPUT: + sprintf(name,"CVDIAG_ILL_INPUT"); + break; + case CVDIAG_MEM_FAIL: + sprintf(name,"CVDIAG_MEM_FAIL"); + break; + case CVDIAG_INV_FAIL: + sprintf(name,"CVDIAG_INV_FAIL"); + break; + case CVDIAG_RHSFUNC_UNRECVR: + sprintf(name,"CVDIAG_RHSFUNC_UNRECVR"); + break; + case CVDIAG_RHSFUNC_RECVR: + sprintf(name,"CVDIAG_RHSFUNC_RECVR"); + break; + default: + sprintf(name,"NONE"); + } + + return(name); +} + +/* + * ----------------------------------------------------------------- + * CVDiagInit + * ----------------------------------------------------------------- + * This routine does remaining initializations specific to the diagonal + * linear solver. + * ----------------------------------------------------------------- + */ + +static int CVDiagInit(CVodeMem cv_mem) +{ + CVDiagMem cvdiag_mem; + + cvdiag_mem = (CVDiagMem) lmem; + + nfeDI = 0; + + last_flag = CVDIAG_SUCCESS; + return(0); +} + +/* + * ----------------------------------------------------------------- + * CVDiagSetup + * ----------------------------------------------------------------- + * This routine does the setup operations for the diagonal linear + * solver. It constructs a diagonal approximation to the Newton matrix + * M = I - gamma*J, updates counters, and inverts M. + * ----------------------------------------------------------------- + */ + +static int CVDiagSetup(CVodeMem cv_mem, int convfail, N_Vector ypred, + N_Vector fpred, booleantype *jcurPtr, N_Vector vtemp1, + N_Vector vtemp2, N_Vector vtemp3) +{ + realtype r; + N_Vector ftemp, y; + booleantype invOK; + CVDiagMem cvdiag_mem; + int retval; + + cvdiag_mem = (CVDiagMem) lmem; + + /* Rename work vectors for use as temporary values of y and f */ + ftemp = vtemp1; + y = vtemp2; + + /* Form y with perturbation = FRACT*(func. iter. correction) */ + r = FRACT * rl1; + N_VLinearSum(h, fpred, -ONE, zn[1], ftemp); + N_VLinearSum(r, ftemp, ONE, ypred, y); + + /* Evaluate f at perturbed y */ + retval = f(tn, y, M, cv_mem->cv_user_data); + nfeDI++; + if (retval < 0) { + cvProcessError(cv_mem, CVDIAG_RHSFUNC_UNRECVR, "CVDIAG", "CVDiagSetup", MSGDG_RHSFUNC_FAILED); + last_flag = CVDIAG_RHSFUNC_UNRECVR; + return(-1); + } + if (retval > 0) { + last_flag = CVDIAG_RHSFUNC_RECVR; + return(1); + } + + /* Construct M = I - gamma*J with J = diag(deltaf_i/deltay_i) */ + N_VLinearSum(ONE, M, -ONE, fpred, M); + N_VLinearSum(FRACT, ftemp, -h, M, M); + N_VProd(ftemp, ewt, y); + /* Protect against deltay_i being at roundoff level */ + N_VCompare(uround, y, bit); + N_VAddConst(bit, -ONE, bitcomp); + N_VProd(ftemp, bit, y); + N_VLinearSum(FRACT, y, -ONE, bitcomp, y); + N_VDiv(M, y, M); + N_VProd(M, bit, M); + N_VLinearSum(ONE, M, -ONE, bitcomp, M); + + /* Invert M with test for zero components */ + invOK = N_VInvTest(M, M); + if (!invOK) { + last_flag = CVDIAG_INV_FAIL; + return(1); + } + + /* Set jcur = SUNTRUE, save gamma in gammasv, and return */ + *jcurPtr = SUNTRUE; + gammasv = gamma; + last_flag = CVDIAG_SUCCESS; + return(0); +} + +/* + * ----------------------------------------------------------------- + * CVDiagSolve + * ----------------------------------------------------------------- + * This routine performs the solve operation for the diagonal linear + * solver. If necessary it first updates gamma in M = I - gamma*J. + * ----------------------------------------------------------------- + */ + +static int CVDiagSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight, + N_Vector ycur, N_Vector fcur) +{ + booleantype invOK; + realtype r; + CVDiagMem cvdiag_mem; + + cvdiag_mem = (CVDiagMem) lmem; + + /* If gamma has changed, update factor in M, and save gamma value */ + + if (gammasv != gamma) { + r = gamma / gammasv; + N_VInv(M, M); + N_VAddConst(M, -ONE, M); + N_VScale(r, M, M); + N_VAddConst(M, ONE, M); + invOK = N_VInvTest(M, M); + if (!invOK) { + last_flag = CVDIAG_INV_FAIL; + return (1); + } + gammasv = gamma; + } + + /* Apply M-inverse to b */ + N_VProd(b, M, b); + + last_flag = CVDIAG_SUCCESS; + return(0); +} + +/* + * ----------------------------------------------------------------- + * CVDiagFree + * ----------------------------------------------------------------- + * This routine frees memory specific to the diagonal linear solver. + * ----------------------------------------------------------------- + */ + +static int CVDiagFree(CVodeMem cv_mem) +{ + CVDiagMem cvdiag_mem; + + cvdiag_mem = (CVDiagMem) lmem; + + N_VDestroy(M); + N_VDestroy(bit); + N_VDestroy(bitcomp); + free(cvdiag_mem); + cv_mem->cv_lmem = NULL; + + return(0); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_diag_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_diag_impl.h new file mode 100644 index 0000000..2d1333a --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_diag_impl.h @@ -0,0 +1,68 @@ +/* + * ----------------------------------------------------------------- + * 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 + * ----------------------------------------------------------------- + * Implementation header file for the diagonal linear solver, CVDIAG. + * ----------------------------------------------------------------- + */ + +#ifndef _CVDIAG_IMPL_H +#define _CVDIAG_IMPL_H + +#include <cvode/cvode_diag.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* + * ----------------------------------------------------------------- + * Types: CVDiagMemRec, CVDiagMem + * ----------------------------------------------------------------- + * The type CVDiagMem is pointer to a CVDiagMemRec. + * This structure contains CVDiag solver-specific data. + * ----------------------------------------------------------------- + */ + +typedef struct { + + realtype di_gammasv; /* gammasv = gamma at the last call to setup */ + /* or solve */ + + N_Vector di_M; /* M = (I - gamma J)^{-1} , gamma = h / l1 */ + + N_Vector di_bit; /* temporary storage vector */ + + N_Vector di_bitcomp; /* temporary storage vector */ + + long int di_nfeDI; /* no. of calls to f due to difference + quotient diagonal Jacobian approximation */ + + long int di_last_flag; /* last error return flag */ + +} CVDiagMemRec, *CVDiagMem; + +/* Error Messages */ + +#define MSGDG_CVMEM_NULL "Integrator memory is NULL." +#define MSGDG_BAD_NVECTOR "A required vector operation is not implemented." +#define MSGDG_MEM_FAIL "A memory request failed." +#define MSGDG_LMEM_NULL "CVDIAG memory is NULL." +#define MSGDG_RHSFUNC_FAILED "The right-hand side routine failed in an unrecoverable manner." + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_direct.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_direct.c new file mode 100644 index 0000000..44f6946 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_direct.c @@ -0,0 +1,55 @@ +/*----------------------------------------------------------------- + * Programmer(s): 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 + *----------------------------------------------------------------- + * 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. + *-----------------------------------------------------------------*/ + +#include <cvode/cvode_ls.h> +#include <cvode/cvode_direct.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*================================================================= + Exported Functions (wrappers for equivalent routines in cvode_ls.h) + =================================================================*/ + +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)); } + +char *CVDlsGetReturnFlagName(long int flag) +{ return(CVodeGetLinReturnFlagName(flag)); } + + +#ifdef __cplusplus +} +#endif + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_impl.h new file mode 100644 index 0000000..42881de --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_impl.h @@ -0,0 +1,556 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * Scott D. Cohen, Alan C. Hindmarsh, Radu Serban + * and Dan Shumaker @ 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 main CVODE integrator. + * ----------------------------------------------------------------- + */ + +#ifndef _CVODE_IMPL_H +#define _CVODE_IMPL_H + +#include <stdarg.h> +#include <cvode/cvode.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +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 + * ================================================================= + */ + +/* Basic CVODE constants */ + +#define ADAMS_Q_MAX 12 /* max value of q for lmm == ADAMS */ +#define BDF_Q_MAX 5 /* max value of q for lmm == BDF */ +#define Q_MAX ADAMS_Q_MAX /* max value of q for either lmm */ +#define L_MAX (Q_MAX+1) /* max value of L for either lmm */ +#define NUM_TESTS 5 /* number of error test quantities */ + +#define HMIN_DEFAULT RCONST(0.0) /* hmin default value */ +#define HMAX_INV_DEFAULT RCONST(0.0) /* hmax_inv default value */ +#define MXHNIL_DEFAULT 10 /* mxhnil default value */ +#define MXSTEP_DEFAULT 500 /* mxstep default value */ + +/* Return values for lower level routines used by CVode and functions + provided to the nonlinear solver */ + +#define RHSFUNC_RECVR +9 + +/* + * ----------------------------------------------------------------- + * Types : struct CVodeMemRec, CVodeMem + * ----------------------------------------------------------------- + * The type CVodeMem is type pointer to struct CVodeMemRec. + * This structure contains fields to keep track of problem state. + * ----------------------------------------------------------------- + */ + +typedef struct CVodeMemRec { + + realtype cv_uround; /* machine unit roundoff */ + + /*-------------------------- + Problem Specification Data + --------------------------*/ + + CVRhsFn cv_f; /* y' = f(t,y(t)) */ + void *cv_user_data; /* user pointer passed to f */ + int cv_lmm; /* lmm = CV_ADAMS or CV_BDF */ + int cv_itol; /* itol = CV_SS, CV_SV, CV_WF, CV_NN */ + + realtype cv_reltol; /* relative tolerance */ + realtype cv_Sabstol; /* scalar absolute tolerance */ + N_Vector cv_Vabstol; /* vector absolute tolerance */ + 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 */ + + booleantype cv_constraintsSet; /* constraints vector present: + do constraints calc */ + + /*----------------------- + 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 * (jth + derivative of the interpolating polynomial */ + + /*-------------------------- + other 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 + 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). On return, + this vector is scaled to give the est. local err. */ + N_Vector cv_tempv; /* temporary storage vector */ + N_Vector cv_ftemp; /* temporary storage vector */ + N_Vector cv_vtemp1; /* temporary storage vector */ + 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 */ + + /*----------------- + Tstop information + -----------------*/ + + booleantype cv_tstopset; + realtype cv_tstop; + + /*--------- + Step Data + ---------*/ + + int cv_q; /* current order */ + int cv_qprime; /* order to be used on the next step + = q-1, q, or q+1 */ + int cv_next_q; /* order to be used on the next step */ + int cv_qwait; /* number of internal steps to wait before + considering a change in q */ + int cv_L; /* L = q + 1 */ + + realtype cv_hin; /* initial step size */ + 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_eta; /* eta = hprime / h */ + realtype cv_hscale; /* value of h used in zn */ + realtype cv_tn; /* current internal value of t */ + realtype cv_tretlast; /* value of tret last returned by CVode */ + + realtype cv_tau[L_MAX+1]; /* array of previous q+1 successful step + sizes indexed from 1 to q+1 */ + realtype cv_tq[NUM_TESTS+1]; /* array of test quantities indexed from + 1 to NUM_TESTS(=5) */ + realtype cv_l[L_MAX]; /* coefficients of l(x) (degree q poly) */ + + realtype cv_rl1; /* the scalar 1/l[1] */ + realtype cv_gamma; /* gamma = h * rl1 */ + realtype cv_gammap; /* gamma at the last setup call */ + realtype cv_gamrat; /* gamma / gammap */ + + realtype cv_crate; /* estimated corrector convergence rate */ + realtype cv_delp; /* norm of previous nonlinear solver update */ + realtype cv_acnrm; /* | acor | wrms */ + realtype cv_nlscoef; /* coeficient in nonlinear convergence test */ + + /*------ + Limits + ------*/ + + int cv_qmax; /* q <= qmax */ + long int cv_mxstep; /* maximum number of internal steps for one user call */ + int cv_maxcor; /* maximum number of corrector iterations for the + solution of the nonlinear equation */ + int cv_mxhnil; /* maximum 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 convergence failures */ + + realtype cv_hmin; /* |h| >= hmin */ + realtype cv_hmax_inv; /* |h| <= 1/hmax_inv */ + realtype cv_etamax; /* eta <= etamax */ + + /*-------- + Counters + --------*/ + + long int cv_nst; /* number of internal steps taken */ + long int cv_nfe; /* number of f calls */ + long int cv_ncfn; /* number of corrector convergence failures */ + long int cv_netf; /* number of error test failures */ + long int cv_nni; /* number of Newton iterations performed */ + long int cv_nsetups; /* number of setup calls */ + int cv_nhnil; /* number of messages issued to the user that + t + h == t for the next iternal step */ + + realtype cv_etaqm1; /* ratio of new to old h for order q-1 */ + realtype cv_etaq; /* ratio of new to old h for order q */ + realtype cv_etaqp1; /* ratio of new to old h for order q+1 */ + + /*---------------------------- + Space requirements for CVODE + ----------------------------*/ + + sunindextype cv_lrw1; /* no. of realtype words in 1 N_Vector */ + sunindextype cv_liw1; /* no. of integer words in 1 N_Vector */ + long int cv_lrw; /* no. of realtype words in CVODE work vectors */ + long int cv_liw; /* no. of integer words in CVODE work vectors */ + + /*--------------------- + Nonlinear Solver Data + ---------------------*/ + + SUNNonlinearSolver NLS; /* Sundials generic nonlinear solver object */ + booleantype ownNLS; /* flag indicating if CVODE created the nonlinear + solver object */ + int convfail; /* flag to indicate when a Jacbian update may + be needed */ + + /*------------------ + Linear Solver Data + ------------------*/ + + /* Linear Solver functions to be called */ + + 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_lsolve)(struct CVodeMemRec *cv_mem, N_Vector b, N_Vector weight, + N_Vector ycur, N_Vector fcur); + + int (*cv_lfree)(struct CVodeMemRec *cv_mem); + + /* Linear Solver specific memory */ + + void *cv_lmem; + + /*------------ + Saved Values + ------------*/ + + int cv_qu; /* last successful q value used */ + long int cv_nstlp; /* step number of last setup call */ + realtype cv_h0u; /* actual initial stepsize */ + realtype cv_hu; /* last successful h value used */ + realtype cv_saved_tq5; /* saved value of tq[5] */ + booleantype cv_jcur; /* is Jacobian info. for lin. solver current? */ + realtype cv_tolsf; /* tolerance scale factor */ + int cv_qmax_alloc; /* value of qmax used when allocating memory */ + int cv_indx_acor; /* index of the zn vector with saved acor */ + + booleantype cv_VabstolMallocDone; + booleantype cv_MallocDone; + booleantype cv_constraintsMallocDone; + + /*------------------------------------------- + Error handler function and error ouput file + -------------------------------------------*/ + + CVErrHandlerFn cv_ehfun; /* error messages are handled by ehfun */ + void *cv_eh_data; /* data pointer passed to ehfun */ + FILE *cv_errfp; /* CVODE error messages are sent to errfp */ + + /*------------------------- + Stability Limit Detection + -------------------------*/ + + booleantype cv_sldeton; /* is Stability Limit Detection on? */ + realtype cv_ssdat[6][4]; /* scaled data array for STALD */ + int cv_nscon; /* counter for STALD method */ + long int cv_nor; /* counter for number of order reductions */ + + /*---------------- + Rootfinding Data + ----------------*/ + + CVRootFn cv_gfun; /* function g for roots sought */ + int cv_nrtfn; /* number of components of g */ + int *cv_iroots; /* array for root information */ + int *cv_rootdir; /* array specifying direction of zero-crossing */ + realtype cv_tlo; /* nearest endpoint of interval in root search */ + realtype cv_thi; /* farthest endpoint of interval in root search */ + realtype cv_trout; /* t value returned by rootfinding routine */ + realtype *cv_glo; /* saved array of g values at t = tlo */ + realtype *cv_ghi; /* saved array of g values at t = thi */ + realtype *cv_grout; /* array of g values at t = trout */ + realtype cv_toutc; /* copy of tout (if NORMAL mode) */ + realtype cv_ttol; /* tolerance on root location */ + int cv_taskc; /* copy of parameter itask */ + int cv_irfnd; /* flag showing whether last step had a root */ + long int cv_nge; /* counter for g evaluations */ + booleantype *cv_gactive; /* array with active/inactive event functions */ + int cv_mxgnull; /* number of warning messages about possible g==0 */ + + /*----------------------- + Fused Vector Operations + -----------------------*/ + + realtype cv_cvals[L_MAX]; /* array of scalars */ + N_Vector cv_Xvecs[L_MAX]; /* array of vectors */ + +} *CVodeMem; + +/* + * ================================================================= + * I N T E R F A C E T O L I N E A R S O L V E R S + * ================================================================= + */ + +/* + * ----------------------------------------------------------------- + * Communication between CVODE and a CVODE Linear Solver + * ----------------------------------------------------------------- + * convfail (input to cv_lsetup) + * + * CV_NO_FAILURES : Either this is the first cv_setup call for this + * step, or the local error test failed on the + * previous attempt at this step (but the Newton + * iteration converged). + * + * CV_FAIL_BAD_J : This value is passed to cv_lsetup if + * + * (a) The previous Newton corrector iteration + * did not converge and the linear solver's + * setup routine indicated that its Jacobian- + * related data is not current + * or + * (b) During the previous Newton corrector + * iteration, the linear solver's solve routine + * failed in a recoverable manner and the + * linear solver's setup routine indicated that + * its Jacobian-related data is not current. + * + * CV_FAIL_OTHER : During the current internal step try, the + * previous Newton iteration failed to converge + * even though the linear solver was using current + * Jacobian-related data. + * ----------------------------------------------------------------- + */ + +/* Constants for convfail (input to cv_lsetup) */ + +#define CV_NO_FAILURES 0 +#define CV_FAIL_BAD_J 1 +#define CV_FAIL_OTHER 2 + +/* + * ----------------------------------------------------------------- + * int (*cv_linit)(CVodeMem cv_mem); + * ----------------------------------------------------------------- + * The purpose of cv_linit is to complete initializations for a + * specific linear solver, such as counters and statistics. + * An LInitFn should return 0 if it has successfully initialized the + * CVODE linear solver and a negative value otherwise. + * If an error does occur, an appropriate message should be sent to + * the error handler function. + * ----------------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------- + * int (*cv_lsetup)(CVodeMem cv_mem, int convfail, N_Vector ypred, + * N_Vector fpred, booleantype *jcurPtr, + * N_Vector vtemp1, N_Vector vtemp2, + * N_Vector vtemp3); + * ----------------------------------------------------------------- + * The job of cv_lsetup is to prepare the linear solver for + * subsequent calls to cv_lsolve. It may recompute Jacobian- + * related data is it deems necessary. Its parameters are as + * follows: + * + * cv_mem - problem memory pointer of type CVodeMem. See the + * typedef earlier in this file. + * + * convfail - a flag to indicate any problem that occurred during + * the solution of the nonlinear equation on the + * current time step for which the linear solver is + * being used. This flag can be used to help decide + * whether the Jacobian data kept by a CVODE linear + * solver needs to be updated or not. + * Its possible values have been documented above. + * + * ypred - the predicted y vector for the current CVODE internal + * step. + * + * fpred - f(tn, ypred). + * + * jcurPtr - a pointer to a boolean to be filled in by cv_lsetup. + * The function should set *jcurPtr=SUNTRUE if its Jacobian + * data is current after the call and should set + * *jcurPtr=SUNFALSE if its Jacobian data is not current. + * Note: If cv_lsetup calls for re-evaluation of + * Jacobian data (based on convfail and CVODE state + * data), it should return *jcurPtr=SUNTRUE always; + * otherwise an infinite loop can result. + * + * vtemp1 - temporary N_Vector provided for use by cv_lsetup. + * + * vtemp3 - temporary N_Vector provided for use by cv_lsetup. + * + * vtemp3 - temporary N_Vector provided for use by cv_lsetup. + * + * The cv_lsetup routine should return 0 if successful, a positive + * value for a recoverable error, and a negative value for an + * unrecoverable error. + * ----------------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------- + * int (*cv_lsolve)(CVodeMem cv_mem, N_Vector b, N_Vector weight, + * N_Vector ycur, N_Vector fcur); + * ----------------------------------------------------------------- + * cv_lsolve must solve the linear equation P x = b, where + * P is some approximation to (I - gamma J), J = (df/dy)(tn,ycur) + * and the RHS vector b is input. The N-vector ycur contains + * the solver's current approximation to y(tn) and the vector + * fcur contains the N_Vector f(tn,ycur). The solution is to be + * returned in the vector b. cv_lsolve returns a positive value + * for a recoverable error and a negative value for an + * unrecoverable error. Success is indicated by a 0 return value. + * ----------------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------- + * int (*cv_lfree)(CVodeMem cv_mem); + * ----------------------------------------------------------------- + * 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 + * return 0 upon success, nonzero on failure. + * ----------------------------------------------------------------- + */ + +/* + * ================================================================= + * C V O D E I N T E R N A L F U N C T I O N S + * ================================================================= + */ + +/* Prototype of internal ewtSet function */ + +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, + const char *msgfmt, ...); + +/* Prototype of internal ErrHandler function */ + +void cvErrHandler(int error_code, const char *module, const char *function, + char *msg, void *data); + +/* Nonlinear solver initializtion function */ + +int cvNlsInit(CVodeMem cv_mem); + +/* + * ================================================================= + * C V O D E E R R O R M E S S A G E S + * ================================================================= + */ + +#if defined(SUNDIALS_EXTENDED_PRECISION) + +#define MSG_TIME "t = %Lg" +#define MSG_TIME_H "t = %Lg and h = %Lg" +#define MSG_TIME_INT "t = %Lg is not between tcur - hu = %Lg and tcur = %Lg." +#define MSG_TIME_TOUT "tout = %Lg" +#define MSG_TIME_TSTOP "tstop = %Lg" + +#elif defined(SUNDIALS_DOUBLE_PRECISION) + +#define MSG_TIME "t = %lg" +#define MSG_TIME_H "t = %lg and h = %lg" +#define MSG_TIME_INT "t = %lg is not between tcur - hu = %lg and tcur = %lg." +#define MSG_TIME_TOUT "tout = %lg" +#define MSG_TIME_TSTOP "tstop = %lg" + +#else + +#define MSG_TIME "t = %g" +#define MSG_TIME_H "t = %g and h = %g" +#define MSG_TIME_INT "t = %g is not between tcur - hu = %g and tcur = %g." +#define MSG_TIME_TOUT "tout = %g" +#define MSG_TIME_TSTOP "tstop = %g" + +#endif + +/* Initialization and I/O error messages */ + +#define MSGCV_NO_MEM "cvode_mem = NULL illegal." +#define MSGCV_CVMEM_FAIL "Allocation of cvode_mem failed." +#define MSGCV_MEM_FAIL "A memory request failed." +#define MSGCV_BAD_LMM "Illegal value for lmm. The legal values are CV_ADAMS and CV_BDF." +#define MSGCV_NO_MALLOC "Attempt to call before CVodeInit." +#define MSGCV_NEG_MAXORD "maxord <= 0 illegal." +#define MSGCV_BAD_MAXORD "Illegal attempt to increase maximum method order." +#define MSGCV_SET_SLDET "Attempt to use stability limit detection with the CV_ADAMS method illegal." +#define MSGCV_NEG_HMIN "hmin < 0 illegal." +#define MSGCV_NEG_HMAX "hmax < 0 illegal." +#define MSGCV_BAD_HMIN_HMAX "Inconsistent step size limits: hmin > hmax." +#define MSGCV_BAD_RELTOL "reltol < 0 illegal." +#define MSGCV_BAD_ABSTOL "abstol has negative component(s) (illegal)." +#define MSGCV_NULL_ABSTOL "abstol = NULL illegal." +#define MSGCV_NULL_Y0 "y0 = NULL illegal." +#define MSGCV_Y0_FAIL_CONSTR "y0 fails to satisfy constraints." +#define MSGCV_NULL_F "f = NULL illegal." +#define MSGCV_NULL_G "g = NULL illegal." +#define MSGCV_BAD_NVECTOR "A required vector operation is not implemented." +#define MSGCV_BAD_CONSTR "Illegal values in constraints vector." +#define MSGCV_BAD_K "Illegal value for k." +#define MSGCV_NULL_DKY "dky = NULL illegal." +#define MSGCV_BAD_T "Illegal value for t." MSG_TIME_INT +#define MSGCV_NO_ROOT "Rootfinding was not initialized." +#define MSGCV_NLS_INIT_FAIL "The nonlinear solver's init routine failed." + +/* CVode Error Messages */ + +#define MSGCV_NO_TOLS "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." +#define MSGCV_BAD_EWT "Initial ewt has component(s) equal to zero (illegal)." +#define MSGCV_EWT_NOW_BAD "At " MSG_TIME ", a component of ewt has become <= 0." +#define MSGCV_BAD_ITASK "Illegal value for itask." +#define MSGCV_BAD_H0 "h0 and tout - t0 inconsistent." +#define MSGCV_BAD_TOUT "Trouble interpolating at " MSG_TIME_TOUT ". tout too far back in direction of integration" +#define MSGCV_EWT_FAIL "The user-provide EwtSet function failed." +#define MSGCV_EWT_NOW_FAIL "At " MSG_TIME ", the user-provide EwtSet function failed." +#define MSGCV_LINIT_FAIL "The linear solver's init routine failed." +#define MSGCV_HNIL_DONE "The above warning has been issued mxhnil times and will not be issued again for this problem." +#define MSGCV_TOO_CLOSE "tout too close to t0 to start integration." +#define MSGCV_MAX_STEPS "At " MSG_TIME ", mxstep steps taken before reaching tout." +#define MSGCV_TOO_MUCH_ACC "At " MSG_TIME ", too much accuracy requested." +#define MSGCV_HNIL "Internal " MSG_TIME_H " are such that t + h = t on the next step. The solver will continue anyway." +#define MSGCV_ERR_FAILS "At " MSG_TIME_H ", the error test failed repeatedly or with |h| = hmin." +#define MSGCV_CONV_FAILS "At " MSG_TIME_H ", the corrector convergence test failed repeatedly or with |h| = hmin." +#define MSGCV_SETUP_FAILED "At " MSG_TIME ", the setup routine failed in an unrecoverable manner." +#define MSGCV_SOLVE_FAILED "At " MSG_TIME ", the solve routine failed in an unrecoverable manner." +#define MSGCV_FAILED_CONSTR "At " MSG_TIME ", unable to satisfy inequality constraints." +#define MSGCV_RHSFUNC_FAILED "At " MSG_TIME ", the right-hand side routine failed in an unrecoverable manner." +#define MSGCV_RHSFUNC_UNREC "At " MSG_TIME ", the right-hand side failed in a recoverable manner, but no recovery is possible." +#define MSGCV_RHSFUNC_REPTD "At " MSG_TIME " repeated recoverable right-hand side function errors." +#define MSGCV_RHSFUNC_FIRST "The right-hand side routine failed at the first call." +#define MSGCV_RTFUNC_FAILED "At " MSG_TIME ", the rootfinding routine failed in an unrecoverable manner." +#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." + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_io.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_io.c new file mode 100644 index 0000000..48d4c02 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_io.c @@ -0,0 +1,1155 @@ +/* + * ----------------------------------------------------------------- + * $Revision$ + * $Date$ + * ----------------------------------------------------------------- + * Programmer(s): 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 optional input and output + * functions for the CVODE solver. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "cvode_impl.h" +#include <sundials/sundials_types.h> + +#define ZERO RCONST(0.0) +#define HALF RCONST(0.5) +#define ONE RCONST(1.0) +#define TWOPT5 RCONST(2.5) + +/* + * ================================================================= + * CVODE optional input functions + * ================================================================= + */ + +/* + * CVodeSetErrHandlerFn + * + * Specifies the error handler function + */ + +int CVodeSetErrHandlerFn(void *cvode_mem, CVErrHandlerFn ehfun, void *eh_data) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSetErrHandlerFn", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + cv_mem->cv_ehfun = ehfun; + cv_mem->cv_eh_data = eh_data; + + return(CV_SUCCESS); +} + +/* + * CVodeSetErrFile + * + * Specifies the FILE pointer for output (NULL means no messages) + */ + +int CVodeSetErrFile(void *cvode_mem, FILE *errfp) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSetErrFile", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + cv_mem->cv_errfp = errfp; + + return(CV_SUCCESS); +} + +/* + * CVodeSetUserData + * + * Specifies the user data pointer for f + */ + +int CVodeSetUserData(void *cvode_mem, void *user_data) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSetUserData", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + cv_mem->cv_user_data = user_data; + + return(CV_SUCCESS); +} + +/* + * CVodeSetMaxOrd + * + * Specifies the maximum method order + */ + +int CVodeSetMaxOrd(void *cvode_mem, int maxord) +{ + CVodeMem cv_mem; + int qmax_alloc; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSetMaxOrd", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + if (maxord <= 0) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "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; + + if (maxord > qmax_alloc) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSetMaxOrd", MSGCV_BAD_MAXORD); + return(CV_ILL_INPUT); + } + + cv_mem->cv_qmax = maxord; + + return(CV_SUCCESS); +} + +/* + * CVodeSetMaxNumSteps + * + * Specifies the maximum number of integration steps + */ + +int CVodeSetMaxNumSteps(void *cvode_mem, long int mxsteps) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSetMaxNumSteps", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + /* Passing mxsteps=0 sets the default. Passing mxsteps<0 disables the test. */ + + if (mxsteps == 0) + cv_mem->cv_mxstep = MXSTEP_DEFAULT; + else + cv_mem->cv_mxstep = mxsteps; + + return(CV_SUCCESS); +} + +/* + * CVodeSetMaxHnilWarns + * + * Specifies the maximum number of warnings for small h + */ + +int CVodeSetMaxHnilWarns(void *cvode_mem, int mxhnil) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSetMaxHnilWarns", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + cv_mem->cv_mxhnil = mxhnil; + + return(CV_SUCCESS); +} + +/* + *CVodeSetStabLimDet + * + * Turns on/off the stability limit detection algorithm + */ + +int CVodeSetStabLimDet(void *cvode_mem, booleantype sldet) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSetStabLimDet", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + if( sldet && (cv_mem->cv_lmm != CV_BDF) ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSetStabLimDet", MSGCV_SET_SLDET); + return(CV_ILL_INPUT); + } + + cv_mem->cv_sldeton = sldet; + + return(CV_SUCCESS); +} + +/* + * CVodeSetInitStep + * + * Specifies the initial step size + */ + +int CVodeSetInitStep(void *cvode_mem, realtype hin) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSetInitStep", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + cv_mem->cv_hin = hin; + + return(CV_SUCCESS); +} + +/* + * CVodeSetMinStep + * + * Specifies the minimum step size + */ + +int CVodeSetMinStep(void *cvode_mem, realtype hmin) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSetMinStep", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + if (hmin<0) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSetMinStep", MSGCV_NEG_HMIN); + return(CV_ILL_INPUT); + } + + /* Passing 0 sets hmin = zero */ + if (hmin == ZERO) { + cv_mem->cv_hmin = HMIN_DEFAULT; + return(CV_SUCCESS); + } + + if (hmin * cv_mem->cv_hmax_inv > ONE) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSetMinStep", MSGCV_BAD_HMIN_HMAX); + return(CV_ILL_INPUT); + } + + cv_mem->cv_hmin = hmin; + + return(CV_SUCCESS); +} + +/* + * CVodeSetMaxStep + * + * Specifies the maximum step size + */ + +int CVodeSetMaxStep(void *cvode_mem, realtype hmax) +{ + realtype hmax_inv; + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSetMaxStep", MSGCV_NO_MEM); + return (CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + if (hmax < 0) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSetMaxStep", MSGCV_NEG_HMAX); + return(CV_ILL_INPUT); + } + + /* Passing 0 sets hmax = infinity */ + if (hmax == ZERO) { + cv_mem->cv_hmax_inv = HMAX_INV_DEFAULT; + return(CV_SUCCESS); + } + + hmax_inv = ONE/hmax; + if (hmax_inv * cv_mem->cv_hmin > ONE) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSetMaxStep", MSGCV_BAD_HMIN_HMAX); + return(CV_ILL_INPUT); + } + + cv_mem->cv_hmax_inv = hmax_inv; + + return(CV_SUCCESS); +} + +/* + * CVodeSetStopTime + * + * Specifies the time beyond which the integration is not to proceed. + */ + +int CVodeSetStopTime(void *cvode_mem, realtype tstop) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSetStopTime", MSGCV_NO_MEM); + return (CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* If CVode was called at least once, test if tstop is legal + * (i.e. if it was not already passed). + * If CVodeSetStopTime is called before the first call to CVode, + * tstop will be checked in CVode. */ + if (cv_mem->cv_nst > 0) { + + if ( (tstop - cv_mem->cv_tn) * cv_mem->cv_h < ZERO ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSetStopTime", MSGCV_BAD_TSTOP, tstop, cv_mem->cv_tn); + return(CV_ILL_INPUT); + } + + } + + cv_mem->cv_tstop = tstop; + cv_mem->cv_tstopset = SUNTRUE; + + return(CV_SUCCESS); +} + +/* + * CVodeSetMaxErrTestFails + * + * Specifies the maximum number of error test failures during one + * step try. + */ + +int CVodeSetMaxErrTestFails(void *cvode_mem, int maxnef) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSetMaxErrTestFails", MSGCV_NO_MEM); + return (CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + cv_mem->cv_maxnef = maxnef; + + return(CV_SUCCESS); +} + +/* + * CVodeSetMaxConvFails + * + * Specifies the maximum number of nonlinear convergence failures + * during one step try. + */ + +int CVodeSetMaxConvFails(void *cvode_mem, int maxncf) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSetMaxConvFails", MSGCV_NO_MEM); + return (CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + cv_mem->cv_maxncf = maxncf; + + return(CV_SUCCESS); +} + +/* + * CVodeSetMaxNonlinIters + * + * Specifies the maximum number of nonlinear iterations during + * one solve. + */ + +int CVodeSetMaxNonlinIters(void *cvode_mem, int maxcor) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSetMaxNonlinIters", MSGCV_NO_MEM); + return (CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + if (cv_mem->NLS == NULL) { + cvProcessError(NULL, CV_MEM_FAIL, "CVODE", "CVodeSetMaxNonlinIters", MSGCV_MEM_FAIL); + return (CV_MEM_FAIL); + } + + return(SUNNonlinSolSetMaxIters(cv_mem->NLS, maxcor)); +} + +/* + * CVodeSetNonlinConvCoef + * + * Specifies the coeficient in the nonlinear solver convergence + * test + */ + +int CVodeSetNonlinConvCoef(void *cvode_mem, realtype nlscoef) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSetNonlinConvCoef", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + cv_mem->cv_nlscoef = nlscoef; + + return(CV_SUCCESS); +} + +/* + * CVodeSetRootDirection + * + * Specifies the direction of zero-crossings to be monitored. + * The default is to monitor both crossings. + */ + +int CVodeSetRootDirection(void *cvode_mem, int *rootdir) +{ + CVodeMem cv_mem; + int i, nrt; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSetRootDirection", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + nrt = cv_mem->cv_nrtfn; + if (nrt==0) { + cvProcessError(NULL, CV_ILL_INPUT, "CVODE", "CVodeSetRootDirection", MSGCV_NO_ROOT); + return(CV_ILL_INPUT); + } + + for(i=0; i<nrt; i++) cv_mem->cv_rootdir[i] = rootdir[i]; + + return(CV_SUCCESS); +} + +/* + * CVodeSetNoInactiveRootWarn + * + * Disables issuing a warning if some root function appears + * to be identically zero at the beginning of the integration + */ + +int CVodeSetNoInactiveRootWarn(void *cvode_mem) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSetNoInactiveRootWarn", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + cv_mem->cv_mxgnull = 0; + + return(CV_SUCCESS); +} + +/* + * CVodeSetConstraints + * + * Setup for constraint handling feature + */ + +int CVodeSetConstraints(void *cvode_mem, N_Vector constraints) +{ + CVodeMem cv_mem; + realtype temptest; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSetConstraints", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + /* If there are no constraints, destroy data structures */ + if (constraints == NULL) { + if (cv_mem->cv_constraintsMallocDone) { + N_VDestroy(cv_mem->cv_constraints); + cv_mem->cv_lrw -= cv_mem->cv_lrw1; + cv_mem->cv_liw -= cv_mem->cv_liw1; + } + cv_mem->cv_constraintsMallocDone = SUNFALSE; + cv_mem->cv_constraintsSet = SUNFALSE; + return(CV_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) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSetConstraints", MSGCV_BAD_NVECTOR); + return(CV_ILL_INPUT); + } + + /* Check the constraints vector */ + temptest = N_VMaxNorm(constraints); + if ((temptest > TWOPT5) || (temptest < HALF)) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSetConstraints", MSGCV_BAD_CONSTR); + return(CV_ILL_INPUT); + } + + if ( !(cv_mem->cv_constraintsMallocDone) ) { + cv_mem->cv_constraints = N_VClone(constraints); + cv_mem->cv_lrw += cv_mem->cv_lrw1; + cv_mem->cv_liw += cv_mem->cv_liw1; + cv_mem->cv_constraintsMallocDone = SUNTRUE; + } + + /* Load the constraints vector */ + N_VScale(ONE, constraints, cv_mem->cv_constraints); + + cv_mem->cv_constraintsSet = SUNTRUE; + + return(CV_SUCCESS); +} + +/* + * ================================================================= + * CVODE optional output functions + * ================================================================= + */ + +/* + * CVodeGetNumSteps + * + * Returns the current number of integration steps + */ + +int CVodeGetNumSteps(void *cvode_mem, long int *nsteps) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetNumSteps", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *nsteps = cv_mem->cv_nst; + + return(CV_SUCCESS); +} + +/* + * CVodeGetNumRhsEvals + * + * Returns the current number of calls to f + */ + +int CVodeGetNumRhsEvals(void *cvode_mem, long int *nfevals) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetNumRhsEvals", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *nfevals = cv_mem->cv_nfe; + + return(CV_SUCCESS); +} + +/* + * CVodeGetNumLinSolvSetups + * + * Returns the current number of calls to the linear solver setup routine + */ + +int CVodeGetNumLinSolvSetups(void *cvode_mem, long int *nlinsetups) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetNumLinSolvSetups", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *nlinsetups = cv_mem->cv_nsetups; + + return(CV_SUCCESS); +} + +/* + * CVodeGetNumErrTestFails + * + * Returns the current number of error test failures + */ + +int CVodeGetNumErrTestFails(void *cvode_mem, long int *netfails) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetNumErrTestFails", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *netfails = cv_mem->cv_netf; + + return(CV_SUCCESS); +} + +/* + * CVodeGetLastOrder + * + * Returns the order on the last succesful step + */ + +int CVodeGetLastOrder(void *cvode_mem, int *qlast) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetLastOrder", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *qlast = cv_mem->cv_qu; + + return(CV_SUCCESS); +} + +/* + * CVodeGetCurrentOrder + * + * Returns the order to be attempted on the next step + */ + +int CVodeGetCurrentOrder(void *cvode_mem, int *qcur) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetCurrentOrder", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *qcur = cv_mem->cv_next_q; + + return(CV_SUCCESS); +} + +/* + * CVodeGetNumStabLimOrderReds + * + * Returns the number of order reductions triggered by the stability + * limit detection algorithm + */ + +int CVodeGetNumStabLimOrderReds(void *cvode_mem, long int *nslred) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetNumStabLimOrderReds", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + if (cv_mem->cv_sldeton==SUNFALSE) + *nslred = 0; + else + *nslred = cv_mem->cv_nor; + + return(CV_SUCCESS); +} + +/* + * CVodeGetActualInitStep + * + * Returns the step size used on the first step + */ + +int CVodeGetActualInitStep(void *cvode_mem, realtype *hinused) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetActualInitStep", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *hinused = cv_mem->cv_h0u; + + return(CV_SUCCESS); +} + +/* + * CVodeGetLastStep + * + * Returns the step size used on the last successful step + */ + +int CVodeGetLastStep(void *cvode_mem, realtype *hlast) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetLastStep", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *hlast = cv_mem->cv_hu; + + return(CV_SUCCESS); +} + +/* + * CVodeGetCurrentStep + * + * Returns the step size to be attempted on the next step + */ + +int CVodeGetCurrentStep(void *cvode_mem, realtype *hcur) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetCurrentStep", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *hcur = cv_mem->cv_next_h; + + return(CV_SUCCESS); +} + +/* + * CVodeGetCurrentTime + * + * Returns the current value of the independent variable + */ + +int CVodeGetCurrentTime(void *cvode_mem, realtype *tcur) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetCurrentTime", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *tcur = cv_mem->cv_tn; + + return(CV_SUCCESS); +} + +/* + * CVodeGetTolScaleFactor + * + * Returns a suggested factor for scaling tolerances + */ + +int CVodeGetTolScaleFactor(void *cvode_mem, realtype *tolsfact) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetTolScaleFactor", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *tolsfact = cv_mem->cv_tolsf; + + return(CV_SUCCESS); +} + +/* + * CVodeGetErrWeights + * + * This routine returns the current weight vector. + */ + +int CVodeGetErrWeights(void *cvode_mem, N_Vector eweight) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetErrWeights", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + N_VScale(ONE, cv_mem->cv_ewt, eweight); + + return(CV_SUCCESS); +} + +/* + * CVodeGetEstLocalErrors + * + * Returns an estimate of the local error + */ + +int CVodeGetEstLocalErrors(void *cvode_mem, N_Vector ele) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetEstLocalErrors", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + N_VScale(ONE, cv_mem->cv_acor, ele); + + return(CV_SUCCESS); +} + +/* + * CVodeGetWorkSpace + * + * Returns integrator work space requirements + */ + +int CVodeGetWorkSpace(void *cvode_mem, long int *lenrw, long int *leniw) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetWorkSpace", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *leniw = cv_mem->cv_liw; + *lenrw = cv_mem->cv_lrw; + + 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, + realtype *hcur, realtype *tcur) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetIntegratorStats", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *nsteps = cv_mem->cv_nst; + *nfevals = cv_mem->cv_nfe; + *nlinsetups = cv_mem->cv_nsetups; + *netfails = cv_mem->cv_netf; + *qlast = cv_mem->cv_qu; + *qcur = cv_mem->cv_next_q; + *hinused = cv_mem->cv_h0u; + *hlast = cv_mem->cv_hu; + *hcur = cv_mem->cv_next_h; + *tcur = cv_mem->cv_tn; + + return(CV_SUCCESS); +} + +/* + * CVodeGetNumGEvals + * + * Returns the current number of calls to g (for rootfinding) + */ + +int CVodeGetNumGEvals(void *cvode_mem, long int *ngevals) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetNumGEvals", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *ngevals = cv_mem->cv_nge; + + return(CV_SUCCESS); +} + +/* + * CVodeGetRootInfo + * + * Returns pointer to array rootsfound showing roots found + */ + +int CVodeGetRootInfo(void *cvode_mem, int *rootsfound) +{ + CVodeMem cv_mem; + int i, nrt; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetRootInfo", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + nrt = cv_mem->cv_nrtfn; + + for (i=0; i<nrt; i++) rootsfound[i] = cv_mem->cv_iroots[i]; + + return(CV_SUCCESS); +} + + +/* + * CVodeGetNumNonlinSolvIters + * + * Returns the current number of iterations in the nonlinear solver + */ + +int CVodeGetNumNonlinSolvIters(void *cvode_mem, long int *nniters) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetNumNonlinSolvIters", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + if (cv_mem->NLS == NULL) { + cvProcessError(NULL, CV_MEM_FAIL, "CVODE", "CVodeGetNumNonlinSolvIters", MSGCV_MEM_FAIL); + return (CV_MEM_FAIL); + } + + return(SUNNonlinSolGetNumIters(cv_mem->NLS, nniters)); +} + +/* + * CVodeGetNumNonlinSolvConvFails + * + * Returns the current number of convergence failures in the + * nonlinear solver + */ + +int CVodeGetNumNonlinSolvConvFails(void *cvode_mem, long int *nncfails) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetNumNonlinSolvConvFails", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *nncfails = cv_mem->cv_ncfn; + + return(CV_SUCCESS); +} + +/* + * CVodeGetNonlinSolvStats + * + * Returns nonlinear solver statistics + */ + +int CVodeGetNonlinSolvStats(void *cvode_mem, long int *nniters, + long int *nncfails) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeGetNonlinSolvStats", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *nncfails = cv_mem->cv_ncfn; + + if (cv_mem->NLS == NULL) { + cvProcessError(NULL, CV_MEM_FAIL, "CVODE", "CVodeGetNonlinSolvStats", MSGCV_MEM_FAIL); + return (CV_MEM_FAIL); + } + + return(SUNNonlinSolGetNumIters(cv_mem->NLS, nniters)); + +} + +/*-----------------------------------------------------------------*/ + +char *CVodeGetReturnFlagName(long int flag) +{ + char *name; + + name = (char *)malloc(24*sizeof(char)); + + switch(flag) { + case CV_SUCCESS: + sprintf(name,"CV_SUCCESS"); + break; + case CV_TSTOP_RETURN: + sprintf(name,"CV_TSTOP_RETURN"); + break; + case CV_ROOT_RETURN: + sprintf(name,"CV_ROOT_RETURN"); + break; + case CV_TOO_MUCH_WORK: + sprintf(name,"CV_TOO_MUCH_WORK"); + break; + case CV_TOO_MUCH_ACC: + sprintf(name,"CV_TOO_MUCH_ACC"); + break; + case CV_ERR_FAILURE: + sprintf(name,"CV_ERR_FAILURE"); + break; + case CV_CONV_FAILURE: + sprintf(name,"CV_CONV_FAILURE"); + break; + case CV_LINIT_FAIL: + sprintf(name,"CV_LINIT_FAIL"); + break; + case CV_LSETUP_FAIL: + sprintf(name,"CV_LSETUP_FAIL"); + break; + case CV_LSOLVE_FAIL: + sprintf(name,"CV_LSOLVE_FAIL"); + break; + case CV_RHSFUNC_FAIL: + sprintf(name,"CV_RHSFUNC_FAIL"); + break; + case CV_FIRST_RHSFUNC_ERR: + sprintf(name,"CV_FIRST_RHSFUNC_ERR"); + break; + case CV_REPTD_RHSFUNC_ERR: + sprintf(name,"CV_REPTD_RHSFUNC_ERR"); + break; + case CV_UNREC_RHSFUNC_ERR: + sprintf(name,"CV_UNREC_RHSFUNC_ERR"); + break; + case CV_RTFUNC_FAIL: + sprintf(name,"CV_RTFUNC_FAIL"); + break; + case CV_MEM_FAIL: + sprintf(name,"CV_MEM_FAIL"); + break; + case CV_MEM_NULL: + sprintf(name,"CV_MEM_NULL"); + break; + case CV_ILL_INPUT: + sprintf(name,"CV_ILL_INPUT"); + break; + case CV_NO_MALLOC: + sprintf(name,"CV_NO_MALLOC"); + break; + case CV_BAD_K: + sprintf(name,"CV_BAD_K"); + break; + case CV_BAD_T: + sprintf(name,"CV_BAD_T"); + break; + case CV_BAD_DKY: + sprintf(name,"CV_BAD_DKY"); + break; + case CV_TOO_CLOSE: + sprintf(name,"CV_TOO_CLOSE"); + break; + case CV_NLS_INIT_FAIL: + sprintf(name,"CV_NLS_INIT_FAIL"); + break; + case CV_NLS_SETUP_FAIL: + sprintf(name,"CV_NLS_SETUPT_FAIL"); + break; + default: + sprintf(name,"NONE"); + } + + return(name); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_ls.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_ls.c new file mode 100644 index 0000000..cc716be --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_ls.c @@ -0,0 +1,1522 @@ +/*----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 + *----------------------------------------------------------------- + * Implementation file for CVode's linear solver interface. + *-----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "cvode_impl.h" +#include "cvode_ls_impl.h" +#include <sundials/sundials_math.h> +#include <sunmatrix/sunmatrix_band.h> +#include <sunmatrix/sunmatrix_dense.h> +#include <sunmatrix/sunmatrix_sparse.h> + +/* constants */ +#define MIN_INC_MULT RCONST(1000.0) +#define MAX_DQITERS 3 /* max. # 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) + + +/*=============================================================== + CVLS Exported functions -- Required + ===============================================================*/ + +/*--------------------------------------------------------------- + CVodeSetLinearSolver specifies the linear solver + ---------------------------------------------------------------*/ +int CVodeSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, + SUNMatrix A) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval, LSType; + + /* Return immediately if either cvode_mem or LS inputs are NULL */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVLS", + "CVodeSetLinearSolver", MSG_LS_CVMEM_NULL); + return(CVLS_MEM_NULL); + } + if (LS == NULL) { + cvProcessError(NULL, CVLS_ILL_INPUT, "CVLS", + "CVodeSetLinearSolver", + "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) ) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", + "CVodeSetLinearSolver", + "LS object is missing a required operation"); + return(CVLS_ILL_INPUT); + } + + /* Test if vector is compatible with LS interface */ + if ( (cv_mem->cv_tempv->ops->nvconst == NULL) || + (cv_mem->cv_tempv->ops->nvdotprod == NULL) ) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", + "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"); + return(CVLS_ILL_INPUT); + } + + /* free any existing system solver attached to CVode */ + if (cv_mem->cv_lfree) cv_mem->cv_lfree(cv_mem); + + /* Set four main system linear solver function fields in cv_mem */ + cv_mem->cv_linit = cvLsInitialize; + cv_mem->cv_lsetup = cvLsSetup; + cv_mem->cv_lsolve = cvLsSolve; + cv_mem->cv_lfree = cvLsFree; + + /* Allocate memory for CVLsMemRec */ + cvls_mem = NULL; + cvls_mem = (CVLsMem) malloc(sizeof(struct CVLsMemRec)); + if (cvls_mem == NULL) { + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVLS", + "CVodeSetLinearSolver", MSG_LS_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + memset(cvls_mem, 0, sizeof(struct CVLsMemRec)); + + /* set SUNLinearSolver pointer */ + cvls_mem->LS = LS; + + /* Set defaults for Jacobian-related fields */ + if (A != NULL) { + cvls_mem->jacDQ = SUNTRUE; + cvls_mem->jac = cvLsDQJac; + cvls_mem->J_data = cv_mem; + } else { + cvls_mem->jacDQ = SUNFALSE; + 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; + + /* Set defaults for preconditioner-related fields */ + cvls_mem->pset = NULL; + cvls_mem->psolve = NULL; + cvls_mem->pfree = NULL; + cvls_mem->P_data = cv_mem->cv_user_data; + + /* Initialize counters */ + cvLsInitializeCounters(cvls_mem); + + /* Set default values for the rest of the LS parameters */ + cvls_mem->msbj = CVLS_MSBJ; + cvls_mem->jbad = SUNTRUE; + cvls_mem->eplifac = CVLS_EPLIN; + cvls_mem->last_flag = CVLS_SUCCESS; + + /* If LS supports ATimes, attach CVLs routine */ + if (LS->ops->setatimes) { + retval = SUNLinSolSetATimes(LS, cv_mem, cvLsATimes); + if (retval != SUNLS_SUCCESS) { + cvProcessError(cv_mem, CVLS_SUNLS_FAIL, "CVLS", + "CVodeSetLinearSolver", + "Error in calling SUNLinSolSetATimes"); + free(cvls_mem); cvls_mem = NULL; + return(CVLS_SUNLS_FAIL); + } + } + + /* If LS supports preconditioning, initialize pset/psol to NULL */ + if (LS->ops->setpreconditioner) { + retval = SUNLinSolSetPreconditioner(LS, cv_mem, NULL, NULL); + if (retval != SUNLS_SUCCESS) { + cvProcessError(cv_mem, CVLS_SUNLS_FAIL, "CVLS", + "CVodeSetLinearSolver", + "Error in calling SUNLinSolSetPreconditioner"); + free(cvls_mem); cvls_mem = NULL; + return(CVLS_SUNLS_FAIL); + } + } + + /* When using a non-NULL SUNMatrix object, store pointer to A and create saved_J */ + 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); + } + } + /* 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); + } + + cvls_mem->x = N_VClone(cv_mem->cv_tempv); + 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) ); + } + + /* Attach linear solver memory to integrator memory */ + cv_mem->cv_lmem = cvls_mem; + + return(CVLS_SUCCESS); +} + + +/*=============================================================== + Optional input/output routines + ===============================================================*/ + + +/* CVodeSetJacFn specifies the Jacobian function. */ +int CVodeSetJacFn(void *cvode_mem, CVLsJacFn jac) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeSetJacFn", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* return with failure if jac cannot be used */ + if ((jac != NULL) && (cvls_mem->A == NULL)) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", "CVodeSetJacFn", + "Jacobian routine cannot be supplied for NULL SUNMatrix"); + return(CVLS_ILL_INPUT); + } + + /* set Jacobian routine pointer, and update relevant flags */ + if (jac != NULL) { + cvls_mem->jacDQ = SUNFALSE; + cvls_mem->jac = jac; + cvls_mem->J_data = cv_mem->cv_user_data; + } else { + cvls_mem->jacDQ = SUNTRUE; + cvls_mem->jac = cvLsDQJac; + cvls_mem->J_data = cv_mem; + } + + return(CVLS_SUCCESS); +} + + +/* CVodeSetEpsLin specifies the nonlinear -> linear tolerance scale factor */ +int CVodeSetEpsLin(void *cvode_mem, realtype eplifac) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeSetEpsLin", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* Check for legal eplifac */ + if(eplifac < ZERO) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", + "CVodeSetEpsLin", MSG_LS_BAD_EPLIN); + return(CVLS_ILL_INPUT); + } + + cvls_mem->eplifac = (eplifac == ZERO) ? CVLS_EPLIN : eplifac; + + return(CVLS_SUCCESS); +} + + +/* CVodeSetMaxStepsBetweenJac specifies the maximum number of + time steps to wait before recomputing the Jacobian matrix + and/or preconditioner */ +int CVodeSetMaxStepsBetweenJac(void *cvode_mem, long int msbj) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure; store input and return */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeSetMaxStepsBetweenJac", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + cvls_mem->msbj = (msbj <= ZERO) ? CVLS_MSBJ : msbj; + + return(CVLS_SUCCESS); +} + + +/* CVodeSetPreconditioner specifies the user-supplied preconditioner + setup and solve routines */ +int CVodeSetPreconditioner(void *cvode_mem, CVLsPrecSetupFn psetup, + CVLsPrecSolveFn psolve) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + PSetupFn cvls_psetup; + PSolveFn cvls_psolve; + int retval; + + /* access CVLsMem structure */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeSetPreconditioner", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* store function pointers for user-supplied routines in CVLs interface */ + cvls_mem->pset = psetup; + cvls_mem->psolve = psolve; + + /* issue error if LS object does not allow user-supplied preconditioning */ + if (cvls_mem->LS->ops->setpreconditioner == NULL) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", + "CVodeSetPreconditioner", + "SUNLinearSolver object does not support user-supplied preconditioning"); + return(CVLS_ILL_INPUT); + } + + /* notify iterative linear solver to call CVLs interface routines */ + cvls_psetup = (psetup == NULL) ? NULL : cvLsPSetup; + cvls_psolve = (psolve == NULL) ? NULL : cvLsPSolve; + retval = SUNLinSolSetPreconditioner(cvls_mem->LS, cv_mem, + cvls_psetup, cvls_psolve); + if (retval != SUNLS_SUCCESS) { + cvProcessError(cv_mem, CVLS_SUNLS_FAIL, "CVLS", + "CVLsSetPreconditioner", + "Error in calling SUNLinSolSetPreconditioner"); + return(CVLS_SUNLS_FAIL); + } + + return(CVLS_SUCCESS); +} + + +/* CVodeSetJacTimes specifies the user-supplied Jacobian-vector product + setup and multiply routines */ +int CVodeSetJacTimes(void *cvode_mem, CVLsJacTimesSetupFn jtsetup, + CVLsJacTimesVecFn jtimes) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeSetJacTimes", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* issue error if LS object does not allow user-supplied ATimes */ + if (cvls_mem->LS->ops->setatimes == NULL) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", + "CVodeSetJacTimes", + "SUNLinearSolver object does not support user-supplied ATimes routine"); + return(CVLS_ILL_INPUT); + } + + /* store function pointers for user-supplied routines in CVLs + interface (NULL jtimes implies use of DQ default) */ + if (jtimes != NULL) { + cvls_mem->jtimesDQ = SUNFALSE; + cvls_mem->jtsetup = jtsetup; + cvls_mem->jtimes = jtimes; + cvls_mem->jt_data = cv_mem->cv_user_data; + } else { + cvls_mem->jtimesDQ = SUNTRUE; + cvls_mem->jtsetup = NULL; + cvls_mem->jtimes = cvLsDQJtimes; + cvls_mem->jt_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, + long int *leniwLS) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + sunindextype lrw1, liw1; + long int lrw, liw; + int retval; + + /* access CVLsMem structure */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeGetLinWorkSpace", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* start with fixed sizes plus vector/matrix pointers */ + *lenrwLS = 2; + *leniwLS = 30; + + /* add NVector sizes */ + if (cv_mem->cv_tempv->ops->nvspace) { + N_VSpace(cv_mem->cv_tempv, &lrw1, &liw1); + *lenrwLS += 2*lrw1; + *leniwLS += 2*liw1; + } + + /* add SUNMatrix size (only account for the one owned by Ls interface) */ + if (cvls_mem->savedJ) + if (cvls_mem->savedJ->ops->space) { + retval = SUNMatSpace(cvls_mem->savedJ, &lrw, &liw); + if (retval == 0) { + *lenrwLS += lrw; + *leniwLS += liw; + } + } + + /* add LS sizes */ + if (cvls_mem->LS->ops->space) { + retval = SUNLinSolSpace(cvls_mem->LS, &lrw, &liw); + if (retval == 0) { + *lenrwLS += lrw; + *leniwLS += liw; + } + } + + return(CVLS_SUCCESS); +} + + +/* CVodeGetNumJacEvals returns the number of Jacobian evaluations */ +int CVodeGetNumJacEvals(void *cvode_mem, long int *njevals) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure; set output value and return */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeGetNumJacEvals", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + *njevals = cvls_mem->nje; + return(CVLS_SUCCESS); +} + + +/* CVodeGetNumLinRhsEvals returns the number of calls to the ODE + function needed for the DQ Jacobian approximation or J*v product + approximation */ +int CVodeGetNumLinRhsEvals(void *cvode_mem, long int *nfevalsLS) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure; set output value and return */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeGetNumLinRhsEvals", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + *nfevalsLS = cvls_mem->nfeDQ; + return(CVLS_SUCCESS); +} + + +/* CVodeGetNumPrecEvals returns the number of calls to the + user- or CVode-supplied preconditioner setup routine */ +int CVodeGetNumPrecEvals(void *cvode_mem, long int *npevals) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure; set output value and return */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeGetNumPrecEvals", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + *npevals = cvls_mem->npe; + return(CVLS_SUCCESS); +} + + +/* CVodeGetNumPrecSolves returns the number of calls to the + user- or CVode-supplied preconditioner solve routine */ +int CVodeGetNumPrecSolves(void *cvode_mem, long int *npsolves) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure; set output value and return */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeGetNumPrecSolves", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + *npsolves = cvls_mem->nps; + return(CVLS_SUCCESS); +} + + +/* CVodeGetNumLinIters returns the number of linear iterations + (if accessible from the LS object) */ +int CVodeGetNumLinIters(void *cvode_mem, long int *nliters) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure; set output value and return */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeGetNumLinIters", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + *nliters = cvls_mem->nli; + return(CVLS_SUCCESS); +} + + +/* CVodeGetNumLinConvFails returns the number of linear solver + convergence failures (as reported by the LS object) */ +int CVodeGetNumLinConvFails(void *cvode_mem, long int *nlcfails) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure; set output value and return */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeGetNumLinConvFails", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + *nlcfails = cvls_mem->ncfl; + return(CVLS_SUCCESS); +} + + +/* CVodeGetNumJTSetupEvals returns the number of calls to the + user-supplied Jacobian-vector product setup routine */ +int CVodeGetNumJTSetupEvals(void *cvode_mem, long int *njtsetups) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure; set output value and return */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeGetNumJTSetupEvals", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + *njtsetups = cvls_mem->njtsetup; + return(CVLS_SUCCESS); +} + + +/* CVodeGetNumJtimesEvals returns the number of calls to the + Jacobian-vector product multiply routine */ +int CVodeGetNumJtimesEvals(void *cvode_mem, long int *njvevals) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure; set output value and return */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeGetNumJtimesEvals", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + *njvevals = cvls_mem->njtimes; + return(CVLS_SUCCESS); +} + + +/* CVodeGetLastLinFlag returns the last flag set in a CVLS function */ +int CVodeGetLastLinFlag(void *cvode_mem, long int *flag) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure; set output value and return */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeGetLastLinFlag", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + *flag = cvls_mem->last_flag; + return(CVLS_SUCCESS); +} + + +/* CVodeGetLinReturnFlagName translates from the integer error code + returned by an CVLs routine to the corresponding string + equivalent for that flag */ +char *CVodeGetLinReturnFlagName(long int flag) +{ + char *name = (char *)malloc(30*sizeof(char)); + + switch(flag) { + case CVLS_SUCCESS: + sprintf(name,"CVLS_SUCCESS"); + break; + case CVLS_MEM_NULL: + sprintf(name,"CVLS_MEM_NULL"); + break; + case CVLS_LMEM_NULL: + sprintf(name,"CVLS_LMEM_NULL"); + break; + case CVLS_ILL_INPUT: + sprintf(name,"CVLS_ILL_INPUT"); + break; + case CVLS_MEM_FAIL: + sprintf(name,"CVLS_MEM_FAIL"); + break; + case CVLS_PMEM_NULL: + sprintf(name,"CVLS_PMEM_NULL"); + break; + case CVLS_JACFUNC_UNRECVR: + sprintf(name,"CVLS_JACFUNC_UNRECVR"); + break; + case CVLS_JACFUNC_RECVR: + sprintf(name,"CVLS_JACFUNC_RECVR"); + break; + case CVLS_SUNMAT_FAIL: + sprintf(name,"CVLS_SUNMAT_FAIL"); + break; + case CVLS_SUNLS_FAIL: + sprintf(name,"CVLS_SUNLS_FAIL"); + break; + default: + sprintf(name,"NONE"); + } + + return(name); +} + + +/*================================================================= + CVLS private functions + =================================================================*/ + +/*----------------------------------------------------------------- + cvLsATimes + + This routine generates the matrix-vector product z = Mv, where + M = I - gamma*J. The product J*v is obtained by calling the jtimes + routine. It is then scaled by -gamma and added to v to obtain M*v. + The return value is the same as the value returned by jtimes -- + 0 if successful, nonzero otherwise. + -----------------------------------------------------------------*/ +int cvLsATimes(void *cvode_mem, N_Vector v, N_Vector z) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure */ + retval = cvLs_AccessLMem(cvode_mem, "cvLsATimes", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* call Jacobian-times-vector product routine + (either user-supplied or internal DQ) */ + retval = cvls_mem->jtimes(v, z, cv_mem->cv_tn, + cvls_mem->ycur, + cvls_mem->fcur, + cvls_mem->jt_data, + cvls_mem->ytemp); + cvls_mem->njtimes++; + if (retval != 0) return(retval); + + /* add contribution from identity matrix */ + N_VLinearSum(ONE, v, -cv_mem->cv_gamma, z, z); + + return(0); +} + + +/*--------------------------------------------------------------- + cvLsPSetup: + + This routine interfaces between the generic iterative linear + solvers and the user's psetup routine. It passes to psetup all + required state information from cvode_mem. Its return value + is the same as that returned by psetup. Note that the generic + iterative linear solvers guarantee that cvLsPSetup will only + be called in the case that the user's psetup routine is non-NULL. + ---------------------------------------------------------------*/ +int cvLsPSetup(void *cvode_mem) +{ + int retval; + CVodeMem cv_mem; + CVLsMem cvls_mem; + + /* access CVLsMem structure */ + retval = cvLs_AccessLMem(cvode_mem, "cvLsPSetup", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* Call user pset routine to update preconditioner and possibly + reset jcur (pass !jbad as update suggestion) */ + retval = cvls_mem->pset(cv_mem->cv_tn, cvls_mem->ycur, + cvls_mem->fcur, !(cvls_mem->jbad), + &cv_mem->cv_jcur, cv_mem->cv_gamma, + cvls_mem->P_data); + return(retval); +} + + +/*----------------------------------------------------------------- + cvLsPSolve + + This routine interfaces between the generic SUNLinSolSolve + routine and the user's psolve routine. It passes to psolve all + required state information from cvode_mem. Its return value is + the same as that returned by psolve. Note that the generic + SUNLinSol solver guarantees that cvLsPSolve will not be called + in the case in which preconditioning is not done. This is the + only case in which the user's psolve routine is allowed to be + NULL. + -----------------------------------------------------------------*/ +int cvLsPSolve(void *cvode_mem, N_Vector r, N_Vector z, realtype tol, int lr) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure */ + retval = cvLs_AccessLMem(cvode_mem, "cvLsPSolve", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* call the user-supplied psolve routine, and accumulate count */ + retval = cvls_mem->psolve(cv_mem->cv_tn, cvls_mem->ycur, + cvls_mem->fcur, r, z, + cv_mem->cv_gamma, tol, lr, + cvls_mem->P_data); + cvls_mem->nps++; + return(retval); +} + + +/*----------------------------------------------------------------- + cvLsDQJac + + This routine is a wrapper for the Dense and Band + implementations of the difference quotient Jacobian + approximation routines. + ---------------------------------------------------------------*/ +int cvLsDQJac(realtype t, N_Vector y, N_Vector fy, + SUNMatrix Jac, void *cvode_mem, N_Vector tmp1, + N_Vector tmp2, N_Vector tmp3) +{ + CVodeMem cv_mem; + int retval; + + /* access CVodeMem structure */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVLS", + "cvLsDQJac", MSG_LS_CVMEM_NULL); + return(CVLS_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* verify that Jac is non-NULL */ + if (Jac == NULL) { + cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVLS", + "cvLsDQJac", MSG_LS_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + + /* Verify that N_Vector supports required operations */ + if (cv_mem->cv_tempv->ops->nvcloneempty == NULL || + cv_mem->cv_tempv->ops->nvwrmsnorm == NULL || + cv_mem->cv_tempv->ops->nvlinearsum == NULL || + cv_mem->cv_tempv->ops->nvdestroy == NULL || + cv_mem->cv_tempv->ops->nvscale == NULL || + cv_mem->cv_tempv->ops->nvgetarraypointer == NULL || + cv_mem->cv_tempv->ops->nvsetarraypointer == NULL) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", + "cvLsDQJac", MSG_LS_BAD_NVECTOR); + return(CVLS_ILL_INPUT); + } + + /* Call the matrix-structure-specific DQ approximation routine */ + if (SUNMatGetID(Jac) == SUNMATRIX_DENSE) { + retval = cvLsDenseDQJac(t, y, fy, Jac, cv_mem, tmp1); + } else if (SUNMatGetID(Jac) == SUNMATRIX_BAND) { + retval = cvLsBandDQJac(t, y, fy, Jac, cv_mem, tmp1, tmp2); + } else { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", "cvLsDQJac", + "unrecognized matrix type for cvLsDQJac"); + retval = CVLS_ILL_INPUT; + } + return(retval); +} + + +/*----------------------------------------------------------------- + cvLsDenseDQJac + + This routine generates a dense difference quotient approximation + to the Jacobian of f(t,y). It assumes that a dense SUNMatrix is + stored column-wise, and that elements within each column are + contiguous. The address of the jth column of J is obtained via + the accessor function SUNDenseMatrix_Column, and this pointer + is associated with an N_Vector using the N_VSetArrayPointer + function. Finally, the actual computation of the jth column of + the Jacobian is done with a call to N_VLinearSum. + -----------------------------------------------------------------*/ +int cvLsDenseDQJac(realtype t, N_Vector y, N_Vector fy, + SUNMatrix Jac, CVodeMem cv_mem, N_Vector tmp1) +{ + realtype fnorm, minInc, inc, inc_inv, yjsaved, srur, conj; + realtype *y_data, *ewt_data, *cns_data; + N_Vector ftemp, jthCol; + sunindextype j, N; + CVLsMem cvls_mem; + int retval = 0; + + /* access LsMem interface structure */ + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + /* access matrix dimension */ + N = SUNDenseMatrix_Rows(Jac); + + /* Rename work vector for readibility */ + ftemp = tmp1; + + /* Create an empty vector for matrix column calculations */ + jthCol = N_VCloneEmpty(tmp1); + + /* 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) + cns_data = N_VGetArrayPointer(cv_mem->cv_constraints); + + /* Set minimum increment based on uround and norm of f */ + srur = SUNRsqrt(cv_mem->cv_uround); + fnorm = N_VWrmsNorm(fy, cv_mem->cv_ewt); + minInc = (fnorm != ZERO) ? + (MIN_INC_MULT * SUNRabs(cv_mem->cv_h) * cv_mem->cv_uround * N * fnorm) : ONE; + + for (j = 0; j < N; j++) { + + /* Generate the jth col of J(tn,y) */ + N_VSetArrayPointer(SUNDenseMatrix_Column(Jac,j), jthCol); + + yjsaved = y_data[j]; + 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) { + 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 = cv_mem->cv_f(t, y, ftemp, cv_mem->cv_user_data); + cvls_mem->nfeDQ++; + if (retval != 0) break; + + y_data[j] = yjsaved; + + inc_inv = ONE/inc; + N_VLinearSum(inc_inv, ftemp, -inc_inv, fy, jthCol); + + } + + /* Destroy jthCol vector */ + N_VSetArrayPointer(NULL, jthCol); /* SHOULDN'T BE NEEDED */ + N_VDestroy(jthCol); + + return(retval); +} + + +/*----------------------------------------------------------------- + cvLsBandDQJac + + 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 in + succession. + -----------------------------------------------------------------*/ +int cvLsBandDQJac(realtype t, N_Vector y, N_Vector fy, SUNMatrix Jac, + CVodeMem cv_mem, N_Vector tmp1, N_Vector tmp2) +{ + N_Vector ftemp, ytemp; + realtype fnorm, minInc, inc, inc_inv, srur, conj; + realtype *col_j, *ewt_data, *fy_data, *ftemp_data; + realtype *y_data, *ytemp_data, *cns_data; + sunindextype group, i, j, width, ngroups, i1, i2; + sunindextype N, mupper, mlower; + CVLsMem cvls_mem; + int retval = 0; + + /* access LsMem interface structure */ + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + /* access matrix dimensions */ + N = SUNBandMatrix_Columns(Jac); + mupper = SUNBandMatrix_UpperBandwidth(Jac); + mlower = SUNBandMatrix_LowerBandwidth(Jac); + + /* Rename work vectors for use as temporary values of y and f */ + ftemp = tmp1; + ytemp = tmp2; + + /* Obtain pointers to the data for ewt, fy, ftemp, y, ytemp */ + ewt_data = N_VGetArrayPointer(cv_mem->cv_ewt); + fy_data = N_VGetArrayPointer(fy); + 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); + + /* Load ytemp with y = predicted y vector */ + N_VScale(ONE, y, ytemp); + + /* Set minimum increment based on uround and norm of f */ + srur = SUNRsqrt(cv_mem->cv_uround); + fnorm = N_VWrmsNorm(fy, cv_mem->cv_ewt); + minInc = (fnorm != ZERO) ? + (MIN_INC_MULT * SUNRabs(cv_mem->cv_h) * cv_mem->cv_uround * N * fnorm) : ONE; + + /* Set bandwidth and number of column groups for band differencing */ + width = mlower + mupper + 1; + ngroups = SUNMIN(width, N); + + /* Loop over column groups. */ + for (group=1; group <= ngroups; group++) { + + /* 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 (cv_mem->cv_constraints != NULL) { + 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; + } + + /* Evaluate f with incremented y */ + retval = cv_mem->cv_f(cv_mem->cv_tn, ytemp, ftemp, cv_mem->cv_user_data); + cvls_mem->nfeDQ++; + if (retval != 0) break; + + /* Restore ytemp, then form and load difference quotients */ + for (j=group-1; j < N; j+=width) { + 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 (cv_mem->cv_constraints != NULL) { + 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); + for (i=i1; i <= i2; i++) + SM_COLUMN_ELEMENT_B(col_j,i,j) = inc_inv * (ftemp_data[i] - fy_data[i]); + } + } + + return(retval); +} + + +/*----------------------------------------------------------------- + cvLsDQJtimes + + This routine generates a difference quotient approximation to + the Jacobian times vector f_y(t,y) * v. The approximation is + Jv = [f(y + v*sig) - f(y)]/sig, where sig = 1 / ||v||_WRMS, + i.e. the WRMS norm of v*sig is 1. + -----------------------------------------------------------------*/ +int cvLsDQJtimes(N_Vector v, N_Vector Jv, realtype t, + N_Vector y, N_Vector fy, void *cvode_mem, + N_Vector work) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + realtype sig, siginv; + int iter, retval; + + /* access CVLsMem structure */ + retval = cvLs_AccessLMem(cvode_mem, "cvLsDQJtimes", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* Initialize perturbation to 1/||v|| */ + sig = ONE/N_VWrmsNorm(v, cv_mem->cv_ewt); + + for (iter=0; iter<MAX_DQITERS; iter++) { + + /* Set work = y + sig*v */ + N_VLinearSum(sig, v, ONE, y, work); + + /* Set Jv = f(tn, y+sig*v) */ + retval = cv_mem->cv_f(t, work, Jv, cv_mem->cv_user_data); + cvls_mem->nfeDQ++; + if (retval == 0) break; + if (retval < 0) return(-1); + + /* If f failed recoverably, shrink sig and retry */ + sig *= PT25; + } + + /* If retval still isn't 0, return with a recoverable failure */ + if (retval > 0) return(+1); + + /* Replace Jv by (Jv - fy)/sig */ + siginv = ONE/sig; + N_VLinearSum(siginv, Jv, -siginv, fy, Jv); + + return(0); +} + + +/*----------------------------------------------------------------- + cvLsInitialize + + This routine performs remaining initializations specific + to the iterative linear solver interface (and solver itself) + -----------------------------------------------------------------*/ +int cvLsInitialize(CVodeMem cv_mem) +{ + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure */ + if (cv_mem->cv_lmem==NULL) { + cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVLS", + "cvLsInitialize", MSG_LS_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + /* Test for valid combinations of matrix & Jacobian routines: */ + 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; + + } else if (cvls_mem->jacDQ) { + + /* 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) { + + 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); + } + + } 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; + } + + /* reset counters */ + cvLsInitializeCounters(cvls_mem); + + /* Set Jacobian-related fields, based on jtimesDQ */ + if (cvls_mem->jtimesDQ) { + cvls_mem->jtsetup = NULL; + cvls_mem->jtimes = cvLsDQJtimes; + cvls_mem->jt_data = cv_mem; + } else { + cvls_mem->jt_data = cv_mem->cv_user_data; + } + + /* if A is NULL and psetup is not present, then cvLsSetup does + not need to be called, so set the lsetup function to NULL */ + if ( (cvls_mem->A == NULL) && (cvls_mem->pset == NULL) ) + cv_mem->cv_lsetup = NULL; + + /* Call LS initialize routine, and return result */ + cvls_mem->last_flag = SUNLinSolInitialize(cvls_mem->LS); + return(cvls_mem->last_flag); +} + + +/*----------------------------------------------------------------- + cvLsSetup + + This conditionally calls the LS 'setup' routine. + + When using a SUNMatrix object, this determines whether + to update a Jacobian matrix (or use a stored version), based + on heuristics regarding previous convergence issues, the number + of time steps since it was last updated, etc.; it then creates + the system matrix from this, the 'gamma' factor and the + identity matrix, A = I-gamma*J. + + This routine then calls the LS 'setup' routine with A. + -----------------------------------------------------------------*/ +int cvLsSetup(CVodeMem cv_mem, int convfail, N_Vector ypred, + N_Vector fpred, booleantype *jcurPtr, + N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3) +{ + CVLsMem cvls_mem; + realtype dgamma; + int retval; + + /* access CVLsMem structure */ + if (cv_mem->cv_lmem==NULL) { + cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVLS", + "cvLsSetup", MSG_LS_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + /* Set CVLs N_Vector pointers to current solution and rhs */ + cvls_mem->ycur = ypred; + cvls_mem->fcur = fpred; + + /* Use nst, gamma/gammap, and convfail to set J/P eval. flag jok */ + dgamma = SUNRabs((cv_mem->cv_gamma/cv_mem->cv_gammap) - ONE); + cvls_mem->jbad = (cv_mem->cv_nst == 0) || + (cv_mem->cv_nst > cvls_mem->nstlj + cvls_mem->msbj) || + ((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, "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 { + + 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); + } + + } + + /* 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); + } + + } + + /* Call LS setup routine -- the LS may call cvLsPSetup, who will + 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 (cvls_mem->A == NULL) { + + /* If user set jcur to SUNTRUE, increment npe and save nst value */ + if (*jcurPtr) { + cvls_mem->npe++; + cvls_mem->nstlj = cv_mem->cv_nst; + } + + /* Update jcur flag if we suggested an update */ + if (cvls_mem->jbad) *jcurPtr = SUNTRUE; + } + + return(cvls_mem->last_flag); +} + + +/*----------------------------------------------------------------- + cvLsSolve + + This routine interfaces between CVode and the generic + SUNLinearSolver object LS, by setting the appropriate tolerance + and scaling vectors, calling the solver, and accumulating + statistics from the solve for use/reporting by CVode. + -----------------------------------------------------------------*/ +int cvLsSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight, + N_Vector ynow, N_Vector fnow) +{ + CVLsMem cvls_mem; + realtype bnorm, deltar, delta, w_mean; + int curiter, nli_inc, retval, LSType; + /* access CVLsMem structure */ + if (cv_mem->cv_lmem==NULL) { + cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVLS", + "cvLsSolve", MSG_LS_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + 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) ) { + deltar = cvls_mem->eplifac * cv_mem->cv_tq[4]; + bnorm = N_VWrmsNorm(b, weight); + if (bnorm <= deltar) { + if (curiter > 0) N_VConst(ZERO, b); + cvls_mem->last_flag = CVLS_SUCCESS; + return(cvls_mem->last_flag); + } + delta = deltar * cvls_mem->sqrtN; + } else { + delta = ZERO; + } + + /* Set vectors ycur and fcur for use by the Atimes and Psolve + interface routines */ + 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, + weight, + weight); + if (retval != SUNLS_SUCCESS) { + cvProcessError(cv_mem, CVLS_SUNLS_FAIL, "CVLS", "cvLsSolve", + "Error in calling SUNLinSolSetScalingVectors"); + cvls_mem->last_flag = CVLS_SUNLS_FAIL; + return(cvls_mem->last_flag); + } + + /* If solver is iterative and does not support scaling vectors, update the + tolerance in an attempt to account for weight vector. We make the + following assumptions: + 1. w_i = w_mean, for i=0,...,n-1 (i.e. the weights are homogeneous) + 2. the linear solver uses a basic 2-norm to measure convergence + Hence (using the notation from sunlinsol_spgmr.h, with S = diag(w)), + || bbar - Abar xbar ||_2 < tol + <=> || S b - S A x ||_2 < tol + <=> || S (b - A x) ||_2 < tol + <=> \sum_{i=0}^{n-1} (w_i (b - A x)_i)^2 < tol^2 + <=> 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) ) { + + w_mean = SUNRsqrt( N_VDotProd(weight, weight) ) / cvls_mem->sqrtN; + delta /= w_mean; + + } + + /* 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, + cvls_mem->jt_data); + cvls_mem->njtsetup++; + if (cvls_mem->last_flag != 0) { + cvProcessError(cv_mem, retval, "CVLS", + "cvLsSolve", MSG_LS_JTSETUP_FAILED); + return(cvls_mem->last_flag); + } + } + + /* Call solver, and copy x to b */ + retval = SUNLinSolSolve(cvls_mem->LS, cvls_mem->A, cvls_mem->x, b, delta); + N_VScale(ONE, cvls_mem->x, b); + + /* 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) ) + 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) ) + nli_inc = SUNLinSolNumIters(cvls_mem->LS); + + /* Increment counters nli and ncfl */ + cvls_mem->nli += nli_inc; + if (retval != SUNLS_SUCCESS) cvls_mem->ncfl++; + + /* Interpret solver return value */ + cvls_mem->last_flag = retval; + + switch(retval) { + + case SUNLS_SUCCESS: + return(0); + break; + case SUNLS_RES_REDUCED: + /* allow reduction but not solution on first Newton iteration, + otherwise return with a recoverable failure */ + if (curiter == 0) return(0); + else return(1); + break; + case SUNLS_CONV_FAIL: + case SUNLS_ATIMES_FAIL_REC: + case SUNLS_PSOLVE_FAIL_REC: + case SUNLS_PACKAGE_FAIL_REC: + case SUNLS_QRFACT_FAIL: + case SUNLS_LUFACT_FAIL: + return(1); + break; + case SUNLS_MEM_NULL: + case SUNLS_ILL_INPUT: + case SUNLS_MEM_FAIL: + case SUNLS_GS_FAIL: + case SUNLS_QRSOL_FAIL: + return(-1); + break; + case SUNLS_PACKAGE_FAIL_UNREC: + cvProcessError(cv_mem, SUNLS_PACKAGE_FAIL_UNREC, "CVLS", + "cvLsSolve", + "Failure in SUNLinSol external package"); + return(-1); + break; + case SUNLS_ATIMES_FAIL_UNREC: + cvProcessError(cv_mem, SUNLS_ATIMES_FAIL_UNREC, "CVLS", + "cvLsSolve", MSG_LS_JTIMES_FAILED); + return(-1); + break; + case SUNLS_PSOLVE_FAIL_UNREC: + cvProcessError(cv_mem, SUNLS_PSOLVE_FAIL_UNREC, "CVLS", + "cvLsSolve", MSG_LS_PSOLVE_FAILED); + return(-1); + break; + } + + return(0); +} + + +/*----------------------------------------------------------------- + cvLsFree + + This routine frees memory associates with the CVLs system + solver interface. + -----------------------------------------------------------------*/ +int cvLsFree(CVodeMem cv_mem) +{ + CVLsMem cvls_mem; + + /* Return immediately if CVodeMem or CVLsMem are NULL */ + if (cv_mem == NULL) return (CVLS_SUCCESS); + if (cv_mem->cv_lmem == NULL) return(CVLS_SUCCESS); + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + /* Free N_Vector memory */ + if (cvls_mem->ytemp) { + N_VDestroy(cvls_mem->ytemp); + cvls_mem->ytemp = NULL; + } + if (cvls_mem->x) { + N_VDestroy(cvls_mem->x); + cvls_mem->x = NULL; + } + + /* Free savedJ memory */ + if (cvls_mem->savedJ) { + SUNMatDestroy(cvls_mem->savedJ); + cvls_mem->savedJ = NULL; + } + + /* Nullify other N_Vector pointers */ + cvls_mem->ycur = NULL; + cvls_mem->fcur = NULL; + + /* Nullify other SUNMatrix pointer */ + cvls_mem->A = NULL; + + /* Free preconditioner memory (if applicable) */ + if (cvls_mem->pfree) cvls_mem->pfree(cv_mem); + + /* free CVLs interface structure */ + free(cv_mem->cv_lmem); + + return(CVLS_SUCCESS); +} + + +/*----------------------------------------------------------------- + cvLsInitializeCounters + + This routine resets all counters from an CVLsMem structure. + -----------------------------------------------------------------*/ +int cvLsInitializeCounters(CVLsMem cvls_mem) +{ + cvls_mem->nje = 0; + cvls_mem->nfeDQ = 0; + cvls_mem->nstlj = 0; + cvls_mem->npe = 0; + cvls_mem->nli = 0; + cvls_mem->nps = 0; + cvls_mem->ncfl = 0; + cvls_mem->njtsetup = 0; + cvls_mem->njtimes = 0; + return(0); +} + + +/*--------------------------------------------------------------- + cvLs_AccessLMem + + This routine unpacks the cv_mem and ls_mem structures from + void* pointer. If either is missing it returns CVLS_MEM_NULL + or CVLS_LMEM_NULL. + ---------------------------------------------------------------*/ +int cvLs_AccessLMem(void* cvode_mem, const char *fname, + CVodeMem *cv_mem, CVLsMem *cvls_mem) +{ + if (cvode_mem==NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVLS", + fname, MSG_LS_CVMEM_NULL); + return(CVLS_MEM_NULL); + } + *cv_mem = (CVodeMem) cvode_mem; + if ((*cv_mem)->cv_lmem==NULL) { + cvProcessError(*cv_mem, CVLS_LMEM_NULL, "CVLS", + fname, MSG_LS_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + *cvls_mem = (CVLsMem) (*cv_mem)->cv_lmem; + return(CVLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + EOF + ---------------------------------------------------------------*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_ls_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_ls_impl.h new file mode 100644 index 0000000..f20ac3f --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_ls_impl.h @@ -0,0 +1,175 @@ +/*----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 + *----------------------------------------------------------------- + * Implementation header file for CVODE's linear solver interface. + *-----------------------------------------------------------------*/ + +#ifndef _CVLS_IMPL_H +#define _CVLS_IMPL_H + +#include <cvode/cvode_ls.h> +#include "cvode_impl.h" + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*----------------------------------------------------------------- + CVLS solver constants + + CVLS_MSBJ maximum number of steps between Jacobian and/or + preconditioner evaluations + CVLS_DGMAX maximum change in gamma between Jacobian and/or + preconditioner evaluations + CVLS_EPLIN default value for factor by which the tolerance on + the nonlinear iteration is multiplied to get a + tolerance on the linear iteration + -----------------------------------------------------------------*/ +#define CVLS_MSBJ 50 +#define CVLS_DGMAX RCONST(0.2) +#define CVLS_EPLIN RCONST(0.05) + + +/*----------------------------------------------------------------- + Types : CVLsMemRec, CVLsMem + + The type CVLsMem is pointer to a CVLsMemRec. + -----------------------------------------------------------------*/ +typedef struct CVLsMemRec { + + /* 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 */ + + /* Iterative solver tolerance */ + realtype sqrtN; /* sqrt(N) */ + realtype eplifac; /* eplifac = user specified or EPLIN_DEFAULT */ + + /* Linear solver, matrix and vector objects/pointers */ + SUNLinearSolver LS; /* generic linear solver object */ + 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 ycur; /* CVODE current y vector in Newton Iteration */ + N_Vector fcur; /* fcur = f(tn, ycur) */ + + /* Statistics and associated parameters */ + long int msbj; /* max num steps between jac/pset calls */ + long int nje; /* nje = no. of calls to jac */ + long int nfeDQ; /* no. of calls to f due to DQ Jacobian or J*v + approximations */ + long int nstlj; /* nstlj = nst at last jac/pset call */ + long int npe; /* npe = total number of pset calls */ + long int nli; /* nli = total number of linear iterations */ + long int nps; /* nps = total number of psolve calls */ + long int ncfl; /* ncfl = total number of convergence failures */ + long int njtsetup; /* njtsetup = total number of calls to jtsetup */ + long int njtimes; /* njtimes = total number of calls to jtimes */ + + /* Preconditioner computation + * (a) user-provided: + * - P_data == user_data + * - pfree == NULL (the user dealocates memory for user_data) + * (b) internal preconditioner module + * - P_data == cvode_mem + * - pfree == set by the prec. module and called in CVodeFree */ + CVLsPrecSetupFn pset; + CVLsPrecSolveFn psolve; + int (*pfree)(CVodeMem cv_mem); + void *P_data; + + /* Jacobian times vector compuation + * (a) jtimes function provided by the user: + * - jt_data == user_data + * - jtimesDQ == SUNFALSE + * (b) internal jtimes + * - jt_data == cvode_mem + * - jtimesDQ == SUNTRUE */ + booleantype jtimesDQ; + CVLsJacTimesSetupFn jtsetup; + CVLsJacTimesVecFn jtimes; + void *jt_data; + + long int last_flag; /* last error flag returned by any function */ + +} *CVLsMem; + +/*----------------------------------------------------------------- + Prototypes of internal functions + -----------------------------------------------------------------*/ + +/* Interface routines called by system SUNLinearSolver */ +int cvLsATimes(void* cvode_mem, N_Vector v, N_Vector z); +int cvLsPSetup(void* cvode_mem); +int cvLsPSolve(void* cvode_mem, N_Vector r, N_Vector z, + realtype tol, int lr); + +/* Difference quotient approximation for Jac times vector */ +int cvLsDQJtimes(N_Vector v, N_Vector Jv, realtype t, + N_Vector y, N_Vector fy, void *data, + N_Vector work); + +/* Difference-quotient Jacobian approximation routines */ +int cvLsDQJac(realtype t, N_Vector y, N_Vector fy, SUNMatrix Jac, + void *data, N_Vector tmp1, N_Vector tmp2, N_Vector tmp3); +int cvLsDenseDQJac(realtype t, N_Vector y, N_Vector fy, + SUNMatrix Jac, CVodeMem cv_mem, N_Vector tmp1); +int cvLsBandDQJac(realtype t, N_Vector y, N_Vector fy, + SUNMatrix Jac, CVodeMem cv_mem, N_Vector tmp1, + N_Vector tmp2); + +/* Generic linit/lsetup/lsolve/lfree interface routines for CVode to call */ +int cvLsInitialize(CVodeMem cv_mem); +int cvLsSetup(CVodeMem cv_mem, int convfail, N_Vector ypred, + N_Vector fpred, booleantype *jcurPtr, + N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3); +int cvLsSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight, + N_Vector ycur, N_Vector fcur); +int cvLsFree(CVodeMem cv_mem); + +/* Auxilliary functions */ +int cvLsInitializeCounters(CVLsMem cvls_mem); +int cvLs_AccessLMem(void* cvode_mem, const char* fname, + CVodeMem* cv_mem, CVLsMem* cvls_mem); + + +/*----------------------------------------------------------------- + Error Messages + -----------------------------------------------------------------*/ + +#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_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_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." +#define MSG_LS_JTSETUP_FAILED "The Jacobian x vector setup routine failed in an unrecoverable manner." +#define MSG_LS_JTIMES_FAILED "The Jacobian x vector routine failed in an unrecoverable manner." +#define MSG_LS_JACFUNC_FAILED "The Jacobian routine failed in an unrecoverable manner." +#define MSG_LS_SUNMAT_FAILED "A SUNMatrix routine failed in an unrecoverable manner." + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_nls.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_nls.c new file mode 100644 index 0000000..9c28e50 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_nls.c @@ -0,0 +1,325 @@ +/* ----------------------------------------------------------------------------- + * 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 the implementation file for the CVODE nonlinear solver interface. + * ---------------------------------------------------------------------------*/ + +#include "cvode_impl.h" +#include "sundials/sundials_math.h" + +/* constant macros */ +#define ONE RCONST(1.0) /* real 1.0 */ + +/* nonlinear solver constants + NLS_MAXCOR maximum no. of corrector iterations for the nonlinear solver + CRDOWN constant used in the estimation of the convergence rate (crate) + of the iterates for the nonlinear equation + RDIV declare divergence if ratio del/delp > RDIV + */ +#define NLS_MAXCOR 3 +#define CRDOWN RCONST(0.3) +#define RDIV RCONST(2.0) + +/* private functions */ +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 cvNlsConvTest(SUNNonlinearSolver NLS, N_Vector ycor, N_Vector del, + realtype tol, N_Vector ewt, void* cvode_mem); + +/* ----------------------------------------------------------------------------- + * Exported functions + * ---------------------------------------------------------------------------*/ + +int CVodeSetNonlinearSolver(void *cvode_mem, SUNNonlinearSolver NLS) +{ + CVodeMem cv_mem; + int retval; + + /* Return immediately if CVode memory is NULL */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "CVodeSetNonlinearSolver", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Return immediately if NLS memory is NULL */ + if (NLS == NULL) { + cvProcessError(NULL, CV_ILL_INPUT, "CVODE", "CVodeSetNonlinearSolver", + "NLS must be non-NULL"); + return (CV_ILL_INPUT); + } + + /* 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"); + return(CV_ILL_INPUT); + } + + /* free any existing nonlinear solver */ + if ((cv_mem->NLS != NULL) && (cv_mem->ownNLS)) + retval = SUNNonlinSolFree(cv_mem->NLS); + + /* set SUNNonlinearSolver pointer */ + cv_mem->NLS = NLS; + + /* Set NLS ownership flag. If this function was called to attach the default + NLS, CVODE will set the flag to SUNTRUE after this function returns. */ + cv_mem->ownNLS = SUNFALSE; + + /* set the nonlinear system function */ + if (SUNNonlinSolGetType(NLS) == SUNNONLINEARSOLVER_ROOTFIND) { + retval = SUNNonlinSolSetSysFn(cv_mem->NLS, cvNlsResidual); + } else if (SUNNonlinSolGetType(NLS) == SUNNONLINEARSOLVER_FIXEDPOINT) { + retval = SUNNonlinSolSetSysFn(cv_mem->NLS, cvNlsFPFunction); + } else { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSetNonlinearSolver", + "Invalid nonlinear solver type"); + return(CV_ILL_INPUT); + } + + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSetNonlinearSolver", + "Setting nonlinear system function failed"); + return(CV_ILL_INPUT); + } + + /* set convergence test function */ + retval = SUNNonlinSolSetConvTestFn(cv_mem->NLS, cvNlsConvTest); + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSetNonlinearSolver", + "Setting convergence test function failed"); + return(CV_ILL_INPUT); + } + + /* set max allowed nonlinear iterations */ + retval = SUNNonlinSolSetMaxIters(cv_mem->NLS, NLS_MAXCOR); + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODE", "CVodeSetNonlinearSolver", + "Setting maximum number of nonlinear iterations failed"); + return(CV_ILL_INPUT); + } + + return(CV_SUCCESS); +} + + +/* ----------------------------------------------------------------------------- + * Private functions + * ---------------------------------------------------------------------------*/ + + +int cvNlsInit(CVodeMem cvode_mem) +{ + int retval; + + /* set the linear solver setup wrapper function */ + if (cvode_mem->cv_lsetup) + retval = SUNNonlinSolSetLSetupFn(cvode_mem->NLS, cvNlsLSetup); + else + retval = SUNNonlinSolSetLSetupFn(cvode_mem->NLS, NULL); + + if (retval != CV_SUCCESS) { + cvProcessError(cvode_mem, CV_ILL_INPUT, "CVODE", "cvNlsInit", + "Setting the linear solver setup function failed"); + return(CV_NLS_INIT_FAIL); + } + + /* set the linear solver solve wrapper function */ + if (cvode_mem->cv_lsolve) + retval = SUNNonlinSolSetLSolveFn(cvode_mem->NLS, cvNlsLSolve); + else + retval = SUNNonlinSolSetLSolveFn(cvode_mem->NLS, NULL); + + if (retval != CV_SUCCESS) { + cvProcessError(cvode_mem, CV_ILL_INPUT, "CVODE", "cvNlsInit", + "Setting linear solver solve function failed"); + return(CV_NLS_INIT_FAIL); + } + + /* initialize nonlinear solver */ + retval = SUNNonlinSolInitialize(cvode_mem->NLS); + + if (retval != CV_SUCCESS) { + cvProcessError(cvode_mem, CV_ILL_INPUT, "CVODE", "cvNlsInit", + MSGCV_NLS_INIT_FAIL); + return(CV_NLS_INIT_FAIL); + } + + return(CV_SUCCESS); +} + + +static int cvNlsLSetup(N_Vector ycor, N_Vector res, booleantype jbad, + booleantype* jcur, void* cvode_mem) +{ + CVodeMem cv_mem; + int retval; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "cvNlsLSetup", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* if the nonlinear solver marked the Jacobian as bad update convfail */ + if (jbad) + cv_mem->convfail = CV_FAIL_BAD_J; + + /* setup the linear solver */ + retval = cv_mem->cv_lsetup(cv_mem, cv_mem->convfail, cv_mem->cv_y, cv_mem->cv_ftemp, + &(cv_mem->cv_jcur), cv_mem->cv_vtemp1, cv_mem->cv_vtemp2, + cv_mem->cv_vtemp3); + cv_mem->cv_nsetups++; + + /* update Jacobian status */ + *jcur = cv_mem->cv_jcur; + + cv_mem->cv_gamrat = ONE; + cv_mem->cv_gammap = cv_mem->cv_gamma; + cv_mem->cv_crate = ONE; + cv_mem->cv_nstlp = cv_mem->cv_nst; + + if (retval < 0) return(CV_LSETUP_FAIL); + if (retval > 0) return(SUN_NLS_CONV_RECVR); + + return(CV_SUCCESS); +} + + +static int cvNlsLSolve(N_Vector ycor, N_Vector delta, void* cvode_mem) +{ + CVodeMem cv_mem; + int retval; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "cvNlsLSolve", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + retval = cv_mem->cv_lsolve(cv_mem, delta, cv_mem->cv_ewt, cv_mem->cv_y, cv_mem->cv_ftemp); + + if (retval < 0) return(CV_LSOLVE_FAIL); + if (retval > 0) return(SUN_NLS_CONV_RECVR); + + return(CV_SUCCESS); +} + + +static int cvNlsConvTest(SUNNonlinearSolver NLS, N_Vector ycor, N_Vector delta, + realtype tol, N_Vector ewt, void* cvode_mem) +{ + CVodeMem cv_mem; + int m, retval; + realtype del; + realtype dcon; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "cvNlsConvTest", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* compute the norm of the correction */ + del = N_VWrmsNorm(delta, ewt); + + /* get the current nonlinear solver iteration count */ + retval = SUNNonlinSolGetCurIter(NLS, &m); + if (retval != CV_SUCCESS) return(CV_MEM_NULL); + + /* Test for convergence. If m > 0, an estimate of the convergence + rate constant is stored in crate, and used in the test. */ + if (m > 0) { + cv_mem->cv_crate = SUNMAX(CRDOWN * cv_mem->cv_crate, del/cv_mem->cv_delp); + } + dcon = del * SUNMIN(ONE, cv_mem->cv_crate) / tol; + + if (dcon <= ONE) { + cv_mem->cv_acnrm = (m==0) ? del : N_VWrmsNorm(ycor, ewt); + return(CV_SUCCESS); /* Nonlinear system was solved successfully */ + } + + /* check if the iteration seems to be diverging */ + if ((m >= 1) && (del > RDIV*cv_mem->cv_delp)) return(SUN_NLS_CONV_RECVR); + + /* Save norm of correction and loop again */ + cv_mem->cv_delp = del; + + /* Not yet converged */ + return(SUN_NLS_CONTINUE); +} + + +static int cvNlsResidual(N_Vector ycor, N_Vector res, void* cvode_mem) +{ + CVodeMem cv_mem; + int retval; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "cvNlsResidual", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* update the state based on the current correction */ + N_VLinearSum(ONE, cv_mem->cv_zn[0], ONE, ycor, cv_mem->cv_y); + + /* evaluate the rhs function */ + 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) return(RHSFUNC_RECVR); + + N_VLinearSum(cv_mem->cv_rl1, cv_mem->cv_zn[1], ONE, ycor, res); + N_VLinearSum(-cv_mem->cv_gamma, cv_mem->cv_ftemp, ONE, res, res); + + return(CV_SUCCESS); +} + + +static int cvNlsFPFunction(N_Vector ycor, N_Vector res, void* cvode_mem) +{ + CVodeMem cv_mem; + int retval; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "cvNlsFPFunction", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* update the state based on the current correction */ + N_VLinearSum(ONE, cv_mem->cv_zn[0], ONE, ycor, cv_mem->cv_y); + + /* evaluate the rhs function */ + retval = cv_mem->cv_f(cv_mem->cv_tn, cv_mem->cv_y, res, + cv_mem->cv_user_data); + cv_mem->cv_nfe++; + if (retval < 0) return(CV_RHSFUNC_FAIL); + if (retval > 0) return(RHSFUNC_RECVR); + + N_VLinearSum(cv_mem->cv_h, res, -ONE, cv_mem->cv_zn[1], res); + N_VScale(cv_mem->cv_rl1, res, res); + + return(CV_SUCCESS); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_spils.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_spils.c new file mode 100644 index 0000000..c4f9ffb --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/cvode_spils.c @@ -0,0 +1,77 @@ +/*----------------------------------------------------------------- + * Programmer(s): 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 + * ----------------------------------------------------------------- + * Implementation file for the deprecated Scaled, Preconditioned Iterative + * Linear Solver interface in CVODE; these routines now just wrap + * the updated CVODE generic linear solver interface in cvode_ls.h. + * -----------------------------------------------------------------*/ + +#include <cvode/cvode_ls.h> +#include <cvode/cvode_spils.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*================================================================= + CVSPILS Exported functions (wrappers for equivalent routines in + cvode_ls.h) + =================================================================*/ + +int CVSpilsSetLinearSolver(void *cvode_mem, SUNLinearSolver LS) +{ return(CVodeSetLinearSolver(cvode_mem, LS, NULL)); } + +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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvband.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvband.c new file mode 100644 index 0000000..855a077 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvband.c @@ -0,0 +1,99 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 + * ----------------------------------------------------------------- + * Fortran/C interface routines for CVODE/CVLS, for the case of + * a user-supplied Jacobian approximation routine. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fcvode.h" /* actual fn. names, prototypes and global vars.*/ +#include "cvode_impl.h" /* definition of CVodeMem type */ + +#include <cvode/cvode_ls.h> +#include <sunmatrix/sunmatrix_band.h> + +/******************************************************************************/ + +/* Prototype of the Fortran routine */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + extern void FCV_BJAC(long int *N, long int *MU, long int *ML, + long int *EBAND, realtype *T, realtype *Y, + realtype *FY, realtype *BJAC, realtype *H, + long int *IPAR, realtype *RPAR, realtype *V1, + realtype *V2, realtype *V3, int *IER); +#ifdef __cplusplus +} +#endif + +/***************************************************************************/ + +void FCV_BANDSETJAC(int *flag, int *ier) +{ + if (*flag == 0) { + *ier = CVodeSetJacFn(CV_cvodemem, NULL); + } else { + *ier = CVodeSetJacFn(CV_cvodemem, FCVBandJac); + } +} + +/***************************************************************************/ + +/* C function CVBandJac interfaces between CVODE and a Fortran subroutine + FCVBJAC for solution of a linear system with band Jacobian approximation. + Addresses of arguments are passed to FCVBJAC, using the accessor routines + from the SUNBandMatrix and N_Vector modules. + The address passed for J is that of the element in column 0 with row + index -mupper. An extended bandwith equal to (J->smu) + mlower + 1 is + passed as the column dimension of the corresponding array. */ + +int FCVBandJac(realtype t, N_Vector y, N_Vector fy, SUNMatrix J, + void *user_data, N_Vector vtemp1, N_Vector vtemp2, + N_Vector vtemp3) +{ + int ier; + realtype *ydata, *fydata, *jacdata, *v1data, *v2data, *v3data; + realtype h; + long int N, mupper, mlower, smu, eband; + FCVUserData CV_userdata; + + CVodeGetLastStep(CV_cvodemem, &h); + + ydata = N_VGetArrayPointer(y); + fydata = N_VGetArrayPointer(fy); + v1data = N_VGetArrayPointer(vtemp1); + v2data = N_VGetArrayPointer(vtemp2); + v3data = N_VGetArrayPointer(vtemp3); + + N = SUNBandMatrix_Columns(J); + mupper = SUNBandMatrix_UpperBandwidth(J); + mlower = SUNBandMatrix_LowerBandwidth(J); + smu = SUNBandMatrix_StoredUpperBandwidth(J); + eband = smu + mlower + 1; + jacdata = SUNBandMatrix_Column(J,0) - mupper; + + CV_userdata = (FCVUserData) user_data; + + FCV_BJAC(&N, &mupper, &mlower, &eband, &t, ydata, fydata, + jacdata, &h, CV_userdata->ipar, CV_userdata->rpar, + v1data, v2data, v3data, &ier); + + return(ier); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvbbd.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvbbd.c new file mode 100644 index 0000000..382fa0b --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvbbd.c @@ -0,0 +1,140 @@ +/* + * ----------------------------------------------------------------- + * 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 + * 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 module contains the routines necessary to interface with the + * CVBBDPRE module and user-supplied Fortran routines. + * The routines here call the generically named routines and provide + * a standard interface to the C code of the CVBBDPRE package. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fcvode.h" /* actual function names, prototypes, global vars.*/ +#include "fcvbbd.h" /* prototypes of interfaces to CVBBDPRE */ + +#include <cvode/cvode_bbdpre.h> /* prototypes of CVBBDPRE functions and macros */ + +/***************************************************************************/ + +/* Prototypes of the Fortran routines */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FCV_GLOCFN(long int *NLOC, realtype *T, + realtype *YLOC, realtype *GLOC, + long int *IPAR, realtype *RPAR, + int *ier); + + extern void FCV_COMMFN(long int *NLOC, realtype *T, + realtype *Y, long int *IPAR, + realtype *RPAR, int *ier); + +#ifdef __cplusplus +} +#endif + +/***************************************************************************/ + +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 + */ + + *ier = CVBBDPrecInit(CV_cvodemem, *Nloc, *mudq, *mldq, *mu, *ml, *dqrely, + (CVLocalFn) FCVgloc, (CVCommFn) FCVcfn); + + return; +} + +/***************************************************************************/ + +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 + */ + + *ier = CVBBDPrecReInit(CV_cvodemem, *mudq, *mldq, *dqrely); +} + +/***************************************************************************/ + +/* 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, + void *user_data) +{ + int ier; + realtype *yloc_data, *gloc_data; + FCVUserData CV_userdata; + + yloc_data = N_VGetArrayPointer(yloc); + gloc_data = N_VGetArrayPointer(gloc); + + CV_userdata = (FCVUserData) user_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 + subroutine FCVCOMMF. */ + +int FCVcfn(long int Nloc, realtype t, N_Vector y, void *user_data) +{ + int ier; + realtype *yloc; + FCVUserData CV_userdata; + + yloc = N_VGetArrayPointer(y); + + CV_userdata = (FCVUserData) user_data; + + FCV_COMMFN(&Nloc, &t, yloc, CV_userdata->ipar, CV_userdata->rpar, &ier); + + return(ier); +} + +/***************************************************************************/ + +/* C function FCVBBDOPT to access optional outputs from CVBBD_Data */ + +void FCV_BBDOPT(long int *lenrwbbd, long int *leniwbbd, long int *ngebbd) +{ + CVBBDPrecGetWorkSpace(CV_cvodemem, lenrwbbd, leniwbbd); + CVBBDPrecGetNumGfnEvals(CV_cvodemem, ngebbd); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvbbd.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvbbd.h new file mode 100644 index 0000000..849e575 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvbbd.h @@ -0,0 +1,524 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * Alan Hindmarsh, Radu Serban 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 Fortran interface include file for the BBD + * preconditioner (CVBBDPRE) + * ----------------------------------------------------------------- + */ + +/* + * ============================================================================== + * + * FCVBBD Interface Package + * + * The FCVBBD Interface Package is a package of C functions which, + * together with the FCVODE Interface Package, support the use of the + * CVODE solver and MPI-parallel N_Vector module, along with the CVBBDPRE + * preconditioner module, for the solution of ODE systems in a mixed + * Fortran/C setting. The combination of CVODE and CVBBDPRE solves systems + * dy/dt = f(t,y) using a Krylov iterative linear solver via the CVSPILS + * interface, and with a preconditioner that is block-diagonal with banded blocks. + * While CVODE and CVBBDPRE are written in C, it is assumed here that the user's + * calling program and user-supplied problem-defining routines are written in + * Fortran. + * + * The user-callable functions in this package, with the corresponding + * CVODE and CVBBDPRE functions, are as follows: + * + * Fortran CVODE + * -------------- --------------------------- + * FCVBBDININT CVBBDPrecInit + * FCVBBDREINIT CVBBDPrecReInit + * FCVBBDOPT (accesses optional outputs) + * -------------- --------------------------- + * + * In addition to the Fortran right-hand side function FCVFUN, the + * user-supplied functions used by this package, are listed below, + * each with the corresponding interface function which calls it (and its + * type within CVBBDPRE or CVODE): + * + * Fortran CVODE Type + * -------------- ----------- ----------------- + * FCVLOCFN FCVgloc CVLocalFn + * FCVCOMMF FCVcfn CVCommFn + * FCVJTSETUP(*) FCVJTSetup CVSpilsJTSetupFn + * FCVJTIMES(*) FCVJtimes CVSpilsJtimesFn + * -------------- ----------- ----------------- + * (*) = optional + * + * Important notes on portability: + * + * The names of all user-supplied routines here are fixed, in order to + * maximize portability for the resulting mixed-language program. + * + * In this package, the names of the interface functions, and the names of + * the Fortran user routines called by them, appear as dummy names + * which are mapped to actual values by a series of definitions in the + * header file fcvbbd.h. + * + * ============================================================================== + * + * Usage of the FCVODE/FCVBBD Interface Packages + * + * The usage of the combined interface packages FCVODE and FCVBBD requires + * calls to a variety of interface functions, and three or more user-supplied + * routines which define the problem to be solved and indirectly define + * the preconditioner. These function calls and user routines are + * summarized separately below. + * + * Some details are omitted, and the user is referred to the CVODE user document + * for more complete information. + * + * (1) User-supplied right-hand side routine: FCVFUN + * + * The user must in all cases supply the following Fortran routine + * + * SUBROUTINE FCVFUN (T, Y, YDOT, IPAR, RPAR, IER) + * + * It must set the YDOT array to f(t,y), the right-hand side of the ODE + * system, as function of T = t and the array Y = y. + * + * The arguments are: + * Y -- array containing state variables [realtype, input] + * YDOT -- array containing state derivatives [realtype, + * output] + * IPAR -- array containing integer user data that was passed + * to FCVMALLOC [long int, input] + * RPAR -- array containing real user data that was passed to + * FCVMALLOC [realtype, input] + * IER -- return flag [int, output]: + * 0 if successful, + * >0 if a recoverable error occurred, + * <0 if an unrecoverable error ocurred. + * + * (2) User-supplied routines to define preconditoner: FCVLOCFN and FCVCOMMF + * + * The routines in the CVBBDPRE module provide a preconditioner matrix + * for CVODE that is block-diagonal with banded blocks. The blocking + * corresponds to the distribution of the dependent variable vector y + * among the processors. Each preconditioner block is generated from the + * Jacobian of the local part (on the current processor) of a given + * function g(t,y) approximating f(t,y). The blocks are generated by a + * difference quotient scheme on each processor independently, utilizing + * an assumed banded structure with given half-bandwidths. A separate + * pair of half-bandwidths defines the band matrix retained. + * + * (2.1) Local approximate function FCVLOCFN. + * + * The user must supply a subroutine of the form + * + * SUBROUTINE FCVLOCFN (NLOC, T, YLOC, GLOC, IPAR, RPAR, IER) + * + * To compute the function g(t,y) which approximates the right-hand side + * function f(t,y). This function is to be computed locally, i.e. without + * interprocess communication. (The case where g is mathematically + * identical to f is allowed.) + * + * The arguments are: + * NLOC -- local problem size [long int, input] + * T -- current time [realtype, input] + * YLOC -- array containing local state variables + * [realtype, input] + * GLOC -- array containing local state derivatives + * [realtype, output] + * IPAR -- array containing integer user data that was passed + * to FCVMALLOC [long int, input] + * RPAR -- array containing real user data that was passed to + * FCVMALLOC [realtype, input] + * IER -- return flag [int, output]: + * 0 if successful, + * >0 if a recoverable error occurred, + * <0 if an unrecoverable error ocurred. + * + * (2.2) Communication function FCVCOMMF. + * + * The user must also supply a subroutine of the form + * + * SUBROUTINE FCVCOMMF (NLOC, T, YLOC, IPAR, RPAR, IER) + * + * which is to perform all interprocess communication necessary to + * evaluate the approximate right-hand side function g described above. + * This function takes as input the local vector length NLOC, the + * independent variable value T = t, and the local real dependent + * variable array YLOC. It is expected to save communicated data in + * work space defined by the user, and made available to CVLOCFN. + * Each call to the FCVCOMMF is preceded by a call to FCVFUN with the same + * (t,y) arguments. Thus FCVCOMMF can omit any communications done by + * FCVFUN if relevant to the evaluation of g. + * + * The arguments are: + * NLOC -- local problem size [long int, input] + * T -- current time [realtype, input] + * YLOC -- array containing local state variables + * [realtype, input] + * IPAR -- array containing integer user data that was passed + * to FCVMALLOC [long int, input] + * RPAR -- array containing real user data that was passed to + * FCVMALLOC [realtype, input] + * IER -- return flag [int, output]: + * 0 if successful, + * >0 if a recoverable error occurred, + * <0 if an unrecoverable error ocurred. + * + * (3) Optional user-supplied Jacobian-vector setup and product + * functions: FCVJTSETUP and FCVJTIMES + * + * As an option, the user may supply a routine that computes the product + * of the system Jacobian J = df/dy and a given vector v. If supplied, a + * 'setup' routine to prepare any user data structures must exist, and + * have the form: + * + * SUBROUTINE FCVJTSETUP(T, Y, FY, H, IPAR, RPAR, IER) + * + * Typically this routine will use only T and Y. It must perform any + * relevant preparations for subsequent calls to the user-provided + * FCVJTIMES routine (see below). + * + * The arguments are: + * T -- current time [realtype, input] + * Y -- array containing state variables [realtype, input] + * FY -- array containing state derivatives [realtype, input] + * H -- current step size [realtype, input] + * IPAR -- array containing integer user data that was passed to + * FCVMALLOC [long int, input] + * RPAR -- array containing real user data that was passed to + * FCVMALLOC [realtype, input] + * IER -- return flag [int, output]: + * 0 if successful, + * nonzero if an error. + * + * The accompanying Jacobian matrix-vector product routine must + * have the following form: + * + * SUBROUTINE FCVJTIMES (V, FJV, T, Y, FY, EWT, IPAR, RPAR, WORK, IER) + * + * Typically this routine will use only NEQ, T, Y, V, and FJV. It must + * compute the product vector Jv, where the vector v is stored in V, and store + * the product in FJV. + * + * The arguments are: + * V -- vector to multiply [realtype, input] + * FJV -- product vector [realtype, output] + * T -- current time [realtype, input] + * Y -- state variables [realtype, input] + * FY -- state derivatives [realtype, input] + * H -- current step size [realtype, input] + * IPAR -- array containing integer user data that was passed + * to FCVMALLOC [long int, input] + * RPAR -- array containing real user data that was passed to + * FCVMALLOC [realtype, input] + * WORK -- array containing temporary workspace of same size + * as Y [realtype, input] + * IER -- return flag [int, output]: + * 0 if successful, + * nonzero if an error. + * + * (4) Initialization: FNVINITP, generic iterative linear solver + * initialization, FCVMALLOC, FCVSPILSINIT, and FCVBBDINIT. + * + * (4.1) To initialize the parallel vector specification, the user must make + * the following call: + * + * CALL FNVINITP(COMM, 1, NLOCAL, NGLOBAL, IER) + * + * where the second argument is an int containing the CVODE + * solver ID (1). The other arguments are: + * COMM = the MPI communicator [int, input] + * NLOCAL = local vector size on this processor + * [long int, input] + * NGLOBAL = system size, and the global size of vectors + * (the sum of all values of NLOCAL) [long int, input] + * IER = return completion flag [int, ouptut]. + * 0 = success, + * -1 = failure. + * + * (4.2) To initialize a generic iterative linear solver structure for + * solving linear systems arising from implicit or IMEX treatment + * of the IVP, the user must make one of the following calls: + * + * CALL FSUNPCGINIT(1, PRETYPE, MAXL, IER) + * CALL FSUNSPBCGSINIT(1, PRETYPE, MAXL, IER) + * CALL FSUNSPFGMRINIT(1, PRETYPE, MAXL, IER) + * CALL FSUNSPGMRINIT(1, PRETYPE, MAXL, IER) + * CALL FSUNSPTFQMRINIT(1, PRETYPE, MAXL, IER) + * + * In each of these, one argument is an int containing the CVODE solver + * ID (1). + * + * The other arguments are: + * + * PRETYPE = type of preconditioning to perform (0=none, 1=left, + * 2=right, 3=both) [int, input] + * MAXL = maximum Krylov subspace dimension [int, input] + * IER = return completion flag [int, output]: + * 0 = success, + * -1 = failure. + * + * (4.3) To set various problem and solution parameters and allocate + * internal memory for CVODE, make the following call: + * + * CALL FCVMALLOC(T0, Y0, METH, IATOL, RTOL, ATOL, + * 1 IOUT, ROUT, IPAR, RPAR, IER) + * + * The arguments are: + * T0 = initial value of t [realtype, input] + * Y0 = array of initial conditions [realtype, input] + * METH = flag denoting integration method [int, input]: + * 1 = Adams (nonstiff), + * 2 = BDF (stiff) + * IATOL = flag denoting type for absolute tolerance ATOL [int, input]: + * 1 = scalar, + * 2 = array + * RTOL = scalar relative tolerance [realtype, input] + * ATOL = scalar or array absolute tolerance [realtype, input] + * IOUT = array of length at least 21 for integer optional outputs + * [long int, output] + * ROUT = array of length at least 6 for real optional outputs + * [realtype, output] + * IPAR = array with user integer data [long int, in/out] + * RPAR = array with user real data [realtype, in/out] + * IER = return completion flag [int, output]: + * 0 = success, + * -1 = failure (see printed message for details). + * + * The user data arrays IPAR and RPAR are passed unmodified to + * all subsequent calls to user-provided routines. Changes to + * either array inside a user-provided routine will be + * propagated. Using these two arrays, the user can dispense + * with COMMON blocks to pass data betwen user-provided + * routines. + * + * (4.3) Create the CVSPILS interface to attach the generic + * iterative linear solver to CVode, by making the following call: + * + * CALL FCVSPILSINIT(IER) + * + * The arguments are: + * IER = error return flag [int, output]: + * 0 = success; + * <0 = an error occured + * + * (4.4) To allocate memory and initialize data associated with the CVBBDPRE + * preconditioner, make the following call: + * + * CALL FCVBBDINIT(NLOCAL, MUDQ, MLDQ, MU, ML, DQRELY, IER) + * + * The arguments are: + * NLOCAL = local vector size on this process + * [long int, input] + * MUDQ = upper half-bandwidth to be used in the computation + * of the local Jacobian blocks by difference + * quotients. These may be smaller than the true + * half-bandwidths of the Jacobian of the local block + * of g, when smaller values may provide greater + * efficiency [long int, input] + * MLDQ = lower half-bandwidth to be used in the computation + * of the local Jacobian blocks by difference + * quotients [long int, input] + * MU = upper half-bandwidth of the band matrix that is + * retained as an approximation of the local Jacobian + * block (may be smaller than MUDQ) [long int, input] + * ML = lower half-bandwidth of the band matrix that is + * retained as an approximation of the local Jacobian + * block (may be smaller than MLDQ) [long int, input] + * DQRELY = relative increment factor in y for difference + * quotients [realtype, input] + * 0.0 = default (sqrt(unit roundoff)) + * IER = return completion flag [int, output]: + * 0 = success + * <0 = an error occurred + * + * (4.5) To specify whether the Krylov linear solver should use the + * supplied FCVJTIMES or the internal finite difference approximation, + * make the call + * + * CALL FCVSPILSSETJAC(FLAG, IER) + * + * with the int FLAG=1 to specify that FCVJTSETUP and FCVJTIMES + * are provided (FLAG=0 specifies to use and internal finite + * difference approximation to this product). The int return + * flag IER=0 if successful, and nonzero otherwise. + * + * (5) Re-initialization: FCVREINIT, FCVBBDREINIT + * + * If a sequence of problems of the same size is being solved using the + * Krylov linear solver in combination with the CVBBDPRE preconditioner, + * then the CVODE package can be reinitialized for the second and + * subsequent problems so as to avoid further memory allocation. First, + * in place of the call to FCVMALLOC, make the following call: + * + * CALL FCVREINIT(T0, Y0, IATOL, RTOL, ATOL, IER) + * + * The arguments have the same names and meanings as those of FCVMALLOC, except + * that METH has been omitted from the argument list (being unchanged + * for the new problem). FCVREINIT performs the same initializations as + * FCVMALLOC, but does no memory allocation, using instead the existing + * internal memory created by the previous FCVMALLOC call. + * + * If there is no change in any of the linear solver or + * preconditioner arguments, then no additional calls are + * necessary. + * + * Following the call to FCVREINIT, if there is no change in any of the + * linear solver arguments, but the user wishes to modify the values of + * MUDQ, MLDQ or DQRELY from the previous call to FCVBBDINIT, then a user + * may call: + * + * CALL FCVBBDREINIT(MUDQ, MLDQ, DQRELY, IER) + * + * This reinitializes the BBD preconditioner, but without reallocating + * its memory. The arguments of the have the same names and meanings as + * FCVBBDINIT. + * + * However, if there is a change in any of the linear solver + * arguments or other preconditioner arguments, then a call to + * FSUNPCGINIT, FSUNSPBCGSINIT, FSUNSPFGMRINIT, FSUNSPGMRINIT, + * or FSUNSPTFQMRINIT is required; in this case the linear + * solver memory is reallocated. Following this call, the + * CVSPILS interface must also be reconstructed using another + * call to FCVSPILSINIT (interface memory is freed and + * reallocated), as well as a subsequent call to FCVBBDINIT. + * + * + * (6) The integrator: FCVODE + * + * Carrying out the integration is accomplished by making calls as follows: + * + * CALL FCVODE (TOUT, T, Y, ITASK, IER) + * + * The arguments are: + * TOUT = next value of t at which a solution is desired [realtype, input] + * T = value of t reached by the solver [realtype, output] + * Y = array containing the computed solution [realtype, output] + * ITASK = task indicator [int, input]: + * 1 = normal mode (overshoot TOUT and interpolate) + * 2 = one-step mode (return after each internal step taken) + * 3 = normal mode with TSTOP check + * 4 = one-step mode with TSTOP check + * IER = completion flag [int, output]: + * 0 = success, + * 1 = TSTOP return, + * 2 = root return, + * negative values are various failure modes (see CVODE User Guide). + * The current values of the optional outputs are available in IOUT and ROUT. + * + * (7) Optional outputs: FCVBBDOPT + * + * Optional outputs specific to the CVSPILS solver interface are + * LENRWLS = IOUT(13) from CVSpilsGetWorkSpace + * LENIWLS = IOUT(14) from CVSpilsGetWorkSpace + * LSTF = IOUT(15) from CVSpilsGetLastFlag + * NFELS = IOUT(16) from CVSpilsGetNumRhsEvals + * NJTV = IOUT(17) from CVSpilsGetNumJtimesEvals + * NPE = IOUT(18) from CVSpilsGetNumPrecEvals + * NPS = IOUT(19) from CVSpilsGetNumPrecSolves + * NLI = IOUT(20) from CVSpilsGetNumLinIters + * NCFL = IOUT(21) from CVSpilsGetNumConvFails + * See the CVODE manual for descriptions. + * + * To obtain the optional outputs associated with the CVBBDPRE module, make + * the following call: + * + * CALL FCVBBDOPT (LENRWBBD, LENIWBBD, NGEBBD) + * + * The arguments returned are: + * LENRWBBD = length of real preconditioner work space, in realtype words. + * This size is local to the current processor [long int, output] + * LENIWBBD = length of integer preconditioner work space, in integer words. + * This size is local to the current processor [long int, output] + * NGEBBD = number of g(t,y) evaluations (calls to CVLOCFN) so far + * [long int, output] + * + * (8) Computing solution derivatives: FCVDKY + * + * To obtain a derivative of the solution (optionally), of order up to + * the current method order, make the following call: + * + * CALL FCVDKY (T, K, DKY) + * + * The arguments are: + * T = time at which solution derivative is desired, within + * the interval [TCUR-HU,TCUR], [realtype, input]. + * K = derivative order (0 .le. K .le. QU) [int, input] + * DKY = array containing computed K-th derivative of y + * [realtype, output] + * IER = return flag [int, output]: + * 0 = success + * <0 = illegal argument. + * + * (9) Memory freeing: FCVFREE + * + * To the free the internal memory created by the calls to FNVINIT*, + * FCVMALLOC, FCVSPILSINIT and FCVBBDINIT, make the following call: + * + * CALL FCVFREE + * + * ============================================================================== + */ + +#ifndef _FCVBBD_H +#define _FCVBBD_H + +/* header files */ +#include <sundials/sundials_nvector.h> /* definition of type N_Vector */ +#include <sundials/sundials_types.h> /* definition of type realtype */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* Definitions of interface function names */ + +#if defined(SUNDIALS_F77_FUNC) + +#define FCV_BBDINIT SUNDIALS_F77_FUNC(fcvbbdinit, FCVBBDINIT) +#define FCV_BBDREINIT SUNDIALS_F77_FUNC(fcvbbdreinit, FCVBBDREINIT) +#define FCV_BBDOPT SUNDIALS_F77_FUNC(fcvbbdopt, FCVBBDOPT) +#define FCV_GLOCFN SUNDIALS_F77_FUNC(fcvglocfn, FCVGLOCFN) +#define FCV_COMMFN SUNDIALS_F77_FUNC(fcvcommfn, FCVCOMMFN) + +#else + +#define FCV_BBDINIT fcvbbdinit_ +#define FCV_BBDREINIT fcvbbdreinit_ +#define FCV_BBDOPT fcvbbdopt_ +#define FCV_GLOCFN fcvglocfn_ +#define FCV_COMMFN fcvcommfn_ + +#endif + +/* Prototypes of exported functions */ + +void FCV_BBDINIT(long int *Nloc, long int *mudq, + long int *mldq, long int *mu, + long int *ml, realtype* dqrely, int *ier); +void FCV_BBDREINIT(long int *mudq, long int *mldq, + realtype* dqrely, int *ier); +void FCV_BBDOPT(long int *lenrwbbd, long int *leniwbbd, + long int *ngebbd); + +/* Prototypes: Functions Called by the CVBBDPRE Module */ + +int FCVgloc(long int Nloc, realtype t, N_Vector yloc, + N_Vector gloc, void *user_data); + +int FCVcfn(long int Nloc, realtype t, N_Vector y, + void *user_data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvbp.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvbp.c new file mode 100644 index 0000000..695fc76 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvbp.c @@ -0,0 +1,54 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * Radu Serban 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 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 + * a standard interface to the C code of the CVBANDPRE package. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fcvode.h" /* actual fn. names, prototypes and global vars.*/ +#include "fcvbp.h" /* prototypes of interfaces to CVBANDPRE */ + +#include <cvode/cvode_bandpre.h> /* prototypes of CVBANDPRE functions and macros */ + +/***************************************************************************/ + +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); + + return; +} + +/***************************************************************************/ + +/* C function FCVBPOPT to access optional outputs from CVBANDPRE_Data */ + +void FCV_BPOPT(long int *lenrwbp, long int *leniwbp, long int *nfebp) +{ + CVBandPrecGetWorkSpace(CV_cvodemem, lenrwbp, leniwbp); + CVBandPrecGetNumRhsEvals(CV_cvodemem, nfebp); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvbp.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvbp.h new file mode 100644 index 0000000..7f47253 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvbp.h @@ -0,0 +1,372 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * Radu Serban 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 Fortran interface include file for the BAND + * preconditioner (CVBANDPRE). + * ----------------------------------------------------------------- + */ + +/* + * ============================================================================== + * + * FCVBP Interface Package + * + * The FCVBP Interface Package is a package of C functions which, + * together with the FCVODE Interface Package, support the use of the + * CVODE solver and serial, OpenMP or PThreads vector module with the + * CVBANDPRE preconditioner module, for the solution of ODE systems in + * a mixed Fortran/C setting. The combination of CVODE and CVBANDPRE solves + * systems dy/dt = f(t,y) using a Krylov iterative linear solver with a banded + * difference quotient Jacobian-based preconditioner. + * + * The user-callable functions in this package, with the corresponding + * CVODE and CVBBDPRE functions, are as follows: + * + * Fortran CVODE + * ------------- --------------------------- + * FCVBPINIT CVBandPrecInit + * FCVBPOPT (accesses optional outputs) + * ------------- --------------------------- + * + * In addition to the Fortran right-hand side function FCVFUN, the + * user may (optionally) supply routines FCVJTSETUP and FCVJTIMES which + * are called by the interface function FCVJTSetup of type CVSpilsJTSetupFn + * and the interface function FCVJtimes of type CVSpilsJtimesFn. + * + * Important notes on portability. + * + * The names of all user-supplied routines here are fixed, in order to + * maximize portability for the resulting mixed-language program. + * + * In this package, the names of the interface functions, and the names of + * the Fortran user routines called by them, appear as dummy names + * which are mapped to actual values by a series of definitions in the + * header file fcvbp.h. + * + * ============================================================================== + * + * Usage of the FCVODE/FCVBP Interface Packages + * + * The usage of the combined interface packages FCVODE and FCVBP requires + * calls to a variety of interface functions, and three or more user-supplied + * routines which define the problem to be solved and indirectly define + * the preconditioner. These function calls and user routines are + * summarized separately below. + * + * Some details are omitted, and the user is referred to the CVODE user document + * for more complete information. + * + * (1) User-supplied right-hand side routine: FCVFUN + * + * The user must in all cases supply the following Fortran routine + * + * SUBROUTINE FCVFUN (T, Y, YDOT, IPAR, RPAR, IER) + * + * It must set the YDOT array to f(t,y), the right-hand side of the ODE + * system, as function of T = t and the array Y = y. + * + * The arguments are: + * Y -- array containing state variables [realtype, input] + * YDOT -- array containing state derivatives [realtype, + * output] + * IPAR -- array containing integer user data that was passed + * to FCVMALLOC [long int, input] + * RPAR -- array containing real user data that was passed to + * FCVMALLOC [realtype, input] + * IER -- return flag [int, output]: + * 0 if successful, + * >0 if a recoverable error occurred, + * <0 if an unrecoverable error ocurred. + * + * + * (2) Optional user-supplied Jacobian-vector setup and product + * functions: FCVJTSETUP and FCVJTIMES + * + * As an option, the user may supply a routine that computes the product + * of the system Jacobian J = df/dy and a given vector v. If supplied, a + * 'setup' routine to prepare any user data structures must exist, and + * have the form: + * + * SUBROUTINE FCVJTSETUP(T, Y, FY, H, IPAR, RPAR, IER) + * + * Typically this routine will use only T and Y. It must perform any + * relevant preparations for subsequent calls to the user-provided + * FCVJTIMES routine (see below). + * + * The arguments are: + * T -- current time [realtype, input] + * Y -- array containing state variables [realtype, input] + * FY -- array containing state derivatives [realtype, input] + * H -- current step size [realtype, input] + * IPAR -- array containing integer user data that was passed to + * FCVMALLOC [long int, input] + * RPAR -- array containing real user data that was passed to + * FCVMALLOC [realtype, input] + * IER -- return flag [int, output]: + * 0 if successful, + * nonzero if an error. + * + * The accompanying Jacobian matrix-vector product routine must + * have the following form: + * + * SUBROUTINE FCVJTIMES (V, FJV, T, Y, FY, EWT, IPAR, RPAR, WORK, IER) + * + * Typically this routine will use only NEQ, T, Y, V, and FJV. It must + * compute the product vector Jv, where the vector v is stored in V, and store + * the product in FJV. + * + * The arguments are: + * V -- vector to multiply [realtype, input] + * FJV -- product vector [realtype, output] + * T -- current time [realtype, input] + * Y -- state variables [realtype, input] + * FY -- state derivatives [realtype, input] + * H -- current step size [realtype, input] + * IPAR -- array containing integer user data that was passed + * to FCVMALLOC [long int, input] + * RPAR -- array containing real user data that was passed to + * FCVMALLOC [realtype, input] + * WORK -- array containing temporary workspace of same size + * as Y [realtype, input] + * IER -- return flag [int, output]: + * 0 if successful, + * nonzero if an error. + * + * (3) Initialization: FNVINITP, generic iterative linear solver + * initialization, FCVMALLOC, FCVSPILSINIT, and FCVBPINIT. + * + * (3.1) To initialize the vector specification, the user must make + * one of the following calls: + * + * (serial) + * CALL FNVINITS(4, NEQ, IER) + * (OpenMP threaded) + * CALL FNVINITOMP(4, NEQ, NUM_THREADS, IER) + * (PThreads threaded) + * CALL FNVINITPTS(4, NEQ, NUM_THREADS, IER) + * + * where the first argument is an int containing the CVODE + * solver ID (4). The other arguments are: + * NEQ = size of vectors [long int, input] + * NUM_THREADS = number of threads + * IER = return completion flag [int, output]: + * 0 = success, + * -1 = failure. + * + * (3.2) To initialize a generic iterative linear solver structure for + * solving linear systems arising from implicit or IMEX treatment + * of the IVP, the user must make one of the following calls: + * + * CALL FSUNPCGINIT(1, PRETYPE, MAXL, IER) + * CALL FSUNSPBCGSINIT(1, PRETYPE, MAXL, IER) + * CALL FSUNSPFGMRINIT(1, PRETYPE, MAXL, IER) + * CALL FSUNSPGMRINIT(1, PRETYPE, MAXL, IER) + * CALL FSUNSPTFQMRINIT(1, PRETYPE, MAXL, IER) + * + * In each of these, one argument is an int containing the CVODE solver + * ID (1). + * + * The other arguments are: + * + * PRETYPE = type of preconditioning to perform (0=none, 1=left, + * 2=right, 3=both) [int, input] + * MAXL = maximum Krylov subspace dimension [int, input] + * IER = return completion flag [int, output]: + * 0 = success, + * -1 = failure. + * + * + * (3.2) To set various problem and solution parameters and allocate + * internal memory for CVODE, make the following call: + * + * CALL FCVMALLOC(T0, Y0, METH, IATOL, RTOL, ATOL, + * 1 IOUT, ROUT, IPAR, RPAR, IER) + * + * The arguments are: + * T0 = initial value of t [realtype, input] + * Y0 = array of initial conditions [realtype, input] + * METH = flag denoting integration method [int, input]: + * 1 = Adams (nonstiff), + * 2 = BDF (stiff) + * IATOL = flag denoting type for absolute tolerance ATOL [int, input]: + * 1 = scalar, + * 2 = array + * RTOL = scalar relative tolerance [realtype, input] + * ATOL = scalar or array absolute tolerance [realtype, input] + * IOUT = array of length at least 21 for integer optional outputs + * [long int, output] + * ROUT = array of length at least 6 for real optional outputs + * [realtype, output] + * IPAR = array with user integer data [long int, in/out] + * RPAR = array with user real data [realtype, in/out] + * IER = return completion flag [int, output]: + * 0 = success, + * -1 = failure (see printed message for details). + * + * The user data arrays IPAR and RPAR are passed unmodified to + * all subsequent calls to user-provided routines. Changes to + * either array inside a user-provided routine will be + * propagated. Using these two arrays, the user can dispense + * with COMMON blocks to pass data betwen user-provided + * routines. + * + * (3.3) Create the CVSPILS interface to attach the generic + * iterative linear solver to CVode, by making the following call: + * + * CALL FCVSPILSINIT(IER) + * + * The arguments are: + * IER = error return flag [int, output]: + * 0 = success; + * <0 = an error occured + * + * (3.4) To allocate memory and initialize data associated with the CVBANDPRE + * preconditioner, make the following call: + * + * CALL FCVBPINIT(NEQ, MU, ML, IER) + * + * The arguments are: + * NEQ = problem size [long int, input] + * MU = upper half-bandwidth of the band matrix that is retained as + * an approximation of the Jacobian [long int, input] + * ML = lower half-bandwidth of the band matrix approximant + * to the Jacobian [long int, input] + * IER = return completion flag [int, output]: + * 0 = success + * <0 = an error occurred + * + * + * (3.5) To specify whether the Krylov linear solver should use the + * supplied FCVJTIMES or the internal finite difference approximation, + * make the call + * + * CALL FCVSPILSSETJAC(FLAG, IER) + * + * with the int FLAG=1 to specify that FCVJTSETUP and FCVJTIMES + * are provided (FLAG=0 specifies to use and internal finite + * difference approximation to this product). The int return + * flag IER=0 if successful, and nonzero otherwise. + * + * (4) The integrator: FCVODE + * + * Carrying out the integration is accomplished by making calls as follows: + * + * CALL FCVODE (TOUT, T, Y, ITASK, IER) + * + * The arguments are: + * TOUT = next value of t at which a solution is desired [realtype, input] + * T = value of t reached by the solver [realtype, output] + * Y = array containing the computed solution [realtype, output] + * ITASK = task indicator [int, input]: + * 1 = normal mode (overshoot TOUT and interpolate) + * 2 = one-step mode (return after each internal step taken) + * 3 = normal mode with TSTOP check + * 4 = one-step mode with TSTOP check + * IER = completion flag [int, output]: + * 0 = success, + * 1 = TSTOP return, + * 2 = root return, + * negative values are various failure modes (see CVODE User Guide). + * The current values of the optional outputs are available in IOUT and ROUT. + * + * (5) Optional outputs: FCVBPOPT + * + * Optional outputs specific to the CVSPILS solver interface are + * LENRWLS = IOUT(13) from CVSpilsGetWorkSpace + * LENIWLS = IOUT(14) from CVSpilsGetWorkSpace + * LSTF = IOUT(15) from CVSpilsGetLastFlag + * NFELS = IOUT(16) from CVSpilsGetNumRhsEvals + * NJTV = IOUT(17) from CVSpilsGetNumJtimesEvals + * NPE = IOUT(18) from CVSpilsGetNumPrecEvals + * NPS = IOUT(19) from CVSpilsGetNumPrecSolves + * NLI = IOUT(20) from CVSpilsGetNumLinIters + * NCFL = IOUT(21) from CVSpilsGetNumConvFails + * See the CVODE manual for descriptions. + * + * To obtain the optional outputs associated with the CVBANDPRE module, make + * the following call: + * + * CALL FCVBPOPT(LENRWBP, LENIWBP, NFEBP) + * + * The arguments returned are: + * LENRWBP = length of real preconditioner work space, in realtype words. + * This size is local to the current processor. + * LENIWBP = length of integer preconditioner work space, in integer words. + * This size is local to the current processor. + * NFEBP = number of f(t,y) evaluations for CVBANDPRE + * + * (6) Computing solution derivatives: FCVDKY + * + * To obtain a derivative of the solution (optionally), of order up to + * the current method order, make the following call: + * + * CALL FCVDKY (T, K, DKY) + * + * The arguments are: + * T = time at which solution derivative is desired, within + * the interval [TCUR-HU,TCUR], [realtype, input]. + * K = derivative order (0 .le. K .le. QU) [int, input] + * DKY = array containing computed K-th derivative of y + * [realtype, output] + * IER = return flag [int, output]: + * 0 = success + * <0 = illegal argument. + * + * (7) Memory freeing: FCVFREE + * + * To the free the internal memory created by the calls to FNVINIT*, + * FCVMALLOC, FCVSPILSINIT and FCVBPINIT, make the following call: + * + * CALL FCVFREE + * + * ============================================================================== + */ + +#ifndef _FCVBP_H +#define _FCVBP_H + +/* header files */ +#include <sundials/sundials_nvector.h> /* definition of type N_Vector */ +#include <sundials/sundials_types.h> /* definition of type realtype */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* Definitions of interface function names */ + +#if defined(SUNDIALS_F77_FUNC) + +#define FCV_BPINIT SUNDIALS_F77_FUNC(fcvbpinit, FCVBPINIT) +#define FCV_BPOPT SUNDIALS_F77_FUNC(fcvbpopt, FCVBPOPT) + +#else + +#define FCV_BPINIT fcvbpinit_ +#define FCV_BPOPT fcvbpopt_ + +#endif + +/* Prototypes of exported function */ +void FCV_BPINIT(long int *N, long int *mu, + long int *ml, int *ier); +void FCV_BPOPT(long int *lenrwbp, long int *leniwbp, + long int *nfebp); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvdense.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvdense.c new file mode 100644 index 0000000..e3c6a2a --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvdense.c @@ -0,0 +1,91 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 + * ----------------------------------------------------------------- + * Fortran/C interface routines for CVODE/CVLS, for the case + * of a user-supplied Jacobian approximation routine. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fcvode.h" /* actual fn. names, prototypes and global vars.*/ +#include "cvode_impl.h" /* definition of CVodeMem type */ + +#include <cvode/cvode_ls.h> +#include <sunmatrix/sunmatrix_dense.h> + +/***************************************************************************/ + +/* Prototype of the Fortran routine */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + extern void FCV_DJAC(long int *N, realtype *T, realtype *Y, + realtype *FY, realtype *DJAC, realtype *H, + long int *IPAR, realtype *RPAR, realtype *V1, + realtype *V2, realtype *V3, int *ier); +#ifdef __cplusplus +} +#endif + +/***************************************************************************/ + +void FCV_DENSESETJAC(int *flag, int *ier) +{ + if (*flag == 0) { + *ier = CVodeSetJacFn(CV_cvodemem, NULL); + } else { + *ier = CVodeSetJacFn(CV_cvodemem, FCVDenseJac); + } +} + +/***************************************************************************/ + +/* C function CVDenseJac interfaces between CVODE and a Fortran subroutine + FCVDJAC for solution of a linear system with dense Jacobian approximation. + Addresses of arguments are passed to FCVDJAC, using accessor functions + from the SUNDenseMatrix and N_Vector modules. */ + +int FCVDenseJac(realtype t, N_Vector y, N_Vector fy, SUNMatrix J, + void *user_data, N_Vector vtemp1, N_Vector vtemp2, + N_Vector vtemp3) +{ + int ier; + realtype *ydata, *fydata, *jacdata, *v1data, *v2data, *v3data; + realtype h; + long int N; + FCVUserData CV_userdata; + + CVodeGetLastStep(CV_cvodemem, &h); + + ydata = N_VGetArrayPointer(y); + fydata = N_VGetArrayPointer(fy); + v1data = N_VGetArrayPointer(vtemp1); + v2data = N_VGetArrayPointer(vtemp2); + v3data = N_VGetArrayPointer(vtemp3); + + N = SUNDenseMatrix_Columns(J); + jacdata = SUNDenseMatrix_Column(J,0); + + CV_userdata = (FCVUserData) user_data; + + FCV_DJAC(&N, &t, ydata, fydata, jacdata, &h, + CV_userdata->ipar, CV_userdata->rpar, v1data, + v2data, v3data, &ier); + return(ier); +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvewt.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvewt.c new file mode 100644 index 0000000..cecf847 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvewt.c @@ -0,0 +1,73 @@ +/* + * ----------------------------------------------------------------- + * Programmer: 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 + * ----------------------------------------------------------------- + * Fortran/C interface routines for CVODE, for the case of a + * user-supplied error weight calculation routine. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fcvode.h" /* actual fn. names, prototypes and global vars. */ +#include "cvode_impl.h" /* definition of CVodeMem type */ + +/***************************************************************************/ + +/* Prototype of the Fortran routine */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + extern void FCV_EWT(realtype *Y, realtype *EWT, + long int *IPAR, realtype *RPAR, + int *IER); +#ifdef __cplusplus +} +#endif + +/***************************************************************************/ + +/* + * User-callable function to interface to CVodeSetEwtFn. + */ + +void FCV_EWTSET(int *flag, int *ier) +{ + if (*flag != 0) { + *ier = CVodeWFtolerances(CV_cvodemem, FCVEwtSet); + } +} + +/***************************************************************************/ + +/* + * C function to interface between CVODE and a Fortran subroutine FCVEWT. + */ + +int FCVEwtSet(N_Vector y, N_Vector ewt, void *user_data) +{ + int ier = 0; + realtype *ydata, *ewtdata; + FCVUserData CV_userdata; + + ydata = N_VGetArrayPointer(y); + ewtdata = N_VGetArrayPointer(ewt); + + CV_userdata = (FCVUserData) user_data; + + FCV_EWT(ydata, ewtdata, CV_userdata->ipar, CV_userdata->rpar, &ier); + + return(ier); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvjtimes.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvjtimes.c new file mode 100644 index 0000000..02ae44e --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvjtimes.c @@ -0,0 +1,124 @@ +/* + * ----------------------------------------------------------------- + * 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 + * 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 + * ----------------------------------------------------------------- + * The C functions FCVJTSetup and FCVJtimes are to interface + * between the CVLS module and the user-supplied + * Jacobian-vector product routines FCVJTSETUP and FCVJTIMES. + * Note the use of the generic names FCV_JTSETUP and FCV_JTIMES + * in the code below. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fcvode.h" /* actual fn. names, prototypes and global vars.*/ +#include "cvode_impl.h" /* definition of CVodeMem type */ + +#include <cvode/cvode_ls.h> + +/***************************************************************************/ + +/* Prototype of the Fortran routine */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FCV_JTSETUP(realtype *T, realtype *Y, realtype *FY, + realtype *H, long int *IPAR, + realtype *RPAR, int *IER); + + extern void FCV_JTIMES(realtype *V, realtype *JV, realtype *T, + realtype *Y, realtype *FY, realtype *H, + long int *IPAR, realtype *RPAR, + realtype *WRK, int *IER); + +#ifdef __cplusplus +} +#endif + +/***************************************************************************/ + +/* ---DEPRECATED--- */ +void FCV_SPILLSSETJAC(int *flag, int *ier) +{ FCV_LSSETJAC(flag, ier); } + + +void FCV_LSSETJAC(int *flag, int *ier) +{ + if (*flag == 0) { + *ier = CVodeSetJacTimes(CV_cvodemem, NULL, NULL); + } else { + *ier = CVodeSetJacTimes(CV_cvodemem, FCVJTSetup, FCVJtimes); + } +} + +/***************************************************************************/ + +/* C function FCVJTSetup to interface between CVODE and user-supplied + Fortran routine FCVJTSETUP for preparing a Jacobian * vector product. + Addresses of t, y, fy and h are passed to FCVJTSETUP, + using the routine N_VGetArrayPointer from NVECTOR. + A return flag ier from FCVJTSETUP is returned by FCVJTSetup. */ + +int FCVJTSetup(realtype t, N_Vector y, N_Vector fy, void *user_data) +{ + realtype *ydata, *fydata; + realtype h; + FCVUserData CV_userdata; + int ier = 0; + + CVodeGetLastStep(CV_cvodemem, &h); + ydata = N_VGetArrayPointer(y); + fydata = N_VGetArrayPointer(fy); + CV_userdata = (FCVUserData) user_data; + + FCV_JTSETUP(&t, ydata, fydata, &h, CV_userdata->ipar, + CV_userdata->rpar, &ier); + return(ier); +} + +/* C function FCVJtimes to interface between CVODE and user-supplied + Fortran routine FCVJTIMES for Jacobian * vector product. + Addresses of v, Jv, t, y, fy, h, and work are passed to FCVJTIMES, + using the routine N_VGetArrayPointer from NVECTOR. + A return flag ier from FCVJTIMES is returned by FCVJtimes. */ + +int FCVJtimes(N_Vector v, N_Vector Jv, realtype t, + N_Vector y, N_Vector fy, + void *user_data, N_Vector work) +{ + realtype *vdata, *Jvdata, *ydata, *fydata, *wkdata; + realtype h; + FCVUserData CV_userdata; + + int ier = 0; + + CVodeGetLastStep(CV_cvodemem, &h); + + vdata = N_VGetArrayPointer(v); + Jvdata = N_VGetArrayPointer(Jv); + ydata = N_VGetArrayPointer(y); + fydata = N_VGetArrayPointer(fy); + wkdata = N_VGetArrayPointer(work); + + CV_userdata = (FCVUserData) user_data; + + FCV_JTIMES (vdata, Jvdata, &t, ydata, fydata, &h, + CV_userdata->ipar, CV_userdata->rpar, wkdata, &ier); + + return(ier); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvnulllinsol.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvnulllinsol.c new file mode 100644 index 0000000..be8ac27 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvnulllinsol.c @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * File that provides a globally-defined, but NULL-valued, + * SUNLinearSolver object, to ensure that F2C_CVODE_linsol is + * defined for cases when no linear solver object is linked in + * with the main executable. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "fcvode.h" +#include "cvode_impl.h" + +/*=============================================================*/ + +/* Define global linear solver variable */ + +SUNLinearSolver F2C_CVODE_linsol; + +/*=============================================================*/ + +/* C routine that is called when using fixed-point nonlinear solvers */ +void FCVNullLinsol() +{ + F2C_CVODE_linsol = NULL; +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvnullmatrix.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvnullmatrix.c new file mode 100644 index 0000000..6f23232 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvnullmatrix.c @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * File that provides a globally-defined, but NULL-valued, + * SUNMatrix object, to ensure that F2C_CVODE_matrix is defined + * for cases when no matrix object is linked in with the main + * executable. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "fcvode.h" +#include "cvode_impl.h" + +/*=============================================================*/ + +/* Define global matrix variable */ + +SUNMatrix F2C_CVODE_matrix; + +/*=============================================================*/ + +/* C routine that is called when using matrix-free linear solvers */ +void FCVNullMatrix() +{ + F2C_CVODE_matrix = NULL; +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvnullnonlinsol.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvnullnonlinsol.c new file mode 100644 index 0000000..824fe0b --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvnullnonlinsol.c @@ -0,0 +1,41 @@ +/* ----------------------------------------------------------------------------- + * 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 + * ----------------------------------------------------------------------------- + * File that provides a globally-defined, but NULL-valued, SUNNonlinearSolver + * object, to ensure that F2C_CVODE_nonlinsol is defined for cases when the + * default nonlinear solver is used and thus no Fortran nonlinear solver object + * is linked in with the main executable. + *----------------------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "fcvode.h" +#include "cvode_impl.h" + +/*=============================================================*/ + +/* Define global linear solver variable */ + +SUNNonlinearSolver F2C_CVODE_nonlinsol; + +/*=============================================================*/ + +/* C routine that is called when using the default nonlinear solver */ +void FCVNullNonlinSol() +{ + F2C_CVODE_nonlinsol = NULL; +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvode.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvode.c new file mode 100644 index 0000000..ca67675 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvode.c @@ -0,0 +1,539 @@ +/* + * ----------------------------------------------------------------- + * 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 + * 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 Fortran interface to + * the CVODE package. See fcvode.h for usage. + * NOTE: some routines are necessarily stored elsewhere to avoid + * linking problems. Therefore, see the othe C files in this folder + * for all the options available. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "fcvode.h" /* actual function names, prototypes, global vars.*/ +#include "cvode_impl.h" /* definition of CVodeMem type */ +#include <sundials/sundials_matrix.h> +#include <cvode/cvode_ls.h> +#include <cvode/cvode_diag.h> + + +/***************************************************************************/ + +/* Definitions for global variables shared amongst various routines */ + +void *CV_cvodemem; +long int *CV_iout; +realtype *CV_rout; +int CV_nrtfn; +int CV_ls; + +/***************************************************************************/ + +/* private constant(s) */ +#define ZERO RCONST(0.0) + +/***************************************************************************/ + +/* Prototypes of the Fortran routines */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + extern void FCV_FUN(realtype*, /* T */ + realtype*, /* Y */ + realtype*, /* YDOT */ + long int*, /* IPAR */ + realtype*, /* RPAR */ + int*); /* IER */ +#ifdef __cplusplus +} +#endif + +/**************************************************************************/ + +void FCV_MALLOC(realtype *t0, realtype *y0, + int *meth, int *iatol, + realtype *rtol, realtype *atol, + long int *iout, realtype *rout, + long int *ipar, realtype *rpar, + int *ier) +{ + int lmm; + N_Vector Vatol; + FCVUserData CV_userdata; + + *ier = 0; + + /* Check for required vector operations */ + if(F2C_CVODE_vec->ops->nvgetarraypointer == NULL || + F2C_CVODE_vec->ops->nvsetarraypointer == NULL) { + *ier = -1; + fprintf(stderr, "A required vector operation is not implemented.\n\n"); + return; + } + + /* Initialize all pointers to NULL */ + CV_cvodemem = NULL; + Vatol = NULL; + FCVNullNonlinSol(); + + /* 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); + if (CV_cvodemem == NULL) { + *ier = -1; + return; + } + + /* Set and attach user data */ + CV_userdata = NULL; + CV_userdata = (FCVUserData) malloc(sizeof *CV_userdata); + if (CV_userdata == NULL) { + *ier = -1; + return; + } + CV_userdata->rpar = rpar; + CV_userdata->ipar = ipar; + + *ier = CVodeSetUserData(CV_cvodemem, CV_userdata); + if(*ier != CV_SUCCESS) { + free(CV_userdata); CV_userdata = NULL; + *ier = -1; + return; + } + + /* Set data in F2C_CVODE_vec to y0 */ + N_VSetArrayPointer(y0, F2C_CVODE_vec); + + /* Call CVodeInit */ + *ier = CVodeInit(CV_cvodemem, FCVf, *t0, F2C_CVODE_vec); + + /* Reset data pointers */ + N_VSetArrayPointer(NULL, F2C_CVODE_vec); + + /* On failure, exit */ + if(*ier != CV_SUCCESS) { + free(CV_userdata); CV_userdata = NULL; + *ier = -1; + return; + } + + /* Set tolerances */ + switch (*iatol) { + case 1: + *ier = CVodeSStolerances(CV_cvodemem, *rtol, *atol); + break; + case 2: + Vatol = NULL; + Vatol = N_VCloneEmpty(F2C_CVODE_vec); + if (Vatol == NULL) { + free(CV_userdata); CV_userdata = NULL; + *ier = -1; + return; + } + N_VSetArrayPointer(atol, Vatol); + *ier = CVodeSVtolerances(CV_cvodemem, *rtol, Vatol); + N_VDestroy(Vatol); + break; + } + + /* On failure, exit */ + if(*ier != CV_SUCCESS) { + free(CV_userdata); CV_userdata = NULL; + *ier = -1; + return; + } + + /* Grab optional output arrays and store them in global variables */ + CV_iout = iout; + CV_rout = rout; + + /* Store the unit roundoff in rout for user access */ + CV_rout[5] = UNIT_ROUNDOFF; + + return; +} + +/***************************************************************************/ + +void FCV_REINIT(realtype *t0, realtype *y0, + int *iatol, realtype *rtol, realtype *atol, + int *ier) +{ + N_Vector Vatol; + + *ier = 0; + + /* Initialize all pointers to NULL */ + Vatol = NULL; + + /* Set data in F2C_CVODE_vec to y0 */ + N_VSetArrayPointer(y0, F2C_CVODE_vec); + + /* Call CVReInit */ + *ier = CVodeReInit(CV_cvodemem, *t0, F2C_CVODE_vec); + + /* Reset data pointers */ + N_VSetArrayPointer(NULL, F2C_CVODE_vec); + + /* On failure, exit */ + if (*ier != CV_SUCCESS) { + *ier = -1; + return; + } + + /* Set tolerances */ + switch (*iatol) { + case 1: + *ier = CVodeSStolerances(CV_cvodemem, *rtol, *atol); + break; + case 2: + Vatol = NULL; + Vatol = N_VCloneEmpty(F2C_CVODE_vec); + if (Vatol == NULL) { + *ier = -1; + return; + } + N_VSetArrayPointer(atol, Vatol); + *ier = CVodeSVtolerances(CV_cvodemem, *rtol, Vatol); + N_VDestroy(Vatol); + break; + } + + /* On failure, exit */ + if (*ier != CV_SUCCESS) { + *ier = -1; + return; + } + + return; +} + +/***************************************************************************/ + +void FCV_SETIIN(char key_name[], long int *ival, int *ier) +{ + if (!strncmp(key_name,"MAX_ORD",7)) + *ier = CVodeSetMaxOrd(CV_cvodemem, (int) *ival); + else if (!strncmp(key_name,"MAX_NSTEPS",10)) + *ier = CVodeSetMaxNumSteps(CV_cvodemem, (long int) *ival); + else if (!strncmp(key_name,"MAX_ERRFAIL",11)) + *ier = CVodeSetMaxErrTestFails(CV_cvodemem, (int) *ival); + else if (!strncmp(key_name,"MAX_NITERS",10)) + *ier = CVodeSetMaxNonlinIters(CV_cvodemem, (int) *ival); + else if (!strncmp(key_name,"MAX_CONVFAIL",12)) + *ier = CVodeSetMaxConvFails(CV_cvodemem, (int) *ival); + else if (!strncmp(key_name,"HNIL_WARNS",10)) + *ier = CVodeSetMaxHnilWarns(CV_cvodemem, (int) *ival); + else if (!strncmp(key_name,"STAB_LIM",8)) + *ier = CVodeSetStabLimDet(CV_cvodemem, (booleantype) *ival); + else { + *ier = -99; + fprintf(stderr, "FCVSETIIN: Unrecognized key.\n\n"); + } + +} + +/***************************************************************************/ + +void FCV_SETRIN(char key_name[], realtype *rval, int *ier) +{ + if (!strncmp(key_name,"INIT_STEP",9)) + *ier = CVodeSetInitStep(CV_cvodemem, *rval); + else if (!strncmp(key_name,"MAX_STEP",8)) + *ier = CVodeSetMaxStep(CV_cvodemem, *rval); + else if (!strncmp(key_name,"MIN_STEP",8)) + *ier = CVodeSetMinStep(CV_cvodemem, *rval); + else if (!strncmp(key_name,"STOP_TIME",9)) + *ier = CVodeSetStopTime(CV_cvodemem, *rval); + else if (!strncmp(key_name,"NLCONV_COEF",11)) + *ier = CVodeSetNonlinConvCoef(CV_cvodemem, *rval); + else { + *ier = -99; + fprintf(stderr, "FCVSETRIN: Unrecognized key.\n\n"); + } + +} + +/***************************************************************************/ + +void FCV_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_CVODE_vec); + if (Vec == NULL) { + *ier = -1; + return; + } + N_VSetArrayPointer(vval, Vec); + CVodeSetConstraints(CV_cvodemem, Vec); + N_VDestroy(Vec); + } + else { + *ier = -99; + fprintf(stderr, "FCVSETVIN: Unrecognized key. \n\n"); + } + +} + +/***************************************************************************/ + +void FCV_LSINIT(int *ier) { + if ( (CV_cvodemem == NULL) || (F2C_CVODE_linsol == NULL) ) { + *ier = -1; + return; + } + *ier = CVodeSetLinearSolver(CV_cvodemem, F2C_CVODE_linsol, + F2C_CVODE_matrix); + CV_ls = CV_LS_STD; + return; +} + +/***************************************************************************/ + +/* ---DEPRECATED--- */ +void FCV_DLSINIT(int *ier) +{ FCV_LSINIT(ier); } + +/***************************************************************************/ + +/* ---DEPRECATED--- */ +void FCV_SPILSINIT(int *ier) +{ FCV_LSINIT(ier); } + +/*=============================================================*/ + +/* ---DEPRECATED--- */ +void FCV_SPILSSETEPSLIN(realtype *eplifac, int *ier) +{ FCV_LSSETEPSLIN(eplifac, ier); } + +void FCV_LSSETEPSLIN(realtype *eplifac, int *ier) +{ *ier = CVodeSetEpsLin(CV_cvodemem, *eplifac); } + +/***************************************************************************/ + +void FCV_DIAG(int *ier) +{ + if (CV_cvodemem == NULL) { + *ier = -1; + return; + } + *ier = CVDiag(CV_cvodemem); + CV_ls = CV_LS_DIAG; + return; +} + +/***************************************************************************/ + +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) + */ + + int qu, qcur; + + N_VSetArrayPointer(y, F2C_CVODE_vec); + + *ier = CVode(CV_cvodemem, *tout, F2C_CVODE_vec, t, *itask); + + N_VSetArrayPointer(NULL, F2C_CVODE_vec); + + /* Load optional outputs in iout & rout */ + CVodeGetWorkSpace(CV_cvodemem, + &CV_iout[0], /* LENRW */ + &CV_iout[1]); /* LENIW */ + CVodeGetIntegratorStats(CV_cvodemem, + &CV_iout[2], /* NST */ + &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_iout[8] = (long int) qu; + CV_iout[9] = (long int) qcur; + 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 */ + CVodeGetLastLinFlag(CV_cvodemem, &CV_iout[14]); /* LSTF */ + CVodeGetNumLinRhsEvals(CV_cvodemem, &CV_iout[15]); /* NFELS */ + CVodeGetNumJacEvals(CV_cvodemem, &CV_iout[16]); /* NJE */ + CVodeGetNumJTSetupEvals(CV_cvodemem, &CV_iout[17]); /* NJTS */ + CVodeGetNumJtimesEvals(CV_cvodemem, &CV_iout[18]); /* NJTV */ + CVodeGetNumPrecEvals(CV_cvodemem, &CV_iout[19]); /* NPE */ + CVodeGetNumPrecSolves(CV_cvodemem, &CV_iout[20]); /* NPS */ + CVodeGetNumLinIters(CV_cvodemem, &CV_iout[21]); /* NLI */ + CVodeGetNumLinConvFails(CV_cvodemem, &CV_iout[22]); /* NCFL */ + break; + case CV_LS_DIAG: + CVDiagGetWorkSpace(CV_cvodemem, &CV_iout[12], &CV_iout[13]); /* LENRWLS,LENIWLS */ + CVDiagGetLastFlag(CV_cvodemem, &CV_iout[14]); /* LSTF */ + CVDiagGetNumRhsEvals(CV_cvodemem, &CV_iout[15]); /* NFELS */ + } +} + +/***************************************************************************/ + +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 + */ + + realtype *f2c_data = N_VGetArrayPointer(F2C_CVODE_vec); + N_VSetArrayPointer(dky, F2C_CVODE_vec); + + *ier = 0; + *ier = CVodeGetDky(CV_cvodemem, *t, *k, F2C_CVODE_vec); + + N_VSetArrayPointer(f2c_data, F2C_CVODE_vec); + +} + +/*************************************************/ + +void FCV_GETERRWEIGHTS(realtype *eweight, int *ier) +{ + /* Attach user data to vector */ + realtype *f2c_data = N_VGetArrayPointer(F2C_CVODE_vec); + N_VSetArrayPointer(eweight, F2C_CVODE_vec); + + *ier = 0; + *ier = CVodeGetErrWeights(CV_cvodemem, F2C_CVODE_vec); + + /* Reset data pointers */ + N_VSetArrayPointer(f2c_data, F2C_CVODE_vec); + + return; +} + +/*************************************************/ + +void FCV_GETESTLOCALERR(realtype *ele, int *ier) +{ + /* Attach user data to vector */ + realtype *f2c_data = N_VGetArrayPointer(F2C_CVODE_vec); + N_VSetArrayPointer(ele, F2C_CVODE_vec); + + *ier = 0; + *ier = CVodeGetEstLocalErrors(CV_cvodemem, F2C_CVODE_vec); + + /* Reset data pointers */ + N_VSetArrayPointer(f2c_data, F2C_CVODE_vec); + + return; +} + +/***************************************************************************/ + +void FCV_FREE () +{ + CVodeMem cv_mem; + + cv_mem = (CVodeMem) CV_cvodemem; + + 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); + + N_VSetArrayPointer(NULL, F2C_CVODE_vec); + N_VDestroy(F2C_CVODE_vec); + if (F2C_CVODE_matrix) + SUNMatDestroy(F2C_CVODE_matrix); + if (F2C_CVODE_linsol) + SUNLinSolFree(F2C_CVODE_linsol); + /* already freed by CVodeFree */ + if (F2C_CVODE_nonlinsol) + F2C_CVODE_nonlinsol = NULL; + 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. + */ + +int FCVf(realtype t, N_Vector y, N_Vector ydot, void *user_data) +{ + int ier; + realtype *ydata, *dydata; + FCVUserData CV_userdata; + + ydata = N_VGetArrayPointer(y); + dydata = N_VGetArrayPointer(ydot); + + CV_userdata = (FCVUserData) user_data; + + FCV_FUN(&t, ydata, dydata, CV_userdata->ipar, CV_userdata->rpar, &ier); + + return(ier); +} + +/* 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) ) { + *ier = -1; + return; + } + if (((CVodeMem) CV_cvodemem)->cv_lsolve == NULL) { + FCVNullMatrix(); + FCVNullLinsol(); + } + + *ier = CVodeSetNonlinearSolver(CV_cvodemem, F2C_CVODE_nonlinsol); + return; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvode.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvode.h new file mode 100644 index 0000000..b16119e --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvode.h @@ -0,0 +1,1084 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds and Ting Yan @ SMU + * Alan C. Hindmarsh, Radu Serban 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 FCVODE, the Fortran interface to + * the CVODE package. + * ----------------------------------------------------------------- + */ + +/* + * ============================================================================= + * + * FCVODE Interface Package + * + * The FCVODE Interface Package is a package of C functions which support + * the use of the CVODE solver, for the solution of ODE systems + * dy/dt = f(t,y), in a mixed Fortran/C setting. While CVODE 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 CVODE for both the + * serial and the parallel NVECTOR implementations. + * + * A summary of the user-callable functions, with the corresponding + * CVODE functions, are as follows: + * + * Fortran CVODE + * --------------------- -------------------------------- + * FNVINITS N_VNew_Serial + * FNVINITP N_VNew_Parallel + * FNVINITOMP N_VNew_OpenMP + * FNVINITPTS N_VNew_Pthreads + * + * FSUNBANDMATINIT SUNBandMatrix + * FSUNDENSEMATINIT SUNDenseMatrix + * FSUNSPARSEMATINIT SUNSparseMatrix + * + * FSUNBANDLINSOLINIT SUNBandLinearSolver + * FSUNDENSELINSOLINIT SUNDenseLinearSolver + * FSUNKLUINIT SUNKLU + * FSUNKLUREINIT SUNKLUReinit + * FSUNLAPACKBANDINIT SUNLapackBand + * FSUNLAPACKDENSEINIT SUNLapackDense + * FSUNPCGINIT SUNPCG + * FSUNSPBCGSINIT SUNSPBCGS + * FSUNSPFGMRINIT SUNSPFGMR + * FSUNSPGMRINIT SUNSPGMR + * FSUNSPTFQMRINIT SUNSPTFQMR + * FSUNSUPERLUMTINIT SUNSuperLUMT + * + * FCVMALLOC CVodeCreate, CVodeSetUserData, + * and CVodeInit + * FCVREINIT CVReInit + * FCVSETIIN CVodeSet* (integer arguments) + * FCVSETRIN CVodeSet* (real arguments) + * FCVSETVIN CVodeSet* (vector arguments) + * FCVEWTSET CVodeWFtolerances + * + * FCVLSINIT CVodeSetLinearSolver + * FCVLSSETEPSLIN CVodeSetEpsLin + * FCVLSSETJAC CVodeSetJacTimes + * FCVLSSETPREC CVodeSetPreconditioner + * FCVDENSESETJAC CVodeSetJacFn + * FCVBANDSETJAC CVodeSetJacFn + * FCVSPARSESETJAC CVodeSetJacFn + * + * FCVDIAG CVDiag + * + * FCVNLSINIT CVSetNonlinearSolver + * + * FCVODE CVode, CVodeGet*, and CV*Get* + * FCVDKY CVodeGetDky + * + * FCVGETERRWEIGHTS CVodeGetErrWeights + * FCVGETESTLOCALERR CVodeGetEstLocalErrors + * + * FCVFREE CVodeFree + * --------------------- -------------------------------- + * + * The user-supplied functions, each listed with the corresponding interface + * function which calls it (and its type within CVODE), are as follows: + * + * Fortran: Interface Fcn: CVODE Type: + * ------------- ------------------ ----------------------- + * FCVFUN FCVf CVRhsFn + * FCVDJAC FCVDenseJac CVLsJacFn + * FCVBJAC FCVBandJac CVLsJacFn + * FCVSPJAC FCVSparseJac CVLsJacFn + * FCVPSET FCVPSet CVLsPrecSetupFn + * FCVPSOL FCVPSol CVLsPrecSolveFn + * FCVJTSETUP FCVJTSetup CVLsJacTimesSetupFn + * FCVJTIMES FCVJtimes CVLsJacTimesVecFn + * FCVEWT FCVEwtSet CVEwtFn + * ------------- ------------------ ----------------------- + * + * In contrast to the case of direct use of CVODE, and of most Fortran ODE + * solvers, the names of all user-supplied routines here are fixed, in + * order to maximize portability for the resulting mixed-language program. + * + * Important note on portability. + * In this package, the names of the interface functions, and the names of + * the Fortran user routines called by them, appear as dummy names + * which are mapped to actual values by a series of definitions, in this + * and other header files. + * + * ============================================================================= + * + * Usage of the FCVODE Interface Package + * + * The usage of FCVODE requires calls to a variety of interface + * functions, depending on the method options selected, and one or more + * user-supplied routines which define the problem to be solved. These + * function calls and user routines are summarized separately below. + * + * Some details are omitted, and the user is referred to the user documents + * on CVODE for more complete documentation. Information on the + * arguments of any given user-callable interface routine, or of a given + * user-supplied function called by an interface function, can be found in + * the documentation on the corresponding function in the CVODE package. + * + * The number labels on the instructions below end with s for instructions + * that are specific to use with the serial/OpenMP/PThreads package; similarly + * those that end with p are specific to use with the N_VParallel package. + * + * ----------------------------------------------------------------------------- + * + * Data Types + * + * Throughout this documentation, we will refer to data types according to + * their usage in SUNDIALS. The equivalent types to these may vary, + * depending on your computer architecture and on how SUNDIALS was compiled. + * A Fortran user should take care that all arguments passed through this + * Fortran/C interface are declared of the appropriate type. + * + * Integers: SUNDIALS uses 'int', 'long int' and 'sunindextype' types. At + * compilation, SUNDIALS allows the configuration of the 'index' type, that + * accepts values of 32-bit signed and 64-bit signed. This choice dictates + * the size of a SUNDIALS 'sunindextype' variable. + * int -- equivalent to an INTEGER or INTEGER*4 in Fortran + * long int -- equivalent to an INTEGER*8 in Fortran (Linux/UNIX/OSX), or + * equivalent to an INTEGER in Windows + * sunindextype -- this will depend on the SUNDIALS configuration: + * 32-bit -- equivalent to an INTEGER or INTEGER*4 in Fortran + * 64-bit -- equivalent to an INTEGER*8 in Fortran + * + * Real numbers: At compilation, SUNDIALS allows the configuration option + * '--with-precision', that accepts values of 'single', 'double' or + * 'extended' (the default is 'double'). This choice dictates the size of a + * SUNDIALS 'realtype' variable. The corresponding Fortran types for these + * 'realtype' sizes are: + * single -- equivalent to a REAL or REAL*4 in Fortran + * double -- equivalent to a DOUBLE PRECISION or REAL*8 in Fortran + * extended -- equivalent to a REAL*16 in Fortran + * + * ----------------------------------------------------------------------------- + * + * (1) User-supplied right-hand side routine: FCVFUN + * + * The user must in all cases supply the following Fortran routine + * + * SUBROUTINE FCVFUN (T, Y, YDOT, IPAR, RPAR, IER) + * + * It must set the YDOT array to f(t,y), the right-hand side of the ODE + * system, as function of T = t and the array Y = y. + * + * The arguments are: + * Y -- array containing state variables [realtype, input] + * YDOT -- array containing state derivatives [realtype, output] + * IPAR -- array containing integer user data that was passed to + * FCVMALLOC [long int, input] + * RPAR -- array containing real user data that was passed to + * FCVMALLOC [realtype, input] + * IER -- return flag [int, output]: + * 0 if successful, + * >0 if a recoverable error occurred, + * <0 if an unrecoverable error ocurred. + * + * (2s) Optional user-supplied dense Jacobian approximation routine: FCVDJAC + * + * As an option when using the DENSE or LAPACKDENSE linear solvers, the user may + * supply a routine that computes a dense approximation of the system Jacobian + * J = df/dy. If supplied, it must have the following form: + * + * SUBROUTINE FCVDJAC(NEQ, T, Y, FY, DJAC, H, IPAR, RPAR, WK1, WK2, WK3, IER) + * + * Typically this routine will use only NEQ, T, Y, and DJAC. It must compute + * the Jacobian and store it columnwise in DJAC. + * + * The arguments are: + * NEQ -- number of rows in the matrix [long int, input] + * T -- current time [realtype, input] + * Y -- array containing state variables [realtype, input] + * FY -- array containing state derivatives [realtype, input] + * DJAC -- 2D array containing the jacobian entries [realtype of size + * (NEQ,NEQ), output] + * H -- current step size [realtype, input] + * IPAR -- array containing integer user data that was passed to + * FCVMALLOC [long int, input] + * RPAR -- array containing real user data that was passed to + * FCVMALLOC [realtype, input] + * WK* -- array containing temporary workspace of same size as Y + * [realtype, input] + * IER -- return flag [int, output]: + * 0 if successful, + * >0 if a recoverable error occurred, + * <0 if an unrecoverable error ocurred. + * + * (2s) Optional user-supplied band Jacobian approximation routine: FCVBJAC + * + * As an option when using the BAND or LAPACKBAND linear solvers, the user + * may supply a routine that computes a band approximation of the system + * Jacobian J = df/dy. If supplied, it must have the following form: + * + * SUBROUTINE FCVBJAC(NEQ, MU, ML, MDIM, T, Y, FY, BJAC, H, + * 1 IPAR, RPAR, WK1, WK2, WK3, IER) + * + * Typically this routine will use only NEQ, MU, ML, T, Y, and BJAC. + * It must load the MDIM by N array BJAC with the Jacobian matrix at the + * current (t,y) in band form. Store in BJAC(k,j) the Jacobian element J(i,j) + * with k = i - j + MU + 1 (k = 1 ... ML+MU+1) and j = 1 ... N. + * + * The arguments are: + * NEQ -- number of rows in the matrix [long int, input] + * MU -- upper half-bandwidth of the matrix [long int, input] + * ML -- lower half-bandwidth of the matrix [long int, input] + * MDIM -- leading dimension of BJAC array [long int, input] + * T -- current time [realtype, input] + * Y -- array containing state variables [realtype, input] + * FY -- array containing state derivatives [realtype, input] + * BJAC -- 2D array containing the jacobian entries [realtype of size + * (MDIM,NEQ), output] + * H -- current step size [realtype, input] + * IPAR -- array containing integer user data that was passed to + * FCVMALLOC [long int, input] + * RPAR -- array containing real user data that was passed to + * FCVMALLOC [realtype, input] + * WK* -- array containing temporary workspace of same size as Y + * [realtype, input] + * IER -- return flag [int, output]: + * 0 if successful, + * >0 if a recoverable error occurred, + * <0 if an unrecoverable error ocurred. + * + * + * (2s) User-supplied sparse Jacobian approximation routine: FCVSPJAC + * + * Required when using the KLU or SuperLUMT linear solvers, the + * user must supply a routine that computes a compressed-sparse-column [or + * compressed-sparse-row] approximation of the system Jacobian + * J = dfi(t,y)/dy. If supplied, it must have the following form: + * + * SUBROUTINE FCVSPJAC(T, Y, FY, N, NNZ, JDATA, JRVALS, JCPTRS, + * 1 H, IPAR, RPAR, WK1, WK2, WK3, IER) + * + * This routine must load the N by N compressed sparse column [or 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 + * (t,y) in CSC [or CSR] form (see sunmatrix_sparse.h for more information). + * + * The arguments are: + * T -- current time [realtype, input] + * Y -- array containing state variables [realtype, input] + * FY -- array containing state derivatives [realtype, input] + * N -- number of matrix rows/columns in Jacobian [int, input] + * NNZ -- allocated length of nonzero storage [int, input] + * JDATA -- nonzero values in Jacobian + * [realtype of length NNZ, output] + * JRVALS -- row [or column] indices for each nonzero in Jacobian + * [int of length NNZ, output] + * JCPTRS -- pointers to each Jacobian column [or row] in preceding arrays + * [int of length N+1, output] + * H -- current step size [realtype, input] + * IPAR -- array containing integer user data that was passed to + * FCVMALLOC [long int, input] + * RPAR -- array containing real user data that was passed to + * FCVMALLOC [realtype, input] + * WK* -- array containing temporary workspace of same size as Y + * [realtype, input] + * IER -- return flag [int, output]: + * 0 if successful, + * >0 if a recoverable error occurred, + * <0 if an unrecoverable error ocurred. + * + * NOTE: this may ONLY be used if SUNDIALS has been configured with + * long int set to 64-bit integers. + * + * (2) Optional user-supplied Jacobian-vector product setup routine: + * FCVJTSETUP + * + * As an option when using the CVLS linear solver interface with a + * matrix-free linear solver, the user may supply a routine that computes + * the product of the system Jacobian J = dfi(t,y)/dy and a given vector v, + * as well as a routine to set up any user data structures in preparation + * for the matrix-vector product. If a 'setup' routine is supplied, it + * must have the following form: + * + * SUBROUTINE FCVJTSETUP(T, Y, FY, H, IPAR, RPAR, IER) + * + * Typically this routine will use only T and Y. It must perform any + * relevant preparations for subsequent calls to the user-provided + * FCVJTIMES routine (see below). + * + * The arguments are: + * T -- current time [realtype, input] + * Y -- array containing state variables [realtype, input] + * FY -- array containing state derivatives [realtype, input] + * H -- current step size [realtype, input] + * IPAR -- array containing integer user data that was passed to + * FCVMALLOC [long int, input] + * RPAR -- array containing real user data that was passed to + * FCVMALLOC [realtype, input] + * IER -- return flag [int, output]: + * 0 if successful, + * nonzero if an error. + * + * (2) Optional user-supplied Jacobian-vector product routine: FCVJTIMES + * + * As an option when using the SP* linear solver, the user may supply + * a routine that computes the product of the system Jacobian J = df/dy and + * a given vector v. If supplied, it must have the following form: + * + * SUBROUTINE FCVJTIMES (V, FJV, T, Y, FY, H, IPAR, RPAR, WORK, IER) + * + * Typically this routine will use only NEQ, T, Y, V, and FJV. It must + * compute the product vector Jv where the vector v is stored in V, and store + * the product in FJV. + * + * The arguments are: + * V -- array containing vector to multiply [realtype, input] + * JV -- array containing product vector [realtype, output] + * T -- current time [realtype, input] + * Y -- array containing state variables [realtype, input] + * FY -- array containing state derivatives [realtype, input] + * H -- current step size [realtype, input] + * IPAR -- array containing integer user data that was passed to + * FCVMALLOC [long int, input] + * RPAR -- array containing real user data that was passed to + * FCVMALLOC [realtype, input] + * WORK -- array containing temporary workspace of same size as Y + * [realtype, input] + * IER -- return flag [int, output]: + * 0 if successful, + * nonzero if an error. + * + * (3) Optional user-supplied preconditioner setup/solve routines: FCVPSET + * and FCVPSOL + * + * As an option when using the CVLS linear solver interface and an + * iterative linear solver, the user may supply routines to setup and + * apply the preconditioner. If supplied, these must have the + * following form: + * + * SUBROUTINE FCVPSET(T,Y,FY,JOK,JCUR,GAMMA,H,IPAR,RPAR,IER) + * + * This routine must set up the preconditioner P to be used in the + * subsequent call to FCVPSOL. The preconditioner (or the product of + * the left and right preconditioners if using both) should be an + * approximation to the matrix A = I - GAMMA*J (J = Jacobian), + * + * The arguments are: + * T = current time [realtype, input] + * Y = current state variable array [realtype, input] + * FY = current state variable derivative array [realtype, input] + * JOK = flag indicating whether Jacobian-related data needs to be + * recomputed [int, input]: + * 0 = recompute, + * 1 = reuse with the current value of GAMMA + * JCUR = return flag to denote if Jacobian data was recomputed + * [realtype, output], 1=yes, 0=no + * GAMMA = Jacobian scaling factor [realtype, input] + * H = current time step [realtype, input] + * IPAR = array of user integer data [long int, input/output] + * RPAR = array with user real data [realtype, input/output] + * IER = return completion flag [int, output]: + * 0 = SUCCESS, + * >0 = recoverable failure + * <0 = non-recoverable failure + * + * The user-supplied routine FCVPSOL must have the form: + * + * SUBROUTINE FCVPSOL(T,Y,FY,R,Z,GAMMA,DELTA,LR,IPAR,RPAR,IER) + * + * Typically this routine will use only T, Y, GAMMA, R, LR, and Z. It + * must solve the preconditioner linear system Pz = r. The preconditioner + * (or the product of the left and right preconditioners if both are + * nontrivial) should be an approximation to the matrix I - GAMMA*J + * (J = Jacobian). + * + * The arguments are: + * T = current time [realtype, input] + * Y = current state variable array [realtype, input] + * FY = current state variable derivative array [realtype, input] + * R = right-hand side array [realtype, input] + * Z = solution array [realtype, output] + * GAMMA = Jacobian scaling factor [realtype, input] + * DELTA = desired residual tolerance [realtype, input] + * LR = flag denoting to solve the right or left preconditioner system + * 1 = left preconditioner + * 2 = right preconditioner + * IPAR = array of user integer data [long int, input/output] + * RPAR = array with user real data [realtype, input/output] + * IER = return completion flag [int, output]: + * 0 = SUCCESS, + * >0 = recoverable failure + * <0 = non-recoverable failure + * + * (4) Optional user-supplied error weight vector routine: FCVEWT + * + * As an option to providing the relative and absolute tolerances, the user + * may supply a routine that computes the weights used in the WRMS norms. + * If supplied, it must have the following form: + * + * SUBROUTINE FCVEWT (Y, EWT, IPAR, RPAR, IER) + * + * It must store the error weights in EWT, given the current solution vector Y. + * + * The arguments are: + * Y -- array containing state variables [realtype, input] + * EWT -- array containing the error weight vector [realtype, output] + * IPAR -- array containing integer user data that was passed to + * FCVMALLOC [long int, input] + * RPAR -- array containing real user data that was passed to + * FCVMALLOC [realtype, input] + * IER -- return flag [int, output]: + * 0 if successful, + * nonzero if an error. + * + * + * ----------------------------------------------------------------------------- + * + * (5) Initialization: FNVINITS / FNVINITP / FNVINITOMP / FNVINITPTS, + * FSUNBANDMATINIT / FSUNDENSEMATINIT / + * FSUNSPARSEMATINIT, + * FSUNBANDLINSOLINIT / FSUNDENSELINSOLINIT / + * FSUNKLUINIT / FSUNKLUREINIT / + * FSUNKLUSETORDERING / FSUNLAPACKBANDINIT / + * FSUNLAPACKDENSEINIT / FSUNPCGINIT / + * FSUNSPBCGSINIT / FSUNSPFGMRINIT / FSUNSPGMRINIT / + * FSUNSPTFQMRINIT / FSUNSUPERLUMTINIT / + * FSUNSUPERLUMTSETORDERING, + * FCVMALLOC, + * FCVLSINIT, + * FCVREINIT + * + * NOTE: the initialization order is important! It *must* proceed as + * shown: vector, matrix (if used), linear solver (if used), CVode, + * CVLs, reinit. + * + * (5.1s) To initialize the a vector specification for storing the solution + * data, the user must make one of the following calls: + * + * (serial) + * CALL FNVINITS(1, NEQ, IER) + * (MPI parallel) + * CALL FNVINITP(COMM, 1, NLOCAL, NGLOBAL, IER) + * (OpenMP threaded) + * CALL FNVINITOMP(1, NEQ, NUM_THREADS, IER) + * (PThreads threaded) + * CALL FNVINITPTS(1, NEQ, NUM_THREADS, IER) + * + * In each of these, one argument is an int containing the CVODE solver + * ID (1). + * + * The other arguments are: + * NEQ = size of vectors [long int, input] + * COMM = the MPI communicator [int, input] + * NLOCAL = local size of vectors on this processor + * [long int, input] + * NGLOBAL = the system size, and the global size of vectors (the sum + * of all values of NLOCAL) [long int, input] + * NUM_THREADS = number of threads + * IER = return completion flag [int, output]: + * 0 = success, + * -1 = failure. + * + * (5.2) To initialize a band/dense/sparse matrix structure for + * storing the system Jacobian and for use within a direct linear solver, + * the user must make one of the following calls: + * + * CALL FSUNBANDMATINIT(1, N, MU, ML, SMU, IER) + * CALL FSUNDENSEMATINIT(1, M, N, IER) + * CALL FSUNSPARSEMATINIT(1, M, N, NNZ, SPARSETYPE, IER) + * + * In each of these, one argument is an int containing the CVODE solver + * ID (1). + * + * The other arguments are: + * + * M = the number of rows of the matrix [long int, input] + * N = the number of columns of the matrix [long int, input] + * MU = the number of upper bands (diagonal not included) in a banded + * matrix [long int, input] + * ML = the number of lower bands (diagonal not included) in a banded + * matrix [long int, input] + * SMU = the number of upper bands to store (diagonal not included) + * for factorization of a banded matrix [long int, input] + * NNZ = the storage size (upper bound on the number of nonzeros) for + * a sparse matrix [long int, input] + * SPARSETYPE = integer denoting use of CSC (0) vs CSR (1) storage + * for a sparse matrix [int, input] + * IER = return completion flag [int, output]: + * 0 = success, + * -1 = failure. + * + * (5.3) To initialize a linear solver structure for solving linear systems + * arising from implicit treatment of the IVP, the user must make + * one of the following calls: + * + * CALL FSUNBANDLINSOLINIT(1, IER) + * CALL FSUNDENSELINSOLINIT(1, IER) + * CALL FSUNKLUINIT(1, IER) + * CALL FSUNLAPACKBANDINIT(1, IER) + * CALL FSUNLAPACKDENSEINIT(1, IER) + * CALL FSUNPCGINIT(1, PRETYPE, MAXL, IER) + * CALL FSUNSPBCGSINIT(1, PRETYPE, MAXL, IER) + * CALL FSUNSPFGMRINIT(1, PRETYPE, MAXL, IER) + * CALL FSUNSPGMRINIT(1, PRETYPE, MAXL, IER) + * CALL FSUNSPTFQMRINIT(1, PRETYPE, MAXL, IER) + * CALL FSUNSUPERLUMTINIT(1, NUM_THREADS, IER) + * + * Or once these have been initialized, their solver parameters may be + * modified via calls to the functions + * + * CALL FSUNKLUSETORDERING(1, ORD_CHOICE, IER) + * CALL FSUNSUPERLUMTSETORDERING(1, ORD_CHOICE, IER) + * + * CALL FSUNPCGSETPRECTYPE(1, PRETYPE, IER) + * CALL FSUNPCGSETMAXL(1, MAXL, IER) + * CALL FSUNSPBCGSSETPRECTYPE(1, PRETYPE, IER) + * CALL FSUNSPBCGSSETMAXL(1, MAXL, IER) + * CALL FSUNSPFGMRSETGSTYPE(1, GSTYPE, IER) + * CALL FSUNSPFGMRSETPRECTYPE(1, PRETYPE, IER) + * CALL FSUNSPGMRSETGSTYPE(1, GSTYPE, IER) + * CALL FSUNSPGMRSETPRECTYPE(1, PRETYPE, IER) + * CALL FSUNSPTFQMRSETPRECTYPE(1, PRETYPE, IER) + * CALL FSUNSPTFQMRSETMAXL(1, MAXL, IER) + * + * In all of the above, one argument is an int containing the CVODE solver + * ID (1). + * + * The other arguments are: + * + * NNZ = the storage size (upper bound on the number of nonzeros) for + * a sparse matrix [long int, input] + * ORD_CHOICE = integer denoting ordering choice (see + * SUNKLUSetOrdering and SUNSuperLUMTSetOrdering documentation + * for details) [int, input] + * PRETYPE = type of preconditioning to perform (0=none, 1=left, + * 2=right, 3=both) [int, input] + * MAXL = maximum Krylov subspace dimension [int, input] + * GSTYPE = choice of Gram-Schmidt orthogonalization algorithm + * (0=modified, 1=classical) [int, input] + * IER = return completion flag [int, output]: + * 0 = success, + * -1 = failure. + * + * + * (5.4) To set various problem and solution parameters and allocate + * internal memory, make the following call: + * + * CALL FCVMALLOC(T0, Y0, METH, IATOL, RTOL, ATOL, + * 1 IOUT, ROUT, IPAR, RPAR, IER) + * + * The arguments are: + * T0 = initial value of t [realtype, input] + * Y0 = array of initial conditions [realtype, input] + * METH = flag denoting basic integration method [int, input]: + * 1 = Adams (nonstiff), + * 2 = BDF (stiff) + * IATOL = flag denoting type for absolute tolerance ATOL [int, input]: + * 1 = scalar, + * 2 = array. + * 3 = user-supplied function; the user must supply a routine + * FCVEWT to compute the error weight vector. + * RTOL = scalar relative tolerance [realtype, input] + * ATOL = scalar or array absolute tolerance [realtype, input] + * IOUT = array of length 21 for integer optional outputs + * [long int, output] + * ROUT = array of length 6 for real optional outputs [realtype, output] + * IPAR = array with user integer data [long int, input/output] + * RPAR = array with user real data [realtype, input/output] + * IER = return completion flag [int, output]: + * 0 = SUCCESS, + * -1 = failure (see printed message for failure details). + * + * The user data arrays IPAR and RPAR are passed unmodified to all subsequent + * calls to user-provided routines. Modifications to either array inside a + * user-provided routine will be propagated. Using these two arrays, the user + * can dispense with Common blocks to pass data betwen user-provided routines. + * + * The optional outputs are: + * LENRW = IOUT( 1) from CVodeGetWorkSpace + * LENIW = IOUT( 2) from CVodeGetWorkSpace + * NST = IOUT( 3) from CVodeGetNumSteps + * NFE = IOUT( 4) from CVodeGetNumRhsEvals + * NETF = IOUT( 5) from CVodeGetNumErrTestFails + * NCFN = IOUT( 6) from CVodeGetNumNonlinSolvConvFails + * NNI = IOUT( 7) from CVodeGetNumNonlinSolvIters + * NSETUPS = IOUT( 8) from CVodeGetNumLinSolvSetups + * QU = IOUT( 9) from CVodeGetLastOrder + * QCUR = IOUT(10) from CVodeGetCurrentOrder + * NOR = IOUT(11) from CVodeGetNumStabLimOrderReds + * NGE = IOUT(12) from CVodeGetNumGEvals + * + * H0U = ROUT( 1) from CVodeGetActualInitStep + * HU = ROUT( 2) from CVodeGetLastStep + * HCUR = ROUT( 3) from CVodeGetCurrentStep + * TCUR = ROUT( 4) from CVodeGetCurrentTime + * TOLSF = ROUT( 5) from CVodeGetTolScaleFactor + * UROUND = ROUT( 6) from UNIT_ROUNDOFF + * See the CVODE manual for details. + * + * (5.5) If a linear solver was created in step (5.3) then it must be + * attached to CVode. If the user called any one of FSUNBANDLINSOLINIT, + * FSUNDENSELINSOLINIT, FSUNKLUINIT, FSUNLAPACKBANDINIT, + * FSUNLAPACKDENSEINIT, FSUNSUPERLUMTINIT, FSUNPCGINIT, + * FSUNSPBCGSINIT, FSUNSPFGMRINIT, FSUNSPGMRINIT, or FSUNSPTFQMRINIT, + * then this must be attached to the CVLS interface using the command: + * + * CALL FCVLSINIT(IER) + * + * The arguments are: + * IER = return completion flag [int, output]: + * 0 = SUCCESS, + * -1 = failure (see printed message for failure details). + * + * (5.5) If the user instead wishes to use a diagonal approximate Jacobian for + * solving the Newton systems, then it must be created and attached to CVode. + * This choice is appropriate when the Jacobian can be well approximated by + * a diagonal matrix. The user must make the call: + * CALL FCVDIAG(IER) + * + * The arguments are: + * IER = return completion flag [int, output]: + * 0 = SUCCESS, + * -1 = failure (see printed message for failure details). + * + * (5.6) If the user program includes the FCVEWT routine for the evaluation + * of the error weights, the following call must be made + * + * CALL FCVEWTSET(FLAG, IER) + * + * with FLAG = 1 to specify that FCVEWT is provided and + * should be used; FLAG = 0 resets to the default EWT formulation. + * The return flag IER is 0 if successful, and nonzero otherwise. + * + * (5.7) If the user program includes the FCVBJAC routine for the + * evaluation of the band approximation to the Jacobian, then following + * the call to FCVLSINIT, the following call must be made + * + * CALL FCVBANDSETJAC(FLAG, IER) + * + * with the int FLAG=1 to specify that FCVBJAC is provided and should be + * used; FLAG=0 specifies a reset to the internal finite difference + * Jacobian approximation. The int return flag IER=0 if successful, + * nonzero otherwise. + * + * If the user program includes the FCVDJAC routine for the evaluation + * of the dense approximation to the Jacobian, then after the call to + * FCVLSINIT, the following call must be made + * + * CALL FCVDENSESETJAC(FLAG, IER) + * + * with the int FLAG=1 to specify that FCVDJAC is provided and should be + * used; FLAG=0 specifies a reset to the internal finite difference + * Jacobian approximation. The int return flag IER=0 if successful, and + * nonzero otherwise. + * + * When using a sparse matrix and linear solver the user must provide the + * FCVSPJAC routine for the evaluation of the sparse approximation to + * the Jacobian. To indicate that this routine has been provided, after + * the call to FCVLSINIT, the following call must be made + * + * CALL FCVSPARSESETJAC(IER) + * + * The int return flag IER=0 if successful, and nonzero otherwise. + * + * (5.8) If the user program includes the FCVJTSETUP and FCVJTIMES + * routines for setup of a Jacobian-times-vector product (for use with + * the CVLS interface), then after creating the CVLS interface, + * the following call must be made: + * + * CALL FCVLSSETJAC(FLAG, IER) + * + * with the int FLAG=1 to specify that FCVJTSETUP and FCVJTIMES are + * provided and should be used; FLAG=0 specifies a reset to the internal + * finite difference approximation to this product). The int return + * flag IER=0 if successful, and nonzero otherwise. + * + * (5.9) If the user program includes the FCVPSET and FCVPSOL routines + * for supplying a preconditioner to an iterative linear solver, then + * after creating the CVLS interface, the following call must be made + * + * CALL FCVLSSETPREC(FLAG, IER) + * + * with the int FLAG=1. If FLAG=0 then preconditioning with these + * routines will be disabled. The return flag IER=0 if successful, + * nonzero otherwise. + * + * (5.10) If the user wishes to use one of CVode's built-in preconditioning + * modules, FCVBP or FCVBBD, then that should be initialized after + * creating the CVLS interface using one of the calls + * + * CALL FCVBPINIT(NEQ, MU, ML, IER) + * CALL FCVBBDINIT(NLOCAL, MUDQ, MLDQ, MU, ML, DQRELY, IER) + * + * Detailed explanation of the inputs to these functions, as well as any + * requirements of user-supplied functions on which these preconditioning + * modules rely, may be found in the header files for each module, + * fcvbp.h or fcvbbd.h, respectively. + * + * + * + * (5.11) To re-initialize the CVODE solver for the solution of a new problem + * of the same size as one already solved, make the following call: + * + * CALL FCVREINIT(T0, Y0, IATOL, RTOL, ATOL, IER) + * + * The arguments have the same names and meanings as those of FCVMALLOC, + * except that METH has been omitted from the argument list + * (being unchanged for the new problem). + * FCVREINIT performs the same initializations as FCVMALLOC, but does no memory + * allocation, using instead the existing internal memory created by the + * previous FCVMALLOC call. The subsequent calls to + * attach the linear system solver is only needed if that object has been re-created. + * + * (5.12) The SUNKLU solver will reuse much of the factorization information + * from one solve to the next. If at any time the user wants to force a + * full refactorization or if the number of nonzeros in the Jacobian + * matrix changes, the user should make the call + * + * CALL FSUNKLUREINIT(4, NNZ, REINIT_TYPE, IER) + * + * The arguments are: + * NNZ = the maximum number of nonzeros [int; input] + * REINIT_TYPE = 1 or 2. For a value of 1, the matrix will be + * destroyed and a new one will be allocated with NNZ nonzeros. + * For a value of 2, only symbolic and numeric factorizations will + * be completed. + * + * (5.13) To set various integer optional inputs, make the folowing call: + * + * CALL FCVSETIIN(KEY, VALUE, IER) + * + * to set the integer value VAL to the optional input specified by the + * quoted character string KEY. VALUE must be a Fortran integer of size + * commensurate with a C "long int". + * KEY must be one of the following: MAX_ORD, MAX_NSTEPS, MAX_ERRFAIL, + * MAX_NITERS, MAX_CONVFAIL, HNIL_WARNS, STAB_LIM. The int return flag + * IER is 0 if successful, and <0 otherwise. + * + * (5.14) To set various real optional inputs, make the folowing call: + * + * CALL FCVSETRIN(KEY, VALUE, IER) + * + * to set the real value VAL to the optional input specified by the + * quoted character string KEY. VALUE must be a Fortran real-valued + * number of size commensurate with the SUNDIALS "realtype". KEY must + * be one of the following: INIT_STEP, MAX_STEP, MIN_STEP, STOP_TIME, + * NLCONV_COEF. The int return flag IER is 0 if successful, and <0 otherwise. + * + * (5.15) To set the vector of constraints, make the following call: + * + * CALL CVSETVIN(KEY, ARRAY, IER) + * + * where ARRAY is an array of realtype and the quoted character string + * KEY is CONSTR_VEC. The int return flag IER is 0 if successful, and + * nonzero otherwise. + * + * ----------------------------------------------------------------------------- + * + * (6) Optional outputs from CVLS linear solvers (stored in the + * IOUT array that was passed to FCVMALLOC) + * + * Optional outputs specific to the CVLS interface: + * LENRWLS = IOUT(13) from CVodeGetLinWorkSpace (realtype space) + * LENIWLS = IOUT(14) from CVodeGetLinWorkSpace (integer space) + * LSTF = IOUT(15) from CVodeGetLastLinFlag + * NFELS = IOUT(16) from CVodeGetNumLinRhsEvals + * NJE = IOUT(17) from CVodeGetNumJacEvals + * NJTS = IOUT(18) from CVodeGetNumJTSetupEvals + * NJTV = IOUT(19) from CVodeGetNumJtimesEvals + * NPE = IOUT(20) from CVodeGetNumPrecEvals + * NPS = IOUT(21) from CVodeGetNumPrecSolves + * NLI = IOUT(22) from CVodeGetNumLinIters + * NCFL = IOUT(23) from CVodeGetNumLinConvFails + * + * Optional outputs specific to the DIAG case are: + * LENRWLS = IOUT(13) from CVDiagGetWorkSpace + * LENIWLS = IOUT(14) from CVDiagGetWorkSpace + * LSTF = IOUT(15) from CVDiagGetLastFlag + * NFELS = IOUT(16) from CVDiagGetNumRhsEvals + * + * See the CVODE manual for more detailed descriptions of any of the + * above. + * + * ----------------------------------------------------------------------------- + * + * (7) The integrator: FCVODE + * + * Carrying out the integration is accomplished by making calls as follows: + * + * CALL FCVODE (TOUT, T, Y, ITASK, IER) + * + * The arguments are: + * TOUT = next value of t at which a solution is desired [realtype, input] + * T = value of t reached by the solver on output [realtype, output] + * Y = array containing the computed solution on output [realtype, output] + * ITASK = task indicator [int, input]: + * 1 = normal mode (overshoot TOUT and interpolate) + * 2 = one-step mode (return after each internal step taken) + * 3 = normal tstop mode (like 1, but integration never proceeds past + * TSTOP, which must be specified through a call to FCVSETRIN + * using the key 'STOP_TIME') + * 4 = one step tstop (like 2, but integration never goes past TSTOP) + * IER = completion flag [int, output]: + * 0 = success, + * 1 = tstop return, + * 2 = root return, + * values -1 ... -10 are various failure modes (see CVODE manual). + * The current values of the optional outputs are available in IOUT and ROUT. + * + * ----------------------------------------------------------------------------- + * + * (8) Computing solution derivatives: FCVDKY + * + * To obtain a derivative of the solution, of order up to the current method + * order, make the following call: + * + * CALL FCVDKY (T, K, DKY, IER) + * + * The arguments are: + * T = value of t at which solution derivative is desired, in + * [TCUR-HU,TCUR], [realtype, input]. + * K = derivative order (0 .le. K .le. QU) [int, input] + * DKY = array containing computed K-th derivative of y [realtype, output] + * IER = return flag [int, output]: = 0 for success, <0 for illegal argument + * + * ----------------------------------------------------------------------------- + * + * (9) Get the current error weight vector: FCVGETERRWEIGHTS + * + * To obtain the current error weight vector, make the following call: + * + * CALL FCVGETERRWEIGHTS(EWT, IER) + * + * The arguments are: + * EWT = array containing the error weight vector [realtype, output] + * IER = return flag [int, output]: 0=success, nonzero if an error. + * + * ----------------------------------------------------------------------------- + * + * (10) Memory freeing: FCVFREE + * + * To free the internal memory created by the calls to FCVMALLOC, + * FCVLSINIT and FNVINIT*, make the call + * + * CALL FCVFREE + * + * ============================================================================= + */ + +#ifndef _FCVODE_H +#define _FCVODE_H + +/* header files */ +#include <cvode/cvode.h> +#include <sundials/sundials_linearsolver.h> /* definition of type SUNLinearSolver */ +#include <sundials/sundials_matrix.h> /* definition of type SUNMatrix */ +#include <sundials/sundials_nvector.h> /* definition of type N_Vector */ +#include <sundials/sundials_types.h> /* definition of type realtype */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* Definitions of interface function names */ + +#if defined(SUNDIALS_F77_FUNC) + +#define FCV_MALLOC SUNDIALS_F77_FUNC(fcvmalloc, FCVMALLOC) +#define FCV_REINIT SUNDIALS_F77_FUNC(fcvreinit, FCVREINIT) +#define FCV_SETIIN SUNDIALS_F77_FUNC(fcvsetiin, FCVSETIIN) +#define FCV_SETRIN SUNDIALS_F77_FUNC(fcvsetrin, FCVSETRIN) +#define FCV_SETVIN SUNDIALS_F77_FUNC(fcvsetvin, FCVSETVIN) +#define FCV_EWTSET SUNDIALS_F77_FUNC(fcvewtset, FCVEWTSET) +#define FCV_LSINIT SUNDIALS_F77_FUNC(fcvlsinit, FCVLSINIT) +#define FCV_LSSETJAC SUNDIALS_F77_FUNC(fcvlssetjac, FCVLSSETJAC) +#define FCV_LSSETPREC SUNDIALS_F77_FUNC(fcvlssetprec, FCVLSSETPREC) +#define FCV_LSSETEPSLIN SUNDIALS_F77_FUNC(fcvlssetepslin, FCVLSSETEPSLIN) +#define FCV_DENSESETJAC SUNDIALS_F77_FUNC(fcvdensesetjac, FCVDENSESETJAC) +#define FCV_BANDSETJAC SUNDIALS_F77_FUNC(fcvbandsetjac, FCVBANDSETJAC) +#define FCV_SPARSESETJAC SUNDIALS_F77_FUNC(fcvsparsesetjac, FCVSPARSESETJAC) +#define FCV_DIAG SUNDIALS_F77_FUNC(fcvdiag, FCVDIAG) +#define FCV_CVODE SUNDIALS_F77_FUNC(fcvode, FCVODE) +#define FCV_DKY SUNDIALS_F77_FUNC(fcvdky, FCVDKY) +#define FCV_FREE SUNDIALS_F77_FUNC(fcvfree, FCVFREE) +#define FCV_FUN SUNDIALS_F77_FUNC(fcvfun, FCVFUN) +#define FCV_DJAC SUNDIALS_F77_FUNC(fcvdjac, FCVDJAC) +#define FCV_BJAC SUNDIALS_F77_FUNC(fcvbjac, FCVBJAC) +#define FCV_SPJAC SUNDIALS_F77_FUNC(fcvspjac, FCVSPJAC) +#define FCV_PSOL SUNDIALS_F77_FUNC(fcvpsol, FCVPSOL) +#define FCV_PSET SUNDIALS_F77_FUNC(fcvpset, FCVPSET) +#define FCV_JTSETUP SUNDIALS_F77_FUNC(fcvjtsetup, FCVJTSETUP) +#define FCV_JTIMES SUNDIALS_F77_FUNC(fcvjtimes, FCVJTIMES) +#define FCV_EWT SUNDIALS_F77_FUNC(fcvewt, FCVEWT) +#define FCV_GETERRWEIGHTS SUNDIALS_F77_FUNC(fcvgeterrweights, FCVGETERRWEIGHTS) +#define FCV_GETESTLOCALERR SUNDIALS_F77_FUNC(fcvgetestlocalerr, FCVGETESTLOCALERR) +#define FCV_NLSINIT SUNDIALS_F77_FUNC(fcvnlsinit, FCVNLSINIT) + +/*---DEPRECATED---*/ +#define FCV_DLSINIT SUNDIALS_F77_FUNC(fcvdlsinit, FCVDLSINIT) +#define FCV_DLSSETJAC SUNDIALS_F77_FUNC(fcvdlssetjac, FCVDLSSETJAC) +#define FCV_SPILSINIT SUNDIALS_F77_FUNC(fcvspilsinit, FCVSPILSINIT) +#define FCV_SPILSSETPREC SUNDIALS_F77_FUNC(fcvspilssetprec, FCVSPILSSETPREC) +/*----------------*/ + +#else + +#define FCV_MALLOC fcvmalloc_ +#define FCV_REINIT fcvreinit_ +#define FCV_SETIIN fcvsetiin_ +#define FCV_SETRIN fcvsetrin_ +#define FCV_SETVIN fcvsetvin_ +#define FCV_EWTSET fcvewtset_ +#define FCV_LSINIT fcvlsinit_ +#define FCV_LSSETJAC fcvlssetjac_ +#define FCV_LSSETPREC fcvlssetprec_ +#define FCV_LSSETEPSLIN fcvlssetepslin_ +#define FCV_DENSESETJAC fcvdensesetjac_ +#define FCV_BANDSETJAC fcvbandsetjac_ +#define FCV_SPARSESETJAC fcvsparsesetjac_ +#define FCV_DIAG fcvdiag_ +#define FCV_CVODE fcvode_ +#define FCV_DKY fcvdky_ +#define FCV_FREE fcvfree_ +#define FCV_FUN fcvfun_ +#define FCV_DJAC fcvdjac_ +#define FCV_BJAC fcvbjac_ +#define FCV_SPJAC fcvspjac_ +#define FCV_PSOL fcvpsol_ +#define FCV_PSET fcvpset_ +#define FCV_JTSETUP fcvjtsetup_ +#define FCV_JTIMES fcvjtimes_ +#define FCV_EWT fcvewt_ +#define FCV_GETERRWEIGHTS fcvgeterrweights_ +#define FCV_GETESTLOCALERR fcvgetestlocalerr_ +#define FCV_NLSINIT fcvnlsinit_ + +/*---DEPRECATED---*/ +#define FCV_DLSINIT fcvdlsinit_ +#define FCV_SPILSINIT fcvspilsinit_ +#define FCV_SPILSINIT fcvspilsinit_ +#define FCV_SPILSSETPREC fcvspilssetprec_ +/*----------------*/ + +#endif + + /* Type for user data */ + + typedef struct { + realtype *rpar; + long int *ipar; + } *FCVUserData; + + /* Prototypes of exported functions */ + + void FCV_MALLOC(realtype *t0, realtype *y0, + int *meth, int *iatol, + realtype *rtol, realtype *atol, + long int *iout, realtype *rout, + long int *ipar, realtype *rpar, + int *ier); + + void FCV_REINIT(realtype *t0, realtype *y0, + int *iatol, realtype *rtol, realtype *atol, + int *ier); + + void FCV_SETIIN(char key_name[], long int *ival, int *ier); + + void FCV_SETRIN(char key_name[], realtype *rval, int *ier); + + void FCV_SETVIN(char key_name[], realtype *vval, int *ier); + void FCV_EWTSET(int *flag, int *ier); + + void FCV_LSINIT(int *ier); + void FCV_LSSETJAC(int *flag, int *ier); + void FCV_LSSETPREC(int *flag, int *ier); + void FCV_LSSETEPSLIN(realtype *eplifac, int *ier); + void FCV_DENSESETJAC(int *flag, int *ier); + void FCV_BANDSETJAC(int *flag, int *ier); + void FCV_SPARSESETJAC(int *ier); + +/*---DEPRECATED---*/ + void FCV_DLSINIT(int *ier); + void FCV_DLSSETJAC(int *flag, int *ier); + void FCV_SPILSINIT(int *ier); + void FCV_SPILSSETPREC(int *flag, int *ier); + void FCV_SPILSSETEPSLIN(realtype *eplifac, int *ier); +/*----------------*/ + + void FCV_DIAG(int *ier); + + void FCV_NLSINIT(int *ier); + + void FCV_CVODE(realtype *tout, realtype *t, realtype *y, int *itask, int *ier); + + void FCV_DKY(realtype *t, int *k, realtype *dky, int *ier); + + void FCV_GETERRWEIGHTS(realtype *eweight, int *ier); + void FCV_GETESTLOCALERR(realtype *ele, int *ier); + + void FCV_FREE(void); + + + /* Prototypes: Functions Called by the CVODE Solver */ + + int FCVf(realtype t, N_Vector y, N_Vector ydot, void *user_data); + + int FCVDenseJac(realtype t, N_Vector y, N_Vector fy, + SUNMatrix J, void *user_data, + N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3); + + int FCVBandJac(realtype t, N_Vector y, N_Vector fy, + SUNMatrix J, void *user_data, + N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3); + + int FCVSparseJac(realtype t, N_Vector y, N_Vector fy, SUNMatrix J, + void *user_data, N_Vector vtemp1, + N_Vector vtemp2, N_Vector vtemp3); + + int FCVPSet(realtype tn, N_Vector y, N_Vector fy, booleantype jok, + booleantype *jcurPtr, realtype gamma, void *user_data); + + int FCVPSol(realtype tn, N_Vector y, N_Vector fy, + N_Vector r, N_Vector z, + realtype gamma, realtype delta, + int lr, void *user_data); + + int FCVJTSetup(realtype t, N_Vector y, N_Vector fy, void *user_data); + + int FCVJtimes(N_Vector v, N_Vector Jv, realtype t, + N_Vector y, N_Vector fy, + void *user_data, N_Vector work); + + int FCVEwtSet(N_Vector y, N_Vector ewt, void *user_data); + + void FCVNullMatrix(); + void FCVNullLinsol(); + void FCVNullNonlinSol(); + + /* Declarations for global variables shared amongst various routines */ + + extern N_Vector F2C_CVODE_vec; /* defined in FNVECTOR module */ + extern SUNMatrix F2C_CVODE_matrix; /* defined in FSUNMATRIX module */ + extern SUNLinearSolver F2C_CVODE_linsol; /* defined in FSUNLINSOL module */ + extern SUNNonlinearSolver F2C_CVODE_nonlinsol; /* defined in FSUNNONLINSOL module */ + + extern void *CV_cvodemem; /* defined in fcvode.c */ + extern long int *CV_iout; /* defined in fcvode.c */ + extern realtype *CV_rout; /* defined in fcvode.c */ + extern int CV_nrtfn; /* defined in fcvode.c */ + extern int CV_ls; /* defined in fcvode.c */ + + /* Linear solver IDs */ + + enum { CV_LS_STD = 0, CV_LS_DIAG = 1 }; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvpreco.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvpreco.c new file mode 100644 index 0000000..b03404b --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvpreco.c @@ -0,0 +1,130 @@ +/* + * ----------------------------------------------------------------- + * 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 + * 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 + * ----------------------------------------------------------------- + * The C functions FCVPSet and FCVPSol are to interface between the + * CVLS module and the user-supplied preconditioner setup/solve + * routines FCVPSET and FCVPSOL. Note the use of the generic names + * FCV_PSET and FCV_PSOL below. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fcvode.h" /* actual fn. names, prototypes and global vars.*/ +#include "cvode_impl.h" /* definition of CVodeMem type */ + +#include <cvode/cvode_ls.h> + +/*********************************************************************/ + +/* Prototype of the Fortran routines */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FCV_PSET(realtype *T, realtype *Y, realtype *FY, + booleantype *JOK, booleantype *JCUR, + realtype *GAMMA, realtype *H, + long int *IPAR, realtype *RPAR, int *IER); + + extern void FCV_PSOL(realtype *T, realtype *Y, realtype *FY, + realtype *R, realtype *Z, + realtype *GAMMA, realtype *DELTA, + int *LR, long int *IPAR, realtype *RPAR, + int *IER); + +#ifdef __cplusplus +} +#endif + +/***************************************************************************/ + +/* ---DEPRECATED--- */ +void FCV_SPILSSETPREC(int *flag, int *ier) +{ FCV_LSSETPREC(flag, ier); } + +void FCV_LSSETPREC(int *flag, int *ier) +{ + if (*flag == 0) { + *ier = CVodeSetPreconditioner(CV_cvodemem, NULL, NULL); + } else { + *ier = CVodeSetPreconditioner(CV_cvodemem, FCVPSet, FCVPSol); + } +} + +/***************************************************************************/ + +/* C function FCVPSet to interface between CVODE and a Fortran subroutine + FCVPSET for setup of a Krylov preconditioner. + Addresses of t, y, fy, jok, gamma, h, vtemp1, vtemp2, vtemp3, and the + address jcurPtr are passed to FCVPSET, using the routine + N_VGetArrayPointer from NVECTOR. + A return flag ier from FCVPSET is returned by FCVPSet. + Auxiliary data is assumed to be communicated by common blocks. */ + +int FCVPSet(realtype t, N_Vector y, N_Vector fy, booleantype jok, + booleantype *jcurPtr, realtype gamma, + void *user_data) +{ + int ier = 0; + realtype *ydata, *fydata; + realtype h; + FCVUserData CV_userdata; + + CVodeGetLastStep(CV_cvodemem, &h); + + ydata = N_VGetArrayPointer(y); + fydata = N_VGetArrayPointer(fy); + + CV_userdata = (FCVUserData) user_data; + + FCV_PSET(&t, ydata, fydata, &jok, jcurPtr, &gamma, &h, + CV_userdata->ipar, CV_userdata->rpar, &ier); + + return(ier); +} + +/***************************************************************************/ + +/* C function FCVPSol to interface between CVODE and a Fortran subroutine + FCVPSOL for solution of a Krylov preconditioner. + Addresses of t, y, fy, gamma, delta, lr, vtemp, r, and z are + passed to FCVPSOL, using the routine N_VGetArrayPointer from NVECTOR. + A return flag ier from FCVPSOL is returned by FCVPSol. + Auxiliary data is assumed to be communicated by Common blocks. */ + +int FCVPSol(realtype t, N_Vector y, N_Vector fy, + N_Vector r, N_Vector z, + realtype gamma, realtype delta, + int lr, void *user_data) +{ + int ier = 0; + realtype *ydata, *fydata, *rdata, *zdata; + FCVUserData CV_userdata; + + ydata = N_VGetArrayPointer(y); + fydata = N_VGetArrayPointer(fy); + rdata = N_VGetArrayPointer(r); + zdata = N_VGetArrayPointer(z); + + CV_userdata = (FCVUserData) user_data; + + FCV_PSOL(&t, ydata, fydata, rdata, zdata, &gamma, &delta, &lr, + CV_userdata->ipar, CV_userdata->rpar, &ier); + + return(ier); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvroot.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvroot.c new file mode 100644 index 0000000..2f99da0 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvroot.c @@ -0,0 +1,85 @@ +/* + * ----------------------------------------------------------------- + * 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 + * ----------------------------------------------------------------- + * The FCVROOT module contains the routines necessary to use + * the rootfinding feature of the CVODE module and to interface + * with the user-supplied Fortran subroutine. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fcvode.h" /* actual fn. names, prototypes and global variables */ +#include "fcvroot.h" /* prototypes of interfaces to CVODE */ +#include "cvode_impl.h" /* definition of CVodeMem type */ + +/***************************************************************************/ + +/* Prototype of the Fortran routine */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + extern void FCV_ROOTFN(realtype *T, realtype *Y, realtype *G, + long int *IPAR, realtype *RPAR, + int *ier); +#ifdef __cplusplus +} +#endif + +/***************************************************************************/ + +void FCV_ROOTINIT(int *nrtfn, int *ier) +{ + *ier = CVodeRootInit(CV_cvodemem, *nrtfn, (CVRootFn) FCVrootfunc); + CV_nrtfn = *nrtfn; + + return; +} + +/***************************************************************************/ + +void FCV_ROOTINFO(int *nrtfn, int *info, int *ier) +{ + *ier = CVodeGetRootInfo(CV_cvodemem, info); + return; +} + +/***************************************************************************/ + +void FCV_ROOTFREE(void) +{ + CVodeRootInit(CV_cvodemem, 0, NULL); + + return; +} + +/***************************************************************************/ + +int FCVrootfunc(realtype t, N_Vector y, realtype *gout, void *user_data) +{ + int ier; + realtype *ydata; + FCVUserData CV_userdata; + + ydata = N_VGetArrayPointer(y); + + CV_userdata = (FCVUserData) user_data; + + FCV_ROOTFN(&t, ydata, gout, CV_userdata->ipar, CV_userdata->rpar, &ier); + + return(ier); +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvroot.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvroot.h new file mode 100644 index 0000000..d92f192 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvroot.h @@ -0,0 +1,141 @@ +/* + * ----------------------------------------------------------------- + * 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 Fortran interface include file for the rootfinding + * feature of CVODE. + * ----------------------------------------------------------------- + */ + +/* + * ============================================================================== + * + * FCVROOT Interface Package + * + * The FCVROOT interface package allows programs written in FORTRAN to + * use the rootfinding feature of the CVODE solver module. + * + * The user-callable functions constituting the FCVROOT package are the + * following: FCVROOTINIT, FCVROOTINFO, and FCVROOTFREE. The corresponding + * CVODE subroutine called by each interface function is given below. + * + * ----------------- ----------------------- + * | FCVROOT routine | | CVODE function called | + * ----------------- ----------------------- + * FCVROOTINIT -> CVodeRootInit + * FCVROOTINFO -> CVodeGetRootInfo + * FCVROOTFREE -> CVodeRootInit + * + * FCVROOTFN is a user-supplied subroutine defining the functions whose + * roots are sought. + * + * ============================================================================== + * + * Usage of the FCVROOT Interface Package + * + * 1. In order to use the rootfinding feature of the CVODE package the user must + * define the following subroutine: + * + * SUBROUTINE FCVROOTFN (T, Y, G, IPAR, RPAR, IER) + * DIMENSION Y(*), G(*), IPAR(*), RPAR(*) + * + * The arguments are: + * T = independent variable value t [input] + * Y = dependent variable vector y [input] + * G = function values g(t,y) [output] + * IPAR, RPAR = user (long int and realtype) data [input/output] + * IER = return flag (0 for success, a non-zero value if an error occurred.) + * + * 2. After calling FCVMALLOC but prior to calling FCVODE, the user must + * allocate and initialize memory for the FCVROOT module by making the + * following call: + * + * CALL FCVROOTINIT (NRTFN, IER) + * + * The arguments are: + * NRTFN = total number of root functions [input] + * IER = return completion flag (0 = success, -1 = CVODE memory NULL and + * -11 memory allocation error) [output] + * + * 3. After calling FCVODE, to see whether a root was found, test the FCVODE + * return flag IER. The value IER = 2 means one or more roots were found. + * + * 4. If a root was found, and if NRTFN > 1, then to determine which root + * functions G(*) were found to have a root, make the following call: + * CALL FCVROOTINFO (NRTFN, INFO, IER) + * The arguments are: + * NRTFN = total number of root functions [input] + * INFO = integer array of length NRTFN, with values 0 or 1 [output] + * For i = 1,...,NRTFN, G(i) was found to have a root if INFO(i) = 1. + * IER = completion flag (0 = success, negative = failure) + * + * 5. The total number of calls made to the root function (FCVROOTFN), NGE, + * can be obtained from IOUT(12). + * + * If the FCVODE/CVODE memory block is reinitialized to solve a different + * problem via a call to FCVREINIT, then the counter variable NGE is cleared + * (reset to zero). + * + * 6. To free the memory resources allocated by a prior call to FCVROOTINIT make + * the following call: + * CALL FCVROOTFREE + * See the CVODE documentation for additional information. + * + * ============================================================================== + */ + +#ifndef _FCVROOT_H +#define _FCVROOT_H + +/* header files */ +#include <sundials/sundials_nvector.h> /* definition of type N_Vector */ +#include <sundials/sundials_types.h> /* definition of SUNDIALS type realtype */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* Definitions of interface function names */ + +#if defined(SUNDIALS_F77_FUNC) + +#define FCV_ROOTINIT SUNDIALS_F77_FUNC(fcvrootinit, FCVROOTINIT) +#define FCV_ROOTINFO SUNDIALS_F77_FUNC(fcvrootinfo, FCVROOTINFO) +#define FCV_ROOTFREE SUNDIALS_F77_FUNC(fcvrootfree, FCVROOTFREE) +#define FCV_ROOTFN SUNDIALS_F77_FUNC(fcvrootfn, FCVROOTFN) + +#else + +#define FCV_ROOTINIT fcvrootinit_ +#define FCV_ROOTINFO fcvrootinfo_ +#define FCV_ROOTFREE fcvrootfree_ +#define FCV_ROOTFN fcvrootfn_ + +#endif + +/* Prototypes of exported function */ + +void FCV_ROOTINIT(int *nrtfn, int *ier); +void FCV_ROOTINFO(int *nrtfn, int *info, int *ier); +void FCV_ROOTFREE(void); + +/* Prototype of function called by CVODE module */ + +int FCVrootfunc(realtype t, N_Vector y, realtype *gout, void *user_data); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvsparse.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvsparse.c new file mode 100644 index 0000000..33dacc1 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvode/fcmix/fcvsparse.c @@ -0,0 +1,93 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds and Ting Yan @ SMU + * Carol 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 + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> +#include "fcvode.h" +#include "cvode_impl.h" +#include <cvode/cvode_ls.h> +#include <sunmatrix/sunmatrix_sparse.h> + +/* Prototype of the Fortran routine */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +extern void FCV_SPJAC(realtype *T, realtype *Y, + realtype *FY, long int *N, + long int *NNZ, realtype *JDATA, + sunindextype *JRVALS, + sunindextype *JCPTRS, realtype *H, + long int *IPAR, realtype *RPAR, + realtype *V1, realtype *V2, + realtype *V3, int *ier); + +#ifdef __cplusplus +} +#endif + +/*=============================================================*/ + +/* Fortran interface to C routine CVSlsSetSparseJacFn; see + fcvode.h for further information */ +void FCV_SPARSESETJAC(int *ier) +{ +#if defined(SUNDIALS_INT32_T) + cvProcessError((CVodeMem) CV_cvodemem, CV_ILL_INPUT, "CVODE", + "FCVSPARSESETJAC", + "Sparse Fortran users must configure SUNDIALS with 64-bit integers."); + *ier = 1; +#else + *ier = CVodeSetJacFn(CV_cvodemem, FCVSparseJac); +#endif +} + +/*=============================================================*/ + +/* C interface to user-supplied Fortran routine FCVSPJAC; see + fcvode.h for additional information */ +int FCVSparseJac(realtype t, N_Vector y, N_Vector fy, + SUNMatrix J, void *user_data, N_Vector vtemp1, + N_Vector vtemp2, N_Vector vtemp3) +{ + int ier; + realtype *ydata, *fydata, *v1data, *v2data, *v3data, *Jdata; + realtype h; + long int NP, NNZ; + sunindextype *indexvals, *indexptrs; + FCVUserData CV_userdata; + + CVodeGetLastStep(CV_cvodemem, &h); + ydata = N_VGetArrayPointer(y); + fydata = N_VGetArrayPointer(fy); + v1data = N_VGetArrayPointer(vtemp1); + v2data = N_VGetArrayPointer(vtemp2); + v3data = N_VGetArrayPointer(vtemp3); + CV_userdata = (FCVUserData) user_data; + NP = SUNSparseMatrix_NP(J); + NNZ = SUNSparseMatrix_NNZ(J); + Jdata = SUNSparseMatrix_Data(J); + indexvals = SUNSparseMatrix_IndexValues(J); + indexptrs = SUNSparseMatrix_IndexPointers(J); + + FCV_SPJAC(&t, ydata, fydata, &NP, &NNZ, Jdata, indexvals, + indexptrs, &h, CV_userdata->ipar, CV_userdata->rpar, + v1data, v2data, v3data, &ier); + return(ier); +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodea.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodea.c new file mode 100644 index 0000000..ed51e23 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodea.c @@ -0,0 +1,3075 @@ +/* + * ----------------------------------------------------------------- + * $Revision$ + * $Date$ + * ----------------------------------------------------------------- + * Programmer(s): 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 CVODEA adjoint integrator. + * ----------------------------------------------------------------- + */ + +/* + * ================================================================= + * IMPORTED HEADER FILES + * ================================================================= + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "cvodes_impl.h" + +#include <sundials/sundials_math.h> +#include <sundials/sundials_types.h> + +/* + * ================================================================= + * CVODEA PRIVATE CONSTANTS + * ================================================================= + */ + +#define ZERO RCONST(0.0) /* real 0.0 */ +#define ONE RCONST(1.0) /* real 1.0 */ +#define TWO RCONST(2.0) /* real 2.0 */ +#define HUNDRED RCONST(100.0) /* real 100.0 */ +#define FUZZ_FACTOR RCONST(1000000.0) /* fuzz factor for IMget */ + +/* + * ================================================================= + * PRIVATE FUNCTION PROTOTYPES + * ================================================================= + */ + +static CkpntMem CVAckpntInit(CVodeMem cv_mem); +static CkpntMem CVAckpntNew(CVodeMem cv_mem); +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 CVAfindIndex(CVodeMem cv_mem, realtype t, + long int *indx, booleantype *newpoint); + +static booleantype CVAhermiteMalloc(CVodeMem cv_mem); +static void CVAhermiteFree(CVodeMem cv_mem); +static int CVAhermiteGetY(CVodeMem cv_mem, realtype t, N_Vector y, N_Vector *yS); +static int CVAhermiteStorePnt(CVodeMem cv_mem, DtpntMem d); + +static booleantype CVApolynomialMalloc(CVodeMem cv_mem); +static void CVApolynomialFree(CVodeMem cv_mem); +static int CVApolynomialGetY(CVodeMem cv_mem, realtype t, N_Vector y, N_Vector *yS); +static int CVApolynomialStorePnt(CVodeMem cv_mem, DtpntMem d); + +/* Wrappers */ + +static int CVArhs(realtype t, N_Vector yB, + N_Vector yBdot, void *cvode_mem); + +static int CVArhsQ(realtype t, N_Vector yB, + N_Vector qBdot, void *cvode_mem); + +/* + * ================================================================= + * EXPORTED FUNCTIONS IMPLEMENTATION + * ================================================================= + */ + +/* + * CVodeAdjInit + * + * This routine initializes ASA and allocates space for the adjoint + * memory structure. + */ + +int CVodeAdjInit(void *cvode_mem, long int steps, int interp) +{ + CVadjMem ca_mem; + CVodeMem cv_mem; + long int i, ii; + + /* --------------- + * Check arguments + * --------------- */ + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeAdjInit", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem)cvode_mem; + + if (steps <= 0) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeAdjInit", MSGCV_BAD_STEPS); + return(CV_ILL_INPUT); + } + + 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 + * ---------------------------- */ + + ca_mem = NULL; + ca_mem = (CVadjMem) malloc(sizeof(struct CVadjMemRec)); + if (ca_mem == NULL) { + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODEA", "CVodeAdjInit", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + /* Attach ca_mem to CVodeMem structure */ + + cv_mem->cv_adj_mem = ca_mem; + + /* ------------------------------ + * Initialization of check points + * ------------------------------ */ + + /* Set Check Points linked list to NULL */ + ca_mem->ck_mem = NULL; + + /* Initialize nckpnts to ZERO */ + ca_mem->ca_nckpnts = 0; + + /* No interpolation data is available */ + ca_mem->ca_ckpntData = NULL; + + /* ------------------------------------ + * Initialization of interpolation data + * ------------------------------------ */ + + /* Interpolation type */ + + ca_mem->ca_IMtype = interp; + + /* Number of steps between check points */ + + ca_mem->ca_nsteps = steps; + + /* Last index used in CVAfindIndex, initailize to invalid value */ + ca_mem->ca_ilast = -1; + + /* Allocate space for the array of Data Point structures */ + + ca_mem->dt_mem = NULL; + ca_mem->dt_mem = (DtpntMem *) malloc((steps+1)*sizeof(struct DtpntMemRec *)); + if (ca_mem->dt_mem == NULL) { + free(ca_mem); ca_mem = NULL; + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODEA", "CVodeAdjInit", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + 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) { + for(ii=0; ii<i; ii++) {free(ca_mem->dt_mem[ii]); ca_mem->dt_mem[ii] = NULL;} + free(ca_mem->dt_mem); ca_mem->dt_mem = NULL; + free(ca_mem); ca_mem = NULL; + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODEA", "CVodeAdjInit", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + } + + /* 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; + ca_mem->ca_IMstore = CVApolynomialStorePnt; + + break; + + } + + /* The interpolation module has not been initialized yet */ + + ca_mem->ca_IMmallocDone = SUNFALSE; + + /* 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 + * - IMinterpSensi will be set in CVodeB to SUNTRUE if IMstoreSensi is + * SUNTRUE and if at least one backward problem requires sensitivities */ + + ca_mem->ca_IMstoreSensi = SUNTRUE; + ca_mem->ca_IMinterpSensi = SUNFALSE; + + /* ------------------------------------ + * Initialize list of backward problems + * ------------------------------------ */ + + ca_mem->cvB_mem = NULL; + ca_mem->ca_bckpbCrt = NULL; + ca_mem->ca_nbckpbs = 0; + + /* -------------------------------- + * CVodeF and CVodeB not called yet + * -------------------------------- */ + + ca_mem->ca_firstCVodeFcall = SUNTRUE; + ca_mem->ca_tstopCVodeFcall = SUNFALSE; + + ca_mem->ca_firstCVodeBcall = SUNTRUE; + + /* --------------------------------------------- + * ASA initialized and allocated + * --------------------------------------------- */ + + cv_mem->cv_adj = SUNTRUE; + cv_mem->cv_adjMallocDone = SUNTRUE; + + return(CV_SUCCESS); +} + +/* CVodeAdjReInit + * + * This routine reinitializes the CVODEA memory structure assuming that the + * 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 + * 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. + * NOTE: if a completely new list of backward problems is also needed, then + * simply free the adjoint memory (by calling CVodeAdjFree) and reinitialize + * ASA with CVodeAdjInit. + */ + +int CVodeAdjReInit(void *cvode_mem) +{ + CVadjMem ca_mem; + CVodeMem cv_mem; + + /* Check cvode_mem */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeAdjReInit", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + 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; + + /* Free current list of Check Points */ + + 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; + + return(CV_SUCCESS); +} + +/* + * CVodeAdjFree + * + * This routine frees the memory allocated by CVodeAdjInit. + */ + +void CVodeAdjFree(void *cvode_mem) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + long int i; + + if (cvode_mem == NULL) return; + cv_mem = (CVodeMem) cvode_mem; + + if (cv_mem->cv_adjMallocDone) { + + ca_mem = cv_mem->cv_adj_mem; + + /* Delete check points one by one */ + while (ca_mem->ck_mem != NULL) CVAckpntDelete(&(ca_mem->ck_mem)); + + /* Free vectors at all data points */ + if (ca_mem->ca_IMmallocDone) { + ca_mem->ca_IMfree(cv_mem); + } + for(i=0; i<=ca_mem->ca_nsteps; i++) { + free(ca_mem->dt_mem[i]); + ca_mem->dt_mem[i] = NULL; + } + free(ca_mem->dt_mem); + ca_mem->dt_mem = NULL; + + /* Delete backward problems one by one */ + while (ca_mem->cvB_mem != NULL) CVAbckpbDelete(&(ca_mem->cvB_mem)); + + /* Free CVODEA memory */ + free(ca_mem); + cv_mem->cv_adj_mem = NULL; + + } + +} + +/* + * CVodeF + * + * This routine integrates to tout and returns solution into yout. + * 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, + realtype *tret, int itask, int *ncheckPtr) +{ + CVadjMem ca_mem; + CVodeMem cv_mem; + CkpntMem tmp; + DtpntMem *dt_mem; + int flag, i; + booleantype iret, allocOK; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeF", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + 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; + + /* Check for yout != NULL */ + if (yout == NULL) { + 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); + return(CV_ILL_INPUT); + } + + /* Check for valid itask */ + if ( (itask != CV_NORMAL) && (itask != CV_ONE_STEP) ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeF", MSGCV_BAD_ITASK); + return(CV_ILL_INPUT); + } + + /* All error checking done */ + + dt_mem = ca_mem->dt_mem; + + /* If tstop is enabled, store some info */ + if (cv_mem->cv_tstopset) { + ca_mem->ca_tstopCVodeFcall = SUNTRUE; + 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. + */ + if ( ca_mem->ca_firstCVodeFcall ) { + + ca_mem->ca_tinitial = cv_mem->cv_tn; + + ca_mem->ck_mem = CVAckpntInit(cv_mem); + if (ca_mem->ck_mem == NULL) { + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODEA", "CVodeF", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + if ( !ca_mem->ca_IMmallocDone ) { + + /* Do we need to store sensitivities? */ + if (!cv_mem->cv_sensi) ca_mem->ca_IMstoreSensi = SUNFALSE; + + /* Allocate space for interpolation data */ + allocOK = ca_mem->ca_IMmalloc(cv_mem); + if (!allocOK) { + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODEA", "CVodeF", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + /* Rename zn and, if needed, znS for use in interpolation */ + for (i=0;i<L_MAX;i++) ca_mem->ca_Y[i] = cv_mem->cv_zn[i]; + if (ca_mem->ca_IMstoreSensi) { + for (i=0;i<L_MAX;i++) ca_mem->ca_YS[i] = cv_mem->cv_znS[i]; + } + + ca_mem->ca_IMmallocDone = SUNTRUE; + + } + + dt_mem[0]->t = ca_mem->ck_mem->ck_t0; + ca_mem->ca_IMstore(cv_mem, dt_mem[0]); + + ca_mem->ca_firstCVodeFcall = SUNFALSE; + + } else if ( (cv_mem->cv_tn - tout)*cv_mem->cv_h >= ZERO ) { + + /* 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; + + return(flag); + + } + + /* Integrate to tout (in CV_ONE_STEP mode) while loading check points */ + for(;;) { + + /* Perform one step of the integration */ + + flag = CVode(cv_mem, tout, yout, tret, CV_ONE_STEP); + if (flag < 0) break; + + /* Test if a new check point is needed */ + + if ( cv_mem->cv_nst % ca_mem->ca_nsteps == 0 ) { + + ca_mem->ck_mem->ck_t1 = *tret; + + /* Create a new check point, load it, and append it to the list */ + tmp = CVAckpntNew(cv_mem); + if (tmp == NULL) { + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODEA", "CVodeF", MSGCV_MEM_FAIL); + flag = CV_MEM_FAIL; + break; + } + tmp->ck_next = ca_mem->ck_mem; + 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]); + + } else { + + /* Load next point in dt_mem */ + dt_mem[cv_mem->cv_nst % ca_mem->ca_nsteps]->t = *tret; + ca_mem->ca_IMstore(cv_mem, dt_mem[cv_mem->cv_nst % ca_mem->ca_nsteps]); + + } + + /* 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; + + /* tfinal is now set to *tret */ + ca_mem->ca_tfinal = *tret; + + /* Return if in CV_ONE_STEP mode */ + if (iret) break; + + /* 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 ) { + *tret = tout; + 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(;;)() */ + + /* Get ncheck from ca_mem */ + *ncheckPtr = ca_mem->ca_nckpnts; + + /* Data is available for the last interval */ + 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); +} + + + +/* + * ================================================================= + * FUNCTIONS FOR BACKWARD PROBLEMS + * ================================================================= + */ + + +int CVodeCreateB(void *cvode_mem, int lmmB, int *which) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem new_cvB_mem; + void *cvodeB_mem; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeCreateB", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeCreateB", MSGCV_NO_ADJ); + return(CV_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + /* Allocate space for new CVodeBMem object */ + + new_cvB_mem = NULL; + new_cvB_mem = (CVodeBMem) malloc(sizeof(struct CVodeBMemRec)); + if (new_cvB_mem == NULL) { + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODEA", "CVodeCreateB", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + /* Create and set a new CVODES object for the backward problem */ + + cvodeB_mem = CVodeCreate(lmmB); + if (cvodeB_mem == NULL) { + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODEA", "CVodeCreateB", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + CVodeSetUserData(cvodeB_mem, cvode_mem); + + CVodeSetMaxHnilWarns(cvodeB_mem, -1); + + CVodeSetErrHandlerFn(cvodeB_mem, cv_mem->cv_ehfun, cv_mem->cv_eh_data); + CVodeSetErrFile(cvodeB_mem, cv_mem->cv_errfp); + + /* Set/initialize fields in the new CVodeBMem object, new_cvB_mem */ + + new_cvB_mem->cv_index = ca_mem->ca_nbckpbs; + + new_cvB_mem->cv_mem = (CVodeMem) cvodeB_mem; + + new_cvB_mem->cv_f = NULL; + new_cvB_mem->cv_fs = NULL; + + new_cvB_mem->cv_fQ = NULL; + new_cvB_mem->cv_fQs = NULL; + + new_cvB_mem->cv_user_data = NULL; + + new_cvB_mem->cv_lmem = NULL; + new_cvB_mem->cv_lfree = NULL; + new_cvB_mem->cv_pmem = NULL; + new_cvB_mem->cv_pfree = NULL; + + new_cvB_mem->cv_y = NULL; + + new_cvB_mem->cv_f_withSensi = SUNFALSE; + new_cvB_mem->cv_fQ_withSensi = SUNFALSE; + + /* Attach the new object to the linked list cvB_mem */ + + 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 + * functions to set optional inputs for this backward problem */ + + *which = ca_mem->ca_nbckpbs; + + ca_mem->ca_nbckpbs++; + + return(CV_SUCCESS); +} + +int CVodeInitB(void *cvode_mem, int which, + CVRhsFnB fB, + realtype tB0, N_Vector yB0) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + int flag; + + /* Check if cvode_mem exists */ + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeInitB", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + + 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 */ + + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeInitB", MSGCV_BAD_WHICH); + return(CV_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + /* Allocate and set the CVODES object */ + + flag = CVodeInit(cvodeB_mem, CVArhs, tB0, yB0); + + if (flag != CV_SUCCESS) return(flag); + + /* Copy fB function in cvB_mem */ + + cvB_mem->cv_f_withSensi = SUNFALSE; + cvB_mem->cv_f = fB; + + /* Allocate space and initialize the y Nvector in cvB_mem */ + + cvB_mem->cv_t0 = tB0; + cvB_mem->cv_y = N_VClone(yB0); + N_VScale(ONE, yB0, cvB_mem->cv_y); + + return(CV_SUCCESS); +} + +int CVodeInitBS(void *cvode_mem, int which, + CVRhsFnBS fBs, + realtype tB0, N_Vector yB0) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + int flag; + + /* Check if cvode_mem exists */ + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeInitBS", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + + 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 */ + + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeInitBS", MSGCV_BAD_WHICH); + return(CV_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + /* Allocate and set the CVODES object */ + + flag = CVodeInit(cvodeB_mem, CVArhs, tB0, yB0); + + if (flag != CV_SUCCESS) return(flag); + + /* Copy fBs function in cvB_mem */ + + cvB_mem->cv_f_withSensi = SUNTRUE; + cvB_mem->cv_fs = fBs; + + /* Allocate space and initialize the y Nvector in cvB_mem */ + + cvB_mem->cv_t0 = tB0; + cvB_mem->cv_y = N_VClone(yB0); + N_VScale(ONE, yB0, cvB_mem->cv_y); + + return(CV_SUCCESS); +} + + +int CVodeReInitB(void *cvode_mem, int which, + realtype tB0, N_Vector yB0) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + int flag; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeReInitB", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeReInitB", MSGCV_NO_ADJ); + return(CV_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + /* Check the value of which */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeReInitB", MSGCV_BAD_WHICH); + return(CV_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + /* Reinitialize CVODES object */ + + flag = CVodeReInit(cvodeB_mem, tB0, yB0); + + return(flag); +} + + +int CVodeSStolerancesB(void *cvode_mem, int which, realtype reltolB, realtype abstolB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + int flag; + + /* Check if cvode_mem exists */ + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeSStolerancesB", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + + 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 */ + + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeSStolerancesB", MSGCV_BAD_WHICH); + return(CV_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + /* Set tolerances */ + + flag = CVodeSStolerances(cvodeB_mem, reltolB, abstolB); + + return(flag); +} + + +int CVodeSVtolerancesB(void *cvode_mem, int which, realtype reltolB, N_Vector abstolB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + int flag; + + /* Check if cvode_mem exists */ + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeSVtolerancesB", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + + 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 */ + + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeSVtolerancesB", MSGCV_BAD_WHICH); + return(CV_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + /* Set tolerances */ + + flag = CVodeSVtolerances(cvodeB_mem, reltolB, abstolB); + + return(flag); +} + + +int CVodeQuadInitB(void *cvode_mem, int which, + CVQuadRhsFnB fQB, N_Vector yQB0) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + int flag; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeQuadInitB", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + 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 */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeQuadInitB", MSGCV_BAD_WHICH); + return(CV_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + flag = CVodeQuadInit(cvodeB_mem, CVArhsQ, yQB0); + if (flag != CV_SUCCESS) return(flag); + + cvB_mem->cv_fQ_withSensi = SUNFALSE; + cvB_mem->cv_fQ = fQB; + + return(CV_SUCCESS); +} + +int CVodeQuadInitBS(void *cvode_mem, int which, + CVQuadRhsFnBS fQBs, N_Vector yQB0) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + int flag; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeQuadInitBS", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + 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 */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeQuadInitBS", MSGCV_BAD_WHICH); + return(CV_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + flag = CVodeQuadInit(cvodeB_mem, CVArhsQ, yQB0); + if (flag != CV_SUCCESS) return(flag); + + cvB_mem->cv_fQ_withSensi = SUNTRUE; + cvB_mem->cv_fQs = fQBs; + + return(CV_SUCCESS); +} + +int CVodeQuadReInitB(void *cvode_mem, int which, N_Vector yQB0) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + int flag; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeQuadReInitB", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + 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 */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeQuadReInitB", MSGCV_BAD_WHICH); + return(CV_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + flag = CVodeQuadReInit(cvodeB_mem, yQB0); + if (flag != CV_SUCCESS) return(flag); + + return(CV_SUCCESS); +} + +int CVodeQuadSStolerancesB(void *cvode_mem, int which, realtype reltolQB, realtype abstolQB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + int flag; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeQuadSStolerancesB", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + 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 */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeQuadSStolerancesB", MSGCV_BAD_WHICH); + return(CV_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + flag = CVodeQuadSStolerances(cvodeB_mem, reltolQB, abstolQB); + + return(flag); +} + +int CVodeQuadSVtolerancesB(void *cvode_mem, int which, realtype reltolQB, N_Vector abstolQB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + int flag; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeQuadSStolerancesB", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + 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 */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeQuadSStolerancesB", MSGCV_BAD_WHICH); + return(CV_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + flag = CVodeQuadSVtolerances(cvodeB_mem, reltolQB, abstolQB); + + return(flag); +} + +/* + * CVodeB + * + * This routine performs the backward integration towards tBout + * of all backward problems that were defined. + * When necessary, it performs a forward integration between two + * consecutive check points to update interpolation data. + * + * On a successful return, CVodeB returns CV_SUCCESS. + * + * NOTE that CVodeB DOES NOT return the solution for the backward + * problem(s). Use CVodeGetB to extract the solution at tBret + * for any given backward problem. + * + * If there are multiple backward problems and multiple check points, + * CVodeB may not succeed in getting all problems to take one step + * when called in ONE_STEP mode. + */ + +int CVodeB(void *cvode_mem, realtype tBout, int itaskB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem, tmp_cvB_mem; + CkpntMem ck_mem; + int sign, flag=0; + realtype tfuzz, tBret, tBn; + booleantype gotCheckpoint, isActive, reachedTBout; + + /* Check if cvode_mem exists */ + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeB", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeB", MSGCV_NO_ADJ); + return(CV_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + /* Check if any backward problem has been defined */ + + if ( ca_mem->ca_nbckpbs == 0 ) { + cvProcessError(cv_mem, CV_NO_BCK, "CVODEA", "CVodeB", MSGCV_NO_BCK); + return(CV_NO_BCK); + } + cvB_mem = ca_mem->cvB_mem; + + /* Check whether CVodeF has been called */ + + if ( ca_mem->ca_firstCVodeFcall ) { + cvProcessError(cv_mem, CV_NO_FWD, "CVODEA", "CVodeB", MSGCV_NO_FWD); + return(CV_NO_FWD); + } + sign = (ca_mem->ca_tfinal - ca_mem->ca_tinitial > ZERO) ? 1 : -1; + + /* If this is the first call, loop over all backward problems and + * - check that tB0 is valid + * - check that tBout is ahead of tB0 in the backward direction + * - check whether we need to interpolate forward sensitivities + */ + + if ( ca_mem->ca_firstCVodeBcall ) { + + tmp_cvB_mem = cvB_mem; + + while(tmp_cvB_mem != NULL) { + + tBn = tmp_cvB_mem->cv_mem->cv_tn; + + if ( (sign*(tBn-ca_mem->ca_tinitial) < ZERO) || (sign*(ca_mem->ca_tfinal-tBn) < ZERO) ) { + cvProcessError(cv_mem, CV_BAD_TB0, "CVODEA", "CVodeB", MSGCV_BAD_TB0, + tmp_cvB_mem->cv_index); + return(CV_BAD_TB0); + } + + if (sign*(tBn-tBout) <= ZERO) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeB", MSGCV_BAD_TBOUT, + tmp_cvB_mem->cv_index); + return(CV_ILL_INPUT); + } + + if ( tmp_cvB_mem->cv_f_withSensi || tmp_cvB_mem->cv_fQ_withSensi ) + ca_mem->ca_IMinterpSensi = SUNTRUE; + + tmp_cvB_mem = tmp_cvB_mem->cv_next; + + } + + if ( ca_mem->ca_IMinterpSensi && !ca_mem->ca_IMstoreSensi) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeB", MSGCV_BAD_SENSI); + return(CV_ILL_INPUT); + } + + ca_mem->ca_firstCVodeBcall = SUNFALSE; + } + + /* Check if itaskB is legal */ + + if ( (itaskB != CV_NORMAL) && (itaskB != CV_ONE_STEP) ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeB", MSGCV_BAD_ITASKB); + return(CV_ILL_INPUT); + } + + /* Check if tBout is legal */ + + if ( (sign*(tBout-ca_mem->ca_tinitial) < ZERO) || (sign*(ca_mem->ca_tfinal-tBout) < ZERO) ) { + tfuzz = HUNDRED*cv_mem->cv_uround*(SUNRabs(ca_mem->ca_tinitial) + SUNRabs(ca_mem->ca_tfinal)); + if ( (sign*(tBout-ca_mem->ca_tinitial) < ZERO) && (SUNRabs(tBout-ca_mem->ca_tinitial) < tfuzz) ) { + tBout = ca_mem->ca_tinitial; + } else { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeB", MSGCV_BAD_TBOUT); + return(CV_ILL_INPUT); + } + } + + /* Loop through the check points and stop as soon as a backward + * problem has its tn value behind the current check point's t0_ + * value (in the backward direction) */ + + ck_mem = ca_mem->ck_mem; + + gotCheckpoint = SUNFALSE; + + for(;;) { + + tmp_cvB_mem = cvB_mem; + while(tmp_cvB_mem != NULL) { + tBn = tmp_cvB_mem->cv_mem->cv_tn; + + if ( sign*(tBn-ck_mem->ck_t0) > ZERO ) { + gotCheckpoint = SUNTRUE; + break; + } + + if ( (itaskB==CV_NORMAL) && (tBn == ck_mem->ck_t0) && (sign*(tBout-ck_mem->ck_t0) >= ZERO) ) { + gotCheckpoint = SUNTRUE; + break; + } + + tmp_cvB_mem = tmp_cvB_mem->cv_next; + } + + if (gotCheckpoint) break; + + if (ck_mem->ck_next == NULL) break; + + ck_mem = ck_mem->ck_next; + } + + /* Starting with the current check point from above, loop over check points + while propagating backward problems */ + + for(;;) { + + /* Store interpolation data if not available. + This is the 2nd forward integration pass */ + + if (ck_mem != ca_mem->ca_ckpntData) { + flag = CVAdataStore(cv_mem, ck_mem); + if (flag != CV_SUCCESS) break; + } + + /* Loop through all backward problems and, if needed, + * propagate their solution towards tBout */ + + tmp_cvB_mem = cvB_mem; + while (tmp_cvB_mem != NULL) { + + /* Decide if current backward problem is "active" in this check point */ + + isActive = SUNTRUE; + + tBn = tmp_cvB_mem->cv_mem->cv_tn; + + if ( (tBn == ck_mem->ck_t0) && (sign*(tBout-ck_mem->ck_t0) < ZERO ) ) isActive = SUNFALSE; + if ( (tBn == ck_mem->ck_t0) && (itaskB==CV_ONE_STEP) ) isActive = SUNFALSE; + + if ( sign * (tBn - ck_mem->ck_t0) < ZERO ) isActive = SUNFALSE; + + if ( isActive ) { + + /* 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; + + /* Integrate current backward problem */ + CVodeSetStopTime(tmp_cvB_mem->cv_mem, ck_mem->ck_t0); + flag = CVode(tmp_cvB_mem->cv_mem, tBout, tmp_cvB_mem->cv_y, &tBret, itaskB); + + /* Set the time at which we will report solution and/or quadratures */ + tmp_cvB_mem->cv_tout = tBret; + + /* If an error occurred, exit while loop */ + if (flag < 0) break; + + } else { + flag = CV_SUCCESS; + tmp_cvB_mem->cv_tout = tBn; + } + + /* Move to next backward problem */ + + tmp_cvB_mem = tmp_cvB_mem->cv_next; + } + + /* If an error occurred, return now */ + + if (flag <0) { + cvProcessError(cv_mem, flag, "CVODEA", "CVodeB", MSGCV_BACK_ERROR, + tmp_cvB_mem->cv_index); + return(flag); + } + + /* If in CV_ONE_STEP mode, return now (flag = CV_SUCCESS) */ + + if (itaskB == CV_ONE_STEP) break; + + /* If all backward problems have succesfully reached tBout, return now */ + + reachedTBout = SUNTRUE; + + tmp_cvB_mem = cvB_mem; + while(tmp_cvB_mem != NULL) { + if ( sign*(tmp_cvB_mem->cv_tout - tBout) > ZERO ) { + reachedTBout = SUNFALSE; + break; + } + tmp_cvB_mem = tmp_cvB_mem->cv_next; + } + + if ( reachedTBout ) break; + + /* Move check point in linked list to next one */ + + ck_mem = ck_mem->ck_next; + + } + + return(flag); +} + + +int CVodeGetB(void *cvode_mem, int which, realtype *tret, N_Vector yB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeGetB", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + 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; + + /* Check the value of which */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeGetB", MSGCV_BAD_WHICH); + return(CV_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + 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; + + return(CV_SUCCESS); +} + + +/* + * CVodeGetQuadB + */ + +int CVodeGetQuadB(void *cvode_mem, int which, realtype *tret, N_Vector qB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + long int nstB; + int flag; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeGetQuadB", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + 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; + + /* Check the value of which */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeGetQuadB", MSGCV_BAD_WHICH); + return(CV_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + /* If the integration for this backward problem has not started yet, + * 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; + } else { + flag = CVodeGetQuad(cvodeB_mem, tret, qB); + } + + return(flag); +} + + +/* + * ================================================================= + * PRIVATE FUNCTIONS FOR CHECK POINTS + * ================================================================= + */ + +/* + * CVAckpntInit + * + * This routine initializes the check point linked list with + * information from the initial time. + */ + +static CkpntMem CVAckpntInit(CVodeMem cv_mem) +{ + CkpntMem ck_mem; + int is; + + /* Allocate space for ckdata */ + ck_mem = NULL; + ck_mem = (CkpntMem) malloc(sizeof(struct CkpntMemRec)); + if (ck_mem == NULL) return(NULL); + + ck_mem->ck_zn[0] = N_VClone(cv_mem->cv_tempv); + if (ck_mem->ck_zn[0] == NULL) { + 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]); + free(ck_mem); ck_mem = NULL; + return(NULL); + } + + /* ck_mem->ck_zn[qmax] was not allocated */ + ck_mem->ck_zqm = 0; + + /* Load ckdata from cv_mem */ + N_VScale(ONE, cv_mem->cv_zn[0], ck_mem->ck_zn[0]); + ck_mem->ck_t0 = cv_mem->cv_tn; + 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; + + if (ck_mem->ck_quadr) { + + ck_mem->ck_znQ[0] = N_VClone(cv_mem->cv_tempvQ); + if (ck_mem->ck_znQ[0] == NULL) { + N_VDestroy(ck_mem->ck_zn[0]); + N_VDestroy(ck_mem->ck_zn[1]); + free(ck_mem); ck_mem = NULL; + return(NULL); + } + + N_VScale(ONE, cv_mem->cv_znQ[0], ck_mem->ck_znQ[0]); + + } + + /* Do we need to carry sensitivities? */ + ck_mem->ck_sensi = cv_mem->cv_sensi; + + if (ck_mem->ck_sensi) { + + ck_mem->ck_Ns = cv_mem->cv_Ns; + + ck_mem->ck_znS[0] = N_VCloneVectorArray(cv_mem->cv_Ns, cv_mem->cv_tempv); + if (ck_mem->ck_znS[0] == NULL) { + N_VDestroy(ck_mem->ck_zn[0]); + N_VDestroy(ck_mem->ck_zn[1]); + if (ck_mem->ck_quadr) N_VDestroy(ck_mem->ck_znQ[0]); + free(ck_mem); ck_mem = NULL; + return(NULL); + } + + for (is=0; is<cv_mem->cv_Ns; is++) + cv_mem->cv_cvals[is] = ONE; + + (void) N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, + cv_mem->cv_znS[0], ck_mem->ck_znS[0]); + } + + /* Do we need to carry quadrature sensitivities? */ + ck_mem->ck_quadr_sensi = cv_mem->cv_quadr_sensi && cv_mem->cv_errconQS; + + if (ck_mem->ck_quadr_sensi) { + ck_mem->ck_znQS[0] = N_VCloneVectorArray(cv_mem->cv_Ns, cv_mem->cv_tempvQ); + if (ck_mem->ck_znQS[0] == NULL) { + N_VDestroy(ck_mem->ck_zn[0]); + N_VDestroy(ck_mem->ck_zn[1]); + if (ck_mem->ck_quadr) N_VDestroy(ck_mem->ck_znQ[0]); + N_VDestroyVectorArray(ck_mem->ck_znS[0], cv_mem->cv_Ns); + free(ck_mem); ck_mem = NULL; + return(NULL); + } + + for (is=0; is<cv_mem->cv_Ns; is++) + cv_mem->cv_cvals[is] = ONE; + + (void) N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, + cv_mem->cv_znQS[0], ck_mem->ck_znQS[0]); + } + + /* Next in list */ + ck_mem->ck_next = NULL; + + return(ck_mem); +} + +/* + * CVAckpntNew + * + * This routine allocates space for a new check point and sets + * its data from current values in cv_mem. + */ + +static CkpntMem CVAckpntNew(CVodeMem cv_mem) +{ + CkpntMem ck_mem; + int j, jj, is, qmax; + + /* Allocate space for ckdata */ + ck_mem = NULL; + ck_mem = (CkpntMem) malloc(sizeof(struct CkpntMemRec)); + if (ck_mem == NULL) return(NULL); + + /* Set cv_next to NULL */ + ck_mem->ck_next = NULL; + + /* Test if we need to allocate space for the last zn. + * NOTE: zn(qmax) may be needed for a hot restart, if an order + * increase is deemed necessary at the first step after a check point */ + qmax = cv_mem->cv_qmax; + ck_mem->ck_zqm = (cv_mem->cv_q < qmax) ? qmax : 0; + + for (j=0; j<=cv_mem->cv_q; j++) { + ck_mem->ck_zn[j] = N_VClone(cv_mem->cv_tempv); + if (ck_mem->ck_zn[j] == NULL) { + for (jj=0; jj<j; jj++) N_VDestroy(ck_mem->ck_zn[jj]); + free(ck_mem); ck_mem = NULL; + return(NULL); + } + } + + if (cv_mem->cv_q < qmax) { + ck_mem->ck_zn[qmax] = N_VClone(cv_mem->cv_tempv); + if (ck_mem->ck_zn[qmax] == NULL) { + for (jj=0; jj<=cv_mem->cv_q; jj++) N_VDestroy(ck_mem->ck_zn[jj]); + free(ck_mem); ck_mem = NULL; + return(NULL); + } + } + + /* Test if we need to carry quadratures */ + ck_mem->ck_quadr = cv_mem->cv_quadr && cv_mem->cv_errconQ; + + if (ck_mem->ck_quadr) { + + for (j=0; j<=cv_mem->cv_q; j++) { + ck_mem->ck_znQ[j] = N_VClone(cv_mem->cv_tempvQ); + if(ck_mem->ck_znQ[j] == NULL) { + for (jj=0; jj<j; jj++) N_VDestroy(ck_mem->ck_znQ[jj]); + if (cv_mem->cv_q < qmax) N_VDestroy(ck_mem->ck_zn[qmax]); + for (jj=0; jj<=cv_mem->cv_q; j++) N_VDestroy(ck_mem->ck_zn[jj]); + free(ck_mem); ck_mem = NULL; + return(NULL); + } + } + + if (cv_mem->cv_q < qmax) { + ck_mem->ck_znQ[qmax] = N_VClone(cv_mem->cv_tempvQ); + if (ck_mem->ck_znQ[qmax] == NULL) { + for (jj=0; jj<=cv_mem->cv_q; jj++) N_VDestroy(ck_mem->ck_znQ[jj]); + N_VDestroy(ck_mem->ck_zn[qmax]); + for (jj=0; jj<=cv_mem->cv_q; jj++) N_VDestroy(ck_mem->ck_zn[jj]); + free(ck_mem); ck_mem = NULL; + return(NULL); + } + } + + } + + /* Test if we need to carry sensitivities */ + ck_mem->ck_sensi = cv_mem->cv_sensi; + + if (ck_mem->ck_sensi) { + + ck_mem->ck_Ns = cv_mem->cv_Ns; + + for (j=0; j<=cv_mem->cv_q; j++) { + ck_mem->ck_znS[j] = N_VCloneVectorArray(cv_mem->cv_Ns, cv_mem->cv_tempv); + if (ck_mem->ck_znS[j] == NULL) { + for (jj=0; jj<j; jj++) N_VDestroyVectorArray(ck_mem->ck_znS[jj], cv_mem->cv_Ns); + if (ck_mem->ck_quadr) { + if (cv_mem->cv_q < qmax) N_VDestroy(ck_mem->ck_znQ[qmax]); + for (jj=0; jj<=cv_mem->cv_q; jj++) N_VDestroy(ck_mem->ck_znQ[jj]); + } + if (cv_mem->cv_q < qmax) N_VDestroy(ck_mem->ck_zn[qmax]); + for (jj=0; jj<=cv_mem->cv_q; jj++) N_VDestroy(ck_mem->ck_zn[jj]); + free(ck_mem); ck_mem = NULL; + return(NULL); + } + } + + if ( cv_mem->cv_q < qmax) { + ck_mem->ck_znS[qmax] = N_VCloneVectorArray(cv_mem->cv_Ns, cv_mem->cv_tempv); + if (ck_mem->ck_znS[qmax] == NULL) { + for (jj=0; jj<=cv_mem->cv_q; jj++) N_VDestroyVectorArray(ck_mem->ck_znS[jj], cv_mem->cv_Ns); + if (ck_mem->ck_quadr) { + N_VDestroy(ck_mem->ck_znQ[qmax]); + for (jj=0; jj<=cv_mem->cv_q; jj++) N_VDestroy(ck_mem->ck_znQ[jj]); + } + N_VDestroy(ck_mem->ck_zn[qmax]); + for (jj=0; jj<=cv_mem->cv_q; jj++) N_VDestroy(ck_mem->ck_zn[jj]); + free(ck_mem); ck_mem = NULL; + return(NULL); + } + } + + } + + /* Test if we need to carry quadrature sensitivities */ + ck_mem->ck_quadr_sensi = cv_mem->cv_quadr_sensi && cv_mem->cv_errconQS; + + if (ck_mem->ck_quadr_sensi) { + + for (j=0; j<=cv_mem->cv_q; j++) { + ck_mem->ck_znQS[j] = N_VCloneVectorArray(cv_mem->cv_Ns, cv_mem->cv_tempvQ); + if (ck_mem->ck_znQS[j] == NULL) { + for (jj=0; jj<j; jj++) N_VDestroyVectorArray(ck_mem->ck_znQS[jj], cv_mem->cv_Ns); + if (cv_mem->cv_q < qmax) N_VDestroyVectorArray(ck_mem->ck_znS[qmax], cv_mem->cv_Ns); + for (jj=0; jj<=cv_mem->cv_q; jj++) N_VDestroyVectorArray(ck_mem->ck_znS[jj], cv_mem->cv_Ns); + if (ck_mem->ck_quadr) { + if (cv_mem->cv_q < qmax) N_VDestroy(ck_mem->ck_znQ[qmax]); + for (jj=0; jj<=cv_mem->cv_q; jj++) N_VDestroy(ck_mem->ck_znQ[jj]); + } + if (cv_mem->cv_q < qmax) N_VDestroy(ck_mem->ck_zn[qmax]); + for (jj=0; jj<=cv_mem->cv_q; jj++) N_VDestroy(ck_mem->ck_zn[jj]); + free(ck_mem); ck_mem = NULL; + return(NULL); + } + } + + if ( cv_mem->cv_q < qmax) { + ck_mem->ck_znQS[qmax] = N_VCloneVectorArray(cv_mem->cv_Ns, cv_mem->cv_tempvQ); + if (ck_mem->ck_znQS[qmax] == NULL) { + for (jj=0; jj<=cv_mem->cv_q; jj++) N_VDestroyVectorArray(ck_mem->ck_znQS[jj], cv_mem->cv_Ns); + N_VDestroyVectorArray(ck_mem->ck_znS[qmax], cv_mem->cv_Ns); + for (jj=0; jj<=cv_mem->cv_q; jj++) N_VDestroyVectorArray(ck_mem->ck_znS[jj], cv_mem->cv_Ns); + if (ck_mem->ck_quadr) { + N_VDestroy(ck_mem->ck_znQ[qmax]); + for (jj=0; jj<=cv_mem->cv_q; jj++) N_VDestroy(ck_mem->ck_zn[jj]); + } + N_VDestroy(ck_mem->ck_zn[qmax]); + for (jj=0; jj<=cv_mem->cv_q; jj++) N_VDestroy(ck_mem->ck_zn[jj]); + free(ck_mem); ck_mem = NULL; + return(NULL); + } + } + + } + + /* Load check point data from cv_mem */ + + for (j=0; j<=cv_mem->cv_q; j++) + cv_mem->cv_cvals[j] = ONE; + + (void) N_VScaleVectorArray(cv_mem->cv_q+1, cv_mem->cv_cvals, + cv_mem->cv_zn, ck_mem->ck_zn); + + if ( cv_mem->cv_q < qmax ) + N_VScale(ONE, cv_mem->cv_zn[qmax], ck_mem->ck_zn[qmax]); + + if (ck_mem->ck_quadr) { + for (j=0; j<=cv_mem->cv_q; j++) + cv_mem->cv_cvals[j] = ONE; + + (void) N_VScaleVectorArray(cv_mem->cv_q+1, cv_mem->cv_cvals, + cv_mem->cv_znQ, ck_mem->ck_znQ); + + if ( cv_mem->cv_q < qmax ) + N_VScale(ONE, cv_mem->cv_znQ[qmax], ck_mem->ck_znQ[qmax]); + } + + if (ck_mem->ck_sensi) { + for (j=0; j<=cv_mem->cv_q; j++) { + for (is=0; is<cv_mem->cv_Ns; is++) { + cv_mem->cv_cvals[j*cv_mem->cv_Ns+is] = ONE; + cv_mem->cv_Xvecs[j*cv_mem->cv_Ns+is] = cv_mem->cv_znS[j][is]; + 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); + + if ( cv_mem->cv_q < qmax ) { + for (is=0; is<cv_mem->cv_Ns; is++) + cv_mem->cv_cvals[is] = ONE; + + (void) N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, + 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; is<cv_mem->cv_Ns; is++) { + cv_mem->cv_cvals[j*cv_mem->cv_Ns+is] = ONE; + cv_mem->cv_Xvecs[j*cv_mem->cv_Ns+is] = cv_mem->cv_znQS[j][is]; + cv_mem->cv_Zvecs[j*cv_mem->cv_Ns+is] = ck_mem->ck_znQS[j][is]; + } + } + + (void) N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, + cv_mem->cv_Xvecs, cv_mem->cv_Zvecs); + + if ( cv_mem->cv_q < qmax ) { + for (is=0; is<cv_mem->cv_Ns; is++) + cv_mem->cv_cvals[is] = ONE; + + (void) N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, + cv_mem->cv_znQS[qmax], ck_mem->ck_znQS[qmax]); + } + } + + for (j=0; j<=L_MAX; j++) ck_mem->ck_tau[j] = cv_mem->cv_tau[j]; + for (j=0; j<=NUM_TESTS; j++) ck_mem->ck_tq[j] = cv_mem->cv_tq[j]; + for (j=0; j<=cv_mem->cv_q; j++) ck_mem->ck_l[j] = cv_mem->cv_l[j]; + ck_mem->ck_nst = cv_mem->cv_nst; + ck_mem->ck_tretlast = cv_mem->cv_tretlast; + ck_mem->ck_q = cv_mem->cv_q; + ck_mem->ck_qprime = cv_mem->cv_qprime; + ck_mem->ck_qwait = cv_mem->cv_qwait; + ck_mem->ck_L = cv_mem->cv_L; + ck_mem->ck_gammap = cv_mem->cv_gammap; + ck_mem->ck_h = cv_mem->cv_h; + ck_mem->ck_hprime = cv_mem->cv_hprime; + ck_mem->ck_hscale = cv_mem->cv_hscale; + ck_mem->ck_eta = cv_mem->cv_eta; + ck_mem->ck_etamax = cv_mem->cv_etamax; + ck_mem->ck_t0 = cv_mem->cv_tn; + ck_mem->ck_saved_tq5 = cv_mem->cv_saved_tq5; + + return(ck_mem); +} + +/* + * CVAckpntDelete + * + * This routine deletes the first check point in list and returns + * the new list head + */ + +static void CVAckpntDelete(CkpntMem *ck_memPtr) +{ + CkpntMem tmp; + int j; + + if (*ck_memPtr == NULL) return; + + /* store head of list */ + tmp = *ck_memPtr; + + /* move head of list */ + *ck_memPtr = (*ck_memPtr)->ck_next; + + /* free N_Vectors in tmp */ + 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] + * was allocated */ + if (tmp->ck_quadr) { + + if (tmp->ck_next != NULL) { + for (j=0;j<=tmp->ck_q;j++) N_VDestroy(tmp->ck_znQ[j]); + if (tmp->ck_zqm != 0) N_VDestroy(tmp->ck_znQ[tmp->ck_zqm]); + } 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] + * 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] + * 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 + * ================================================================= + */ + +static void CVAbckpbDelete(CVodeBMem *cvB_memPtr) +{ + CVodeBMem tmp; + void *cvode_mem; + + if (*cvB_memPtr != NULL) { + + /* Save head of the list */ + tmp = *cvB_memPtr; + + /* Move head of the list */ + *cvB_memPtr = (*cvB_memPtr)->cv_next; + + /* Free CVODES memory in tmp */ + cvode_mem = (void *)(tmp->cv_mem); + CVodeFree(&cvode_mem); + + /* Free linear solver memory */ + if (tmp->cv_lfree != NULL) tmp->cv_lfree(tmp); + + /* Free preconditioner memory */ + if (tmp->cv_pfree != NULL) tmp->cv_pfree(tmp); + + /* Free workspace Nvector */ + N_VDestroy(tmp->cv_y); + + free(tmp); tmp = NULL; + + } + +} + +/* + * ================================================================= + * PRIVATE FUNCTIONS FOR INTERPOLATION + * ================================================================= + */ + +/* + * CVAdataStore + * + * This routine integrates the forward model starting at the check + * point ck_mem and stores y and yprime at all intermediate steps. + * + * Return values: + * CV_SUCCESS + * CV_REIFWD_FAIL + * CV_FWD_FAIL + */ + +static int CVAdataStore(CVodeMem cv_mem, CkpntMem ck_mem) +{ + CVadjMem ca_mem; + DtpntMem *dt_mem; + realtype t; + long int i; + int flag, sign; + + ca_mem = cv_mem->cv_adj_mem; + dt_mem = ca_mem->dt_mem; + + /* Initialize cv_mem with data from ck_mem */ + flag = CVAckpntGet(cv_mem, ck_mem); + if (flag != CV_SUCCESS) + return(CV_REIFWD_FAIL); + + /* Set first structure in dt_mem[0] */ + dt_mem[0]->t = ck_mem->ck_t0; + ca_mem->ca_IMstore(cv_mem, dt_mem[0]); + + /* Decide whether TSTOP must be activated */ + if (ca_mem->ca_tstopCVodeFcall) { + CVodeSetStopTime(cv_mem, ca_mem->ca_tstopCVodeF); + } + + sign = (ca_mem->ca_tfinal - ca_mem->ca_tinitial > ZERO) ? 1 : -1; + + + /* Run CVode to set following structures in dt_mem[i] */ + i = 1; + do { + + flag = CVode(cv_mem, ck_mem->ck_t1, ca_mem->ca_ytmp, &t, CV_ONE_STEP); + if (flag < 0) return(CV_FWD_FAIL); + + dt_mem[i]->t = t; + ca_mem->ca_IMstore(cv_mem, dt_mem[i]); + i++; + + } while ( sign*(ck_mem->ck_t1 - t) > ZERO ); + + + ca_mem->ca_IMnewData = SUNTRUE; /* New data is now available */ + ca_mem->ca_ckpntData = ck_mem; /* starting at this check point */ + ca_mem->ca_np = i; /* and we have this many points */ + + return(CV_SUCCESS); +} + +/* + * CVAckpntGet + * + * This routine prepares CVODES for a hot restart from + * the check point 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 + * the first run. */ + + CVodeSetInitStep(cv_mem, cv_mem->cv_h0u); + + flag = CVodeReInit(cv_mem, ck_mem->ck_t0, ck_mem->ck_zn[0]); + if (flag != CV_SUCCESS) return(flag); + + if (ck_mem->ck_quadr) { + flag = CVodeQuadReInit(cv_mem, ck_mem->ck_znQ[0]); + if (flag != CV_SUCCESS) return(flag); + } + + if (ck_mem->ck_sensi) { + flag = CVodeSensReInit(cv_mem, cv_mem->cv_ism, ck_mem->ck_znS[0]); + if (flag != CV_SUCCESS) return(flag); + } + + if (ck_mem->ck_quadr_sensi) { + flag = CVodeQuadSensReInit(cv_mem, ck_mem->ck_znQS[0]); + if (flag != CV_SUCCESS) return(flag); + } + + } else { + + qmax = cv_mem->cv_qmax; + + /* Copy parameters from check point data structure */ + + cv_mem->cv_nst = ck_mem->ck_nst; + cv_mem->cv_tretlast = ck_mem->ck_tretlast; + cv_mem->cv_q = ck_mem->ck_q; + cv_mem->cv_qprime = ck_mem->ck_qprime; + cv_mem->cv_qwait = ck_mem->ck_qwait; + cv_mem->cv_L = ck_mem->ck_L; + cv_mem->cv_gammap = ck_mem->ck_gammap; + cv_mem->cv_h = ck_mem->ck_h; + cv_mem->cv_hprime = ck_mem->ck_hprime; + cv_mem->cv_hscale = ck_mem->ck_hscale; + cv_mem->cv_eta = ck_mem->ck_eta; + 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++) + cv_mem->cv_cvals[j] = ONE; + + retval = N_VScaleVectorArray(cv_mem->cv_q+1, cv_mem->cv_cvals, + ck_mem->ck_zn, cv_mem->cv_zn); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + + if ( cv_mem->cv_q < qmax ) + N_VScale(ONE, ck_mem->ck_zn[qmax], cv_mem->cv_zn[qmax]); + + if (ck_mem->ck_quadr) { + for (j=0; j<=cv_mem->cv_q; j++) + cv_mem->cv_cvals[j] = ONE; + + retval = N_VScaleVectorArray(cv_mem->cv_q+1, cv_mem->cv_cvals, + ck_mem->ck_znQ, cv_mem->cv_znQ); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + + if ( cv_mem->cv_q < qmax ) + N_VScale(ONE, ck_mem->ck_znQ[qmax], cv_mem->cv_znQ[qmax]); + } + + if (ck_mem->ck_sensi) { + for (j=0; j<=cv_mem->cv_q; j++) { + for (is=0; is<cv_mem->cv_Ns; is++) { + cv_mem->cv_cvals[j*cv_mem->cv_Ns+is] = ONE; + cv_mem->cv_Xvecs[j*cv_mem->cv_Ns+is] = ck_mem->ck_znS[j][is]; + cv_mem->cv_Zvecs[j*cv_mem->cv_Ns+is] = cv_mem->cv_znS[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); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + + if ( cv_mem->cv_q < qmax ) { + for (is=0; is<cv_mem->cv_Ns; is++) + cv_mem->cv_cvals[is] = ONE; + + retval = N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, + ck_mem->ck_znS[qmax], cv_mem->cv_znS[qmax]); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + } + } + + if (ck_mem->ck_quadr_sensi) { + for (j=0; j<=cv_mem->cv_q; j++) { + for (is=0; is<cv_mem->cv_Ns; is++) { + cv_mem->cv_cvals[j*cv_mem->cv_Ns+is] = ONE; + cv_mem->cv_Xvecs[j*cv_mem->cv_Ns+is] = ck_mem->ck_znQS[j][is]; + 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); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + + if ( cv_mem->cv_q < qmax ) { + for (is=0; is<cv_mem->cv_Ns; is++) + cv_mem->cv_cvals[is] = ONE; + + retval = N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, + ck_mem->ck_znQS[qmax], cv_mem->cv_znQS[qmax]); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + } + } + + 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; + + } + + return(CV_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Functions for interpolation + * ----------------------------------------------------------------- + */ + +/* + * CVAfindIndex + * + * Finds the index in the array of data point strctures such that + * dt_mem[indx-1].t <= t < dt_mem[indx].t + * If indx is changed from the previous invocation, then newpoint = SUNTRUE + * + * If t is beyond the leftmost limit, but close enough, indx=0. + * + * Returns CV_SUCCESS if successful and CV_GETY_BADT if unable to + * find indx (t is too far beyond limits). + */ + +static int CVAfindIndex(CVodeMem cv_mem, realtype t, + long int *indx, booleantype *newpoint) +{ + CVadjMem ca_mem; + DtpntMem *dt_mem; + int sign; + booleantype to_left, to_right; + + ca_mem = cv_mem->cv_adj_mem; + dt_mem = ca_mem->dt_mem; + + *newpoint = SUNFALSE; + + /* Find the direction of integration */ + sign = (ca_mem->ca_tfinal - ca_mem->ca_tinitial > ZERO) ? 1 : -1; + + /* If this is the first time we use new data */ + if (ca_mem->ca_IMnewData) { + ca_mem->ca_ilast = ca_mem->ca_np-1; + *newpoint = SUNTRUE; + ca_mem->ca_IMnewData = SUNFALSE; + } + + /* Search for indx starting from ilast */ + to_left = ( sign*(t - dt_mem[ca_mem->ca_ilast-1]->t) < ZERO); + to_right = ( sign*(t - dt_mem[ca_mem->ca_ilast]->t) > ZERO); + + if ( to_left ) { + /* look for a new indx to the left */ + + *newpoint = SUNTRUE; + + *indx = ca_mem->ca_ilast; + for(;;) { + if ( *indx == 0 ) break; + if ( sign*(t - dt_mem[*indx-1]->t) <= ZERO ) (*indx)--; + else break; + } + + if ( *indx == 0 ) + ca_mem->ca_ilast = 1; + else + ca_mem->ca_ilast = *indx; + + if ( *indx == 0 ) { + /* 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); + } + } + + } else if ( to_right ) { + /* look for a new indx to the right */ + + *newpoint = SUNTRUE; + + *indx = ca_mem->ca_ilast; + for(;;) { + if ( sign*(t - dt_mem[*indx]->t) > ZERO) (*indx)++; + else break; + } + + ca_mem->ca_ilast = *indx; + + + } else { + /* ilast is still OK */ + + *indx = ca_mem->ca_ilast; + + } + + return(CV_SUCCESS); + + +} + +/* + * CVodeGetAdjY + * + * This routine returns the interpolated forward solution at time t. + * The user must allocate space for y. + */ + +int CVodeGetAdjY(void *cvode_mem, realtype t, N_Vector y) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + int flag; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeGetAdjY", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + ca_mem = cv_mem->cv_adj_mem; + + flag = ca_mem->ca_IMget(cv_mem, t, y, NULL); + + return(flag); +} + +/* + * ----------------------------------------------------------------- + * Functions specific to cubic Hermite interpolation + * ----------------------------------------------------------------- + */ + +/* + * 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 + * at any other time. + */ + +static booleantype CVAhermiteMalloc(CVodeMem cv_mem) +{ + CVadjMem ca_mem; + DtpntMem *dt_mem; + HermiteDataMem content; + long int i, ii=0; + booleantype allocOK; + + allocOK = SUNTRUE; + + ca_mem = cv_mem->cv_adj_mem; + + /* Allocate space for the vectors ytmp and yStmp */ + + ca_mem->ca_ytmp = N_VClone(cv_mem->cv_tempv); + if (ca_mem->ca_ytmp == NULL) { + return(SUNFALSE); + } + + if (ca_mem->ca_IMstoreSensi) { + ca_mem->ca_yStmp = N_VCloneVectorArray(cv_mem->cv_Ns, cv_mem->cv_tempv); + if (ca_mem->ca_yStmp == NULL) { + N_VDestroy(ca_mem->ca_ytmp); + return(SUNFALSE); + } + } + + /* Allocate space for the content field of the dt structures */ + + dt_mem = ca_mem->dt_mem; + + for (i=0; i<=ca_mem->ca_nsteps; i++) { + + content = NULL; + content = (HermiteDataMem) malloc(sizeof(struct HermiteDataMemRec)); + if (content == NULL) { + ii = i; + allocOK = SUNFALSE; + break; + } + + content->y = N_VClone(cv_mem->cv_tempv); + if (content->y == NULL) { + free(content); content = NULL; + ii = i; + allocOK = SUNFALSE; + break; + } + + content->yd = N_VClone(cv_mem->cv_tempv); + if (content->yd == NULL) { + N_VDestroy(content->y); + free(content); content = NULL; + ii = i; + allocOK = SUNFALSE; + break; + } + + if (ca_mem->ca_IMstoreSensi) { + + content->yS = N_VCloneVectorArray(cv_mem->cv_Ns, cv_mem->cv_tempv); + if (content->yS == NULL) { + N_VDestroy(content->y); + N_VDestroy(content->yd); + free(content); content = NULL; + ii = i; + allocOK = SUNFALSE; + break; + } + + content->ySd = N_VCloneVectorArray(cv_mem->cv_Ns, cv_mem->cv_tempv); + if (content->ySd == NULL) { + N_VDestroy(content->y); + N_VDestroy(content->yd); + N_VDestroyVectorArray(content->yS, cv_mem->cv_Ns); + free(content); content = NULL; + ii = i; + allocOK = SUNFALSE; + break; + } + + } + + dt_mem[i]->content = content; + + } + + /* If an error occurred, deallocate and return */ + + if (!allocOK) { + + N_VDestroy(ca_mem->ca_ytmp); + + if (ca_mem->ca_IMstoreSensi) { + N_VDestroyVectorArray(ca_mem->ca_yStmp, cv_mem->cv_Ns); + } + + for (i=0; i<ii; i++) { + content = (HermiteDataMem) (dt_mem[i]->content); + N_VDestroy(content->y); + N_VDestroy(content->yd); + if (ca_mem->ca_IMstoreSensi) { + N_VDestroyVectorArray(content->yS, cv_mem->cv_Ns); + N_VDestroyVectorArray(content->ySd, cv_mem->cv_Ns); + } + free(dt_mem[i]->content); dt_mem[i]->content = NULL; + } + + } + + return(allocOK); +} + +/* + * CVAhermiteFree + * + * This routine frees the memory allocated for data storage. + */ + +static void CVAhermiteFree(CVodeMem cv_mem) +{ + CVadjMem ca_mem; + DtpntMem *dt_mem; + HermiteDataMem content; + long int i; + + ca_mem = cv_mem->cv_adj_mem; + + N_VDestroy(ca_mem->ca_ytmp); + + if (ca_mem->ca_IMstoreSensi) { + N_VDestroyVectorArray(ca_mem->ca_yStmp, cv_mem->cv_Ns); + } + + dt_mem = ca_mem->dt_mem; + + for (i=0; i<=ca_mem->ca_nsteps; i++) { + content = (HermiteDataMem) (dt_mem[i]->content); + N_VDestroy(content->y); + N_VDestroy(content->yd); + if (ca_mem->ca_IMstoreSensi) { + N_VDestroyVectorArray(content->yS, cv_mem->cv_Ns); + N_VDestroyVectorArray(content->ySd, cv_mem->cv_Ns); + } + free(dt_mem[i]->content); dt_mem[i]->content = NULL; + } +} + +/* + * CVAhermiteStorePnt ( -> IMstore ) + * + * This routine stores a new point (y,yd) in the structure d for use + * in the cubic Hermite interpolation. + * Note that the time is already stored. + */ + +static int CVAhermiteStorePnt(CVodeMem cv_mem, DtpntMem d) +{ + CVadjMem ca_mem; + HermiteDataMem content; + int is, retval; + + ca_mem = cv_mem->cv_adj_mem; + + content = (HermiteDataMem) d->content; + + /* Load solution */ + + N_VScale(ONE, cv_mem->cv_zn[0], content->y); + + if (ca_mem->ca_IMstoreSensi) { + for (is=0; is<cv_mem->cv_Ns; is++) + cv_mem->cv_cvals[is] = ONE; + + retval = N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, + cv_mem->cv_znS[0], content->yS); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + } + + /* Load derivative */ + + if (cv_mem->cv_nst == 0) { + + /* retval = */ cv_mem->cv_f(cv_mem->cv_tn, content->y, content->yd, cv_mem->cv_user_data); + + if (ca_mem->ca_IMstoreSensi) { + /* retval = */ cvSensRhsWrapper(cv_mem, cv_mem->cv_tn, content->y, content->yd, + content->yS, content->ySd, + cv_mem->cv_tempv, cv_mem->cv_ftemp); + } + + } else { + + N_VScale(ONE/cv_mem->cv_h, cv_mem->cv_zn[1], content->yd); + + if (ca_mem->ca_IMstoreSensi) { + for (is=0; is<cv_mem->cv_Ns; is++) + cv_mem->cv_cvals[is] = ONE/cv_mem->cv_h; + + retval = N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, + cv_mem->cv_znS[1], content->ySd); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + } + + } + + return(0); +} + +/* + * CVAhermiteGetY ( -> IMget ) + * + * 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 + */ + +static int CVAhermiteGetY(CVodeMem cv_mem, realtype t, + N_Vector y, N_Vector *yS) +{ + CVadjMem ca_mem; + DtpntMem *dt_mem; + HermiteDataMem content0, content1; + + realtype t0, t1, delta; + realtype factor1, factor2, factor3; + + N_Vector y0, yd0, y1, yd1; + N_Vector *yS0=NULL, *ySd0=NULL, *yS1, *ySd1; + + int flag, is, NS; + long int indx; + booleantype newpoint; + + /* local variables for fused vector oerations */ + int retval; + 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 */ + + flag = CVAfindIndex(cv_mem, t, &indx, &newpoint); + if (flag != CV_SUCCESS) return(flag); + + /* If we are beyond the left limit but close enough, + then return y at the left limit. */ + + if (indx == 0) { + content0 = (HermiteDataMem) (dt_mem[0]->content); + N_VScale(ONE, content0->y, y); + + if (NS > 0) { + for (is=0; is<NS; is++) + cv_mem->cv_cvals[is] = ONE; + + retval = N_VScaleVectorArray(NS, cv_mem->cv_cvals, + content0->yS, yS); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + } + + return(CV_SUCCESS); + } + + /* Extract stuff from the appropriate data points */ + + t0 = dt_mem[indx-1]->t; + t1 = dt_mem[indx]->t; + delta = t1 - t0; + + content0 = (HermiteDataMem) (dt_mem[indx-1]->content); + y0 = content0->y; + yd0 = content0->yd; + if (ca_mem->ca_IMinterpSensi) { + yS0 = content0->yS; + ySd0 = content0->ySd; + } + + if (newpoint) { + + /* Recompute Y0 and Y1 */ + + content1 = (HermiteDataMem) (dt_mem[indx]->content); + + y1 = content1->y; + yd1 = content1->yd; + + /* Y1 = delta (yd1 + yd0) - 2 (y1 - y0) */ + cvals[0] = -TWO; Xvecs[0] = y1; + cvals[1] = TWO; Xvecs[1] = y0; + cvals[2] = delta; Xvecs[2] = yd1; + cvals[3] = delta; Xvecs[3] = yd0; + + retval = N_VLinearCombination(4, cvals, Xvecs, ca_mem->ca_Y[1]); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + + /* Y0 = y1 - y0 - delta * yd0 */ + cvals[0] = ONE; Xvecs[0] = y1; + cvals[1] = -ONE; Xvecs[1] = y0; + cvals[2] = -delta; Xvecs[2] = yd0; + + retval = N_VLinearCombination(3, cvals, Xvecs, ca_mem->ca_Y[0]); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + + /* Recompute YS0 and YS1, if needed */ + + if (NS > 0) { + + yS1 = content1->yS; + ySd1 = content1->ySd; + + /* YS1 = delta (ySd1 + ySd0) - 2 (yS1 - yS0) */ + cvals[0] = -TWO; XXvecs[0] = yS1; + cvals[1] = TWO; XXvecs[1] = yS0; + cvals[2] = delta; XXvecs[2] = ySd1; + cvals[3] = delta; XXvecs[3] = ySd0; + + retval = N_VLinearCombinationVectorArray(NS, 4, cvals, XXvecs, ca_mem->ca_YS[1]); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + + /* YS0 = yS1 - yS0 - delta * ySd0 */ + cvals[0] = ONE; XXvecs[0] = yS1; + cvals[1] = -ONE; XXvecs[1] = yS0; + cvals[2] = -delta; XXvecs[2] = ySd0; + + retval = N_VLinearCombinationVectorArray(NS, 3, cvals, XXvecs, ca_mem->ca_YS[0]); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + + } + + } + + /* Perform the actual interpolation. */ + + factor1 = t - t0; + + factor2 = factor1/delta; + factor2 = factor2*factor2; + + factor3 = factor2*(t-t1)/delta; + + cvals[0] = ONE; + cvals[1] = factor1; + cvals[2] = factor2; + cvals[3] = factor3; + + /* y = y0 + factor1 yd0 + factor2 * Y[0] + factor3 Y[1] */ + Xvecs[0] = y0; + Xvecs[1] = yd0; + Xvecs[2] = ca_mem->ca_Y[0]; + Xvecs[3] = ca_mem->ca_Y[1]; + + retval = N_VLinearCombination(4, cvals, Xvecs, y); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + + /* yS = yS0 + factor1 ySd0 + factor2 * YS[0] + factor3 YS[1], if needed */ + if (NS > 0) { + + XXvecs[0] = yS0; + XXvecs[1] = ySd0; + XXvecs[2] = ca_mem->ca_YS[0]; + XXvecs[3] = ca_mem->ca_YS[1]; + + retval = N_VLinearCombinationVectorArray(NS, 4, cvals, XXvecs, yS); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + + } + + return(CV_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Functions specific to Polynomial interpolation + * ----------------------------------------------------------------- + */ + +/* + * 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 + * at any other time. + */ + +static booleantype CVApolynomialMalloc(CVodeMem cv_mem) +{ + CVadjMem ca_mem; + DtpntMem *dt_mem; + PolynomialDataMem content; + long int i, ii=0; + booleantype allocOK; + + allocOK = SUNTRUE; + + ca_mem = cv_mem->cv_adj_mem; + + /* Allocate space for the vectors ytmp and yStmp */ + + ca_mem->ca_ytmp = N_VClone(cv_mem->cv_tempv); + if (ca_mem->ca_ytmp == NULL) { + return(SUNFALSE); + } + + if (ca_mem->ca_IMstoreSensi) { + ca_mem->ca_yStmp = N_VCloneVectorArray(cv_mem->cv_Ns, cv_mem->cv_tempv); + if (ca_mem->ca_yStmp == NULL) { + N_VDestroy(ca_mem->ca_ytmp); + return(SUNFALSE); + } + } + + /* Allocate space for the content field of the dt structures */ + + dt_mem = ca_mem->dt_mem; + + for (i=0; i<=ca_mem->ca_nsteps; i++) { + + content = NULL; + content = (PolynomialDataMem) malloc(sizeof(struct PolynomialDataMemRec)); + if (content == NULL) { + ii = i; + allocOK = SUNFALSE; + break; + } + + content->y = N_VClone(cv_mem->cv_tempv); + if (content->y == NULL) { + free(content); content = NULL; + ii = i; + allocOK = SUNFALSE; + break; + } + + if (ca_mem->ca_IMstoreSensi) { + + content->yS = N_VCloneVectorArray(cv_mem->cv_Ns, cv_mem->cv_tempv); + if (content->yS == NULL) { + N_VDestroy(content->y); + free(content); content = NULL; + ii = i; + allocOK = SUNFALSE; + break; + } + + } + + dt_mem[i]->content = content; + + } + + /* If an error occurred, deallocate and return */ + + if (!allocOK) { + + N_VDestroy(ca_mem->ca_ytmp); + + if (ca_mem->ca_IMstoreSensi) { + N_VDestroyVectorArray(ca_mem->ca_yStmp, cv_mem->cv_Ns); + } + + for (i=0; i<ii; i++) { + content = (PolynomialDataMem) (dt_mem[i]->content); + N_VDestroy(content->y); + if (ca_mem->ca_IMstoreSensi) { + N_VDestroyVectorArray(content->yS, cv_mem->cv_Ns); + } + free(dt_mem[i]->content); dt_mem[i]->content = NULL; + } + + } + + return(allocOK); + +} + +/* + * CVApolynomialFree + * + * This routine frees the memeory allocated for data storage. + */ + +static void CVApolynomialFree(CVodeMem cv_mem) +{ + CVadjMem ca_mem; + DtpntMem *dt_mem; + PolynomialDataMem content; + long int i; + + ca_mem = cv_mem->cv_adj_mem; + + N_VDestroy(ca_mem->ca_ytmp); + + if (ca_mem->ca_IMstoreSensi) { + N_VDestroyVectorArray(ca_mem->ca_yStmp, cv_mem->cv_Ns); + } + + dt_mem = ca_mem->dt_mem; + + for (i=0; i<=ca_mem->ca_nsteps; i++) { + content = (PolynomialDataMem) (dt_mem[i]->content); + N_VDestroy(content->y); + if (ca_mem->ca_IMstoreSensi) { + N_VDestroyVectorArray(content->yS, cv_mem->cv_Ns); + } + free(dt_mem[i]->content); dt_mem[i]->content = NULL; + } +} + +/* + * CVApolynomialStorePnt ( -> IMstore ) + * + * This routine stores a new point y in the structure d for use + * in the Polynomial interpolation. + * Note that the time is already stored. + */ + +static int CVApolynomialStorePnt(CVodeMem cv_mem, DtpntMem d) +{ + CVadjMem ca_mem; + PolynomialDataMem content; + int is, retval; + + ca_mem = cv_mem->cv_adj_mem; + + content = (PolynomialDataMem) d->content; + + N_VScale(ONE, cv_mem->cv_zn[0], content->y); + + if (ca_mem->ca_IMstoreSensi) { + for (is=0; is<cv_mem->cv_Ns; is++) + cv_mem->cv_cvals[is] = ONE; + retval = N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, + cv_mem->cv_znS[0], content->yS); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + } + + content->order = cv_mem->cv_qu; + + return(0); +} + +/* + * CVApolynomialGetY ( -> IMget ) + * + * 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. + */ + +static int CVApolynomialGetY(CVodeMem cv_mem, realtype t, + N_Vector y, N_Vector *yS) +{ + CVadjMem ca_mem; + DtpntMem *dt_mem; + PolynomialDataMem content; + + int flag, dir, order, i, j, is, NS, retval; + long int indx, base; + booleantype newpoint; + realtype dt, factor; + + 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 */ + + flag = CVAfindIndex(cv_mem, t, &indx, &newpoint); + if (flag != CV_SUCCESS) return(flag); + + /* If we are beyond the left limit but close enough, + then return y at the left limit. */ + + if (indx == 0) { + content = (PolynomialDataMem) (dt_mem[0]->content); + N_VScale(ONE, content->y, y); + + if (NS > 0) { + for (is=0; is<NS; is++) + cv_mem->cv_cvals[is] = ONE; + retval = N_VScaleVectorArray(NS, cv_mem->cv_cvals, content->yS, yS); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + } + + return(CV_SUCCESS); + } + + /* Scaling factor */ + + dt = SUNRabs(dt_mem[indx]->t - dt_mem[indx-1]->t); + + /* Find the direction of the forward integration */ + + dir = (ca_mem->ca_tfinal - ca_mem->ca_tinitial > ZERO) ? 1 : -1; + + /* Establish the base point depending on the integration direction. + Modify the base if there are not enough points for the current order */ + + if (dir == 1) { + base = indx; + content = (PolynomialDataMem) (dt_mem[base]->content); + order = content->order; + if(indx < order) base += order-indx; + } else { + base = indx-1; + content = (PolynomialDataMem) (dt_mem[base]->content); + order = content->order; + if (ca_mem->ca_np-indx > order) base -= indx+order-ca_mem->ca_np; + } + + /* Recompute Y (divided differences for Newton polynomial) if needed */ + + if (newpoint) { + + /* Store 0-th order DD */ + if (dir == 1) { + for(j=0;j<=order;j++) { + ca_mem->ca_T[j] = dt_mem[base-j]->t; + content = (PolynomialDataMem) (dt_mem[base-j]->content); + N_VScale(ONE, content->y, ca_mem->ca_Y[j]); + + if (NS > 0) { + for (is=0; is<NS; is++) + cv_mem->cv_cvals[is] = ONE; + retval = N_VScaleVectorArray(NS, cv_mem->cv_cvals, + content->yS, ca_mem->ca_YS[j]); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + } + } + } else { + for(j=0;j<=order;j++) { + ca_mem->ca_T[j] = dt_mem[base-1+j]->t; + content = (PolynomialDataMem) (dt_mem[base-1+j]->content); + N_VScale(ONE, content->y, ca_mem->ca_Y[j]); + if (NS > 0) { + for (is=0; is<NS; is++) + cv_mem->cv_cvals[is] = ONE; + retval = N_VScaleVectorArray(NS, cv_mem->cv_cvals, + content->yS, ca_mem->ca_YS[j]); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + } + } + } + + /* Compute higher-order DD */ + for(i=1;i<=order;i++) { + for(j=order;j>=i;j--) { + factor = dt/(ca_mem->ca_T[j]-ca_mem->ca_T[j-i]); + N_VLinearSum(factor, ca_mem->ca_Y[j], -factor, ca_mem->ca_Y[j-1], ca_mem->ca_Y[j]); + + if (NS > 0) { + retval = N_VLinearSumVectorArray(NS, + factor, ca_mem->ca_YS[j], + -factor, ca_mem->ca_YS[j-1], + ca_mem->ca_YS[j]); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + } + } + } + } + + /* Perform the actual interpolation using nested multiplications */ + + cv_mem->cv_cvals[0] = ONE; + for (i=0; i<order; i++) + cv_mem->cv_cvals[i+1] = cv_mem->cv_cvals[i] * (t-ca_mem->ca_T[i]) / dt; + + retval = N_VLinearCombination(order+1, cv_mem->cv_cvals, ca_mem->ca_Y, y); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + + if (NS > 0) { + retval = N_VLinearCombinationVectorArray(NS, order+1, cv_mem->cv_cvals, ca_mem->ca_YS, yS); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + } + + return(CV_SUCCESS); + +} + +/* + * ================================================================= + * WRAPPERS FOR ADJOINT SYSTEM + * ================================================================= + */ +/* + * CVArhs + * + * This routine interfaces to the CVRhsFnB (or CVRhsFnBS) routine + * provided by the user. + */ + +static int CVArhs(realtype t, N_Vector yB, + N_Vector yBdot, void *cvode_mem) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + int flag, retval; + + cv_mem = (CVodeMem) cvode_mem; + + ca_mem = cv_mem->cv_adj_mem; + + cvB_mem = ca_mem->ca_bckpbCrt; + + /* Get forward solution from interpolation */ + + if (ca_mem->ca_IMinterpSensi) + flag = ca_mem->ca_IMget(cv_mem, t, ca_mem->ca_ytmp, ca_mem->ca_yStmp); + else + flag = ca_mem->ca_IMget(cv_mem, t, ca_mem->ca_ytmp, NULL); + + if (flag != CV_SUCCESS) { + cvProcessError(cv_mem, -1, "CVODEA", "CVArhs", MSGCV_BAD_TINTERP, t); + return(-1); + } + + /* Call the user's RHS function */ + + if (cvB_mem->cv_f_withSensi) + retval = (cvB_mem->cv_fs)(t, ca_mem->ca_ytmp, ca_mem->ca_yStmp, yB, yBdot, cvB_mem->cv_user_data); + else + retval = (cvB_mem->cv_f)(t, ca_mem->ca_ytmp, yB, yBdot, cvB_mem->cv_user_data); + + return(retval); +} + +/* + * CVArhsQ + * + * This routine interfaces to the CVQuadRhsFnB (or CVQuadRhsFnBS) routine + * provided by the user. + */ + +static int CVArhsQ(realtype t, N_Vector yB, + N_Vector qBdot, void *cvode_mem) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + /* int flag; */ + int retval; + + cv_mem = (CVodeMem) cvode_mem; + + ca_mem = cv_mem->cv_adj_mem; + + cvB_mem = ca_mem->ca_bckpbCrt; + + /* Get forward solution from interpolation */ + + if (ca_mem->ca_IMinterpSensi) + /* flag = */ ca_mem->ca_IMget(cv_mem, t, ca_mem->ca_ytmp, ca_mem->ca_yStmp); + else + /* flag = */ ca_mem->ca_IMget(cv_mem, t, ca_mem->ca_ytmp, NULL); + + /* Call the user's RHS function */ + + if (cvB_mem->cv_fQ_withSensi) + retval = (cvB_mem->cv_fQs)(t, ca_mem->ca_ytmp, ca_mem->ca_yStmp, yB, qBdot, cvB_mem->cv_user_data); + else + retval = (cvB_mem->cv_fQ)(t, ca_mem->ca_ytmp, yB, qBdot, cvB_mem->cv_user_data); + + return(retval); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodea_io.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodea_io.c new file mode 100644 index 0000000..167b2eb --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodea_io.c @@ -0,0 +1,747 @@ +/* + * ----------------------------------------------------------------- + * $Revision$ + * $Date$ + * ----------------------------------------------------------------- + * Programmer: 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 optional input and output + * functions for the adjoint module in the CVODES solver. + * ----------------------------------------------------------------- + */ + +/* + * ================================================================= + * IMPORTED HEADER FILES + * ================================================================= + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "cvodes_impl.h" +#include <sundials/sundials_types.h> + +/* + * ================================================================= + * CVODEA PRIVATE CONSTANTS + * ================================================================= + */ + +#define ONE RCONST(1.0) + +/* + * ================================================================= + * EXPORTED FUNCTIONS IMPLEMENTATION + * ================================================================= + */ + +/* + * ----------------------------------------------------------------- + * Optional input functions for ASA + * ----------------------------------------------------------------- + */ + +int CVodeSetAdjNoSensi(void *cvode_mem) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeSetAdjNoSensi", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeSetAdjNoSensi", MSGCV_NO_ADJ); + return(CV_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + ca_mem->ca_IMstoreSensi = SUNFALSE; + + return(CV_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Optional input functions for backward integration + * ----------------------------------------------------------------- + */ + +int CVodeSetNonlinearSolverB(void *cvode_mem, int which, SUNNonlinearSolver NLS) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", + "CVodeSetNonlinearSolverB", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", + "CVodeSetNonlinearSolverB", MSGCV_NO_ADJ); + return(CV_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + /* Check which */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", + "CVodeSetNonlinearSolverB", MSGCV_BAD_WHICH); + return(CV_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + return(CVodeSetNonlinearSolver(cvodeB_mem, NLS)); +} + +int CVodeSetUserDataB(void *cvode_mem, int which, void *user_dataB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeSetUserDataB", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeSetUserDataB", MSGCV_NO_ADJ); + return(CV_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + /* Check which */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeSetUserDataB", MSGCV_BAD_WHICH); + return(CV_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + cvB_mem->cv_user_data = user_dataB; + + return(CV_SUCCESS); +} + +int CVodeSetMaxOrdB(void *cvode_mem, int which, int maxordB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + int flag; + + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeSetMaxOrdB", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeSetMaxOrdB", MSGCV_NO_ADJ); + return(CV_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + /* Check which */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeSetMaxOrdB", MSGCV_BAD_WHICH); + return(CV_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + flag = CVodeSetMaxOrd(cvodeB_mem, maxordB); + + return(flag); +} + + +int CVodeSetMaxNumStepsB(void *cvode_mem, int which, long int mxstepsB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + int flag; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeSetMaxNumStepsB", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeSetMaxNumStepsB", MSGCV_NO_ADJ); + return(CV_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + /* Check which */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeSetMaxNumStepsB", MSGCV_BAD_WHICH); + return(CV_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + flag = CVodeSetMaxNumSteps(cvodeB_mem, mxstepsB); + + return(flag); +} + +int CVodeSetStabLimDetB(void *cvode_mem, int which, booleantype stldetB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + int flag; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeSetStabLimDetB", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeSetStabLimDetB", MSGCV_NO_ADJ); + return(CV_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + /* Check which */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeSetStabLimDetB", MSGCV_BAD_WHICH); + return(CV_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + flag = CVodeSetStabLimDet(cvodeB_mem, stldetB); + + return(flag); +} + +int CVodeSetInitStepB(void *cvode_mem, int which, realtype hinB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + int flag; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeSetInitStepB", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeSetInitStepB", MSGCV_NO_ADJ); + return(CV_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + /* Check which */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeSetInitStepB", MSGCV_BAD_WHICH); + return(CV_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + flag = CVodeSetInitStep(cvodeB_mem, hinB); + + return(flag); +} + +int CVodeSetMinStepB(void *cvode_mem, int which, realtype hminB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + int flag; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeSetMinStepB", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeSetMinStepB", MSGCV_NO_ADJ); + return(CV_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + /* Check which */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeSetMinStepB", MSGCV_BAD_WHICH); + return(CV_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + flag = CVodeSetMinStep(cvodeB_mem, hminB); + + return(flag); +} + +int CVodeSetMaxStepB(void *cvode_mem, int which, realtype hmaxB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + int flag; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeSetMaxStepB", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeSetMaxStepB", MSGCV_NO_ADJ); + return(CV_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + /* Check which */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeSetMaxStepB", MSGCV_BAD_WHICH); + return(CV_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + flag = CVodeSetMaxStep(cvodeB_mem, hmaxB); + + return(flag); +} + +int CVodeSetConstraintsB(void *cvode_mem, int which, N_Vector constraintsB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + int flag; + + /* Is cvode_mem valid? */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeSetConstraintsB", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Is ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeSetConstraintsB", MSGCV_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + /* Check the value of which */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeSetConstraintsB", MSGCV_BAD_WHICH); + return(CV_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to 'which'. */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index) break; + /* advance */ + cvB_mem = cvB_mem->cv_next; + } + cvodeB_mem = (void *) cvB_mem->cv_mem; + + flag = CVodeSetConstraints(cvodeB_mem, constraintsB); + return(flag); +} + +/* + * CVodeSetQuad*B + * + * Wrappers for the backward phase around the corresponding + * CVODES quadrature optional input functions + */ + +int CVodeSetQuadErrConB(void *cvode_mem, int which, booleantype errconQB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + int flag; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeSetQuadErrConB", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeSetQuadErrConB", MSGCV_NO_ADJ); + return(CV_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + /* Check which */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVodeSetQuadErrConB", MSGCV_BAD_WHICH); + return(CV_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + flag = CVodeSetQuadErrCon(cvodeB_mem, errconQB); + + return(flag); +} + +/* + * ----------------------------------------------------------------- + * Optional output functions for backward integration + * ----------------------------------------------------------------- + */ + +/* + * CVodeGetAdjCVodeBmem + * + * This function returns a (void *) pointer to the CVODES + * memory allocated for the backward problem. This pointer can + * then be used to call any of the CVodeGet* CVODES routines to + * extract optional output for the backward integration phase. + */ + +void *CVodeGetAdjCVodeBmem(void *cvode_mem, int which) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, 0, "CVODEA", "CVodeGetAdjCVodeBmem", MSGCV_NO_MEM); + return(NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, 0, "CVODEA", "CVodeGetAdjCVodeBmem", MSGCV_NO_ADJ); + return(NULL); + } + ca_mem = cv_mem->cv_adj_mem; + + /* Check which */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, 0, "CVODEA", "CVodeGetAdjCVodeBmem", MSGCV_BAD_WHICH); + return(NULL); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + return(cvodeB_mem); +} + +/* + * CVodeGetAdjCheckPointsInfo + * + * This routine loads an array of nckpnts structures of type CVadjCheckPointRec. + * The user must allocate space for ckpnt. + */ + +int CVodeGetAdjCheckPointsInfo(void *cvode_mem, CVadjCheckPointRec *ckpnt) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CkpntMem ck_mem; + int i; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeGetAdjCheckPointsInfo", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeGetAdjCheckPointsInfo", MSGCV_NO_ADJ); + return(CV_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + ck_mem = ca_mem->ck_mem; + + i = 0; + + while (ck_mem != NULL) { + + ckpnt[i].my_addr = (void *) ck_mem; + ckpnt[i].next_addr = (void *) ck_mem->ck_next; + ckpnt[i].t0 = ck_mem->ck_t0; + ckpnt[i].t1 = ck_mem->ck_t1; + ckpnt[i].nstep = ck_mem->ck_nst; + ckpnt[i].order = ck_mem->ck_q; + ckpnt[i].step = ck_mem->ck_h; + + ck_mem = ck_mem->ck_next; + i++; + + } + + return(CV_SUCCESS); + +} + + +/* + * ----------------------------------------------------------------- + * Undocumented Development User-Callable Functions + * ----------------------------------------------------------------- + */ + + +/* + * CVodeGetAdjDataPointHermite + * + * This routine returns the solution stored in the data structure + * at the 'which' data point. Cubic Hermite interpolation. + */ + +int CVodeGetAdjDataPointHermite(void *cvode_mem, int which, + realtype *t, N_Vector y, N_Vector yd) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + DtpntMem *dt_mem; + HermiteDataMem content; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeGetAdjDataPointHermite", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeGetAdjDataPointHermite", MSGCV_NO_ADJ); + return(CV_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + dt_mem = ca_mem->dt_mem; + + if (ca_mem->ca_IMtype != CV_HERMITE) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVadjGetDataPointHermite", MSGCV_WRONG_INTERP); + return(CV_ILL_INPUT); + } + + *t = dt_mem[which]->t; + + content = (HermiteDataMem) (dt_mem[which]->content); + + if (y != NULL) + N_VScale(ONE, content->y, y); + + if (yd != NULL) + N_VScale(ONE, content->yd, yd); + + return(CV_SUCCESS); +} + +/* + * CVodeGetAdjDataPointPolynomial + * + * This routine returns the solution stored in the data structure + * at the 'which' data point. Polynomial interpolation. + */ + +int CVodeGetAdjDataPointPolynomial(void *cvode_mem, int which, + realtype *t, int *order, N_Vector y) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + DtpntMem *dt_mem; + PolynomialDataMem content; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeGetAdjDataPointPolynomial", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeGetAdjDataPointPolynomial", MSGCV_NO_ADJ); + return(CV_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + dt_mem = ca_mem->dt_mem; + + if (ca_mem->ca_IMtype != CV_POLYNOMIAL) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODEA", "CVadjGetDataPointPolynomial", MSGCV_WRONG_INTERP); + return(CV_ILL_INPUT); + } + + *t = dt_mem[which]->t; + + content = (PolynomialDataMem) (dt_mem[which]->content); + + if (y != NULL) + N_VScale(ONE, content->y, y); + + *order = content->order; + + return(CV_SUCCESS); +} + + +/* + * CVodeGetAdjCurrentCheckPoint + * + * Returns the address of the 'active' check point. + */ + +int CVodeGetAdjCurrentCheckPoint(void *cvode_mem, void **addr) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODEA", "CVodeGetAdjCurrentCheckPoint", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_ADJ, "CVODEA", "CVodeGetAdjCurrentCheckPoint", MSGCV_NO_ADJ); + return(CV_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + *addr = (void *) ca_mem->ca_ckpntData; + + return(CV_SUCCESS); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes.c new file mode 100644 index 0000000..025f3e9 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes.c @@ -0,0 +1,8813 @@ +/* + * ----------------------------------------------------------------- + * $Revision$ + * $Date$ + * ----------------------------------------------------------------- + * Programmer(s): 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 main CVODES integrator + * with sensitivity analysis capabilities. + * ----------------------------------------------------------------- + * + * EXPORTED FUNCTIONS + * ------------------ + * + * Creation, allocation and re-initialization functions + * + * CVodeCreate + * + * CVodeInit + * CVodeReInit + * CVodeSStolerances + * CVodeSVtolerances + * CVodeWFtolerances + * + * CVodeQuadInit + * CVodeQuadReInit + * CVodeQuadSStolerances + * CVodeQuadSVtolerances + * + * CVodeSensInit + * CVodeSensInit1 + * CVodeSensReInit + * CVodeSensSStolerances + * CVodeSensSVtolerances + * CVodeSensEEtolerances + * + * CVodeQuadSensInit + * CVodeQuadSensReInit + * + * CVodeSensToggleOff + * + * CVodeRootInit + * + * Main solver function + * CVode + * + * Interpolated output and extraction functions + * CVodeGetDky + * CVodeGetQuad + * CVodeGetQuadDky + * CVodeGetSens + * CVodeGetSens1 + * CVodeGetSensDky + * CVodeGetSensDky1 + * CVodeGetQuadSens + * CVodeGetQuadSens1 + * CVodeGetQuadSensDky + * CVodeGetQuadSensDky1 + * + * Deallocation functions + * CVodeFree + * CVodeQuadFree + * CVodeSensFree + * CVodeQuadSensFree + * + * PRIVATE FUNCTIONS + * ----------------- + * + * cvCheckNvector + * + * Memory allocation/deallocation + * cvAllocVectors + * cvFreeVectors + * cvQuadAllocVectors + * cvQuadFreeVectors + * cvSensAllocVectors + * cvSensFreeVectors + * cvQuadSensAllocVectors + * cvQuadSensFreeVectors + * + * Initial stepsize calculation + * cvHin + * cvUpperBoundH0 + * cvYddNorm + * + * Initial setup + * cvInitialSetup + * cvEwtSet + * cvEwtSetSS + * cvEwtSetSV + * cvQuadEwtSet + * cvQuadEwtSetSS + * cvQuadEwtSetSV + * cvSensEwtSet + * cvSensEwtSetEE + * cvSensEwtSetSS + * cvSensEwtSetSV + * cvQuadSensEwtSet + * cvQuadSensEwtSetEE + * cvQuadSensEwtSetSS + * cvQuadSensEwtSetSV + * + * Main cvStep function + * cvStep + * + * Functions called at beginning of step + * cvAdjustParams + * cvAdjustOrder + * cvAdjustAdams + * cvAdjustBDF + * cvIncreaseBDF + * cvDecreaseBDF + * cvRescale + * cvPredict + * cvSet + * cvSetAdams + * cvAdamsStart + * cvAdamsFinish + * cvAltSum + * cvSetBDF + * cvSetTqBDF + * + * Nonlinear solver functions + * cvNls + * cvQuadNls + * cvStgrNls + * cvStgr1Nls + * cvQuadSensNls + * cvHandleNFlag + * cvRestore + * + * Error Test + * cvDoErrorTest + * + * Functions called after a successful step + * cvCompleteStep + * cvPrepareNextStep + * cvSetEta + * cvComputeEtaqm1 + * cvComputeEtaqp1 + * cvChooseEta + * + * Function to handle failures + * cvHandleFailure + * + * Functions for BDF Stability Limit Detection + * cvBDFStab + * cvSLdet + * + * Functions for rootfinding + * cvRcheck1 + * cvRcheck2 + * cvRcheck3 + * cvRootfind + * + * Functions for combined norms + * cvQuadUpdateNorm + * cvSensNorm + * cvSensUpdateNorm + * cvQuadSensNorm + * cvQuadSensUpdateNorm + * + * Wrappers for sensitivity RHS + * cvSensRhsWrapper + * cvSensRhs1Wrapper + * + * Internal DQ approximations for sensitivity RHS + * cvSensRhsInternalDQ + * cvSensRhs1InternalDQ + * cvQuadSensRhsDQ + * + * Error message handling functions + * cvProcessError + * cvErrHandler + * + * ----------------------------------------------------------------- + */ + +/* + * ================================================================= + * IMPORTED HEADER FILES + * ================================================================= + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> + +#include "cvodes_impl.h" +#include <sundials/sundials_math.h> +#include <sundials/sundials_types.h> +#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 + * ================================================================= + */ + +/* + * Control constants for lower-level functions used by cvStep + * ---------------------------------------------------------- + * + * cvHin return values: + * CV_SUCCESS, + * CV_RHSFUNC_FAIL, CV_RPTD_RHSFUNC_ERR, + * CV_QRHSFUNC_FAIL, CV_RPTD_QRHSFUNC_ERR, + * CV_SRHSFUNC_FAIL, CV_RPTD_SRHSFUNC_ERR, + * CV_TOO_CLOSE + * + * cvStep control constants: + * DO_ERROR_TEST + * PREDICT_AGAIN + * + * cvStep return values: + * CV_SUCCESS, + * CV_CONV_FAILURE, CV_ERR_FAILURE, + * CV_LSETUP_FAIL, CV_LSOLVE_FAIL, + * CV_RTFUNC_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, + * + * cvNls input nflag values: + * FIRST_CALL + * PREV_CONV_FAIL + * PREV_ERR_FAIL + * + * cvNls return values: + * CV_SUCCESS, + * CV_LSETUP_FAIL, CV_LSOLVE_FAIL, + * CV_RHSFUNC_FAIL, CV_SRHSFUNC_FAIL, + * SUN_NLS_CONV_RECVR, + * RHSFUNC_RECVR, SRHSFUNC_RECVR + * + */ + +#define DO_ERROR_TEST +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 CONSTR_RECVR +10 + +#define QRHSFUNC_RECVR +11 +#define QSRHSFUNC_RECVR +13 + +/* + * Control constants for lower-level rootfinding functions + * ------------------------------------------------------- + * + * cvRcheck1 return values: + * CV_SUCCESS, + * CV_RTFUNC_FAIL, + * cvRcheck2 return values: + * CV_SUCCESS, + * CV_RTFUNC_FAIL, + * CLOSERT, + * RTFOUND + * cvRcheck3 return values: + * CV_SUCCESS, + * CV_RTFUNC_FAIL, + * RTFOUND + * cvRootfind return values: + * CV_SUCCESS, + * CV_RTFUNC_FAIL, + * RTFOUND + */ + +#define RTFOUND +1 +#define CLOSERT +3 + +/* + * Control constants for sensitivity DQ + * ------------------------------------ + */ + +#define CENTERED1 +1 +#define CENTERED2 +2 +#define FORWARD1 +3 +#define FORWARD2 +4 + +/* + * Control constants for type of sensitivity RHS + * --------------------------------------------- + */ + +#define CV_ONESENS 1 +#define CV_ALLSENS 2 + +/* + * Control constants for tolerances + * -------------------------------- + */ + +#define CV_NN 0 +#define CV_SS 1 +#define CV_SV 2 +#define CV_WF 3 +#define CV_EE 4 + +/* + * Algorithmic constants + * --------------------- + * + * CVodeGetDky and cvStep + * + * FUZZ_FACTOR fuzz factor used to estimate infinitesimal time intervals + * + * cvHin + * + * 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 constant in nonlinear iteration convergence test + * + * cvStep + * + * 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 + * MXNEF max no. of error test failures during one step try + * MXNEF1 max no. of error test failures before forcing a reduction of order + * SMALL_NEF if an error failure occurs and SMALL_NEF <= nef <= MXNEF1, then + * reset eta = SUNMIN(eta, ETAMXF) + * LONG_WAIT number of steps to wait before considering an order change when + * q==1 and MXNEF1 error test failures have occurred + * + * cvNls + * + * DGMAX |gamma/gammap-1| > DGMAX => call lsetup + * MSBP max no. of steps between lsetup calls + * + */ + + +#define FUZZ_FACTOR RCONST(100.0) + +#define HLB_FACTOR RCONST(100.0) +#define HUB_FACTOR RCONST(0.1) +#define H_BIAS HALF +#define MAX_ITERS 4 + +#define CORTES RCONST(0.1) + +#define THRESH RCONST(1.5) +#define ETAMX1 RCONST(10000.0) +#define ETAMX2 RCONST(10.0) +#define ETAMX3 RCONST(10.0) +#define ETAMXF RCONST(0.2) +#define ETAMIN RCONST(0.1) +#define ETACF RCONST(0.25) +#define ADDON RCONST(0.000001) +#define BIAS1 RCONST(6.0) +#define BIAS2 RCONST(6.0) +#define BIAS3 RCONST(10.0) +#define ONEPSM RCONST(1.000001) + +#define SMALL_NST 10 +#define MXNCF 10 +#define MXNEF 7 +#define MXNEF1 3 +#define SMALL_NEF 2 +#define LONG_WAIT 10 + +#define DGMAX RCONST(0.3) +#define MSBP 20 + +/* + * ================================================================= + * PRIVATE FUNCTION PROTOTYPES + * ================================================================= + */ + +static booleantype cvCheckNvector(N_Vector tmpl); + +/* Memory allocation/deallocation */ + +static booleantype cvAllocVectors(CVodeMem cv_mem, N_Vector tmpl); +static void cvFreeVectors(CVodeMem cv_mem); + +static booleantype cvQuadAllocVectors(CVodeMem cv_mem, N_Vector tmpl); +static void cvQuadFreeVectors(CVodeMem cv_mem); + +static booleantype cvSensAllocVectors(CVodeMem cv_mem, N_Vector tmpl); +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); + +static int cvQuadEwtSet(CVodeMem cv_mem, N_Vector qcur, N_Vector weightQ); +static int cvQuadEwtSetSS(CVodeMem cv_mem, N_Vector qcur, N_Vector weightQ); +static int cvQuadEwtSetSV(CVodeMem cv_mem, N_Vector qcur, N_Vector weightQ); + +static int cvSensEwtSet(CVodeMem cv_mem, N_Vector *yScur, N_Vector *weightS); +static int cvSensEwtSetEE(CVodeMem cv_mem, N_Vector *yScur, N_Vector *weightS); +static int cvSensEwtSetSS(CVodeMem cv_mem, N_Vector *yScur, N_Vector *weightS); +static int cvSensEwtSetSV(CVodeMem cv_mem, N_Vector *yScur, N_Vector *weightS); + +static int cvQuadSensEwtSet(CVodeMem cv_mem, N_Vector *yQScur, N_Vector *weightQS); +static int cvQuadSensEwtSetEE(CVodeMem cv_mem, N_Vector *yQScur, N_Vector *weightQS); +static int cvQuadSensEwtSetSS(CVodeMem cv_mem, N_Vector *yQScur, N_Vector *weightQS); +static int cvQuadSensEwtSetSV(CVodeMem cv_mem, N_Vector *yQScur, N_Vector *weightQS); + +/* Main cvStep function */ + +static int cvStep(CVodeMem cv_mem); + +/* Function called at beginning of step */ + +static void cvAdjustParams(CVodeMem cv_mem); +static void cvAdjustOrder(CVodeMem cv_mem, int deltaq); +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[]); +static void cvAdamsFinish(CVodeMem cv_mem, realtype m[], realtype M[], realtype hsum); +static realtype cvAltSum(int iend, realtype a[], int k); +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 cvQuadNls(CVodeMem cv_mem); +static int cvStgrNls(CVodeMem cv_mem); +static int cvStgr1Nls(CVodeMem cv_mem, int is); +static int cvQuadSensNls(CVodeMem cv_mem); + +static int cvCheckConstraints(CVodeMem cv_mem); + +static int cvHandleNFlag(CVodeMem cv_mem, int *nflagPtr, realtype saved_t, + int *ncfPtr, long int *ncfnPtr); + +static void cvRestore(CVodeMem cv_mem, realtype saved_t); + +/* Error Test */ + +static int cvDoErrorTest(CVodeMem cv_mem, int *nflagPtr, realtype saved_t, + realtype acor_nrm, + int *nefPtr, long int *netfPtr, realtype *dsmPtr); + +/* 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); + +/* 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); +static int cvRootfind(CVodeMem cv_mem); + +/* Function for combined norms */ + +static realtype cvQuadUpdateNorm(CVodeMem cv_mem, realtype old_nrm, + N_Vector xQ, N_Vector wQ); + +static realtype cvQuadSensNorm(CVodeMem cv_mem, N_Vector *xQS, N_Vector *wQS); +static realtype cvQuadSensUpdateNorm(CVodeMem cv_mem, realtype old_nrm, + N_Vector *xQS, N_Vector *wQS); + +/* Internal sensitivity RHS DQ functions */ + +static int cvQuadSensRhsInternalDQ(int Ns, realtype t, + N_Vector y, N_Vector *yS, + N_Vector yQdot, N_Vector *yQSdot, + void *cvode_mem, + N_Vector tmp, N_Vector tmpQ); + +static int cvQuadSensRhs1InternalDQ(CVodeMem cv_mem, int is, realtype t, + N_Vector y, N_Vector yS, + N_Vector yQdot, N_Vector yQSdot, + N_Vector tmp, N_Vector tmpQ); + +/* + * ================================================================= + * EXPORTED FUNCTIONS IMPLEMENTATION + * ================================================================= + */ + +/* + * ----------------------------------------------------------------- + * Creation, allocation and re-initialization functions + * ----------------------------------------------------------------- + */ + +/* + * CVodeCreate + * + * 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. + */ + +void *CVodeCreate(int lmm) +{ + int maxord; + CVodeMem cv_mem; + + /* Test inputs */ + + if ((lmm != CV_ADAMS) && (lmm != CV_BDF)) { + cvProcessError(NULL, 0, "CVODES", "CVodeCreate", MSGCV_BAD_LMM); + return(NULL); + } + + cv_mem = NULL; + cv_mem = (CVodeMem) malloc(sizeof(struct CVodeMemRec)); + if (cv_mem == NULL) { + cvProcessError(NULL, 0, "CVODES", "CVodeCreate", MSGCV_CVMEM_FAIL); + return(NULL); + } + + /* Zero out cv_mem */ + memset(cv_mem, 0, sizeof(struct CVodeMemRec)); + + maxord = (lmm == CV_ADAMS) ? ADAMS_Q_MAX : BDF_Q_MAX; + + /* copy input parameter 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_constraints = NULL; + cv_mem->cv_constraintsSet = SUNFALSE; + + /* Initialize root finding variables */ + + cv_mem->cv_glo = NULL; + cv_mem->cv_ghi = NULL; + cv_mem->cv_grout = NULL; + cv_mem->cv_iroots = NULL; + cv_mem->cv_rootdir = NULL; + cv_mem->cv_gfun = NULL; + cv_mem->cv_nrtfn = 0; + cv_mem->cv_gactive = NULL; + cv_mem->cv_mxgnull = 1; + + /* Set default values for quad. optional inputs */ + + cv_mem->cv_quadr = SUNFALSE; + cv_mem->cv_fQ = NULL; + cv_mem->cv_errconQ = SUNFALSE; + cv_mem->cv_itolQ = CV_NN; + + /* Set default values for sensi. optional inputs */ + + cv_mem->cv_sensi = SUNFALSE; + cv_mem->cv_fS_data = NULL; + cv_mem->cv_fS = cvSensRhsInternalDQ; + cv_mem->cv_fS1 = cvSensRhs1InternalDQ; + cv_mem->cv_fSDQ = SUNTRUE; + cv_mem->cv_ifS = CV_ONESENS; + cv_mem->cv_DQtype = CV_CENTERED; + cv_mem->cv_DQrhomax = ZERO; + cv_mem->cv_p = NULL; + cv_mem->cv_pbar = NULL; + cv_mem->cv_plist = NULL; + cv_mem->cv_errconS = SUNFALSE; + cv_mem->cv_ncfS1 = NULL; + cv_mem->cv_ncfnS1 = NULL; + cv_mem->cv_nniS1 = NULL; + cv_mem->cv_itolS = CV_NN; + + /* Set default values for quad. sensi. optional inputs */ + + cv_mem->cv_quadr_sensi = SUNFALSE; + cv_mem->cv_fQS = NULL; + cv_mem->cv_fQS_data = NULL; + cv_mem->cv_fQSDQ = SUNTRUE; + cv_mem->cv_errconQS = SUNFALSE; + cv_mem->cv_itolQS = CV_NN; + + /* Set default for ASA */ + + cv_mem->cv_adj = SUNFALSE; + cv_mem->cv_adj_mem = NULL; + + /* Set the saved values for qmax_alloc */ + + cv_mem->cv_qmax_alloc = maxord; + cv_mem->cv_qmax_allocQ = maxord; + cv_mem->cv_qmax_allocS = maxord; + + /* Initialize lrw and liw */ + + cv_mem->cv_lrw = 65 + 2*L_MAX + NUM_TESTS; + cv_mem->cv_liw = 52; + + /* No mallocs have been done yet */ + + cv_mem->cv_VabstolMallocDone = SUNFALSE; + cv_mem->cv_MallocDone = SUNFALSE; + cv_mem->cv_constraintsMallocDone = SUNFALSE; + + cv_mem->cv_VabstolQMallocDone = SUNFALSE; + cv_mem->cv_QuadMallocDone = SUNFALSE; + + cv_mem->cv_VabstolSMallocDone = SUNFALSE; + cv_mem->cv_SabstolSMallocDone = SUNFALSE; + cv_mem->cv_SensMallocDone = SUNFALSE; + + cv_mem->cv_VabstolQSMallocDone = SUNFALSE; + cv_mem->cv_SabstolQSMallocDone = SUNFALSE; + cv_mem->cv_QuadSensMallocDone = SUNFALSE; + + cv_mem->cv_adjMallocDone = SUNFALSE; + + /* Initialize nonlinear solver variables */ + cv_mem->NLS = NULL; + cv_mem->ownNLS = SUNFALSE; + + cv_mem->NLSsim = NULL; + cv_mem->ownNLSsim = SUNFALSE; + cv_mem->ycor0Sim = 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->ycorStg = NULL; + cv_mem->ewtStg = NULL; + cv_mem->stgMallocDone = SUNFALSE; + + cv_mem->NLSstg1 = NULL; + cv_mem->ownNLSstg1 = SUNFALSE; + + cv_mem->sens_solve = SUNFALSE; + cv_mem->sens_solve_idx = -1; + + /* Return pointer to CVODES memory block */ + + return((void *)cv_mem); +} + +/*-----------------------------------------------------------------*/ + +/* + * 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 + * errfp and an error flag is returned. Otherwise, it returns CV_SUCCESS + */ + +int CVodeInit(void *cvode_mem, CVRhsFn f, realtype t0, N_Vector y0) +{ + CVodeMem cv_mem; + booleantype nvectorOK, allocOK; + sunindextype lrw1, liw1; + int i,k, retval; + SUNNonlinearSolver NLS; + + /* Check cvode_mem */ + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeInit", + MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Check for legal input parameters */ + + if (y0==NULL) { + 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); + return(CV_ILL_INPUT); + } + + /* Test if all required vector operations are implemented */ + + nvectorOK = cvCheckNvector(y0); + if(!nvectorOK) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeInit", + MSGCV_BAD_NVECTOR); + return(CV_ILL_INPUT); + } + + /* Set space requirements for one N_Vector */ + + if (y0->ops->nvspace != NULL) { + N_VSpace(y0, &lrw1, &liw1); + } else { + lrw1 = 0; + liw1 = 0; + } + cv_mem->cv_lrw1 = lrw1; + cv_mem->cv_liw1 = liw1; + + /* Allocate the vectors (using y0 as a template) */ + + allocOK = cvAllocVectors(cv_mem, y0); + if (!allocOK) { + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeInit", + MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + /* Allocate temporary work arrays for fused vector ops */ + cv_mem->cv_cvals = NULL; + cv_mem->cv_cvals = (realtype *) malloc(L_MAX*sizeof(realtype)); + + cv_mem->cv_Xvecs = NULL; + cv_mem->cv_Xvecs = (N_Vector *) malloc(L_MAX*sizeof(N_Vector)); + + cv_mem->cv_Zvecs = NULL; + cv_mem->cv_Zvecs = (N_Vector *) malloc(L_MAX*sizeof(N_Vector)); + + if ((cv_mem->cv_cvals == NULL) || + (cv_mem->cv_Xvecs == NULL) || + (cv_mem->cv_Zvecs == NULL)) { + cvFreeVectors(cv_mem); + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeInit", + MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + /* create a Newton nonlinear solver object by default */ + NLS = SUNNonlinSol_Newton(y0); + + /* check that nonlinear solver is non-NULL */ + if (NLS == NULL) { + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeInit", MSGCV_MEM_FAIL); + cvFreeVectors(cv_mem); + return(CV_MEM_FAIL); + } + + /* attach the nonlinear solver to the CVODE memory */ + retval = CVodeSetNonlinearSolver(cv_mem, NLS); + + /* check that the nonlinear solver was successfully attached */ + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, retval, "CVODES", "CVodeInit", + "Setting the nonlinear solver failed"); + cvFreeVectors(cv_mem); + SUNNonlinSolFree(NLS); + return(CV_MEM_FAIL); + } + + /* set ownership flag */ + cv_mem->ownNLS = SUNTRUE; + + /* All error checking is complete at this point */ + + /* Copy the input parameters into CVODES state */ + + cv_mem->cv_f = f; + cv_mem->cv_tn = t0; + + /* Set step parameters */ + + cv_mem->cv_q = 1; + cv_mem->cv_L = 2; + 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; + + /* Set the linear solver addresses to NULL. + (We check != NULL later, in CVode) */ + + cv_mem->cv_linit = NULL; + cv_mem->cv_lsetup = NULL; + cv_mem->cv_lsolve = NULL; + cv_mem->cv_lfree = NULL; + cv_mem->cv_lmem = NULL; + + /* Set forceSetup to SUNFALSE */ + + cv_mem->cv_forceSetup = SUNFALSE; + + /* 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; + cv_mem->cv_nfe = 0; + cv_mem->cv_ncfn = 0; + cv_mem->cv_netf = 0; + cv_mem->cv_nni = 0; + cv_mem->cv_nsetups = 0; + cv_mem->cv_nhnil = 0; + cv_mem->cv_nstlp = 0; + cv_mem->cv_nscon = 0; + cv_mem->cv_nge = 0; + + cv_mem->cv_irfnd = 0; + + /* Initialize other integrator optional outputs */ + + cv_mem->cv_h0u = ZERO; + cv_mem->cv_next_h = ZERO; + cv_mem->cv_next_q = 0; + + /* Initialize Stablilty Limit Detection data */ + /* NOTE: We do this even if stab lim det was not + turned on yet. This way, the user can turn it + on at any time */ + + cv_mem->cv_nor = 0; + for (i = 1; i <= 5; i++) + for (k = 1; k <= 3; k++) + cv_mem->cv_ssdat[i-1][k-1] = ZERO; + + /* Problem has been successfully initialized */ + + cv_mem->cv_MallocDone = SUNTRUE; + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +/* + * CVodeReInit + * + * CVodeReInit re-initializes CVODES's memory for a problem, assuming + * it has already been allocated in a prior CVodeInit call. + * 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. + */ + +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); + 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", "CVodeReInit", + MSGCV_NO_MALLOC); + return(CV_NO_MALLOC); + } + + /* Check for legal input parameters */ + + if (y0 == NULL) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeReInit", + MSGCV_NULL_Y0); + return(CV_ILL_INPUT); + } + + /* Copy the input parameters into CVODES state */ + + cv_mem->cv_tn = t0; + + /* Set step parameters */ + + cv_mem->cv_q = 1; + cv_mem->cv_L = 2; + 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; + + /* Set forceSetup to SUNFALSE */ + + cv_mem->cv_forceSetup = SUNFALSE; + + /* 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; + cv_mem->cv_nfe = 0; + cv_mem->cv_ncfn = 0; + cv_mem->cv_netf = 0; + cv_mem->cv_nni = 0; + cv_mem->cv_nsetups = 0; + cv_mem->cv_nhnil = 0; + cv_mem->cv_nstlp = 0; + cv_mem->cv_nscon = 0; + cv_mem->cv_nge = 0; + + cv_mem->cv_irfnd = 0; + + /* Initialize other integrator optional outputs */ + + cv_mem->cv_h0u = ZERO; + cv_mem->cv_next_h = ZERO; + cv_mem->cv_next_q = 0; + + /* Initialize Stablilty Limit Detection data */ + + cv_mem->cv_nor = 0; + for (i = 1; i <= 5; i++) + for (k = 1; k <= 3; k++) + cv_mem->cv_ssdat[i-1][k-1] = ZERO; + + /* Problem has been successfully re-initialized */ + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +/* + * CVodeSStolerances + * CVodeSVtolerances + * CVodeWFtolerances + * + * These functions specify the integration tolerances. One of them + * MUST be called before the first call to CVode. + * + * CVodeSStolerances specifies scalar relative and absolute tolerances. + * CVodeSVtolerances specifies scalar relative tolerance and a vector + * 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. + */ + +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); + 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); + return(CV_NO_MALLOC); + } + + /* Check inputs */ + + if (reltol < ZERO) { + 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); + return(CV_ILL_INPUT); + } + + /* Copy tolerances into memory */ + + cv_mem->cv_reltol = reltol; + cv_mem->cv_Sabstol = abstol; + + cv_mem->cv_itol = CV_SS; + + cv_mem->cv_user_efun = SUNFALSE; + cv_mem->cv_efun = cvEwtSet; + cv_mem->cv_e_data = NULL; /* will be set to cvode_mem in InitialSetup */ + + return(CV_SUCCESS); +} + + +int CVodeSVtolerances(void *cvode_mem, realtype reltol, N_Vector abstol) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + 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); + return(CV_NO_MALLOC); + } + + /* Check inputs */ + + if (reltol < ZERO) { + 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); + 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; + cv_mem->cv_liw += cv_mem->cv_liw1; + cv_mem->cv_VabstolMallocDone = SUNTRUE; + } + + cv_mem->cv_reltol = reltol; + N_VScale(ONE, abstol, cv_mem->cv_Vabstol); + + cv_mem->cv_itol = CV_SV; + + cv_mem->cv_user_efun = SUNFALSE; + cv_mem->cv_efun = cvEwtSet; + cv_mem->cv_e_data = NULL; /* will be set to cvode_mem in InitialSetup */ + + return(CV_SUCCESS); +} + + +int CVodeWFtolerances(void *cvode_mem, CVEwtFn efun) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + 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); + return(CV_NO_MALLOC); + } + + cv_mem->cv_itol = CV_WF; + + cv_mem->cv_user_efun = SUNTRUE; + cv_mem->cv_efun = efun; + cv_mem->cv_e_data = NULL; /* will be set to user_data in InitialSetup */ + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +/* + * 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. + * The return value is CV_SUCCESS = 0 if no errors occurred, or + * a negative value otherwise. + */ + +int CVodeQuadInit(void *cvode_mem, CVQuadRhsFn fQ, N_Vector yQ0) +{ + CVodeMem cv_mem; + booleantype allocOK; + sunindextype lrw1Q, liw1Q; + + /* Check cvode_mem */ + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeQuadInit", + MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Set space requirements for one N_Vector */ + N_VSpace(yQ0, &lrw1Q, &liw1Q); + cv_mem->cv_lrw1Q = lrw1Q; + cv_mem->cv_liw1Q = liw1Q; + + /* Allocate the vectors (using yQ0 as a template) */ + allocOK = cvQuadAllocVectors(cv_mem, yQ0); + if (!allocOK) { + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", + "CVodeQuadInit", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + /* Initialize znQ[0] in the history array */ + N_VScale(ONE, yQ0, cv_mem->cv_znQ[0]); + + /* Copy the input parameters into CVODES state */ + cv_mem->cv_fQ = fQ; + + /* Initialize counters */ + cv_mem->cv_nfQe = 0; + cv_mem->cv_netfQ = 0; + + /* Quadrature integration turned ON */ + cv_mem->cv_quadr = SUNTRUE; + cv_mem->cv_QuadMallocDone = SUNTRUE; + + /* Quadrature initialization was successfull */ + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +/* + * 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. + * 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. + */ + +int CVodeQuadReInit(void *cvode_mem, N_Vector yQ0) +{ + CVodeMem cv_mem; + + /* Check cvode_mem */ + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "CVodeQuadReInit", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Ckeck if quadrature was initialized? */ + if (cv_mem->cv_QuadMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_QUAD, "CVODES", + "CVodeQuadReInit", MSGCV_NO_QUAD); + return(CV_NO_QUAD); + } + + /* Initialize znQ[0] in the history array */ + N_VScale(ONE, yQ0, cv_mem->cv_znQ[0]); + + /* Initialize counters */ + cv_mem->cv_nfQe = 0; + cv_mem->cv_netfQ = 0; + + /* Quadrature integration turned ON */ + cv_mem->cv_quadr = SUNTRUE; + + /* Quadrature re-initialization was successfull */ + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +/* + * CVodeQuadSStolerances + * CVodeQuadSVtolerances + * + * These functions specify the integration tolerances for sensitivity + * variables. One of them MUST be called before the first call to + * CVode IF error control on the quadrature variables is enabled + * (see CVodeSetQuadErrCon). + * + * CVodeQuadSStolerances specifies scalar relative and absolute tolerances. + * CVodeQuadSVtolerances specifies scalar relative tolerance and a vector + * absolute toleranc (a potentially different absolute tolerance for each + * vector component). + */ + +int CVodeQuadSStolerances(void *cvode_mem, realtype reltolQ, realtype abstolQ) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "CVodeQuadSStolerances", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Ckeck if quadrature was initialized? */ + + if (cv_mem->cv_QuadMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_QUAD, "CVODES", + "CVodeQuadSStolerances", MSGCV_NO_QUAD); + return(CV_NO_QUAD); + } + + /* Test user-supplied tolerances */ + + if (reltolQ < ZERO) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeQuadSStolerances", MSGCV_BAD_RELTOLQ); + return(CV_ILL_INPUT); + } + + if (abstolQ < 0) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeQuadSStolerances", MSGCV_BAD_ABSTOLQ); + return(CV_ILL_INPUT); + } + + /* Copy tolerances into memory */ + + cv_mem->cv_itolQ = CV_SS; + + cv_mem->cv_reltolQ = reltolQ; + cv_mem->cv_SabstolQ = abstolQ; + + return(CV_SUCCESS); +} + +int CVodeQuadSVtolerances(void *cvode_mem, realtype reltolQ, N_Vector abstolQ) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "CVodeQuadSVtolerances", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Ckeck if quadrature was initialized? */ + + if (cv_mem->cv_QuadMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_QUAD, "CVODES", + "CVodeQuadSVtolerances", MSGCV_NO_QUAD); + return(CV_NO_QUAD); + } + + /* Test user-supplied tolerances */ + + if (reltolQ < ZERO) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeQuadSVtolerances", MSGCV_BAD_RELTOLQ); + return(CV_ILL_INPUT); + } + + if (abstolQ == NULL) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeQuadSVtolerances", MSGCV_NULL_ABSTOLQ); + return(CV_ILL_INPUT); + } + + if (N_VMin(abstolQ) < ZERO) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeQuadSVtolerances", MSGCV_BAD_ABSTOLQ); + return(CV_ILL_INPUT); + } + + /* Copy tolerances into memory */ + + cv_mem->cv_itolQ = CV_SV; + + cv_mem->cv_reltolQ = reltolQ; + + if ( !(cv_mem->cv_VabstolQMallocDone) ) { + cv_mem->cv_VabstolQ = N_VClone(cv_mem->cv_tempvQ); + cv_mem->cv_lrw += cv_mem->cv_lrw1Q; + cv_mem->cv_liw += cv_mem->cv_liw1Q; + cv_mem->cv_VabstolQMallocDone = SUNTRUE; + } + + N_VScale(ONE, abstolQ, cv_mem->cv_VabstolQ); + + return(CV_SUCCESS); +} + + +/*-----------------------------------------------------------------*/ + +/* + * CVodeSensInit + * + * 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 + * errors. + * The return value is CV_SUCCESS = 0 if no errors occurred, or + * a negative value otherwise. + */ + +int CVodeSensInit(void *cvode_mem, int Ns, int ism, CVSensRhsFn fS, N_Vector *yS0) +{ + CVodeMem cv_mem; + booleantype allocOK; + int is, retval; + SUNNonlinearSolver NLS; + + /* Check cvode_mem */ + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSensInit", + MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Check if CVodeSensInit or CVodeSensInit1 was already called */ + + if (cv_mem->cv_SensMallocDone) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSensInit", + MSGCV_SENSINIT_2); + return(CV_ILL_INPUT); + } + + /* Check if Ns is legal */ + + if (Ns<=0) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSensInit", + MSGCV_BAD_NS); + return(CV_ILL_INPUT); + } + cv_mem->cv_Ns = Ns; + + /* Check if ism is compatible */ + + if (ism==CV_STAGGERED1) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSensInit", + MSGCV_BAD_ISM_IFS); + return(CV_ILL_INPUT); + } + + /* Check if ism is legal */ + + if ((ism!=CV_SIMULTANEOUS) && (ism!=CV_STAGGERED)) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSensInit", + MSGCV_BAD_ISM); + return(CV_ILL_INPUT); + } + cv_mem->cv_ism = ism; + + /* Check if yS0 is non-null */ + + if (yS0 == NULL) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSensInit", + MSGCV_NULL_YS0); + return(CV_ILL_INPUT); + } + + /* Store sensitivity RHS-related data */ + + cv_mem->cv_ifS = CV_ALLSENS; + cv_mem->cv_fS1 = NULL; + + if (fS == NULL) { + + cv_mem->cv_fSDQ = SUNTRUE; + cv_mem->cv_fS = cvSensRhsInternalDQ; + cv_mem->cv_fS_data = cvode_mem; + + } else { + + cv_mem->cv_fSDQ = SUNFALSE; + cv_mem->cv_fS = fS; + cv_mem->cv_fS_data = cv_mem->cv_user_data; + + } + + /* No memory allocation for STAGGERED1 */ + + cv_mem->cv_stgr1alloc = SUNFALSE; + + /* Allocate the vectors (using yS0[0] as a template) */ + + allocOK = cvSensAllocVectors(cv_mem, yS0[0]); + if (!allocOK) { + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeSensInit", + 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; + free(cv_mem->cv_Xvecs); cv_mem->cv_Xvecs = NULL; + free(cv_mem->cv_Zvecs); cv_mem->cv_Zvecs = NULL; + + cv_mem->cv_cvals = (realtype *) malloc((Ns*L_MAX)*sizeof(realtype)); + cv_mem->cv_Xvecs = (N_Vector *) malloc((Ns*L_MAX)*sizeof(N_Vector)); + cv_mem->cv_Zvecs = (N_Vector *) malloc((Ns*L_MAX)*sizeof(N_Vector)); + + if ((cv_mem->cv_cvals == NULL) || + (cv_mem->cv_Xvecs == NULL) || + (cv_mem->cv_Zvecs == NULL)) { + cvSensFreeVectors(cv_mem); + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeSensInit", + MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + } + + /*---------------------------------------------- + All error checking is complete at this point + -----------------------------------------------*/ + + /* Initialize znS[0] in the history array */ + + for (is=0; is<Ns; is++) + cv_mem->cv_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); + + /* Initialize all sensitivity related counters */ + + cv_mem->cv_nfSe = 0; + cv_mem->cv_nfeS = 0; + cv_mem->cv_ncfnS = 0; + cv_mem->cv_netfS = 0; + cv_mem->cv_nniS = 0; + cv_mem->cv_nsetupsS = 0; + + /* Set default values for plist and pbar */ + + for (is=0; is<Ns; is++) { + cv_mem->cv_plist[is] = is; + cv_mem->cv_pbar[is] = ONE; + } + + /* Sensitivities will be computed */ + + cv_mem->cv_sensi = SUNTRUE; + cv_mem->cv_SensMallocDone = SUNTRUE; + + /* create a Newton nonlinear solver object by default */ + if (ism == CV_SIMULTANEOUS) + NLS = SUNNonlinSol_NewtonSens(Ns+1, cv_mem->cv_acor); + else + NLS = SUNNonlinSol_NewtonSens(Ns, cv_mem->cv_acor); + + /* check that the nonlinear solver is non-NULL */ + if (NLS == NULL) { + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", + "CVodeSensInit", MSGCV_MEM_FAIL); + cvSensFreeVectors(cv_mem); + return(CV_MEM_FAIL); + } + + /* attach the nonlinear solver to the CVODE memory */ + if (ism == CV_SIMULTANEOUS) + retval = CVodeSetNonlinearSolverSensSim(cv_mem, NLS); + else + retval = CVodeSetNonlinearSolverSensStg(cv_mem, NLS); + + /* check that the nonlinear solver was successfully attached */ + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, retval, "CVODES", "CVodeSensInit", + "Setting the nonlinear solver failed"); + cvSensFreeVectors(cv_mem); + SUNNonlinSolFree(NLS); + return(CV_MEM_FAIL); + } + + /* set ownership flag */ + if (ism == CV_SIMULTANEOUS) + cv_mem->ownNLSsim = SUNTRUE; + else + cv_mem->ownNLSstg = SUNTRUE; + + /* Sensitivity initialization was successfull */ + return(CV_SUCCESS); +} + +/* + * CVodeSensInit1 + * + * 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 + * errors. + * The return value is CV_SUCCESS = 0 if no errors occurred, or + * a negative value otherwise. + */ + +int CVodeSensInit1(void *cvode_mem, int Ns, int ism, CVSensRhs1Fn fS1, N_Vector *yS0) +{ + CVodeMem cv_mem; + booleantype allocOK; + int is, retval; + SUNNonlinearSolver NLS; + + /* Check cvode_mem */ + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSensInit1", + MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Check if CVodeSensInit or CVodeSensInit1 was already called */ + + if (cv_mem->cv_SensMallocDone) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSensInit1", + MSGCV_SENSINIT_2); + return(CV_ILL_INPUT); + } + + /* Check if Ns is legal */ + + if (Ns<=0) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSensInit1", + MSGCV_BAD_NS); + return(CV_ILL_INPUT); + } + cv_mem->cv_Ns = Ns; + + /* Check if ism is legal */ + + if ((ism!=CV_SIMULTANEOUS) && (ism!=CV_STAGGERED) && (ism!=CV_STAGGERED1)) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSensInit1", + MSGCV_BAD_ISM); + return(CV_ILL_INPUT); + } + cv_mem->cv_ism = ism; + + /* Check if yS0 is non-null */ + + if (yS0 == NULL) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSensInit1", + MSGCV_NULL_YS0); + return(CV_ILL_INPUT); + } + + /* Store sensitivity RHS-related data */ + + cv_mem->cv_ifS = CV_ONESENS; + cv_mem->cv_fS = NULL; + + if (fS1 == NULL) { + + cv_mem->cv_fSDQ = SUNTRUE; + cv_mem->cv_fS1 = cvSensRhs1InternalDQ; + cv_mem->cv_fS_data = cvode_mem; + + } else { + + cv_mem->cv_fSDQ = SUNFALSE; + cv_mem->cv_fS1 = fS1; + cv_mem->cv_fS_data = cv_mem->cv_user_data; + + } + + /* Allocate ncfS1, ncfnS1, and nniS1 if needed */ + + if (ism == CV_STAGGERED1) { + cv_mem->cv_stgr1alloc = SUNTRUE; + cv_mem->cv_ncfS1 = NULL; + cv_mem->cv_ncfS1 = (int*)malloc(Ns*sizeof(int)); + cv_mem->cv_ncfnS1 = NULL; + cv_mem->cv_ncfnS1 = (long int*)malloc(Ns*sizeof(long int)); + cv_mem->cv_nniS1 = NULL; + cv_mem->cv_nniS1 = (long int*)malloc(Ns*sizeof(long int)); + if ( (cv_mem->cv_ncfS1 == NULL) || + (cv_mem->cv_ncfnS1 == NULL) || + (cv_mem->cv_nniS1 == NULL) ) { + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeSensInit1", + MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + } else { + cv_mem->cv_stgr1alloc = SUNFALSE; + } + + /* Allocate the vectors (using yS0[0] as a template) */ + + allocOK = cvSensAllocVectors(cv_mem, yS0[0]); + if (!allocOK) { + if (cv_mem->cv_stgr1alloc) { + 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; + } + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeSensInit1", + 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; + free(cv_mem->cv_Xvecs); cv_mem->cv_Xvecs = NULL; + free(cv_mem->cv_Zvecs); cv_mem->cv_Zvecs = NULL; + + cv_mem->cv_cvals = (realtype *) malloc((Ns*L_MAX)*sizeof(realtype)); + cv_mem->cv_Xvecs = (N_Vector *) malloc((Ns*L_MAX)*sizeof(N_Vector)); + cv_mem->cv_Zvecs = (N_Vector *) malloc((Ns*L_MAX)*sizeof(N_Vector)); + + if ((cv_mem->cv_cvals == NULL) || + (cv_mem->cv_Xvecs == NULL) || + (cv_mem->cv_Zvecs == NULL)) { + if (cv_mem->cv_stgr1alloc) { + 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; + } + cvSensFreeVectors(cv_mem); + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeSensInit1", + MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + } + + /*---------------------------------------------- + All error checking is complete at this point + -----------------------------------------------*/ + + /* Initialize znS[0] in the history array */ + + for (is=0; is<Ns; is++) + cv_mem->cv_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); + + /* Initialize all sensitivity related counters */ + + cv_mem->cv_nfSe = 0; + cv_mem->cv_nfeS = 0; + cv_mem->cv_ncfnS = 0; + cv_mem->cv_netfS = 0; + cv_mem->cv_nniS = 0; + cv_mem->cv_nsetupsS = 0; + if (ism==CV_STAGGERED1) + for (is=0; is<Ns; is++) { + cv_mem->cv_ncfnS1[is] = 0; + cv_mem->cv_nniS1[is] = 0; + } + + /* Set default values for plist and pbar */ + + for (is=0; is<Ns; is++) { + cv_mem->cv_plist[is] = is; + cv_mem->cv_pbar[is] = ONE; + } + + /* Sensitivities will be computed */ + + cv_mem->cv_sensi = SUNTRUE; + cv_mem->cv_SensMallocDone = SUNTRUE; + + /* create a Newton nonlinear solver object by default */ + if (ism == CV_SIMULTANEOUS) + NLS = SUNNonlinSol_NewtonSens(Ns+1, cv_mem->cv_acor); + else if (ism == CV_STAGGERED) + NLS = SUNNonlinSol_NewtonSens(Ns, cv_mem->cv_acor); + else + NLS = SUNNonlinSol_Newton(cv_mem->cv_acor); + + /* check that the nonlinear solver is non-NULL */ + if (NLS == NULL) { + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", + "CVodeSensInit1", MSGCV_MEM_FAIL); + cvSensFreeVectors(cv_mem); + return(CV_MEM_FAIL); + } + + /* attach the nonlinear solver to the CVODE memory */ + if (ism == CV_SIMULTANEOUS) + retval = CVodeSetNonlinearSolverSensSim(cv_mem, NLS); + else if (ism == CV_STAGGERED) + retval = CVodeSetNonlinearSolverSensStg(cv_mem, NLS); + else + retval = CVodeSetNonlinearSolverSensStg1(cv_mem, NLS); + + /* check that the nonlinear solver was successfully attached */ + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, retval, "CVODES", "CVodeSensInit1", + "Setting the nonlinear solver failed"); + cvSensFreeVectors(cv_mem); + SUNNonlinSolFree(NLS); + return(CV_MEM_FAIL); + } + + /* set ownership flag */ + if (ism == CV_SIMULTANEOUS) + cv_mem->ownNLSsim = SUNTRUE; + else if (ism == CV_STAGGERED) + cv_mem->ownNLSstg = SUNTRUE; + else + cv_mem->ownNLSstg1 = SUNTRUE; + + /* Sensitivity initialization was successfull */ + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +/* + * 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. + * All problem specification inputs are checked for errors. + * The number of sensitivities Ns is assumed to be unchanged since + * the previous call to CVodeSensInit. + * 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. + */ + +int CVodeSensReInit(void *cvode_mem, int ism, N_Vector *yS0) +{ + CVodeMem cv_mem; + int is, retval; + SUNNonlinearSolver NLS; + + /* Check cvode_mem */ + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSensReInit", + MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was sensitivity initialized? */ + + if (cv_mem->cv_SensMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeSensReInit", + MSGCV_NO_SENSI); + return(CV_NO_SENS); + } + + /* Check if ism is compatible */ + + if ((cv_mem->cv_ifS==CV_ALLSENS) && (ism==CV_STAGGERED1)) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSensReInit", MSGCV_BAD_ISM_IFS); + return(CV_ILL_INPUT); + } + + /* Check if ism is legal */ + + if ((ism!=CV_SIMULTANEOUS) && (ism!=CV_STAGGERED) && (ism!=CV_STAGGERED1)) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSensReInit", MSGCV_BAD_ISM); + return(CV_ILL_INPUT); + } + cv_mem->cv_ism = ism; + + /* Check if yS0 is non-null */ + + if (yS0 == NULL) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSensReInit", MSGCV_NULL_YS0); + return(CV_ILL_INPUT); + } + + /* Allocate ncfS1, ncfnS1, and nniS1 if needed */ + + if ( (ism==CV_STAGGERED1) && (cv_mem->cv_stgr1alloc==SUNFALSE) ) { + cv_mem->cv_stgr1alloc = SUNTRUE; + cv_mem->cv_ncfS1 = NULL; + cv_mem->cv_ncfS1 = (int*)malloc(cv_mem->cv_Ns*sizeof(int)); + cv_mem->cv_ncfnS1 = NULL; + cv_mem->cv_ncfnS1 = (long int*)malloc(cv_mem->cv_Ns*sizeof(long int)); + cv_mem->cv_nniS1 = NULL; + cv_mem->cv_nniS1 = (long int*)malloc(cv_mem->cv_Ns*sizeof(long int)); + if ( (cv_mem->cv_ncfS1==NULL) || + (cv_mem->cv_ncfnS1==NULL) || + (cv_mem->cv_nniS1==NULL) ) { + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", + "CVodeSensReInit", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + } + + /*---------------------------------------------- + All error checking is complete at this point + -----------------------------------------------*/ + + /* Initialize znS[0] in the history array */ + + for (is=0; is<cv_mem->cv_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); + + /* Initialize all sensitivity related counters */ + + cv_mem->cv_nfSe = 0; + cv_mem->cv_nfeS = 0; + cv_mem->cv_ncfnS = 0; + cv_mem->cv_netfS = 0; + cv_mem->cv_nniS = 0; + cv_mem->cv_nsetupsS = 0; + if (ism==CV_STAGGERED1) + for (is=0; is<cv_mem->cv_Ns; is++) { + cv_mem->cv_ncfnS1[is] = 0; + cv_mem->cv_nniS1[is] = 0; + } + + /* Problem has been successfully re-initialized */ + + cv_mem->cv_sensi = SUNTRUE; + + /* Check if the NLS exists, create the default NLS if needed */ + if ( (ism == CV_SIMULTANEOUS && cv_mem->NLSsim == NULL) || + (ism == CV_STAGGERED && cv_mem->NLSstg == NULL) || + (ism == CV_STAGGERED1 && cv_mem->NLSstg1 == NULL) ) { + + /* create a Newton nonlinear solver object by default */ + if (ism == CV_SIMULTANEOUS) + NLS = SUNNonlinSol_NewtonSens(cv_mem->cv_Ns+1, cv_mem->cv_acor); + else if (ism == CV_STAGGERED) + NLS = SUNNonlinSol_NewtonSens(cv_mem->cv_Ns, cv_mem->cv_acor); + else + NLS = SUNNonlinSol_Newton(cv_mem->cv_acor); + + /* check that the nonlinear solver is non-NULL */ + if (NLS == NULL) { + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", + "CVodeSensReInit", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + /* attach the nonlinear solver to the CVODES memory */ + if (ism == CV_SIMULTANEOUS) + retval = CVodeSetNonlinearSolverSensSim(cv_mem, NLS); + else if (ism == CV_STAGGERED) + retval = CVodeSetNonlinearSolverSensStg(cv_mem, NLS); + else + retval = CVodeSetNonlinearSolverSensStg1(cv_mem, NLS); + + /* check that the nonlinear solver was successfully attached */ + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, retval, "CVODES", "CVodeSensReInit", + "Setting the nonlinear solver failed"); + SUNNonlinSolFree(NLS); + return(CV_MEM_FAIL); + } + + /* set ownership flag */ + if (ism == CV_SIMULTANEOUS) + cv_mem->ownNLSsim = SUNTRUE; + else if (ism == CV_STAGGERED) + cv_mem->ownNLSstg = SUNTRUE; + else + cv_mem->ownNLSstg1 = SUNTRUE; + + /* initialize the NLS object, this assumes that the linear solver has + already been initialized in CVodeInit */ + if (ism == CV_SIMULTANEOUS) + retval = cvNlsInitSensSim(cv_mem); + else if (ism == CV_STAGGERED) + retval = cvNlsInitSensStg(cv_mem); + else + retval = cvNlsInitSensStg1(cv_mem); + + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, CV_NLS_INIT_FAIL, "CVODES", + "CVodeSensReInit", MSGCV_NLS_INIT_FAIL); + return(CV_NLS_INIT_FAIL); + } + } + + /* Sensitivity re-initialization was successfull */ + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +/* + * CVodeSensSStolerances + * CVodeSensSVtolerances + * CVodeSensEEtolerances + * + * These functions specify the integration tolerances for sensitivity + * variables. One of them MUST be called before the first call to CVode. + * + * CVodeSensSStolerances specifies scalar relative and absolute tolerances. + * CVodeSensSVtolerances specifies scalar relative tolerance and a vector + * absolute tolerance for each sensitivity vector (a potentially different + * absolute tolerance for each vector component). + * CVodeEEtolerances specifies that tolerances for sensitivity variables + * should be estimated from those provided for the state variables. + */ + +int CVodeSensSStolerances(void *cvode_mem, realtype reltolS, realtype *abstolS) +{ + CVodeMem cv_mem; + int is; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSensSStolerances", + MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was sensitivity initialized? */ + + if (cv_mem->cv_SensMallocDone == SUNFALSE) { + 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); + return(CV_ILL_INPUT); + } + + if (abstolS == NULL) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSensSStolerances", + MSGCV_NULL_ABSTOLS); + return(CV_ILL_INPUT); + } + + for (is=0; is<cv_mem->cv_Ns; is++) + if (abstolS[is] < ZERO) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSensSStolerances", + MSGCV_BAD_ABSTOLS); + return(CV_ILL_INPUT); + } + + /* Copy tolerances into memory */ + + cv_mem->cv_itolS = CV_SS; + + cv_mem->cv_reltolS = reltolS; + + 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_lrw += cv_mem->cv_Ns; + cv_mem->cv_SabstolSMallocDone = SUNTRUE; + } + + for (is=0; is<cv_mem->cv_Ns; is++) + cv_mem->cv_SabstolS[is] = abstolS[is]; + + return(CV_SUCCESS); +} + +int CVodeSensSVtolerances(void *cvode_mem, realtype reltolS, N_Vector *abstolS) +{ + CVodeMem cv_mem; + int is, retval; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSensSVtolerances", + MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was sensitivity initialized? */ + + if (cv_mem->cv_SensMallocDone == SUNFALSE) { + 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); + return(CV_ILL_INPUT); + } + + if (abstolS == NULL) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSensSVtolerances", MSGCV_NULL_ABSTOLS); + return(CV_ILL_INPUT); + } + + for (is=0; is<cv_mem->cv_Ns; is++) + if (N_VMin(abstolS[is]) < ZERO) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSensSVtolerances", MSGCV_BAD_ABSTOLS); + return(CV_ILL_INPUT); + } + + /* Copy tolerances into memory */ + + cv_mem->cv_itolS = CV_SV; + + cv_mem->cv_reltolS = reltolS; + + if ( !(cv_mem->cv_VabstolSMallocDone) ) { + cv_mem->cv_VabstolS = N_VCloneVectorArray(cv_mem->cv_Ns, cv_mem->cv_tempv); + 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; is<cv_mem->cv_Ns; is++) + cv_mem->cv_cvals[is] = ONE; + + retval = N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, + abstolS, cv_mem->cv_VabstolS); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + + return(CV_SUCCESS); +} + + +int CVodeSensEEtolerances(void *cvode_mem) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSensEEtolerances", + MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was sensitivity initialized? */ + + if (cv_mem->cv_SensMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeSensEEtolerances", + MSGCV_NO_SENSI); + return(CV_NO_SENS); + } + + cv_mem->cv_itolS = CV_EE; + + return(CV_SUCCESS); +} + + +/*-----------------------------------------------------------------*/ + +/* + * CVodeQuadSensInit + * + */ + +int CVodeQuadSensInit(void *cvode_mem, CVQuadSensRhsFn fQS, N_Vector *yQS0) +{ + CVodeMem cv_mem; + booleantype allocOK; + int is, retval; + + /* Check cvode_mem */ + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeQuadSensInit", + MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Check if sensitivity analysis is active */ + if (!cv_mem->cv_sensi) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeQuadSensInit", + MSGCV_NO_SENSI); + return(CV_ILL_INPUT); + } + + /* Check if yQS0 is non-null */ + if (yQS0 == NULL) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeQuadSensInit", + MSGCV_NULL_YQS0); + return(CV_ILL_INPUT); + } + + /* Allocate the vectors (using yQS0[0] as a template) */ + allocOK = cvQuadSensAllocVectors(cv_mem, yQS0[0]); + if (!allocOK) { + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeQuadSensInit", + MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + /*---------------------------------------------- + All error checking is complete at this point + -----------------------------------------------*/ + + /* Set fQS */ + if (fQS == NULL) { + + cv_mem->cv_fQSDQ = SUNTRUE; + cv_mem->cv_fQS = cvQuadSensRhsInternalDQ; + + cv_mem->cv_fQS_data = cvode_mem; + + } else { + + cv_mem->cv_fQSDQ = SUNFALSE; + cv_mem->cv_fQS = fQS; + + cv_mem->cv_fQS_data = cv_mem->cv_user_data; + + } + + /* Initialize znQS[0] in the history array */ + for (is=0; is<cv_mem->cv_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); + + /* Initialize all sensitivity related counters */ + 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; + + /* Sensitivity initialization was successfull */ + return(CV_SUCCESS); +} + +/* + * CVodeQuadSensReInit + * + */ + +int CVodeQuadSensReInit(void *cvode_mem, N_Vector *yQS0) +{ + CVodeMem cv_mem; + int is, retval; + + /* Check cvode_mem */ + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeQuadSensReInit", + MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Check if sensitivity analysis is active */ + if (!cv_mem->cv_sensi) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeQuadSensReInit", MSGCV_NO_SENSI); + return(CV_NO_SENS); + } + + /* Was quadrature sensitivity initialized? */ + if (cv_mem->cv_QuadSensMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_QUADSENS, "CVODES", + "CVodeQuadSensReInit", MSGCV_NO_QUADSENSI); + return(CV_NO_QUADSENS); + } + + /* Check if yQS0 is non-null */ + if (yQS0 == NULL) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeQuadSensReInit", MSGCV_NULL_YQS0); + return(CV_ILL_INPUT); + } + + /*---------------------------------------------- + All error checking is complete at this point + -----------------------------------------------*/ + + /* Initialize znQS[0] in the history array */ + for (is=0; is<cv_mem->cv_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); + + /* Initialize all sensitivity related counters */ + 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; + + /* Problem has been successfully re-initialized */ + return(CV_SUCCESS); +} + + +/* + * CVodeQuadSensSStolerances + * CVodeQuadSensSVtolerances + * CVodeQuadSensEEtolerances + * + * These functions specify the integration tolerances for quadrature + * sensitivity variables. One of them MUST be called before the first + * call to CVode IF these variables are included in the error test. + * + * CVodeQuadSensSStolerances specifies scalar relative and absolute tolerances. + * CVodeQuadSensSVtolerances specifies scalar relative tolerance and a vector + * absolute tolerance for each quadrature sensitivity vector (a potentially + * different absolute tolerance for each vector component). + * CVodeQuadSensEEtolerances specifies that tolerances for sensitivity variables + * should be estimated from those provided for the quadrature variables. + * In this case, tolerances for the quadrature variables must be + * specified through a call to one of CVodeQuad**tolerances. + */ + +int CVodeQuadSensSStolerances(void *cvode_mem, realtype reltolQS, realtype *abstolQS) +{ + CVodeMem cv_mem; + int is; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "CVodeQuadSensSStolerances", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Check if sensitivity was initialized */ + + if (cv_mem->cv_SensMallocDone == SUNFALSE) { + 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); + return(CV_NO_QUAD); + } + + /* Test user-supplied tolerances */ + + if (reltolQS < ZERO) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeQuadSensSStolerances", MSGCV_BAD_RELTOLQS); + return(CV_ILL_INPUT); + } + + if (abstolQS == NULL) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeQuadSensSStolerances", MSGCV_NULL_ABSTOLQS); + return(CV_ILL_INPUT); + } + + for (is=0; is<cv_mem->cv_Ns; is++) + if (abstolQS[is] < ZERO) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeQuadSensSStolerances", MSGCV_BAD_ABSTOLQS); + return(CV_ILL_INPUT); + } + + /* Copy tolerances into memory */ + + cv_mem->cv_itolQS = CV_SS; + + cv_mem->cv_reltolQS = reltolQS; + + 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_lrw += cv_mem->cv_Ns; + cv_mem->cv_SabstolQSMallocDone = SUNTRUE; + } + + for (is=0; is<cv_mem->cv_Ns; is++) + cv_mem->cv_SabstolQS[is] = abstolQS[is]; + + return(CV_SUCCESS); +} + +int CVodeQuadSensSVtolerances(void *cvode_mem, realtype reltolQS, N_Vector *abstolQS) +{ + CVodeMem cv_mem; + int is, retval; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "CVodeQuadSensSVtolerances", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* check if sensitivity was initialized */ + + if (cv_mem->cv_SensMallocDone == SUNFALSE) { + 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); + return(CV_NO_QUAD); + } + + /* Test user-supplied tolerances */ + + if (reltolQS < ZERO) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeQuadSensSVtolerances", MSGCV_BAD_RELTOLQS); + return(CV_ILL_INPUT); + } + + if (abstolQS == NULL) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSensSVtolerances", MSGCV_NULL_ABSTOLQS); + return(CV_ILL_INPUT); + } + + for (is=0; is<cv_mem->cv_Ns; is++) + if (N_VMin(abstolQS[is]) < ZERO) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeQuadSensSVtolerances", MSGCV_BAD_ABSTOLQS); + return(CV_ILL_INPUT); + } + + /* Copy tolerances into memory */ + + cv_mem->cv_itolQS = CV_SV; + + cv_mem->cv_reltolQS = reltolQS; + + if ( !(cv_mem->cv_VabstolQSMallocDone) ) { + cv_mem->cv_VabstolQS = N_VCloneVectorArray(cv_mem->cv_Ns, cv_mem->cv_tempvQ); + 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; is<cv_mem->cv_Ns; is++) + cv_mem->cv_cvals[is] = ONE; + + retval = N_VScaleVectorArray(cv_mem->cv_Ns, cv_mem->cv_cvals, + abstolQS, cv_mem->cv_VabstolQS); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + + return(CV_SUCCESS); +} + + +int CVodeQuadSensEEtolerances(void *cvode_mem) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "CVodeQuadSensEEtolerances", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* check if sensitivity was initialized */ + + if (cv_mem->cv_SensMallocDone == SUNFALSE) { + 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); + return(CV_NO_QUAD); + } + + cv_mem->cv_itolQS = CV_EE; + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +/* + * CVodeSensToggleOff + * + * CVodeSensToggleOff deactivates sensitivity calculations. + * It does NOT deallocate sensitivity-related memory. + */ + +int CVodeSensToggleOff(void *cvode_mem) +{ + CVodeMem cv_mem; + + /* Check cvode_mem */ + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSensToggleOff", + MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Disable sensitivities */ + cv_mem->cv_sensi = SUNFALSE; + cv_mem->cv_quadr_sensi = SUNFALSE; + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +/* + * CVodeRootInit + * + * CVodeRootInit initializes a rootfinding problem to be solved + * during the integration of the ODE system. It loads the root + * function pointer and the number of root functions, and allocates + * workspace memory. The return value is CV_SUCCESS = 0 if no errors + * occurred, or a negative value otherwise. + */ + +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); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + nrt = (nrtfn < 0) ? 0 : nrtfn; + + /* If rerunning CVodeRootInit() with a different number of root + functions (changing number of gfun components), then free + currently held memory resources */ + if ((nrt != cv_mem->cv_nrtfn) && (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_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; + + 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 + zero and cv_gfun to NULL before returning */ + if (nrt == 0) { + cv_mem->cv_nrtfn = nrt; + cv_mem->cv_gfun = NULL; + return(CV_SUCCESS); + } + + /* If rerunning CVodeRootInit() with the same number of root functions + (not changing number of gfun components), then check if the root + function argument has changed */ + /* If g != NULL then return as currently reserved memory resources + will suffice */ + 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_rootdir); cv_mem->cv_rootdir = NULL; + free(cv_mem->cv_gactive); cv_mem->cv_gactive = NULL; + + cv_mem->cv_lrw -= 3*nrt; + cv_mem->cv_liw -= 3*nrt; + + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeRootInit", + MSGCV_NULL_G); + return(CV_ILL_INPUT); + } + else { + cv_mem->cv_gfun = g; + return(CV_SUCCESS); + } + } + else return(CV_SUCCESS); + } + + /* Set variable values in CVode memory block */ + cv_mem->cv_nrtfn = nrt; + if (g == NULL) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeRootInit", + MSGCV_NULL_G); + return(CV_ILL_INPUT); + } + else cv_mem->cv_gfun = g; + + /* Allocate necessary memory and return */ + 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, "CVODES", "CVodeRootInit", + 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) { + free(cv_mem->cv_glo); cv_mem->cv_glo = NULL; + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeRootInit", + 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) { + 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, "CVODES", "CVodeRootInit", + MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + cv_mem->cv_iroots = NULL; + cv_mem->cv_iroots = (int *) malloc(nrt*sizeof(int)); + if (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; + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeRootInit", + MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + 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_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, "CVODES", "CVodeRootInit", + MSGCV_MEM_FAIL); + 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_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; + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeRootInit", + MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + + /* Set default values for rootdir (both directions) */ + for(i=0; i<nrt; i++) cv_mem->cv_rootdir[i] = 0; + + /* Set default values for gactive (all active) */ + for(i=0; i<nrt; i++) cv_mem->cv_gactive[i] = SUNTRUE; + + cv_mem->cv_lrw += 3*nrt; + cv_mem->cv_liw += 3*nrt; + + return(CV_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Main solver function + * ----------------------------------------------------------------- + */ + +/* + * CVode + * + * 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. + * + * The first time that CVode is called for a successfully initialized + * problem, it computes a tentative initial step size h. + * + * CVode supports two modes, specified by itask: CV_NORMAL, CV_ONE_STEP. + * In the CV_NORMAL mode, the solver steps until it reaches or passes tout + * and then interpolates to obtain y(tout). + * In the CV_ONE_STEP mode, it takes one internal step and returns. + */ + +int CVode(void *cvode_mem, realtype tout, N_Vector yout, + realtype *tret, int itask) +{ + CVodeMem cv_mem; + long int nstloc; + int retval, hflag, kflag, istate, is, ir, ier, irfndp; + realtype troundoff, tout_hin, rh, nrm; + booleantype inactive_roots; + + /* + * ------------------------------------- + * 1. Check and process inputs + * ------------------------------------- + */ + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + 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); + 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); + return(CV_ILL_INPUT); + } + + /* Check for tret != NULL */ + if (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); + return(CV_ILL_INPUT); + } + + if (itask == CV_NORMAL) cv_mem->cv_toutc = tout; + cv_mem->cv_taskc = itask; + + /* + * ---------------------------------------- + * 2. Initializations performed only at + * the first step (nst=0): + * - initial setup + * - initialize Nordsieck history array + * - compute initial step size + * - check for approach to tstop + * - check for approach to a root + * ---------------------------------------- + */ + + if (cv_mem->cv_nst == 0) { + + 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). + * 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_nfe++; + if (retval < 0) { + cvProcessError(cv_mem, CV_RHSFUNC_FAIL, "CVODES", "CVode", + MSGCV_RHSFUNC_FAILED, cv_mem->cv_tn); + return(CV_RHSFUNC_FAIL); + } + if (retval > 0) { + cvProcessError(cv_mem, CV_FIRST_RHSFUNC_ERR, "CVODES", "CVode", + MSGCV_RHSFUNC_FIRST); + return(CV_FIRST_RHSFUNC_ERR); + } + + if (cv_mem->cv_quadr) { + retval = cv_mem->cv_fQ(cv_mem->cv_tn, cv_mem->cv_zn[0], + cv_mem->cv_znQ[1], cv_mem->cv_user_data); + cv_mem->cv_nfQe++; + if (retval < 0) { + cvProcessError(cv_mem, CV_QRHSFUNC_FAIL, "CVODES", "CVode", + MSGCV_QRHSFUNC_FAILED, cv_mem->cv_tn); + return(CV_QRHSFUNC_FAIL); + } + if (retval > 0) { + cvProcessError(cv_mem, CV_FIRST_QRHSFUNC_ERR, "CVODES", + "CVode", MSGCV_QRHSFUNC_FIRST); + return(CV_FIRST_QRHSFUNC_ERR); + } + } + + if (cv_mem->cv_sensi) { + retval = cvSensRhsWrapper(cv_mem, cv_mem->cv_tn, cv_mem->cv_zn[0], + cv_mem->cv_zn[1], cv_mem->cv_znS[0], + cv_mem->cv_znS[1], cv_mem->cv_tempv, + cv_mem->cv_ftemp); + if (retval < 0) { + 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); + return(CV_FIRST_SRHSFUNC_ERR); + } + } + + if (cv_mem->cv_quadr_sensi) { + 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_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); + return(CV_FIRST_QSRHSFUNC_ERR); + } + } + + /* Test input tstop for legality. */ + + if (cv_mem->cv_tstopset) { + if ( (cv_mem->cv_tstop - cv_mem->cv_tn)*(tout - cv_mem->cv_tn) <= ZERO ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", + MSGCV_BAD_TSTOP, cv_mem->cv_tstop, cv_mem->cv_tn); + return(CV_ILL_INPUT); + } + } + + /* 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); + return(CV_ILL_INPUT); + } + 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 ) + tout_hin = cv_mem->cv_tstop; + hflag = cvHin(cv_mem, tout_hin); + if (hflag != CV_SUCCESS) { + istate = cvHandleFailure(cv_mem, hflag); + return(istate); + } + } + rh = SUNRabs(cv_mem->cv_h)*cv_mem->cv_hmax_inv; + if (rh > ONE) cv_mem->cv_h /= rh; + if (SUNRabs(cv_mem->cv_h) < cv_mem->cv_hmin) + cv_mem->cv_h *= cv_mem->cv_hmin/SUNRabs(cv_mem->cv_h); + + /* 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 ) + 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. + */ + + cv_mem->cv_hscale = cv_mem->cv_h; + cv_mem->cv_h0u = cv_mem->cv_h; + 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]); + + if (cv_mem->cv_sensi) { + for (is=0; is<cv_mem->cv_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_znS[1], cv_mem->cv_znS[1]); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + } + + if (cv_mem->cv_quadr_sensi) { + for (is=0; is<cv_mem->cv_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_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) { + + retval = cvRcheck1(cv_mem); + + if (retval == CV_RTFUNC_FAIL) { + cvProcessError(cv_mem, CV_RTFUNC_FAIL, "CVODES", "cvRcheck1", + MSGCV_RTFUNC_FAILED, cv_mem->cv_tn); + return(CV_RTFUNC_FAIL); + } + + } + + } /* end first call block */ + + /* + * ------------------------------------------------------ + * 3. At following steps, perform stop tests: + * - check for root in last step + * - check if we passed tstop + * - check if we passed tout (NORMAL mode) + * - check if current tn was returned (ONE_STEP mode) + * - check if we are close to tstop + * (adjust step size if needed) + * ------------------------------------------------------- + */ + + if (cv_mem->cv_nst > 0) { + + /* 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)); + + /* 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) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "cvRcheck2", + MSGCV_CLOSE_ROOTS, cv_mem->cv_tlo); + return(CV_ILL_INPUT); + } else if (retval == CV_RTFUNC_FAIL) { + cvProcessError(cv_mem, CV_RTFUNC_FAIL, "CVODES", "cvRcheck2", + MSGCV_RTFUNC_FAILED, cv_mem->cv_tlo); + return(CV_RTFUNC_FAIL); + } else if (retval == RTFOUND) { + 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 ) { + + retval = cvRcheck3(cv_mem); + + if (retval == CV_SUCCESS) { /* no root found */ + cv_mem->cv_irfnd = 0; + if ((irfndp == 1) && (itask == CV_ONE_STEP)) { + cv_mem->cv_tretlast = *tret = cv_mem->cv_tn; + N_VScale(ONE, cv_mem->cv_zn[0], yout); + return(CV_SUCCESS); + } + } else if (retval == RTFOUND) { /* a new root was found */ + cv_mem->cv_irfnd = 1; + 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", + 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; + ier = CVodeGetDky(cv_mem, tout, 0, yout); + if (ier != CV_SUCCESS) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", + MSGCV_BAD_TOUT, tout); + return(CV_ILL_INPUT); + } + 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 ) { + cv_mem->cv_tretlast = *tret = cv_mem->cv_tn; + 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) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", + MSGCV_BAD_TSTOP, cv_mem->cv_tstop, cv_mem->cv_tn); + return(CV_ILL_INPUT); + } + cv_mem->cv_tretlast = *tret = cv_mem->cv_tstop; + 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 */ + + /* + * -------------------------------------------------- + * 4. Looping point for internal steps + * + * 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.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 */ + 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); + if(ier != 0) { + if (cv_mem->cv_itol == CV_WF) + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", + MSGCV_EWT_NOW_FAIL, cv_mem->cv_tn); + 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); + break; + } + + if (cv_mem->cv_quadr && cv_mem->cv_errconQ) { + ier = cvQuadEwtSet(cv_mem, cv_mem->cv_znQ[0], cv_mem->cv_ewtQ); + if(ier != 0) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", + MSGCV_EWTQ_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); + break; + } + } + + if (cv_mem->cv_sensi) { + ier = cvSensEwtSet(cv_mem, cv_mem->cv_znS[0], cv_mem->cv_ewtS); + if (ier != 0) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", + MSGCV_EWTS_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); + break; + } + } + + if (cv_mem->cv_quadr_sensi && cv_mem->cv_errconQS) { + ier = cvQuadSensEwtSet(cv_mem, cv_mem->cv_znQS[0], cv_mem->cv_ewtQS); + if (ier != 0) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", + MSGCV_EWTQS_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); + break; + } + } + + } + + /* Check for too many steps */ + if ( (cv_mem->cv_mxstep>0) && (nstloc >= cv_mem->cv_mxstep) ) { + cvProcessError(cv_mem, CV_TOO_MUCH_WORK, "CVODES", "CVode", + MSGCV_MAX_STEPS, cv_mem->cv_tn); + istate = CV_TOO_MUCH_WORK; + cv_mem->cv_tretlast = *tret = cv_mem->cv_tn; + N_VScale(ONE, cv_mem->cv_zn[0], yout); + break; + } + + /* 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); + } + if (cv_mem->cv_sensi && cv_mem->cv_errconS) { + nrm = cvSensUpdateNorm(cv_mem, nrm, cv_mem->cv_znS[0], cv_mem->cv_ewtS); + } + if (cv_mem->cv_quadr_sensi && cv_mem->cv_errconQS) { + nrm = cvQuadSensUpdateNorm(cv_mem, nrm, cv_mem->cv_znQS[0], cv_mem->cv_ewtQS); + } + cv_mem->cv_tolsf = cv_mem->cv_uround * nrm; + if (cv_mem->cv_tolsf > ONE) { + cvProcessError(cv_mem, CV_TOO_MUCH_ACC, "CVODES", "CVode", + MSGCV_TOO_MUCH_ACC, cv_mem->cv_tn); + istate = CV_TOO_MUCH_ACC; + cv_mem->cv_tretlast = *tret = cv_mem->cv_tn; + N_VScale(ONE, cv_mem->cv_zn[0], yout); + cv_mem->cv_tolsf *= TWO; + break; + } 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) + 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) + cvProcessError(cv_mem, CV_WARNING, "CVODES", "CVode", MSGCV_HNIL_DONE); + } + + /* Call cvStep to take a step */ + kflag = cvStep(cv_mem); + + /* Process failed step cases, and exit loop */ + if (kflag != CV_SUCCESS) { + istate = cvHandleFailure(cv_mem, kflag); + cv_mem->cv_tretlast = *tret = cv_mem->cv_tn; + N_VScale(ONE, cv_mem->cv_zn[0], yout); + break; + } + + nstloc++; + + /* If tstop is set and was reached, reset tn = tstop */ + if ( cv_mem->cv_tstopset ) { + 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) + cv_mem->cv_tn = cv_mem->cv_tstop; + } + + /* 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; + cv_mem->cv_tretlast = *tret = cv_mem->cv_tlo; + break; + } else if (retval == CV_RTFUNC_FAIL) { /* g failed */ + cvProcessError(cv_mem, CV_RTFUNC_FAIL, "CVODES", "cvRcheck3", + MSGCV_RTFUNC_FAILED, cv_mem->cv_tlo); + istate = CV_RTFUNC_FAIL; + break; + } + + /* If we are at the end of the first step and we still have + * some event functions that are inactive, issue a warning + * as this may indicate a user error in the implementation + * of the root function. */ + + if (cv_mem->cv_nst==1) { + inactive_roots = SUNFALSE; + for (ir=0; ir<cv_mem->cv_nrtfn; ir++) { + if (!cv_mem->cv_gactive[ir]) { + inactive_roots = SUNTRUE; + break; + } + } + if ((cv_mem->cv_mxgnull > 0) && inactive_roots) { + cvProcessError(cv_mem, CV_WARNING, "CVODES", "CVode", + MSGCV_INACTIVE_ROOTS); + } + } + + } + + /* In NORMAL mode, check if tout reached */ + if ( (itask == CV_NORMAL) && (cv_mem->cv_tn-tout)*cv_mem->cv_h >= ZERO ) { + istate = CV_SUCCESS; + cv_mem->cv_tretlast = *tret = tout; + (void) CVodeGetDky(cv_mem, tout, 0, yout); + cv_mem->cv_next_q = cv_mem->cv_qprime; + cv_mem->cv_next_h = cv_mem->cv_hprime; + break; + } + + /* Check if tn is at tstop, or about to pass tstop */ + if ( cv_mem->cv_tstopset ) { + + 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; + cv_mem->cv_tstopset = SUNFALSE; + istate = CV_TSTOP_RETURN; + break; + } + + 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; + } + + } + + /* In ONE_STEP mode, copy y and exit loop */ + if (itask == CV_ONE_STEP) { + istate = CV_SUCCESS; + cv_mem->cv_tretlast = *tret = cv_mem->cv_tn; + N_VScale(ONE, cv_mem->cv_zn[0], yout); + cv_mem->cv_next_q = cv_mem->cv_qprime; + cv_mem->cv_next_h = cv_mem->cv_hprime; + break; + } + + } /* end looping for internal steps */ + + /* Load optional output */ + if (cv_mem->cv_sensi && (cv_mem->cv_ism==CV_STAGGERED1)) { + cv_mem->cv_nniS = 0; + cv_mem->cv_ncfnS = 0; + for (is=0; is<cv_mem->cv_Ns; is++) { + cv_mem->cv_nniS += cv_mem->cv_nniS1[is]; + cv_mem->cv_ncfnS += cv_mem->cv_ncfnS1[is]; + } + } + + return(istate); + +} + +/* + * ----------------------------------------------------------------- + * Interpolated output and extraction functions + * ----------------------------------------------------------------- + */ + +/* + * CVodeGetDky + * + * 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 + * 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. + * + * This function is called by CVode with k = 0 and t = tout, but + * may also be called directly by the user. + */ + +int CVodeGetDky(void *cvode_mem, realtype t, int k, N_Vector dky) +{ + 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", "CVodeGetDky", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + if (dky == NULL) { + cvProcessError(cv_mem, CV_BAD_DKY, "CVODES", "CVodeGetDky", MSGCV_NULL_DKY); + return(CV_BAD_DKY); + } + + if ((k < 0) || (k > cv_mem->cv_q)) { + 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)); + if (cv_mem->cv_hu < ZERO) tfuzz = -tfuzz; + tp = cv_mem->cv_tn - cv_mem->cv_hu - tfuzz; + tn1 = cv_mem->cv_tn + tfuzz; + if ((t-tp)*(t-tn1) > ZERO) { + cvProcessError(cv_mem, CV_BAD_T, "CVODES", "CVodeGetDky", MSGCV_BAD_T, + t, cv_mem->cv_tn-cv_mem->cv_hu, cv_mem->cv_tn); + 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; + for (i=j; i >= j-k+1; i--) + cv_mem->cv_cvals[nvec] *= i; + for (i=0; i < j-k; i++) + cv_mem->cv_cvals[nvec] *= s; + cv_mem->cv_Xvecs[nvec] = cv_mem->cv_zn[j]; + nvec += 1; + } + ier = N_VLinearCombination(nvec, cv_mem->cv_cvals, cv_mem->cv_Xvecs, dky); + if (ier != CV_SUCCESS) return (CV_VECTOROP_ERR); + + if (k == 0) return(CV_SUCCESS); + 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; + int flag; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuad", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + *tret = cv_mem->cv_tretlast; + + flag = CVodeGetQuadDky(cvode_mem,cv_mem->cv_tretlast,0,yQout); + + return(flag); +} + +/* + * 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 + * 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; + + if(cv_mem->cv_quadr != SUNTRUE) { + cvProcessError(cv_mem, CV_NO_QUAD, "CVODES", "CVodeGetQuadDky", MSGCV_NO_QUAD); + return(CV_NO_QUAD); + } + + if (dkyQ == NULL) { + 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)); + if (cv_mem->cv_hu < ZERO) tfuzz = -tfuzz; + tp = cv_mem->cv_tn - cv_mem->cv_hu - tfuzz; + tn1 = cv_mem->cv_tn + tfuzz; + if ((t-tp)*(t-tn1) > ZERO) { + cvProcessError(cv_mem, CV_BAD_T, "CVODES", "CVodeGetQuadDky", 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; + for (i=j; i >= j-k+1; i--) + cv_mem->cv_cvals[nvec] *= i; + for (i=0; i < j-k; i++) + cv_mem->cv_cvals[nvec] *= s; + cv_mem->cv_Xvecs[nvec] = cv_mem->cv_znQ[j]; + nvec += 1; + } + ier = N_VLinearCombination(nvec, cv_mem->cv_cvals, cv_mem->cv_Xvecs, dkyQ); + if (ier != CV_SUCCESS) return (CV_VECTOROP_ERR); + + if (k == 0) return(CV_SUCCESS); + 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; + int flag; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetSens", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + *tret = cv_mem->cv_tretlast; + + flag = CVodeGetSensDky(cvode_mem,cv_mem->cv_tretlast,0,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; + int flag; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetSens1", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + *tret = cv_mem->cv_tretlast; + + flag = CVodeGetSensDky1(cvode_mem,cv_mem->cv_tretlast,0,is,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 + * ier=CV_BAD_T are possible. + */ + +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; + + if (dkyS == NULL) { + cvProcessError(cv_mem, CV_BAD_DKY, "CVODES", + "CVodeGetSensDky", MSGCV_NULL_DKYA); + return(CV_BAD_DKY); + } + + for (is=0; is<cv_mem->cv_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 + * 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 + * 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; + + if(cv_mem->cv_sensi != SUNTRUE) { + cvProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetSensDky1", + MSGCV_NO_SENSI); + return(CV_NO_SENS); + } + + if (dkyS == NULL) { + cvProcessError(cv_mem, CV_BAD_DKY, "CVODES", "CVodeGetSensDky1", + 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)); + if (cv_mem->cv_hu < ZERO) tfuzz = -tfuzz; + tp = cv_mem->cv_tn - cv_mem->cv_hu - tfuzz; + tn1 = cv_mem->cv_tn + tfuzz; + if ((t-tp)*(t-tn1) > ZERO) { + cvProcessError(cv_mem, CV_BAD_T, "CVODES", "CVodeGetSensDky1", + 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; + for (i=j; i >= j-k+1; i--) + cv_mem->cv_cvals[nvec] *= i; + for (i=0; i < j-k; i++) + cv_mem->cv_cvals[nvec] *= s; + cv_mem->cv_Xvecs[nvec] = cv_mem->cv_znS[j][is]; + nvec += 1; + } + ier = N_VLinearCombination(nvec, cv_mem->cv_cvals, cv_mem->cv_Xvecs, dkyS); + if (ier != CV_SUCCESS) return (CV_VECTOROP_ERR); + + if (k == 0) return(CV_SUCCESS); + 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 + * vectors at the time at which CVode returned the ODE solution. + */ + +int CVodeGetQuadSens(void *cvode_mem, realtype *tret, N_Vector *yQSout) +{ + CVodeMem cv_mem; + int flag; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadSens", + MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + *tret = cv_mem->cv_tretlast; + + flag = CVodeGetQuadSensDky(cvode_mem,cv_mem->cv_tretlast,0,yQSout); + + return(flag); +} + +int CVodeGetQuadSens1(void *cvode_mem, realtype *tret, int is, N_Vector yQSout) +{ + CVodeMem cv_mem; + int flag; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadSens1", + MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + *tret = cv_mem->cv_tretlast; + + flag = CVodeGetQuadSensDky1(cvode_mem,cv_mem->cv_tretlast,0,is,yQSout); + + return(flag); +} + +/* + * CVodeGetQuadSensDky and CVodeGetQuadSensDky1 + * + * Dense output functions for all or only one of the quadrature sensitivity + * vectors (or derivative thereof). + */ + +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; + + if (dkyQS_all == NULL) { + cvProcessError(cv_mem, CV_BAD_DKY, "CVODES", "CVodeGetSensDky", + MSGCV_NULL_DKYA); + return(CV_BAD_DKY); + } + + for (is=0; is<cv_mem->cv_Ns; is++) { + ier = CVodeGetQuadSensDky1(cvode_mem,t,k,is,dkyQS_all[is]); + if (ier!=CV_SUCCESS) break; + } + + return(ier); +} + +int CVodeGetQuadSensDky1(void *cvode_mem, realtype t, int k, int is, N_Vector dkyQS) +{ + 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", "CVodeGetQuadSensDky1", + MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + if(cv_mem->cv_quadr_sensi != SUNTRUE) { + cvProcessError(cv_mem, CV_NO_QUADSENS, "CVODES", "CVodeGetQuadSensDky1", + MSGCV_NO_QUADSENSI); + return(CV_NO_QUADSENS); + } + + if (dkyQS == NULL) { + cvProcessError(cv_mem, CV_BAD_DKY, "CVODES", "CVodeGetQuadSensDky1", + 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)); + if (cv_mem->cv_hu < ZERO) tfuzz = -tfuzz; + tp = cv_mem->cv_tn - cv_mem->cv_hu - tfuzz; + tn1 = cv_mem->cv_tn + tfuzz; + if ((t-tp)*(t-tn1) > ZERO) { + cvProcessError(cv_mem, CV_BAD_T, "CVODES", "CVodeGetQuadSensDky1", + 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; + for (i=j; i >= j-k+1; i--) + cv_mem->cv_cvals[nvec] *= i; + for (i=0; i < j-k; i++) + cv_mem->cv_cvals[nvec] *= s; + cv_mem->cv_Xvecs[nvec] = cv_mem->cv_znQS[j][is]; + nvec += 1; + } + ier = N_VLinearCombination(nvec, cv_mem->cv_cvals, cv_mem->cv_Xvecs, dkyQS); + if (ier != CV_SUCCESS) return (CV_VECTOROP_ERR); + + if (k == 0) return(CV_SUCCESS); + r = SUNRpowerI(cv_mem->cv_h, -k); + N_VScale(r, dkyQS, dkyQS); + return(CV_SUCCESS); + +} + +/* + * ----------------------------------------------------------------- + * Deallocation functions + * ----------------------------------------------------------------- + */ + +/* + * CVodeFree + * + * 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 + * sensitivity computations by CVodeSensInit. + */ + +void CVodeFree(void **cvode_mem) +{ + CVodeMem cv_mem; + + if (*cvode_mem == NULL) return; + + cv_mem = (CVodeMem) (*cvode_mem); + + cvFreeVectors(cv_mem); + + if (cv_mem->ownNLS) { + SUNNonlinSolFree(cv_mem->NLS); + cv_mem->ownNLS = SUNFALSE; + cv_mem->NLS = NULL; + } + + CVodeQuadFree(cv_mem); + + CVodeSensFree(cv_mem); + + CVodeQuadSensFree(cv_mem); + + CVodeAdjFree(cv_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_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; + } + + free(cv_mem->cv_cvals); cv_mem->cv_cvals = NULL; + free(cv_mem->cv_Xvecs); cv_mem->cv_Xvecs = NULL; + free(cv_mem->cv_Zvecs); cv_mem->cv_Zvecs = NULL; + + free(*cvode_mem); + *cvode_mem = NULL; +} + +/* + * CVodeQuadFree + * + * CVodeQuadFree frees the problem memory in cvode_mem allocated + * for quadrature integration. Its only argument is the pointer + * cvode_mem returned by CVodeCreate. + */ + +void CVodeQuadFree(void *cvode_mem) +{ + CVodeMem cv_mem; + + if (cvode_mem == NULL) return; + cv_mem = (CVodeMem) cvode_mem; + + if(cv_mem->cv_QuadMallocDone) { + cvQuadFreeVectors(cv_mem); + cv_mem->cv_QuadMallocDone = SUNFALSE; + cv_mem->cv_quadr = SUNFALSE; + } +} + +/* + * CVodeSensFree + * + * CVodeSensFree frees the problem memory in cvode_mem allocated + * for sensitivity analysis. Its only argument is the pointer + * 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_ncfnS1); cv_mem->cv_ncfnS1 = NULL; + free(cv_mem->cv_nniS1); cv_mem->cv_nniS1 = NULL; + cv_mem->cv_stgr1alloc = SUNFALSE; + } + cvSensFreeVectors(cv_mem); + cv_mem->cv_SensMallocDone = SUNFALSE; + cv_mem->cv_sensi = SUNFALSE; + } + + /* 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; + 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; + cv_mem->stgMallocDone = SUNFALSE; + } + + /* if CVODES created a NLS object then free it */ + if (cv_mem->ownNLSsim) { + SUNNonlinSolFree(cv_mem->NLSsim); + cv_mem->ownNLSsim = SUNFALSE; + cv_mem->NLSsim = NULL; + } + if (cv_mem->ownNLSstg) { + SUNNonlinSolFree(cv_mem->NLSstg); + cv_mem->ownNLSstg = SUNFALSE; + cv_mem->NLSstg = NULL; + } + if (cv_mem->ownNLSstg1) { + SUNNonlinSolFree(cv_mem->NLSstg1); + cv_mem->ownNLSstg1 = SUNFALSE; + cv_mem->NLSstg1 = NULL; + } + +} + +/* + * CVodeQuadSensFree + * + * CVodeQuadSensFree frees the problem memory in cvode_mem allocated + * for quadrature sensitivity analysis. Its only argument is the pointer + * cvode_mem returned by CVodeCreate. + */ + +void CVodeQuadSensFree(void *cvode_mem) +{ + CVodeMem cv_mem; + + if (cvode_mem == NULL) return; + cv_mem = (CVodeMem) cvode_mem; + + if(cv_mem->cv_QuadSensMallocDone) { + cvQuadSensFreeVectors(cv_mem); + cv_mem->cv_QuadSensMallocDone = SUNFALSE; + cv_mem->cv_quadr_sensi = SUNFALSE; + } +} + + +/* + * ================================================================= + * PRIVATE FUNCTIONS + * ================================================================= + */ + +/* + * cvCheckNvector + * This routine checks if all required vector operations are present. + * If any of them is missing it returns SUNFALSE. + */ + +static booleantype cvCheckNvector(N_Vector tmpl) +{ + if((tmpl->ops->nvclone == NULL) || + (tmpl->ops->nvdestroy == NULL) || + (tmpl->ops->nvlinearsum == NULL) || + (tmpl->ops->nvconst == NULL) || + (tmpl->ops->nvprod == NULL) || + (tmpl->ops->nvdiv == NULL) || + (tmpl->ops->nvscale == NULL) || + (tmpl->ops->nvabs == NULL) || + (tmpl->ops->nvinv == NULL) || + (tmpl->ops->nvaddconst == NULL) || + (tmpl->ops->nvmaxnorm == NULL) || + (tmpl->ops->nvwrmsnorm == NULL) || + (tmpl->ops->nvmin == NULL)) + return(SUNFALSE); + else + return(SUNTRUE); +} + +/* + * ----------------------------------------------------------------- + * Memory allocation/deallocation + * ----------------------------------------------------------------- + */ + +/* + * cvAllocVectors + * + * This routine allocates the CVODES vectors ewt, acor, tempv, ftemp, and + * zn[0], ..., zn[maxord]. + * 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 + * allocated here. + */ + +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); + + cv_mem->cv_acor = N_VClone(tmpl); + if (cv_mem->cv_acor == NULL) { + N_VDestroy(cv_mem->cv_ewt); + return(SUNFALSE); + } + + cv_mem->cv_tempv = N_VClone(tmpl); + if (cv_mem->cv_tempv == NULL) { + N_VDestroy(cv_mem->cv_ewt); + N_VDestroy(cv_mem->cv_acor); + return(SUNFALSE); + } + + cv_mem->cv_ftemp = N_VClone(tmpl); + if (cv_mem->cv_ftemp == NULL) { + N_VDestroy(cv_mem->cv_tempv); + N_VDestroy(cv_mem->cv_ewt); + N_VDestroy(cv_mem->cv_acor); + return(SUNFALSE); + } + + cv_mem->cv_vtemp1 = N_VClone(tmpl); + if (cv_mem->cv_vtemp1 == NULL) { + N_VDestroy(cv_mem->cv_ftemp); + N_VDestroy(cv_mem->cv_tempv); + N_VDestroy(cv_mem->cv_ewt); + N_VDestroy(cv_mem->cv_acor); + return(SUNFALSE); + } + + cv_mem->cv_vtemp2 = N_VClone(tmpl); + if (cv_mem->cv_vtemp2 == NULL) { + N_VDestroy(cv_mem->cv_vtemp1); + N_VDestroy(cv_mem->cv_ftemp); + N_VDestroy(cv_mem->cv_tempv); + N_VDestroy(cv_mem->cv_ewt); + N_VDestroy(cv_mem->cv_acor); + return(SUNFALSE); + } + + cv_mem->cv_vtemp3 = N_VClone(tmpl); + if (cv_mem->cv_vtemp3 == NULL) { + N_VDestroy(cv_mem->cv_vtemp2); + N_VDestroy(cv_mem->cv_vtemp1); + N_VDestroy(cv_mem->cv_ftemp); + N_VDestroy(cv_mem->cv_tempv); + N_VDestroy(cv_mem->cv_ewt); + N_VDestroy(cv_mem->cv_acor); + return(SUNFALSE); + } + + /* Allocate zn[0] ... zn[qmax] */ + + for (j=0; j <= cv_mem->cv_qmax; j++) { + cv_mem->cv_zn[j] = N_VClone(tmpl); + if (cv_mem->cv_zn[j] == NULL) { + N_VDestroy(cv_mem->cv_ewt); + N_VDestroy(cv_mem->cv_acor); + N_VDestroy(cv_mem->cv_tempv); + N_VDestroy(cv_mem->cv_ftemp); + N_VDestroy(cv_mem->cv_vtemp1); + N_VDestroy(cv_mem->cv_vtemp2); + N_VDestroy(cv_mem->cv_vtemp3); + for (i=0; i < j; i++) N_VDestroy(cv_mem->cv_zn[i]); + return(SUNFALSE); + } + } + + /* Update solver workspace lengths */ + cv_mem->cv_lrw += (cv_mem->cv_qmax + 8)*cv_mem->cv_lrw1; + cv_mem->cv_liw += (cv_mem->cv_qmax + 8)*cv_mem->cv_liw1; + + /* Store the value of qmax used here */ + cv_mem->cv_qmax_alloc = cv_mem->cv_qmax; + + return(SUNTRUE); +} + +/* + * cvFreeVectors + * + * This routine frees the CVODES 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); + N_VDestroy(cv_mem->cv_acor); + N_VDestroy(cv_mem->cv_tempv); + N_VDestroy(cv_mem->cv_ftemp); + N_VDestroy(cv_mem->cv_vtemp1); + N_VDestroy(cv_mem->cv_vtemp2); + N_VDestroy(cv_mem->cv_vtemp3); + for (j=0; j <= maxord; j++) N_VDestroy(cv_mem->cv_zn[j]); + + cv_mem->cv_lrw -= (maxord + 8)*cv_mem->cv_lrw1; + cv_mem->cv_liw -= (maxord + 8)*cv_mem->cv_liw1; + + if (cv_mem->cv_VabstolMallocDone) { + N_VDestroy(cv_mem->cv_Vabstol); + cv_mem->cv_lrw -= cv_mem->cv_lrw1; + cv_mem->cv_liw -= cv_mem->cv_liw1; + } + + if (cv_mem->cv_constraintsMallocDone) { + N_VDestroy(cv_mem->cv_constraints); + cv_mem->cv_lrw -= cv_mem->cv_lrw1; + cv_mem->cv_liw -= cv_mem->cv_liw1; + } +} + +/* + * CVodeQuadAllocVectors + * + * 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 + * CVodeQuadReInit. + */ + +static booleantype cvQuadAllocVectors(CVodeMem cv_mem, N_Vector tmpl) +{ + int i, j; + + /* Allocate ewtQ */ + cv_mem->cv_ewtQ = N_VClone(tmpl); + if (cv_mem->cv_ewtQ == NULL) { + return(SUNFALSE); + } + + /* Allocate acorQ */ + cv_mem->cv_acorQ = N_VClone(tmpl); + if (cv_mem->cv_acorQ == NULL) { + N_VDestroy(cv_mem->cv_ewtQ); + return(SUNFALSE); + } + + /* Allocate yQ */ + cv_mem->cv_yQ = N_VClone(tmpl); + if (cv_mem->cv_yQ == NULL) { + N_VDestroy(cv_mem->cv_ewtQ); + N_VDestroy(cv_mem->cv_acorQ); + return(SUNFALSE); + } + + /* Allocate tempvQ */ + cv_mem->cv_tempvQ = N_VClone(tmpl); + if (cv_mem->cv_tempvQ == NULL) { + N_VDestroy(cv_mem->cv_ewtQ); + N_VDestroy(cv_mem->cv_acorQ); + N_VDestroy(cv_mem->cv_yQ); + return(SUNFALSE); + } + + /* Allocate zQn[0] ... zQn[maxord] */ + + for (j=0; j <= cv_mem->cv_qmax; j++) { + cv_mem->cv_znQ[j] = N_VClone(tmpl); + if (cv_mem->cv_znQ[j] == NULL) { + 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 (i=0; i < j; i++) N_VDestroy(cv_mem->cv_znQ[i]); + return(SUNFALSE); + } + } + + /* Store the value of qmax used here */ + cv_mem->cv_qmax_allocQ = cv_mem->cv_qmax; + + /* Update solver workspace lengths */ + cv_mem->cv_lrw += (cv_mem->cv_qmax + 5)*cv_mem->cv_lrw1Q; + cv_mem->cv_liw += (cv_mem->cv_qmax + 5)*cv_mem->cv_liw1Q; + + return(SUNTRUE); +} + +/* + * cvQuadFreeVectors + * + * This routine frees the CVODES vectors allocated in cvQuadAllocVectors. + */ + +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; + cv_mem->cv_liw -= (maxord + 5)*cv_mem->cv_liw1Q; + + if (cv_mem->cv_VabstolQMallocDone) { + N_VDestroy(cv_mem->cv_VabstolQ); + cv_mem->cv_lrw -= cv_mem->cv_lrw1Q; + cv_mem->cv_liw -= cv_mem->cv_liw1Q; + } + + cv_mem->cv_VabstolQMallocDone = SUNFALSE; +} + +/* + * cvSensAllocVectors + * + * 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) +{ + int i, j; + + /* Allocate yS */ + cv_mem->cv_yS = N_VCloneVectorArray(cv_mem->cv_Ns, tmpl); + if (cv_mem->cv_yS == NULL) { + return(SUNFALSE); + } + + /* Allocate ewtS */ + cv_mem->cv_ewtS = N_VCloneVectorArray(cv_mem->cv_Ns, tmpl); + if (cv_mem->cv_ewtS == NULL) { + 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) { + N_VDestroyVectorArray(cv_mem->cv_yS, cv_mem->cv_Ns); + 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) { + N_VDestroyVectorArray(cv_mem->cv_yS, cv_mem->cv_Ns); + N_VDestroyVectorArray(cv_mem->cv_ewtS, cv_mem->cv_Ns); + 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) { + N_VDestroyVectorArray(cv_mem->cv_yS, cv_mem->cv_Ns); + N_VDestroyVectorArray(cv_mem->cv_ewtS, cv_mem->cv_Ns); + N_VDestroyVectorArray(cv_mem->cv_acorS, cv_mem->cv_Ns); + 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); + if (cv_mem->cv_znS[j] == NULL) { + N_VDestroyVectorArray(cv_mem->cv_yS, cv_mem->cv_Ns); + N_VDestroyVectorArray(cv_mem->cv_ewtS, cv_mem->cv_Ns); + 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 (i=0; i<j; i++) + N_VDestroyVectorArray(cv_mem->cv_znS[i], cv_mem->cv_Ns); + 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)); + if (cv_mem->cv_pbar == NULL) { + N_VDestroyVectorArray(cv_mem->cv_yS, cv_mem->cv_Ns); + N_VDestroyVectorArray(cv_mem->cv_ewtS, cv_mem->cv_Ns); + 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 (i=0; i<=cv_mem->cv_qmax; i++) + N_VDestroyVectorArray(cv_mem->cv_znS[i], cv_mem->cv_Ns); + return(SUNFALSE); + } + + cv_mem->cv_plist = NULL; + cv_mem->cv_plist = (int *)malloc(cv_mem->cv_Ns*sizeof(int)); + if (cv_mem->cv_plist == NULL) { + N_VDestroyVectorArray(cv_mem->cv_yS, cv_mem->cv_Ns); + N_VDestroyVectorArray(cv_mem->cv_ewtS, cv_mem->cv_Ns); + 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 (i=0; i<=cv_mem->cv_qmax; i++) + N_VDestroyVectorArray(cv_mem->cv_znS[i], cv_mem->cv_Ns); + free(cv_mem->cv_pbar); cv_mem->cv_pbar = NULL; + return(SUNFALSE); + } + + /* 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; + + return(SUNTRUE); +} + +/* + * cvSensFreeVectors + * + * This routine frees the CVODES vectors allocated in cvSensAllocVectors. + */ + +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); + N_VDestroyVectorArray(cv_mem->cv_ewtS, cv_mem->cv_Ns); + 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); + + free(cv_mem->cv_pbar); cv_mem->cv_pbar = NULL; + free(cv_mem->cv_plist); cv_mem->cv_plist = NULL; + + cv_mem->cv_lrw -= (maxord + 6)*cv_mem->cv_Ns*cv_mem->cv_lrw1 + cv_mem->cv_Ns; + cv_mem->cv_liw -= (maxord + 6)*cv_mem->cv_Ns*cv_mem->cv_liw1 + cv_mem->cv_Ns; + + if (cv_mem->cv_VabstolSMallocDone) { + N_VDestroyVectorArray(cv_mem->cv_VabstolS, cv_mem->cv_Ns); + cv_mem->cv_lrw -= cv_mem->cv_Ns*cv_mem->cv_lrw1; + cv_mem->cv_liw -= cv_mem->cv_Ns*cv_mem->cv_liw1; + } + if (cv_mem->cv_SabstolSMallocDone) { + free(cv_mem->cv_SabstolS); cv_mem->cv_SabstolS = NULL; + cv_mem->cv_lrw -= cv_mem->cv_Ns; + } + cv_mem->cv_VabstolSMallocDone = SUNFALSE; + cv_mem->cv_SabstolSMallocDone = SUNFALSE; +} + +/* + * cvQuadSensAllocVectors + * + * 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) +{ + int i, j; + + /* Allocate ftempQ */ + cv_mem->cv_ftempQ = N_VClone(tmpl); + if (cv_mem->cv_ftempQ == NULL) { + return(SUNFALSE); + } + + /* Allocate yQS */ + cv_mem->cv_yQS = N_VCloneVectorArray(cv_mem->cv_Ns, tmpl); + if (cv_mem->cv_yQS == NULL) { + N_VDestroy(cv_mem->cv_ftempQ); + return(SUNFALSE); + } + + /* Allocate ewtQS */ + cv_mem->cv_ewtQS = N_VCloneVectorArray(cv_mem->cv_Ns, tmpl); + if (cv_mem->cv_ewtQS == NULL) { + N_VDestroy(cv_mem->cv_ftempQ); + N_VDestroyVectorArray(cv_mem->cv_yQS, cv_mem->cv_Ns); + return(SUNFALSE); + } + + /* Allocate acorQS */ + cv_mem->cv_acorQS = N_VCloneVectorArray(cv_mem->cv_Ns, tmpl); + if (cv_mem->cv_acorQS == NULL) { + N_VDestroy(cv_mem->cv_ftempQ); + N_VDestroyVectorArray(cv_mem->cv_yQS, cv_mem->cv_Ns); + 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) { + N_VDestroy(cv_mem->cv_ftempQ); + N_VDestroyVectorArray(cv_mem->cv_yQS, cv_mem->cv_Ns); + N_VDestroyVectorArray(cv_mem->cv_ewtQS, cv_mem->cv_Ns); + N_VDestroyVectorArray(cv_mem->cv_acorQS, cv_mem->cv_Ns); + return(SUNFALSE); + } + + /* Allocate znQS */ + for (j=0; j<=cv_mem->cv_qmax; j++) { + cv_mem->cv_znQS[j] = N_VCloneVectorArray(cv_mem->cv_Ns, tmpl); + if (cv_mem->cv_znQS[j] == NULL) { + N_VDestroy(cv_mem->cv_ftempQ); + N_VDestroyVectorArray(cv_mem->cv_yQS, cv_mem->cv_Ns); + 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 (i=0; i<j; i++) + N_VDestroyVectorArray(cv_mem->cv_znQS[i], cv_mem->cv_Ns); + return(SUNFALSE); + } + } + + /* Update solver workspace lengths */ + cv_mem->cv_lrw += (cv_mem->cv_qmax + 5)*cv_mem->cv_Ns*cv_mem->cv_lrw1Q; + cv_mem->cv_liw += (cv_mem->cv_qmax + 5)*cv_mem->cv_Ns*cv_mem->cv_liw1Q; + + /* Store the value of qmax used here */ + cv_mem->cv_qmax_allocQS = cv_mem->cv_qmax; + + return(SUNTRUE); +} + +/* + * cvQuadSensFreeVectors + * + * This routine frees the CVODES vectors allocated in cvQuadSensAllocVectors. + */ + +static void cvQuadSensFreeVectors(CVodeMem cv_mem) +{ + int j, maxord; + + maxord = cv_mem->cv_qmax_allocQS; + + N_VDestroy(cv_mem->cv_ftempQ); + + N_VDestroyVectorArray(cv_mem->cv_yQS, cv_mem->cv_Ns); + 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); + + 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; + + if (cv_mem->cv_VabstolQSMallocDone) { + N_VDestroyVectorArray(cv_mem->cv_VabstolQS, cv_mem->cv_Ns); + cv_mem->cv_lrw -= cv_mem->cv_Ns*cv_mem->cv_lrw1Q; + cv_mem->cv_liw -= cv_mem->cv_Ns*cv_mem->cv_liw1Q; + } + if (cv_mem->cv_SabstolQSMallocDone) { + free(cv_mem->cv_SabstolQS); cv_mem->cv_SabstolQS = NULL; + cv_mem->cv_lrw -= cv_mem->cv_Ns; + } + cv_mem->cv_VabstolQSMallocDone = SUNFALSE; + cv_mem->cv_SabstolQSMallocDone = SUNFALSE; + +} + + +/* + * ----------------------------------------------------------------- + * Initial stepsize calculation + * ----------------------------------------------------------------- + */ + +/* + * cvHin + * + * 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 + * 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 + * not possible, cvHin returns CV_REPTD_*RHSFUNC_ERR. + * 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, + * where ydd = estimated second derivative of y. Here, y includes + * all variables considered in the error test. + * + * We start with an initial estimate equal to the geometric mean of the + * lower and upper bounds on the step size. + * + * 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. + * + * 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 + * still cannot be found, fall back on a previous value if possible, + * or else return CV_REPTD_RHSFUNC_ERR. + * + * Finally, we apply a bias (0.5) and verify that h0 is within bounds. + */ + +static int cvHin(CVodeMem cv_mem, realtype tout) +{ + int retval, sign, count1, count2; + realtype tdiff, tdist, tround, hlb, hub; + realtype hg, hgs, hs, hnew, hrat, h0, yddnrm; + 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 + as first trial value. + Exit with this value if the bounds cross each other. + */ + + hlb = HLB_FACTOR * tround; + hub = cvUpperBoundH0(cv_mem, tdist); + + hg = SUNRsqrt(hlb*hub); + + if (hub < hlb) { + if (sign == -1) cv_mem->cv_h = -hg; + else cv_mem->cv_h = hg; + return(CV_SUCCESS); + } + + /* Outer loop */ + + hs = hg; /* safeguard against 'uninitialized variable' warning */ + + for(count1 = 1; count1 <= MAX_ITERS; count1++) { + + /* Attempts to estimate ydd */ + + hgOK = SUNFALSE; + + for (count2 = 1; count2 <= MAX_ITERS; count2++) { + hgs = hg*sign; + retval = cvYddNorm(cv_mem, hgs, &yddnrm); + /* If a RHS function failed unrecoverably, give up */ + 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 */ + hg *= POINT2; + } + + /* If a RHS function failed recoverably MAX_ITERS times */ + + if (!hgOK) { + /* Exit if this is the first or second pass. No recovery possible */ + if (count1 <= 2) { + if (retval == RHSFUNC_RECVR) return(CV_REPTD_RHSFUNC_ERR); + if (retval == QRHSFUNC_RECVR) return(CV_REPTD_QRHSFUNC_ERR); + if (retval == SRHSFUNC_RECVR) return(CV_REPTD_SRHSFUNC_ERR); + } + /* We have a fall-back option. The value hs is a previous hnew which + passed through f(). Use it and break */ + hnew = hs; + break; + } + + /* The proposed step size is feasible. Save it. */ + hs = hg; + + /* 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; + + /* After one pass, if ydd seems to be bad, use fall-back value. */ + if ((count1 > 1) && (hrat > TWO)) { + hnew = hg; + break; + } + + /* Send this value back through f() */ + hg = hnew; + + } + + /* Apply bounds, bias factor, and attach sign */ + + h0 = H_BIAS*hnew; + if (h0 < hlb) h0 = hlb; + if (h0 > hub) h0 = hub; + if (sign == -1) h0 = -h0; + cv_mem->cv_h = h0; + + return(CV_SUCCESS); +} + +/* + * cvUpperBoundH0 + * + * This routine sets an upper bound on abs(h0) based on + * tdist = tn - t0 and the values of y[i]/y'[i]. + */ + +static realtype cvUpperBoundH0(CVodeMem cv_mem, realtype tdist) +{ + realtype hub_inv, hubQ_inv, hubS_inv, hubQS_inv, hub; + N_Vector temp1, temp2; + N_Vector tempQ1, tempQ2; + N_Vector *tempS1; + 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. + */ + + temp1 = cv_mem->cv_tempv; + temp2 = cv_mem->cv_acor; + + N_VAbs(cv_mem->cv_zn[0], temp2); + cv_mem->cv_efun(cv_mem->cv_zn[0], temp1, cv_mem->cv_e_data); + N_VInv(temp1, temp1); + N_VLinearSum(HUB_FACTOR, temp2, ONE, temp1, temp1); + + N_VAbs(cv_mem->cv_zn[1], temp2); + + N_VDiv(temp2, temp1, temp1); + hub_inv = N_VMaxNorm(temp1); + + /* Bound based on |yQ|/|yQ'| */ + + if (cv_mem->cv_quadr && cv_mem->cv_errconQ) { + + tempQ1 = cv_mem->cv_tempvQ; + tempQ2 = cv_mem->cv_acorQ; + + N_VAbs(cv_mem->cv_znQ[0], tempQ2); + 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); + + if (hubQ_inv > hub_inv) hub_inv = hubQ_inv; + + } + + /* Bound based on |yS|/|yS'| */ + + if (cv_mem->cv_sensi && cv_mem->cv_errconS) { + + tempS1 = cv_mem->cv_acorS; + cvSensEwtSet(cv_mem, cv_mem->cv_znS[0], tempS1); + + for (is=0; is<cv_mem->cv_Ns; is++) { + + 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); + + if (hubS_inv > hub_inv) hub_inv = hubS_inv; + + } + + } + + /* Bound based on |yQS|/|yQS'| */ + + if (cv_mem->cv_quadr_sensi && cv_mem->cv_errconQS) { + + tempQ1 = cv_mem->cv_tempvQ; + tempQ2 = cv_mem->cv_acorQ; + + tempQS1 = cv_mem->cv_acorQS; + cvQuadSensEwtSet(cv_mem, cv_mem->cv_znQS[0], tempQS1); + + for (is=0; is<cv_mem->cv_Ns; is++) { + + 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); + + if (hubQS_inv > hub_inv) hub_inv = hubQS_inv; + + } + + } + + + /* + * bound based on tdist -- allow at most a step of magnitude + * HUB_FACTOR * tdist + */ + + hub = HUB_FACTOR*tdist; + + /* Use the smaler of the two */ + + if (hub*hub_inv > ONE) hub = ONE/hub_inv; + + return(hub); +} + +/* + * cvYddNorm + * + * 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. + */ + +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], + ONE, cv_mem->cv_znS[0], + 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, + cv_mem->cv_tempv, cv_mem->cv_user_data); + cv_mem->cv_nfe++; + if (retval < 0) return(CV_RHSFUNC_FAIL); + if (retval > 0) return(RHSFUNC_RECVR); + + if (cv_mem->cv_quadr && cv_mem->cv_errconQ) { + retval = cv_mem->cv_fQ(cv_mem->cv_tn+hg, cv_mem->cv_y, + cv_mem->cv_tempvQ, 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 && cv_mem->cv_errconS) { + wrk1 = cv_mem->cv_ftemp; + wrk2 = cv_mem->cv_acor; + retval = cvSensRhsWrapper(cv_mem, cv_mem->cv_tn+hg, cv_mem->cv_y, + cv_mem->cv_tempv, cv_mem->cv_yS, + 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; + wrk2 = cv_mem->cv_acorQ; + retval = cv_mem->cv_fQS(cv_mem->cv_Ns, cv_mem->cv_tn+hg, + cv_mem->cv_y, cv_mem->cv_yS, + 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(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); + + if (cv_mem->cv_quadr && cv_mem->cv_errconQ) { + N_VLinearSum(ONE/hg, cv_mem->cv_tempvQ, -ONE/hg, cv_mem->cv_znQ[1], + cv_mem->cv_tempvQ); + + *yddnrm = cvQuadUpdateNorm(cv_mem, *yddnrm, cv_mem->cv_tempvQ, + cv_mem->cv_ewtQ); + } + + if (cv_mem->cv_sensi && cv_mem->cv_errconS) { + retval = N_VLinearSumVectorArray(cv_mem->cv_Ns, + ONE/hg, cv_mem->cv_tempvS, + -ONE/hg, cv_mem->cv_znS[1], + cv_mem->cv_tempvS); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + + *yddnrm = cvSensUpdateNorm(cv_mem, *yddnrm, cv_mem->cv_tempvS, + cv_mem->cv_ewtS); + } + + if (cv_mem->cv_quadr_sensi && cv_mem->cv_errconQS) { + retval = N_VLinearSumVectorArray(cv_mem->cv_Ns, + ONE/hg, cv_mem->cv_tempvQS, + -ONE/hg, cv_mem->cv_znQS[1], + cv_mem->cv_tempvQS); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + + *yddnrm = cvQuadSensUpdateNorm(cv_mem, *yddnrm, cv_mem->cv_tempvQS, + cv_mem->cv_ewtQS); + } + + return(CV_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * 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); + } + + /* 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); +} + +/* + * 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. + * 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 (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. + * 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 (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 (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 (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; is<cv_mem->cv_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; is<cv_mem->cv_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]); + } + return(0); +} + +/* + * cvSensEwtSetSV + * + */ + +static int cvSensEwtSetSV(CVodeMem cv_mem, N_Vector *yScur, N_Vector *weightS) +{ + int is; + + for (is=0; is<cv_mem->cv_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]); + } + + return(0); +} + +/* + * cvQuadSensEwtSet + * + */ + +static int cvQuadSensEwtSet(CVodeMem cv_mem, N_Vector *yQScur, N_Vector *weightQS) +{ + 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; + } + + 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. + * + */ +static int cvQuadSensEwtSetEE(CVodeMem cv_mem, N_Vector *yQScur, N_Vector *weightQS) +{ + 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; is<cv_mem->cv_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); +} + +static int cvQuadSensEwtSetSS(CVodeMem cv_mem, N_Vector *yQScur, N_Vector *weightQS) +{ + int is; + + for (is=0; is<cv_mem->cv_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]); + } + + return(0); +} + +static int cvQuadSensEwtSetSV(CVodeMem cv_mem, N_Vector *yQScur, N_Vector *weightQS) +{ + int is; + + for (is=0; is<cv_mem->cv_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]); + } + + return(0); +} + + + +/* + * ----------------------------------------------------------------- + * Main cvStep function + * ----------------------------------------------------------------- + */ + +/* + * cvStep + * + * 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 cvStep(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; + + /* 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; is<cv_mem->cv_Ns; is++) + cv_mem->cv_ncfS1[is] = 0; + } + + /* If needed, adjust method parameters */ + + if ((cv_mem->cv_nst > 0) && (cv_mem->cv_hprime != cv_mem->cv_h)) + cvAdjustParams(cv_mem); + + /* Looping point for attempts to take a step */ + + saved_t = cv_mem->cv_tn; + nflag = FIRST_CALL; + + for(;;) { + + cvPredict(cv_mem); + cvSet(cv_mem); + + /* ------ Correct state variables ------ */ + + 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; + + /* Return if nonlinear solve failed and recovery not possible. */ + if (kflag != DO_ERROR_TEST) return(kflag); + + /* Perform error test (nflag=CV_SUCCESS) */ + eflag = cvDoErrorTest(cv_mem, &nflag, saved_t, cv_mem->cv_acnrm, + &nef, &(cv_mem->cv_netf), &dsm); + + /* Go back in loop if we need to predict again (nflag=PREV_ERR_FAIL) */ + if (eflag == TRY_AGAIN) continue; + + /* Return if error test failed and recovery not possible. */ + if (eflag != CV_SUCCESS) return(eflag); + + /* Error test passed (eflag=CV_SUCCESS, nflag=CV_SUCCESS), go on */ + + /* ------ Correct the quadrature variables ------ */ + + if (cv_mem->cv_quadr) { + + ncf = nef = 0; /* reset counters for states */ + + nflag = cvQuadNls(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 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 (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; + } + + } + + /* ------ Correct the sensitivity variables (STAGGERED or STAGGERED1) ------- */ + + 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; + } + + 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; is<cv_mem->cv_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; is<cv_mem->cv_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); + + /* Set dsm = max(dsm, dsmQS) to be used in cvPrepareNextStep */ + if (dsmQS > dsm) dsm = dsmQS; + } + + + } + + + /* Everything went fine; exit loop */ + break; + + } + + /* 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); + + 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; is<cv_mem->cv_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); + } + + if (cv_mem->cv_quadr_sensi) { + for (is=0; is<cv_mem->cv_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); + +} + +/* + * ----------------------------------------------------------------- + * Function called at beginning of step + * ----------------------------------------------------------------- + */ + +/* + * 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 void cvAdjustParams(CVodeMem cv_mem) +{ + 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); +} + +/* + * 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 void cvAdjustOrder(CVodeMem cv_mem, int deltaq) +{ + 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; + } +} + +/* + * cvAdjustAdams + * + * This routine adjusts the history array on a change of order q by + * deltaq, in the case that lmm == CV_ADAMS. + */ + +static void cvAdjustAdams(CVodeMem cv_mem, int deltaq) +{ + int i, j; + realtype xi, hsum; + + /* 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); + } + +} + +/* + * 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 void cvAdjustBDF(CVodeMem cv_mem, int deltaq) +{ + switch(deltaq) { + case 1: + cvIncreaseBDF(cv_mem); + return; + case -1: + cvDecreaseBDF(cv_mem); + return; + } +} + +/* + * 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 void cvIncreaseBDF(CVodeMem cv_mem) +{ + realtype alpha0, alpha1, prod, xi, xiold, hsum, A1; + int i, j; + int 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; + + /* + 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); + + 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); + } + + if (cv_mem->cv_sensi) { + + for (is=0; is<cv_mem->cv_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); + } + + if (cv_mem->cv_quadr_sensi) { + + for (is=0; is<cv_mem->cv_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]); + + /* 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); + } + +} + +/* + * cvDecreaseBDF + * + * 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 void cvDecreaseBDF(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) { + + 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); + + 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); + } + +} + + +/* + * 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. + */ + +static void cvRescale(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; is<cv_mem->cv_Ns; is++) + cv_mem->cv_cvals[is] = cv_mem->cv_eta; + for (j=1; j < cv_mem->cv_q; j++) + for (is=0; is<cv_mem->cv_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]; + } + + if (cv_mem->cv_sensi) { + for (j=1; j <= cv_mem->cv_q; j++) + for (is=0; is<cv_mem->cv_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); + } + + if (cv_mem->cv_quadr_sensi) { + for (j=1; j <= cv_mem->cv_q; j++) + for (is=0; is<cv_mem->cv_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); + } + + 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; + +} + +/* + * 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. + */ + +static void cvPredict(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]); + + 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]); + } + +} + +/* + * 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 */ +} + +/* + * 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. + */ + +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); +} + +/* + * 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]; + } + 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. + */ + +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]; + + 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; + } + + cv_mem->cv_tq[4] = cv_mem->cv_nlscoef / cv_mem->cv_tq[2]; +} + +/* + * 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). + */ + +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); +} + +/* + * cvSetBDF + * + * 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 cvSetBDF(CVodeMem cv_mem) +{ + 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); +} + +/* + * cvSetTqBDF + * + * This routine sets the test quantity array tq in the case + * lmm == CV_BDF. + */ + +static void cvSetTqBDF(CVodeMem cv_mem, realtype hsum, realtype alpha0, + realtype alpha0_hat, realtype xi_inv, realtype xistar_inv) +{ + 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)); + } + cv_mem->cv_tq[4] = cv_mem->cv_nlscoef / cv_mem->cv_tq[2]; +} + +/* + * ----------------------------------------------------------------- + * Nonlinear solver functions + * ----------------------------------------------------------------- + */ + +/* + * cvNls + * + * 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)); + + /* 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; + } + + /* 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); + + /* 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); + + if (flag < 0) return(CV_NLS_SETUP_FAIL); + if (flag > 0) return(SUN_NLS_CONV_RECVR); + } + + /* 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); + } + + /* 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 (cv_mem->cv_constraintsSet) + flag = cvCheckConstraints(cv_mem); + + return(flag); + +} + +/* + * 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 + */ + +static int cvCheckConstraints(CVodeMem cv_mem) +{ + booleantype constraintsPassed; + realtype vnorm; + cv_mem->cv_mm = cv_mem->cv_ftemp; + + /* Get mask vector mm, set where constraints failed */ + + 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 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); + } + + 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); +} + +/* + * 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 + * + */ + +static int cvQuadSensNls(CVodeMem cv_mem) +{ + int is, retval; + + /* 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); + + + for (is=0; is<cv_mem->cv_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); +} + + +/* + * cvStgrNls + * + * 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 int cvStgrNls(CVodeMem cv_mem) +{ + booleantype callSetup; + int flag=CV_SUCCESS; + + cv_mem->sens_solve = SUNTRUE; + + callSetup = SUNFALSE; + if (cv_mem->cv_lsetup == NULL) + cv_mem->cv_crateS = ONE; + + /* initial guess for the correction to the predictor */ + N_VConst(ZERO, cv_mem->ycor0Stg); + + /* 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); + + /* 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 the solve is successful, update Jacobian status */ + if (flag == CV_SUCCESS) cv_mem->cv_jcur = SUNFALSE; + + cv_mem->sens_solve = SUNFALSE; + + return(flag); + +} + +/* + * 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. + */ + +static int cvStgr1Nls(CVodeMem cv_mem, int is) +{ + booleantype callSetup; + long int nni; + int flag=CV_SUCCESS; + + cv_mem->sens_solve = SUNTRUE; + + callSetup = SUNFALSE; + if (cv_mem->cv_lsetup == NULL) + cv_mem->cv_crateS = ONE; + + /* initial guess for the correction to the predictor */ + N_VConst(ZERO, cv_mem->cv_tempvS[is]); + + /* 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); + + /* 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]); + + /* if the solve is successful, update Jacobian status */ + if (flag == CV_SUCCESS) cv_mem->cv_jcur = SUNFALSE; + + /* update nniS iteration count */ + (void) SUNNonlinSolGetNumIters(cv_mem->NLSstg1, &nni); + cv_mem->cv_nniS1[is] += nni - cv_mem->nnip; + cv_mem->nnip = nni; + + cv_mem->sens_solve = SUNFALSE; + + return(flag); + +} + +/* + * 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. + * + */ + +static int cvHandleNFlag(CVodeMem cv_mem, int *nflagPtr, realtype saved_t, + int *ncfPtr, long int *ncfnPtr) +{ + 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); + } + + /* 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 + * + * 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. + */ + +static void cvRestore(CVodeMem cv_mem, realtype saved_t) +{ + 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]); + } +} + +/* + * ----------------------------------------------------------------- + * 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. + * + */ + +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; + + dsm = acor_nrm * cv_mem->cv_tq[2]; + + /* 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); + + /* 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); + + /* Set etamax = 1 to prevent step size increase at end of this step */ + cv_mem->cv_etamax = ONE; + + /* 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 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; + + 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]); + + if (cv_mem->cv_quadr) { + + 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); + + N_VScale(cv_mem->cv_h, cv_mem->cv_tempvQ, cv_mem->cv_znQ[1]); + + } + + if (cv_mem->cv_sensi) { + + wrk1 = cv_mem->cv_ftemp; + wrk2 = cv_mem->cv_ftempS[0]; + + 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); + + for (is=0; is<cv_mem->cv_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_quadr_sensi) { + + wrk1 = cv_mem->cv_ftemp; + wrk2 = cv_mem->cv_ftempQ; + + 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; is<cv_mem->cv_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_tempvQS, cv_mem->cv_znQS[1]); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + } + + return(TRY_AGAIN); +} + +/* + * ----------------------------------------------------------------- + * Functions called after a successful step + * ----------------------------------------------------------------- + */ + +/* + * cvCompleteStep + * + * 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 void cvCompleteStep(CVodeMem cv_mem) +{ + 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; is<cv_mem->cv_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; is<cv_mem->cv_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; is<cv_mem->cv_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; is<cv_mem->cv_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); + */ + + /* Depending on flag, print error message and return error flag */ + switch (flag) { + case CV_ERR_FAILURE: + cvProcessError(cv_mem, CV_ERR_FAILURE, "CVODES", "CVode", + MSGCV_ERR_FAILS, cv_mem->cv_tn, cv_mem->cv_h); + break; + case CV_CONV_FAILURE: + cvProcessError(cv_mem, CV_CONV_FAILURE, "CVODES", "CVode", + MSGCV_CONV_FAILS, cv_mem->cv_tn, cv_mem->cv_h); + break; + case CV_LSETUP_FAIL: + cvProcessError(cv_mem, CV_LSETUP_FAIL, "CVODES", "CVode", + MSGCV_SETUP_FAILED, cv_mem->cv_tn); + break; + case CV_LSOLVE_FAIL: + cvProcessError(cv_mem, CV_LSOLVE_FAIL, "CVODES", "CVode", + MSGCV_SOLVE_FAILED, cv_mem->cv_tn); + break; + case CV_RHSFUNC_FAIL: + cvProcessError(cv_mem, CV_RHSFUNC_FAIL, "CVODES", "CVode", + MSGCV_RHSFUNC_FAILED, cv_mem->cv_tn); + break; + case CV_UNREC_RHSFUNC_ERR: + cvProcessError(cv_mem, CV_UNREC_RHSFUNC_ERR, "CVODES", "CVode", + MSGCV_RHSFUNC_UNREC, cv_mem->cv_tn); + break; + case CV_REPTD_RHSFUNC_ERR: + cvProcessError(cv_mem, CV_REPTD_RHSFUNC_ERR, "CVODES", "CVode", + MSGCV_RHSFUNC_REPTD, cv_mem->cv_tn); + break; + case CV_RTFUNC_FAIL: + cvProcessError(cv_mem, CV_RTFUNC_FAIL, "CVODES", "CVode", + MSGCV_RTFUNC_FAILED, cv_mem->cv_tn); + break; + case CV_QRHSFUNC_FAIL: + cvProcessError(cv_mem, CV_QRHSFUNC_FAIL, "CVODES", "CVode", + MSGCV_QRHSFUNC_FAILED, cv_mem->cv_tn); + break; + case CV_UNREC_QRHSFUNC_ERR: + cvProcessError(cv_mem, CV_UNREC_QRHSFUNC_ERR, "CVODES", "CVode", + MSGCV_QRHSFUNC_UNREC, cv_mem->cv_tn); + break; + case CV_REPTD_QRHSFUNC_ERR: + cvProcessError(cv_mem, CV_REPTD_QRHSFUNC_ERR, "CVODES", "CVode", + MSGCV_QRHSFUNC_REPTD, cv_mem->cv_tn); + break; + case CV_SRHSFUNC_FAIL: + cvProcessError(cv_mem, CV_SRHSFUNC_FAIL, "CVODES", "CVode", + MSGCV_SRHSFUNC_FAILED, cv_mem->cv_tn); + break; + case CV_UNREC_SRHSFUNC_ERR: + cvProcessError(cv_mem, CV_UNREC_SRHSFUNC_ERR, "CVODES", "CVode", + MSGCV_SRHSFUNC_UNREC, cv_mem->cv_tn); + break; + case CV_REPTD_SRHSFUNC_ERR: + cvProcessError(cv_mem, CV_REPTD_SRHSFUNC_ERR, "CVODES", "CVode", + MSGCV_SRHSFUNC_REPTD, cv_mem->cv_tn); + break; + case CV_QSRHSFUNC_FAIL: + cvProcessError(cv_mem, CV_QSRHSFUNC_FAIL, "CVODES", "CVode", + MSGCV_QSRHSFUNC_FAILED, cv_mem->cv_tn); + break; + case CV_UNREC_QSRHSFUNC_ERR: + cvProcessError(cv_mem, CV_UNREC_QSRHSFUNC_ERR, "CVODES", "CVode", + MSGCV_QSRHSFUNC_UNREC, cv_mem->cv_tn); + break; + case CV_REPTD_QSRHSFUNC_ERR: + cvProcessError(cv_mem, CV_REPTD_QSRHSFUNC_ERR, "CVODES", "CVode", + MSGCV_QSRHSFUNC_REPTD, cv_mem->cv_tn); + break; + case CV_TOO_CLOSE: + cvProcessError(cv_mem, CV_TOO_CLOSE, "CVODES", "CVode", + MSGCV_TOO_CLOSE); + break; + case CV_MEM_NULL: + 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); + break; + case CV_NLS_SETUP_FAIL: + 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); + default: + return(CV_SUCCESS); + } + + return(flag); +} + +/* + * ----------------------------------------------------------------- + * Functions for BDF Stability Limit Detection + * ----------------------------------------------------------------- + */ + +/* + * cvBDFStab + * + * This routine handles the BDF Stability Limit Detection Algorithm + * STALD. It is called if lmm = CV_BDF and the SLDET option is on. + * If the order is 3 or more, the required norm data is saved. + * If a decision to reduce order has not already been made, and + * enough data has been saved, cvSLdet is called. If it signals + * a stability limit violation, the order is reduced, and the step + * size is reset accordingly. + */ + +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. */ + + if (cv_mem->cv_q >= 3) { + for (k = 1; k <= 3; k++) + for (i = 5; i >= 2; i--) + cv_mem->cv_ssdat[i][k] = cv_mem->cv_ssdat[i-1][k]; + factorial = 1; + for (i = 1; i <= cv_mem->cv_q-1; i++) factorial *= i; + sq = factorial * cv_mem->cv_q * (cv_mem->cv_q+1) * + 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); + 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, + nscon >= q+5, then call stability limit detection routine. */ + + if ( (cv_mem->cv_q >= 3) && (cv_mem->cv_nscon >= cv_mem->cv_q+5) ) { + ldflag = cvSLdet(cv_mem); + if (ldflag > 3) { + /* A stability limit violation is indicated by + 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 = 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_nor = cv_mem->cv_nor + 1; + } + } + } + else { + /* Otherwise, let order increase happen, and + reset stability limit counter, nscon. */ + cv_mem->cv_nscon = 0; + } +} + +/* + * cvSLdet + * + * 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", + * 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. + * + * Returned values: + * kflag = 1 -> Found stable characteristic root, normal matrix case + * kflag = 2 -> Found stable characteristic root, quartic solution + * kflag = 3 -> Found stable characteristic root, quartic solution, + * with Newton correction + * kflag = 4 -> Found stability violation, normal matrix case + * kflag = 5 -> Found stability violation, quartic solution + * kflag = 6 -> Found stability violation, quartic solution, + * with Newton correction + * + * 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 = -5 -> R value from quartics not consistent. + * kflag = -6 -> No corrected root passes test on qk values + * kflag = -7 -> Trouble solving for sigsq. + * kflag = -8 -> Trouble solving for B, or R via B. + * kflag = -9 -> R via sigsq[k] disagrees with R from data. + */ + +static int cvSLdet(CVodeMem cv_mem) +{ + int i, k, j, it, kmin = 0, kflag = 0; + realtype rat[5][4], rav[4], qkr[4], sigsq[4], smax[4], ssmax[4]; + realtype drr[4], rrc[4],sqmx[4], qjk[4][4], vrat[5], qc[6][4], qco[6][4]; + realtype rr, rrcut, vrrtol, vrrt2, sqtol, rrtol; + 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 ratp, ratm, qfac1, qfac2, bb, rrb; + + /* The following are cutoffs and tolerances used by this routine */ + + rrcut = RCONST(0.98); + vrrtol = RCONST(1.0e-4); + vrrt2 = RCONST(5.0e-4); + sqtol = RCONST(1.0e-3); + rrtol = RCONST(1.0e-2); + + rr = ZERO; + + /* Index k corresponds to the degree of the interpolating polynomial. */ + /* k = 1 -> q-1 */ + /* k = 2 -> q */ + /* k = 3 -> q+1 */ + + /* Index i is a backward-in-time index, i = 1 -> current time, */ + /* i = 2 -> previous step, etc */ + + /* get maxima, minima, and variances, and form quartic coefficients */ + + 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; + return(kflag); + } + smax[k] = smaxk; + ssmax[k] = smaxk*smaxk; + + 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]; + 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]); + + qc[5][k] = cv_mem->cv_ssdat[1][k] * cv_mem->cv_ssdat[3][k] - + cv_mem->cv_ssdat[2][k] * cv_mem->cv_ssdat[2][k]; + qc[4][k] = cv_mem->cv_ssdat[2][k] * cv_mem->cv_ssdat[3][k] - + cv_mem->cv_ssdat[1][k] * cv_mem->cv_ssdat[4][k]; + qc[3][k] = ZERO; + qc[2][k] = cv_mem->cv_ssdat[2][k] * cv_mem->cv_ssdat[5][k] - + cv_mem->cv_ssdat[3][k] * cv_mem->cv_ssdat[4][k]; + 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++) { + 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; + return(kflag); + } else { + rr = (rav[1] + rav[2] + rav[3])/THREE; + drrmax = ZERO; + for (k = 1;k<=3;k++) { + adrr = SUNRabs(rav[k] - rr); + drrmax = SUNMAX(drrmax, adrr); + } + if (drrmax > vrrt2) { kflag = -3; return(kflag); } + + kflag = 1; + + /* can compute charactistic root, drop to next section */ + } + + } else { + + /* use the quartics to get rr. */ + + if (SUNRabs(qco[1][1]) < TINY*ssmax[1]) { + kflag = -4; + return(kflag); + } + + tem = qco[1][2]/qco[1][1]; + for (i=2; i<=5; i++) { + qco[i][2] = qco[i][2] - tem*qco[i][1]; + } + + qco[1][2] = ZERO; + tem = qco[1][3]/qco[1][1]; + for (i=2; i<=5; i++) { + qco[i][3] = qco[i][3] - tem*qco[i][1]; + } + qco[1][3] = ZERO; + + if (SUNRabs(qco[2][2]) < TINY*ssmax[2]) { + kflag = -4; + return(kflag); + } + + tem = qco[2][3]/qco[2][2]; + for (i=3; i<=5; i++) { + qco[i][3] = qco[i][3] - tem*qco[i][2]; + } + + if (SUNRabs(qco[4][3]) < TINY*ssmax[3]) { + kflag = -4; + return(kflag); + } + + rr = -qco[5][3]/qco[4][3]; + + if (rr < TINY || rr > HUNDRED) { + kflag = -5; + return(kflag); + } + + for (k=1; k<=3; k++) + qkr[k] = qc[5][k] + rr*(qc[4][k] + rr*rr*(qc[2][k] + rr*qc[1][k])); + + sqmax = ZERO; + for (k=1; k<=3; k++) { + saqk = SUNRabs(qkr[k])/ssmax[k]; + if (saqk > sqmax) sqmax = saqk; + } + + if (sqmax < sqtol) { + kflag = 2; + + /* can compute charactistic root, drop to "given rr,etc" */ + + } else { + + /* do Newton corrections to improve rr. */ + + for (it=1; it<=3; it++) { + for (k=1; k<=3; k++) { + qp = qc[4][k] + rr*rr*(THREE*qc[2][k] + rr*FOUR*qc[1][k]); + 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]; + sqmaxk = ZERO; + for (j=1; j<=3; j++) { + 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; + } + + sqmin = sqmx[1] + ONE; + for (k=1; k<=3; k++) { + if (sqmx[k] < sqmin) { + 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; + } else { + for (j=1; j<=3; j++) { + qkr[j] = qjk[j][kmin]; + } + } + } /* end of Newton correction loop */ + + if (sqmin > sqtol) { + kflag = -6; + return(kflag); + } + } /* end of if (sqmax < sqtol) else */ + } /* end of if (vmin < vrrtol*vrrtol) else, quartics to get rr. */ + + /* 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; + rsc = cv_mem->cv_ssdat[3][k]*rr*rr; + rsd = cv_mem->cv_ssdat[4][k]*rr*rr*rr; + rd1a = rsa - rsb; + rd1b = rsb - rsc; + rd1c = rsc - rsd; + 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; + return(kflag); + } + 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 + * information, and checks whether g has a zero both at and very near + * the initial point of the IVP. + * + * This routine returns an int equal to: + * CV_RTFUNC_FAIL < 0 if the g function failed, or + * CV_SUCCESS = 0 otherwise. + */ + +static int cvRcheck1(CVodeMem cv_mem) +{ + int i, retval; + realtype smallh, hratio, tplus; + booleantype zroot; + + 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; + + /* Evaluate g at initial t and check for zero values. */ + retval = cv_mem->cv_gfun(cv_mem->cv_tlo, cv_mem->cv_zn[0], + cv_mem->cv_glo, cv_mem->cv_user_data); + cv_mem->cv_nge = 1; + if (retval != 0) return(CV_RTFUNC_FAIL); + + zroot = SUNFALSE; + for (i = 0; i < cv_mem->cv_nrtfn; i++) { + if (SUNRabs(cv_mem->cv_glo[i]) == ZERO) { + zroot = SUNTRUE; + cv_mem->cv_gactive[i] = SUNFALSE; + } + } + if (!zroot) return(CV_SUCCESS); + + /* Some g_i is zero at t0; look at g at t0+(small increment). */ + 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); + retval = cv_mem->cv_gfun(tplus, cv_mem->cv_y, + cv_mem->cv_ghi, cv_mem->cv_user_data); + cv_mem->cv_nge++; + if (retval != 0) return(CV_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 < cv_mem->cv_nrtfn; i++) { + if (!cv_mem->cv_gactive[i] && SUNRabs(cv_mem->cv_ghi[i]) != ZERO) { + cv_mem->cv_gactive[i] = SUNTRUE; + cv_mem->cv_glo[i] = cv_mem->cv_ghi[i]; + } + } + return(CV_SUCCESS); +} + +/* + * cvRcheck2 + * + * This routine checks for exact zeros of g at the last root found, + * if the last return was a root. It then checks for a close pair of + * zeros (an error condition), and for a new root at a nearby point. + * The array glo = g(tlo) at the left endpoint of the search interval + * is adjusted if necessary to assure that all g_i are nonzero + * there, before returning to do a root search in the interval. + * + * On entry, tlo = tretlast is the last value of tret returned by + * CVode. This may be the previous tn, the previous tout value, + * or the last root location. + * + * This routine returns an int equal to: + * CV_RTFUNC_FAIL < 0 if the g function failed, or + * CLOSERT = 3 if a close pair of zeros was found, or + * RTFOUND = 1 if a new zero of g was found near tlo, or + * CV_SUCCESS = 0 otherwise. + */ + +static int cvRcheck2(CVodeMem cv_mem) +{ + int i, retval; + realtype smallh, hratio, tplus; + booleantype zroot; + + if (cv_mem->cv_irfnd == 0) return(CV_SUCCESS); + + (void) CVodeGetDky(cv_mem, cv_mem->cv_tlo, 0, cv_mem->cv_y); + retval = cv_mem->cv_gfun(cv_mem->cv_tlo, cv_mem->cv_y, + cv_mem->cv_glo, cv_mem->cv_user_data); + cv_mem->cv_nge++; + 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++) { + if (!cv_mem->cv_gactive[i]) continue; + if (SUNRabs(cv_mem->cv_glo[i]) == ZERO) { + zroot = SUNTRUE; + cv_mem->cv_iroots[i] = 1; + } + } + if (!zroot) return(CV_SUCCESS); + + /* 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; + 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) { + hratio = smallh/cv_mem->cv_h; + N_VLinearSum(ONE, cv_mem->cv_y, hratio, cv_mem->cv_zn[1], cv_mem->cv_y); + } else { + (void) CVodeGetDky(cv_mem, tplus, 0, 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++; + if (retval != 0) return(CV_RTFUNC_FAIL); + + /* Check for close roots (error return), for a new zero at tlo+smallh, + and for a g_i that changed from zero to nonzero. */ + zroot = SUNFALSE; + for (i = 0; i < cv_mem->cv_nrtfn; i++) { + if (!cv_mem->cv_gactive[i]) continue; + if (SUNRabs(cv_mem->cv_ghi[i]) == ZERO) { + if (cv_mem->cv_iroots[i] == 1) return(CLOSERT); + zroot = SUNTRUE; + cv_mem->cv_iroots[i] = 1; + } else { + if (cv_mem->cv_iroots[i] == 1) + cv_mem->cv_glo[i] = cv_mem->cv_ghi[i]; + } + } + if (zroot) return(RTFOUND); + return(CV_SUCCESS); +} + +/* + * cvRcheck3 + * + * This routine interfaces to cvRootfind to look for a root of g + * between tlo and either tn or tout, whichever comes first. + * Only roots beyond tlo in the direction of integration are sought. + * + * This routine returns an int equal to: + * CV_RTFUNC_FAIL < 0 if the g function failed, or + * RTFOUND = 1 if a root of g was found, or + * CV_SUCCESS = 0 otherwise. + */ + +static int cvRcheck3(CVodeMem cv_mem) +{ + int i, ier, retval; + + /* Set thi = tn or tout, whichever comes first; set y = y(thi). */ + if (cv_mem->cv_taskc == CV_ONE_STEP) { + cv_mem->cv_thi = cv_mem->cv_tn; + N_VScale(ONE, cv_mem->cv_zn[0], cv_mem->cv_y); + } + 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; + N_VScale(ONE, cv_mem->cv_zn[0], cv_mem->cv_y); + } else { + cv_mem->cv_thi = cv_mem->cv_toutc; + (void) CVodeGetDky(cv_mem, cv_mem->cv_thi, 0, cv_mem->cv_y); + } + } + + /* Set ghi = g(thi) and call cvRootfind to search (tlo,thi) for roots. */ + retval = cv_mem->cv_gfun(cv_mem->cv_thi, cv_mem->cv_y, + cv_mem->cv_ghi, cv_mem->cv_user_data); + cv_mem->cv_nge++; + 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; + ier = cvRootfind(cv_mem); + if (ier == CV_RTFUNC_FAIL) return(CV_RTFUNC_FAIL); + for(i=0; i<cv_mem->cv_nrtfn; i++) { + if(!cv_mem->cv_gactive[i] && cv_mem->cv_grout[i] != ZERO) + cv_mem->cv_gactive[i] = SUNTRUE; + } + cv_mem->cv_tlo = cv_mem->cv_trout; + 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 (ier == CV_SUCCESS) return(CV_SUCCESS); + + /* If a root was found, interpolate to get y(trout) and return. */ + (void) CVodeGetDky(cv_mem, cv_mem->cv_trout, 0, cv_mem->cv_y); + return(RTFOUND); +} + +/* + * cvRootfind + * + * This routine solves for a root of g(t) between tlo and thi, if + * one exists. Only roots of odd multiplicity (i.e. with a change + * of sign in one of the g_i), or exact zeros, are found. + * Here the sign of tlo - thi is arbitrary, but if multiple roots + * are found, the one closest to tlo is returned. + * + * The method used is the Illinois algorithm, a modified secant method. + * Reference: Kathie L. Hiebert and Lawrence F. Shampine, Implicitly + * Defined Output Points for Solutions of ODEs, Sandia National + * Laboratory Report SAND80-0180, February 1980. + * + * This routine uses the following parameters for communication: + * + * nrtfn = number of functions g_i, or number of components of + * the vector-valued function g(t). Input only. + * + * gfun = user-defined function for g(t). Its form is + * (void) gfun(t, y, gt, user_data) + * + * rootdir = in array specifying the direction of zero-crossings. + * If rootdir[i] > 0, search for roots of g_i only if + * g_i is increasing; if rootdir[i] < 0, search for + * roots of g_i only if g_i is decreasing; otherwise + * always search for roots of g_i. + * + * gactive = array specifying whether a component of g should + * or should not be monitored. gactive[i] is initially + * 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 + * corresponding g function moves away from 0.0. + * + * nge = cumulative counter for gfun calls. + * + * ttol = a convergence tolerance for trout. Input only. + * When a root at trout is found, it is located only to + * within a tolerance of ttol. Typically, ttol should + * be set to a value on the order of + * 100 * UROUND * max (SUNRabs(tlo), SUNRabs(thi)) + * where UROUND is the unit roundoff of the machine. + * + * tlo, thi = endpoints of the interval in which roots are sought. + * On input, these must be distinct, but tlo - thi may + * be of either sign. The direction of integration is + * assumed to be from tlo to thi. On return, tlo and thi + * are the endpoints of the final relevant interval. + * + * glo, ghi = arrays of length nrtfn containing the vectors g(tlo) + * and g(thi) respectively. Input and output. On input, + * none of the glo[i] should be zero. + * + * trout = root location, if a root was found, or thi if not. + * Output only. If a root was found other than an exact + * zero of g, trout is the endpoint thi of the final + * interval bracketing the root, with size at most ttol. + * + * grout = array of length nrtfn containing g(trout) on return. + * + * iroots = int array of length nrtfn with root information. + * Output only. If a root was found, iroots indicates + * which components g_i have a root at trout. For + * i = 0, ..., nrtfn-1, iroots[i] = 1 if g_i has a root + * and g_i is increasing, iroots[i] = -1 if g_i has a + * root and g_i is decreasing, and iroots[i] = 0 if g_i + * has no roots or g_i varies in the direction opposite + * to that indicated by rootdir[i]. + * + * This routine returns an int equal to: + * CV_RTFUNC_FAIL < 0 if the g function failed, or + * RTFOUND = 1 if a root of g was found, or + * CV_SUCCESS = 0 otherwise. + */ + +static int cvRootfind(CVodeMem cv_mem) +{ + realtype alph, tmid, gfrac, maxfrac, fracint, fracsub; + int i, retval, imax, side, sideprev; + booleantype zroot, sgnchg; + + imax = 0; + + /* First check for change in sign in ghi or for a zero in ghi. */ + maxfrac = ZERO; + zroot = SUNFALSE; + sgnchg = SUNFALSE; + for (i = 0; i < cv_mem->cv_nrtfn; i++) { + if(!cv_mem->cv_gactive[i]) continue; + if (SUNRabs(cv_mem->cv_ghi[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_ghi[i] < ZERO) && + (cv_mem->cv_rootdir[i]*cv_mem->cv_glo[i] <= ZERO) ) { + gfrac = SUNRabs(cv_mem->cv_ghi[i]/(cv_mem->cv_ghi[i] - cv_mem->cv_glo[i])); + if (gfrac > maxfrac) { + sgnchg = SUNTRUE; + maxfrac = gfrac; + imax = i; + } + } + } + } + + /* 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 cv_mem->cv_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); +} + +/* + * ----------------------------------------------------------------- + * Functions for combined norms + * ----------------------------------------------------------------- + */ + +/* + * cvQuadUpdateNorm + * + * Updates the norm old_nrm to account for all quadratures. + */ + +static realtype cvQuadUpdateNorm(CVodeMem cv_mem, realtype old_nrm, + N_Vector xQ, N_Vector wQ) +{ + realtype qnrm; + + qnrm = N_VWrmsNorm(xQ, wQ); + if (old_nrm > qnrm) return(old_nrm); + else return(qnrm); +} + +/* + * cvSensNorm + * + * 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]) } + * + * Called by cvSensUpdateNorm or directly in the CV_STAGGERED approach + * during the NLS solution and before the error test. + */ + +realtype cvSensNorm(CVodeMem cv_mem, N_Vector *xS, N_Vector *wS) +{ + int is; + realtype nrm; + + (void) N_VWrmsNormVectorArray(cv_mem->cv_Ns, xS, wS, cv_mem->cv_cvals); + + nrm = cv_mem->cv_cvals[0]; + for (is=1; is<cv_mem->cv_Ns; is++) + if ( cv_mem->cv_cvals[is] > nrm ) nrm = cv_mem->cv_cvals[is]; + + return(nrm); +} + +/* + * cvSensUpdateNorm + * + * Updates the norm old_nrm to account for all sensitivities. + */ + +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); +} + +/* + * cvQuadSensNorm + * + * 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]) } + * + * Called by cvQuadSensUpdateNorm. + */ + +static realtype cvQuadSensNorm(CVodeMem cv_mem, N_Vector *xQS, N_Vector *wQS) +{ + int is; + realtype nrm; + + (void) N_VWrmsNormVectorArray(cv_mem->cv_Ns, xQS, wQS, cv_mem->cv_cvals); + + nrm = cv_mem->cv_cvals[0]; + for (is=1; is<cv_mem->cv_Ns; is++) + if ( cv_mem->cv_cvals[is] > nrm ) nrm = cv_mem->cv_cvals[is]; + + return(nrm); +} + +/* + * cvSensUpdateNorm + * + * Updates the norm old_nrm to account for all quadrature sensitivities. + */ + +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 + * ----------------------------------------------------------------- + */ + +/* + * 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) + * calls the fS1 routine in a loop over all sensitivities. + * + * CVSensRhs is called: + * (*) by CVode at the first step + * (*) by cvYddNorm if errcon=SUNTRUE + * (*) 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 + * + * The return value is that of the sensitivity RHS function fS, + * + */ + +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, + fScur, cv_mem->cv_fS_data, temp1, temp2); + cv_mem->cv_nfSe++; + } else { + for (is=0; is<cv_mem->cv_Ns; 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; + } + } + + return(retval); +} + +/* + * cvSensRhs1Wrapper + * + * cvSensRhs1Wrapper is a high level routine that returns right-hand + * 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 + * 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 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, + fScur, cv_mem->cv_fS_data, temp1, temp2); + cv_mem->cv_nfSe++; + + return(retval); +} + +/* + * ----------------------------------------------------------------- + * Internal DQ approximations for sensitivity RHS + * ----------------------------------------------------------------- + */ + +/* Undefine Readibility Constants */ + +#undef y + +/* + * cvSensRhsInternalDQ - internal CVSensRhsFn + * + * cvSensRhsInternalDQ computes right hand side of all sensitivity equations + * by finite differences + */ + +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; is<Ns; is++) { + retval = cvSensRhs1InternalDQ(Ns, t, y, ydot, is, yS[is], + ySdot[is], cvode_mem, ytemp, ftemp); + if (retval!=0) return(retval); + } + + return(0); +} + +/* + * cvSensRhs1InternalDQ - internal CVSensRhs1Fn + * + * cvSensRhs1InternalDQ computes the right hand side of the is-th sensitivity + * equation by finite differences + * + * cvSensRhs1InternalDQ returns 0 if successful. Otherwise it returns the + * non-zero return value from f(). + */ + +int cvSensRhs1InternalDQ(int Ns, realtype t, + N_Vector y, N_Vector ydot, + int is, N_Vector yS, N_Vector ySdot, + void *cvode_mem, + N_Vector ytemp, N_Vector ftemp) +{ + CVodeMem cv_mem; + int retval, method; + int nfel = 0, which; + realtype psave, pbari; + realtype delta , rdelta; + realtype Deltap, rDeltap, r2Deltap; + realtype Deltay, rDeltay, r2Deltay; + realtype Delta , rDelta , r2Delta ; + realtype norms, ratio; + + /* local variables for fused vector operations */ + realtype cvals[3]; + N_Vector Xvecs[3]; + + /* cvode_mem is passed here as user data */ + cv_mem = (CVodeMem) cvode_mem; + + delta = SUNRsqrt(SUNMAX(cv_mem->cv_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; + } else { + /* switch between simultaneous/separate DQ */ + ratio = Deltay * rDeltap; + if ( SUNMAX(ONE/ratio, ratio) <= cv_mem->cv_DQrhomax ) + method = (cv_mem->cv_DQtype==CV_CENTERED) ? CENTERED1 : FORWARD1; + else + method = (cv_mem->cv_DQtype==CV_CENTERED) ? CENTERED2 : FORWARD2; + } + + 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; + + retval = cv_mem->cv_f(t, ytemp, ftemp, cv_mem->cv_user_data); + nfel++; + 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); + nfel++; + if (retval != 0) return(retval); + + N_VLinearSum(ONE,y,-Deltay,yS,ytemp); + + retval = cv_mem->cv_f(t, ytemp, ftemp, cv_mem->cv_user_data); + nfel++; + 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++; + if (retval != 0) return(retval); + + cv_mem->cv_p[which] = psave - Deltap; + 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; + cvals[2] = -r2Deltap; Xvecs[2] = ftemp; + + retval = N_VLinearCombination(3, cvals, Xvecs, ySdot); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + + 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); + nfel++; + 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++; + if (retval != 0) return(retval); + + /* ySdot = ySdot + rDeltap * ytemp - rDeltap * ydot */ + cvals[0] = ONE; Xvecs[0] = ySdot; + cvals[1] = rDeltap; Xvecs[1] = ytemp; + cvals[2] = -rDeltap; Xvecs[2] = ydot; + + retval = N_VLinearCombination(3, cvals, Xvecs, ySdot); + if (retval != CV_SUCCESS) return (CV_VECTOROP_ERR); + + break; + + } + + cv_mem->cv_p[which] = psave; + + /* Increment counter nfeS */ + cv_mem->cv_nfeS += nfel; + + return(0); +} + + +/* + * cvQuadSensRhsInternalDQ - internal CVQuadSensRhsFn + * + * cvQuadSensRhsInternalDQ computes right hand side of all quadrature + * sensitivity equations by finite differences. All work is actually + * done in cvQuadSensRhs1InternalDQ. + */ + +static int cvQuadSensRhsInternalDQ(int Ns, realtype t, + N_Vector y, N_Vector *yS, + N_Vector yQdot, N_Vector *yQSdot, + 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; is<Ns; is++) { + retval = cvQuadSensRhs1InternalDQ(cv_mem, is, t, + y, yS[is], + yQdot, yQSdot[is], + tmp, tmpQ); + if (retval!=0) return(retval); + } + + return(0); +} + +static int cvQuadSensRhs1InternalDQ(CVodeMem cv_mem, int is, realtype t, + N_Vector y, N_Vector yS, + N_Vector yQdot, N_Vector yQSdot, + N_Vector tmp, N_Vector tmpQ) +{ + int retval, method; + int nfel = 0, which; + realtype psave, pbari; + realtype delta , rdelta; + realtype Deltap; + realtype Deltay, rDeltay; + realtype Delta , rDelta , r2Delta ; + realtype norms; + + delta = SUNRsqrt(SUNMAX(cv_mem->cv_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; + + retval = cv_mem->cv_fQ(t, tmp, tmpQ, cv_mem->cv_user_data); + nfel++; + 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 + * ----------------------------------------------------------------- + */ + +/* + * 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 + * pointed to by cv_ehfun. + */ + +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 + (msgfmt is the last required argument to cvProcessError) */ + + va_start(ap, msgfmt); + + /* Compose the message */ + + vsprintf(msg, msgfmt, ap); + + if (cv_mem == NULL) { /* We write to stderr */ +#ifndef NO_FPRINTF_OUTPUT + fprintf(stderr, "\n[%s ERROR] %s\n ", module, fname); + fprintf(stderr, "%s\n\n", msg); +#endif + + } else { /* We can call ehfun */ + cv_mem->cv_ehfun(error_code, module, fname, msg, cv_mem->cv_eh_data); + } + + /* Finalize argument processing */ + va_end(ap); + + return; +} + +/* + * cvErrHandler is the default error handling function. + * It sends the error message to the stream pointed to by cv_errfp. + */ + +void cvErrHandler(int error_code, const char *module, + const char *function, char *msg, void *data) +{ + CVodeMem cv_mem; + char err_type[10]; + + /* data points to cv_mem here */ + + cv_mem = (CVodeMem) data; + + if (error_code == CV_WARNING) + sprintf(err_type,"WARNING"); + else + sprintf(err_type,"ERROR"); + +#ifndef NO_FPRINTF_OUTPUT + if (cv_mem->cv_errfp!=NULL) { + fprintf(cv_mem->cv_errfp,"\n[%s %s] %s\n",module,err_type,function); + fprintf(cv_mem->cv_errfp," %s\n\n",msg); + } +#endif + + return; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_bandpre.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_bandpre.c new file mode 100644 index 0000000..844754c --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_bandpre.c @@ -0,0 +1,623 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * Radu Serban 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 file contains implementations of the banded difference + * quotient Jacobian-based preconditioner and solver routines for + * use with the CVSLS linear solver interface. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "cvodes_impl.h" +#include "cvodes_bandpre_impl.h" +#include "cvodes_ls_impl.h" +#include <sundials/sundials_math.h> + +#define MIN_INC_MULT RCONST(1000.0) +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) +#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, + realtype gamma, void *bp_data); +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); + +/* Prototype for cvBandPrecFree */ +static int cvBandPrecFree(CVodeMem cv_mem); + +/* Prototype for difference quotient Jacobian calculation routine */ +static int cvBandPrecDQJac(CVBandPrecData pdata, realtype t, N_Vector y, + N_Vector fy, N_Vector ftemp, N_Vector ytemp); + + +/*================================================================ + PART I - Forward Problems + ================================================================*/ + +/*----------------------------------------------------------------- + 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 + N_VGetArrayPointer exists. + -----------------------------------------------------------------*/ +int CVBandPrecInit(void *cvode_mem, sunindextype N, + sunindextype mu, sunindextype ml) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + CVBandPrecData pdata; + sunindextype mup, mlp, storagemu; + int flag; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVSBANDPRE", + "CVBandPrecInit", MSGBP_MEM_NULL); + return(CVLS_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Test if the CVSLS linear solver interface has been attached */ + if (cv_mem->cv_lmem == NULL) { + cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVSBANDPRE", + "CVBandPrecInit", MSGBP_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + /* Test compatibility of NVECTOR package with the BAND preconditioner */ + if(cv_mem->cv_tempv->ops->nvgetarraypointer == NULL) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVSBANDPRE", + "CVBandPrecInit", MSGBP_BAD_NVECTOR); + return(CVLS_ILL_INPUT); + } + + /* Allocate data memory */ + pdata = NULL; + pdata = (CVBandPrecData) malloc(sizeof *pdata); + if (pdata == NULL) { + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBANDPRE", + "CVBandPrecInit", MSGBP_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + + /* Load pointers and bandwidths into pdata block. */ + pdata->cvode_mem = cvode_mem; + pdata->N = N; + pdata->mu = mup = SUNMIN(N-1, SUNMAX(0,mu)); + pdata->ml = mlp = SUNMIN(N-1, SUNMAX(0,ml)); + + /* Initialize nfeBP counter */ + pdata->nfeBP = 0; + + /* Allocate memory for saved banded Jacobian approximation. */ + pdata->savedJ = NULL; + pdata->savedJ = SUNBandMatrixStorage(N, mup, mlp, mup); + if (pdata->savedJ == NULL) { + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBANDPRE", + "CVBandPrecInit", MSGBP_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + + /* Allocate memory for banded preconditioner. */ + storagemu = SUNMIN(N-1, mup+mlp); + pdata->savedP = NULL; + pdata->savedP = SUNBandMatrixStorage(N, mup, mlp, storagemu); + if (pdata->savedP == NULL) { + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBANDPRE", + "CVBandPrecInit", MSGBP_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + + /* Allocate memory for banded linear solver */ + pdata->LS = NULL; + pdata->LS = SUNLinSol_Band(cv_mem->cv_tempv, pdata->savedP); + if (pdata->LS == NULL) { + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBANDPRE", + "CVBandPrecInit", MSGBP_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + + /* allocate memory for temporary N_Vectors */ + pdata->tmp1 = NULL; + pdata->tmp1 = N_VClone(cv_mem->cv_tempv); + if (pdata->tmp1 == NULL) { + SUNLinSolFree(pdata->LS); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBANDPRE", + "CVBandPrecInit", MSGBP_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + pdata->tmp2 = NULL; + pdata->tmp2 = N_VClone(cv_mem->cv_tempv); + if (pdata->tmp2 == NULL) { + SUNLinSolFree(pdata->LS); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + N_VDestroy(pdata->tmp1); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBANDPRE", + "CVBandPrecInit", MSGBP_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + + /* initialize band linear solver object */ + flag = SUNLinSolInitialize(pdata->LS); + if (flag != SUNLS_SUCCESS) { + SUNLinSolFree(pdata->LS); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + N_VDestroy(pdata->tmp1); + N_VDestroy(pdata->tmp2); + free(pdata); pdata = NULL; + 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); + + /* Point to the new P_data field in the LS memory */ + cvls_mem->P_data = pdata; + + /* Attach the pfree function */ + cvls_mem->pfree = cvBandPrecFree; + + /* Attach preconditioner solve and setup functions */ + flag = CVodeSetPreconditioner(cvode_mem, cvBandPrecSetup, + cvBandPrecSolve); + return(flag); +} + + +int CVBandPrecGetWorkSpace(void *cvode_mem, long int *lenrwBP, + long int *leniwBP) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + CVBandPrecData pdata; + sunindextype lrw1, liw1; + long int lrw, liw; + int flag; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVSBANDPRE", + "CVBandPrecGetWorkSpace", MSGBP_MEM_NULL); + return(CVLS_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + if (cv_mem->cv_lmem == NULL) { + cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVSBANDPRE", + "CVBandPrecGetWorkSpace", MSGBP_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + if (cvls_mem->P_data == NULL) { + 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 */ + *leniwBP = 4; + *lenrwBP = 0; + if (cv_mem->cv_tempv->ops->nvspace) { + N_VSpace(cv_mem->cv_tempv, &lrw1, &liw1); + *leniwBP += 2*liw1; + *lenrwBP += 2*lrw1; + } + if (pdata->savedJ->ops->space) { + flag = SUNMatSpace(pdata->savedJ, &lrw, &liw); + if (flag != 0) return(-1); + *leniwBP += liw; + *lenrwBP += lrw; + } + if (pdata->savedP->ops->space) { + flag = SUNMatSpace(pdata->savedP, &lrw, &liw); + if (flag != 0) return(-1); + *leniwBP += liw; + *lenrwBP += lrw; + } + if (pdata->LS->ops->space) { + flag = SUNLinSolSpace(pdata->LS, &lrw, &liw); + if (flag != 0) return(-1); + *leniwBP += liw; + *lenrwBP += lrw; + } + + return(CVLS_SUCCESS); +} + + +int CVBandPrecGetNumRhsEvals(void *cvode_mem, long int *nfevalsBP) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + CVBandPrecData pdata; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVSBANDPRE", + "CVBandPrecGetNumRhsEvals", MSGBP_MEM_NULL); + return(CVLS_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + if (cv_mem->cv_lmem == NULL) { + cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVSBANDPRE", + "CVBandPrecGetNumRhsEvals", MSGBP_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + if (cvls_mem->P_data == NULL) { + cvProcessError(cv_mem, CVLS_PMEM_NULL, "CVSBANDPRE", + "CVBandPrecGetNumRhsEvals", MSGBP_PMEM_NULL); + return(CVLS_PMEM_NULL); + } + pdata = (CVBandPrecData) cvls_mem->P_data; + + *nfevalsBP = pdata->nfeBP; + + return(CVLS_SUCCESS); +} + + +/*----------------------------------------------------------------- + cvBandPrecSetup + ----------------------------------------------------------------- + Together cvBandPrecSetup and cvBandPrecSolve use a banded + 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 + from scratch. + jok == SUNTRUE means that Jacobian data from the + previous PrecSetup call will be reused + (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, + 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; + cv_mem = (CVodeMem) pdata->cvode_mem; + + if (jok) { + + /* If jok = SUNTRUE, use saved copy of J. */ + *jcurPtr = SUNFALSE; + retval = SUNMatCopy(pdata->savedJ, pdata->savedP); + if (retval < 0) { + cvProcessError(cv_mem, -1, "CVBANDPRE", + "cvBandPrecSetup", MSGBP_SUNMAT_FAIL); + return(-1); + } + if (retval > 0) { + return(1); + } + + } else { + + /* If jok = SUNFALSE, call CVBandPDQJac for new J value. */ + *jcurPtr = SUNTRUE; + retval = SUNMatZero(pdata->savedJ); + if (retval < 0) { + cvProcessError(cv_mem, -1, "CVBANDPRE", + "cvBandPrecSetup", MSGBP_SUNMAT_FAIL); + return(-1); + } + if (retval > 0) { + return(1); + } + + retval = cvBandPrecDQJac(pdata, t, y, fy, + pdata->tmp1, pdata->tmp2); + if (retval < 0) { + cvProcessError(cv_mem, -1, "CVBANDPRE", + "cvBandPrecSetup", MSGBP_RHSFUNC_FAILED); + return(-1); + } + if (retval > 0) { + return(1); + } + + retval = SUNMatCopy(pdata->savedJ, pdata->savedP); + if (retval < 0) { + cvProcessError(cv_mem, -1, "CVBANDPRE", + "cvBandPrecSetup", MSGBP_SUNMAT_FAIL); + return(-1); + } + if (retval > 0) { + return(1); + } + + } + + /* Scale and add identity to get savedP = I - gamma*J. */ + retval = SUNMatScaleAddI(-gamma, pdata->savedP); + if (retval) { + 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); +} + + +/*----------------------------------------------------------------- + cvBandPrecSolve + ----------------------------------------------------------------- + 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, + realtype delta, int lr, void *bp_data) +{ + CVBandPrecData pdata; + int retval; + + /* Assume matrix and lpivots have already been allocated. */ + pdata = (CVBandPrecData) bp_data; + + /* Call banded solver object to do the work */ + retval = SUNLinSolSolve(pdata->LS, pdata->savedP, z, r, ZERO); + return(retval); +} + + +static int cvBandPrecFree(CVodeMem cv_mem) +{ + CVLsMem cvls_mem; + CVBandPrecData 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 = (CVBandPrecData) cvls_mem->P_data; + + SUNLinSolFree(pdata->LS); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + N_VDestroy(pdata->tmp1); + N_VDestroy(pdata->tmp2); + + free(pdata); + pdata = NULL; + + return(0); +} + + +/*----------------------------------------------------------------- + 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 + 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 + in succession. + -----------------------------------------------------------------*/ +static int cvBandPrecDQJac(CVBandPrecData pdata, realtype t, N_Vector y, + N_Vector fy, N_Vector ftemp, N_Vector ytemp) +{ + CVodeMem cv_mem; + 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; + realtype *y_data, *ytemp_data, *cns_data; + int retval; + + cv_mem = (CVodeMem) pdata->cvode_mem; + + /* Obtain pointers to the data for ewt, fy, ftemp, y, ytemp. */ + ewt_data = N_VGetArrayPointer(cv_mem->cv_ewt); + fy_data = N_VGetArrayPointer(fy); + 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); + + /* Load ytemp with y = predicted y vector. */ + N_VScale(ONE, y, ytemp); + + /* Set minimum increment based on uround and norm of f. */ + srur = SUNRsqrt(cv_mem->cv_uround); + fnorm = N_VWrmsNorm(fy, cv_mem->cv_ewt); + minInc = (fnorm != ZERO) ? + (MIN_INC_MULT * SUNRabs(cv_mem->cv_h) * cv_mem->cv_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 (cv_mem->cv_constraints != NULL) { + 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 f with incremented y. */ + retval = cv_mem->cv_f(t, ytemp, ftemp, cv_mem->cv_user_data); + pdata->nfeBP++; + if (retval != 0) return(retval); + + /* 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 (cv_mem->cv_constraints != NULL) { + 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); + for (i=i1; i <= i2; i++) + SM_COLUMN_ELEMENT_B(col_j,i,j) = inc_inv * (ftemp_data[i] - fy_data[i]); + } + } + + return(0); +} + + +/*================================================================ + PART II - Backward Problems + ================================================================*/ + +/*--------------------------------------------------------------- + User-Callable initialization function: wrapper for the backward + phase around the corresponding CVODES functions + ---------------------------------------------------------------*/ +int CVBandPrecInitB(void *cvode_mem, int which, sunindextype nB, + sunindextype muB, sunindextype mlB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + int flag; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVSBANDPRE", + "CVBandPrecInitB", MSGBP_MEM_NULL); + return(CVLS_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CVLS_NO_ADJ, "CVSBANDPRE", + "CVBandPrecInitB", MSGBP_NO_ADJ); + return(CVLS_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + /* Check which */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVSBANDPRE", + "CVBandPrecInitB", MSGBP_BAD_WHICH); + return(CVLS_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + /* advance */ + cvB_mem = cvB_mem->cv_next; + } + /* cv_mem corresponding to 'which' problem. */ + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + /* 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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_bandpre_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_bandpre_impl.h new file mode 100644 index 0000000..de1b147 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_bandpre_impl.h @@ -0,0 +1,77 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 + * ----------------------------------------------------------------- + * Implementation header file for the CVSBANDPRE module. + * ----------------------------------------------------------------- + */ + +#ifndef _CVSBANDPRE_IMPL_H +#define _CVSBANDPRE_IMPL_H + +#include <cvodes/cvodes_bandpre.h> +#include <sunmatrix/sunmatrix_band.h> +#include <sunlinsol/sunlinsol_band.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*----------------------------------------------------------------- + Type: CVBandPrecData + -----------------------------------------------------------------*/ + +typedef struct CVBandPrecDataRec { + + /* Data set by user in CVBandPrecInit */ + sunindextype N; + sunindextype ml, mu; + + /* Data set by CVBandPrecSetup */ + SUNMatrix savedJ; + SUNMatrix savedP; + SUNLinearSolver LS; + N_Vector tmp1; + N_Vector tmp2; + + /* Rhs calls */ + long int nfeBP; + + /* Pointer to cvode_mem */ + void *cvode_mem; + +} *CVBandPrecData; + + +/*----------------------------------------------------------------- + CVBANDPRE error messages + -----------------------------------------------------------------*/ + +#define MSGBP_MEM_NULL "Integrator memory is NULL." +#define MSGBP_LMEM_NULL "Linear solver memory is NULL. One of the SPILS linear solvers must be attached." +#define MSGBP_MEM_FAIL "A memory request failed." +#define MSGBP_BAD_NVECTOR "A required vector operation is not implemented." +#define MSGBP_SUNMAT_FAIL "An error arose from a SUNBandMatrix routine." +#define MSGBP_SUNLS_FAIL "An error arose from a SUNBandLinearSolver routine." +#define MSGBP_PMEM_NULL "Band preconditioner memory is NULL. CVBandPrecInit must be called." +#define MSGBP_RHSFUNC_FAILED "The right-hand side routine failed in an unrecoverable manner." + +#define MSGBP_NO_ADJ "Illegal attempt to call before calling CVodeAdjInit." +#define MSGBP_BAD_WHICH "Illegal value for parameter which." + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_bbdpre.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_bbdpre.c new file mode 100644 index 0000000..65ac4fe --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_bbdpre.c @@ -0,0 +1,912 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * Radu Serban 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 file contains implementations of routines for a + * band-block-diagonal preconditioner, i.e. a block-diagonal + * matrix with banded blocks, for use with CVODE, the CVSLS linear + * solver interface, and the MPI-parallel implementation of NVECTOR. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "cvodes_impl.h" +#include "cvodes_bbdpre_impl.h" +#include "cvodes_ls_impl.h" +#include <sundials/sundials_math.h> +#include <nvector/nvector_serial.h> + +#define MIN_INC_MULT RCONST(1000.0) +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) +#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, + realtype gamma, void *bbd_data); +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); + +/* Prototype for cvBBDPrecFree */ +static int cvBBDPrecFree(CVodeMem cv_mem); + +/* Wrapper functions for adjoint code */ +static int cvGlocWrapper(sunindextype NlocalB, realtype t, + 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, + N_Vector ytemp, N_Vector gtemp); + +/* Prototype for the backward pfree routine */ +static int CVBBDPrecFreeB(CVodeBMem cvB_mem); + + +/*================================================================ + PART I - forward problems + ================================================================*/ + +/*----------------------------------------------------------------- + User-Callable Functions: initialization, reinit and free + -----------------------------------------------------------------*/ +int CVBBDPrecInit(void *cvode_mem, sunindextype Nlocal, + sunindextype mudq, sunindextype mldq, + sunindextype mukeep, sunindextype mlkeep, + realtype dqrely, CVLocalFn gloc, CVCommFn cfn) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + CVBBDPrecData pdata; + sunindextype muk, mlk, storage_mu, lrw1, liw1; + long int lrw, liw; + int flag; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVSBBDPRE", + "CVBBDPrecInit", MSGBBD_MEM_NULL); + return(CVLS_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Test if the CVSLS linear solver interface has been created */ + if (cv_mem->cv_lmem == NULL) { + cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVSBBDPRE", + "CVBBDPrecInit", MSGBBD_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + /* Test compatibility of NVECTOR package with the BBD preconditioner */ + if(cv_mem->cv_tempv->ops->nvgetarraypointer == NULL) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVSBBDPRE", + "CVBBDPrecInit", MSGBBD_BAD_NVECTOR); + return(CVLS_ILL_INPUT); + } + + /* Allocate data memory */ + pdata = NULL; + pdata = (CVBBDPrecData) malloc(sizeof *pdata); + if (pdata == NULL) { + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", + "CVBBDPrecInit", MSGBBD_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + + /* Set pointers to gloc and cfn; load half-bandwidths */ + pdata->cvode_mem = cvode_mem; + pdata->gloc = gloc; + pdata->cfn = cfn; + pdata->mudq = SUNMIN(Nlocal-1, SUNMAX(0,mudq)); + pdata->mldq = SUNMIN(Nlocal-1, SUNMAX(0,mldq)); + muk = SUNMIN(Nlocal-1, SUNMAX(0,mukeep)); + mlk = SUNMIN(Nlocal-1, SUNMAX(0,mlkeep)); + pdata->mukeep = muk; + pdata->mlkeep = mlk; + + /* Allocate memory for saved Jacobian */ + pdata->savedJ = SUNBandMatrixStorage(Nlocal, muk, mlk, muk); + if (pdata->savedJ == NULL) { + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", + "CVBBDPrecInit", MSGBBD_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + + /* Allocate memory for preconditioner matrix */ + storage_mu = SUNMIN(Nlocal-1, muk + mlk); + pdata->savedP = NULL; + pdata->savedP = SUNBandMatrixStorage(Nlocal, muk, mlk, storage_mu); + if (pdata->savedP == NULL) { + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", + "CVBBDPrecInit", MSGBBD_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + + /* Allocate memory for temporary N_Vectors */ + pdata->zlocal = NULL; + pdata->zlocal = N_VNewEmpty_Serial(Nlocal); + if (pdata->zlocal == NULL) { + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", + "CVBBDPrecInit", MSGBBD_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + pdata->rlocal = NULL; + pdata->rlocal = N_VNewEmpty_Serial(Nlocal); + if (pdata->rlocal == NULL) { + N_VDestroy(pdata->zlocal); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", + "CVBBDPrecInit", MSGBBD_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + pdata->tmp1 = NULL; + pdata->tmp1 = N_VClone(cv_mem->cv_tempv); + if (pdata->tmp1 == NULL) { + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", + "CVBBDPrecInit", MSGBBD_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + pdata->tmp2 = NULL; + pdata->tmp2 = N_VClone(cv_mem->cv_tempv); + if (pdata->tmp2 == NULL) { + N_VDestroy(pdata->tmp1); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", + "CVBBDPrecInit", MSGBBD_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + pdata->tmp3 = NULL; + pdata->tmp3 = N_VClone(cv_mem->cv_tempv); + if (pdata->tmp3 == NULL) { + N_VDestroy(pdata->tmp1); + N_VDestroy(pdata->tmp2); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", + "CVBBDPrecInit", MSGBBD_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + + /* Allocate memory for banded linear solver */ + pdata->LS = NULL; + pdata->LS = SUNLinSol_Band(pdata->rlocal, pdata->savedP); + if (pdata->LS == NULL) { + N_VDestroy(pdata->tmp1); + N_VDestroy(pdata->tmp2); + N_VDestroy(pdata->tmp3); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", + "CVBBDPrecInit", MSGBBD_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + + /* initialize band linear solver object */ + flag = SUNLinSolInitialize(pdata->LS); + if (flag != SUNLS_SUCCESS) { + N_VDestroy(pdata->tmp1); + N_VDestroy(pdata->tmp2); + N_VDestroy(pdata->tmp3); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + SUNLinSolFree(pdata->LS); + free(pdata); pdata = NULL; + cvProcessError(cv_mem, CVLS_SUNLS_FAIL, "CVSBBDPRE", + "CVBBDPrecInit", MSGBBD_SUNLS_FAIL); + return(CVLS_SUNLS_FAIL); + } + + /* Set pdata->dqrely based on input dqrely (0 implies default). */ + pdata->dqrely = (dqrely > ZERO) ? + dqrely : SUNRsqrt(cv_mem->cv_uround); + + /* Store Nlocal to be used in CVBBDPrecSetup */ + pdata->n_local = Nlocal; + + /* Set work space sizes and initialize nge */ + pdata->rpwsize = 0; + pdata->ipwsize = 0; + if (cv_mem->cv_tempv->ops->nvspace) { + N_VSpace(cv_mem->cv_tempv, &lrw1, &liw1); + pdata->rpwsize += 3*lrw1; + pdata->ipwsize += 3*liw1; + } + if (pdata->rlocal->ops->nvspace) { + N_VSpace(pdata->rlocal, &lrw1, &liw1); + pdata->rpwsize += 2*lrw1; + pdata->ipwsize += 2*liw1; + } + if (pdata->savedJ->ops->space) { + flag = SUNMatSpace(pdata->savedJ, &lrw, &liw); + pdata->rpwsize += lrw; + pdata->ipwsize += liw; + } + if (pdata->savedP->ops->space) { + flag = SUNMatSpace(pdata->savedP, &lrw, &liw); + pdata->rpwsize += lrw; + pdata->ipwsize += liw; + } + if (pdata->LS->ops->space) { + flag = SUNLinSolSpace(pdata->LS, &lrw, &liw); + pdata->rpwsize += lrw; + pdata->ipwsize += liw; + } + pdata->nge = 0; + + /* make sure s_P_data is free from any previous allocations */ + if (cvls_mem->pfree) + cvls_mem->pfree(cv_mem); + + /* Point to the new P_data field in the LS memory */ + cvls_mem->P_data = pdata; + + /* Attach the pfree function */ + cvls_mem->pfree = cvBBDPrecFree; + + /* Attach preconditioner solve and setup functions */ + flag = CVodeSetPreconditioner(cvode_mem, cvBBDPrecSetup, + cvBBDPrecSolve); + return(flag); +} + + +int CVBBDPrecReInit(void *cvode_mem, sunindextype mudq, + sunindextype mldq, realtype dqrely) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + CVBBDPrecData pdata; + sunindextype Nlocal; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVSBBDPRE", + "CVBBDPrecReInit", MSGBBD_MEM_NULL); + return(CVLS_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Test if the LS linear solver interface has been created */ + if (cv_mem->cv_lmem == NULL) { + cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVSBBDPRE", + "CVBBDPrecReInit", MSGBBD_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + /* Test if the preconditioner data is non-NULL */ + if (cvls_mem->P_data == NULL) { + cvProcessError(cv_mem, CVLS_PMEM_NULL, "CVSBBDPRE", + "CVBBDPrecReInit", MSGBBD_PMEM_NULL); + return(CVLS_PMEM_NULL); + } + pdata = (CVBBDPrecData) cvls_mem->P_data; + + /* Load half-bandwidths */ + Nlocal = pdata->n_local; + pdata->mudq = SUNMIN(Nlocal-1, SUNMAX(0,mudq)); + pdata->mldq = SUNMIN(Nlocal-1, SUNMAX(0,mldq)); + + /* Set pdata->dqrely based on input dqrely (0 implies default). */ + pdata->dqrely = (dqrely > ZERO) ? + dqrely : SUNRsqrt(cv_mem->cv_uround); + + /* Re-initialize nge */ + pdata->nge = 0; + + return(CVLS_SUCCESS); +} + + +int CVBBDPrecGetWorkSpace(void *cvode_mem, + long int *lenrwBBDP, + long int *leniwBBDP) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + CVBBDPrecData pdata; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVSBBDPRE", + "CVBBDPrecGetWorkSpace", MSGBBD_MEM_NULL); + return(CVLS_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + if (cv_mem->cv_lmem == NULL) { + cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVSBBDPRE", + "CVBBDPrecGetWorkSpace", MSGBBD_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + if (cvls_mem->P_data == NULL) { + cvProcessError(cv_mem, CVLS_PMEM_NULL, "CVSBBDPRE", + "CVBBDPrecGetWorkSpace", MSGBBD_PMEM_NULL); + return(CVLS_PMEM_NULL); + } + pdata = (CVBBDPrecData) cvls_mem->P_data; + + *lenrwBBDP = pdata->rpwsize; + *leniwBBDP = pdata->ipwsize; + + return(CVLS_SUCCESS); +} + + +int CVBBDPrecGetNumGfnEvals(void *cvode_mem, + long int *ngevalsBBDP) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + CVBBDPrecData pdata; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVSBBDPRE", + "CVBBDPrecGetNumGfnEvals", MSGBBD_MEM_NULL); + return(CVLS_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + if (cv_mem->cv_lmem == NULL) { + cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVSBBDPRE", + "CVBBDPrecGetNumGfnEvals", MSGBBD_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + if (cvls_mem->P_data == NULL) { + cvProcessError(cv_mem, CVLS_PMEM_NULL, "CVSBBDPRE", + "CVBBDPrecGetNumGfnEvals", MSGBBD_PMEM_NULL); + return(CVLS_PMEM_NULL); + } + pdata = (CVBBDPrecData) cvls_mem->P_data; + + *ngevalsBBDP = pdata->nge; + + return(CVLS_SUCCESS); +} + + +/*----------------------------------------------------------------- + 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 + from scratch. + jok == SUNTRUE means that Jacobian data from the + previous CVBBDPrecon call can be reused + (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, + realtype gamma, void *bbd_data) +{ + sunindextype ier; + CVBBDPrecData pdata; + CVodeMem cv_mem; + int retval; + + pdata = (CVBBDPrecData) bbd_data; + cv_mem = (CVodeMem) pdata->cvode_mem; + + /* If jok = SUNTRUE, use saved copy of J */ + if (jok) { + *jcurPtr = SUNFALSE; + retval = SUNMatCopy(pdata->savedJ, pdata->savedP); + if (retval < 0) { + cvProcessError(cv_mem, -1, "CVBBDPRE", + "CVBBDPrecSetup", MSGBBD_SUNMAT_FAIL); + return(-1); + } + if (retval > 0) { + return(1); + } + + /* Otherwise call cvBBDDQJac for new J value */ + } else { + + *jcurPtr = SUNTRUE; + retval = SUNMatZero(pdata->savedJ); + if (retval < 0) { + cvProcessError(cv_mem, -1, "CVBBDPRE", + "CVBBDPrecSetup", MSGBBD_SUNMAT_FAIL); + return(-1); + } + if (retval > 0) { + return(1); + } + + retval = cvBBDDQJac(pdata, t, y, pdata->tmp1, + pdata->tmp2, pdata->tmp3); + if (retval < 0) { + cvProcessError(cv_mem, -1, "CVBBDPRE", "CVBBDPrecSetup", + MSGBBD_FUNC_FAILED); + return(-1); + } + if (retval > 0) { + return(1); + } + + retval = SUNMatCopy(pdata->savedJ, pdata->savedP); + if (retval < 0) { + cvProcessError(cv_mem, -1, "CVBBDPRE", + "CVBBDPrecSetup", MSGBBD_SUNMAT_FAIL); + return(-1); + } + if (retval > 0) { + return(1); + } + + } + + /* Scale and add I to get P = I - gamma*J */ + retval = SUNMatScaleAddI(-gamma, pdata->savedP); + if (retval) { + 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); +} + + +/*----------------------------------------------------------------- + Function : cvBBDPrecSolve + ----------------------------------------------------------------- + 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, + realtype gamma, realtype delta, + int lr, void *bbd_data) +{ + int retval; + CVBBDPrecData pdata; + + pdata = (CVBBDPrecData) bbd_data; + + /* 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, + pdata->rlocal, ZERO); + + /* Detach local data arrays from rlocal and zlocal */ + N_VSetArrayPointer(NULL, pdata->rlocal); + N_VSetArrayPointer(NULL, pdata->zlocal); + + return(retval); +} + + +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; + + SUNLinSolFree(pdata->LS); + N_VDestroy(pdata->tmp1); + N_VDestroy(pdata->tmp2); + N_VDestroy(pdata->tmp3); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + SUNMatDestroy(pdata->savedP); + SUNMatDestroy(pdata->savedJ); + + free(pdata); + pdata = NULL; + + return(0); +} + + +/*----------------------------------------------------------------- + Function : cvBBDDQJac + ----------------------------------------------------------------- + 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 + 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 cvBBDDQJac(CVBBDPrecData pdata, realtype t, N_Vector y, + N_Vector gy, N_Vector ytemp, N_Vector gtemp) +{ + CVodeMem cv_mem; + 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; + realtype *ytemp_data, *col_j, *cns_data; + int retval; + + cv_mem = (CVodeMem) pdata->cvode_mem; + + /* Load ytemp with y = predicted solution vector */ + N_VScale(ONE, y, ytemp); + + /* Call cfn and gloc to get base value of g(t,y) */ + if (pdata->cfn != NULL) { + retval = pdata->cfn(pdata->n_local, t, y, cv_mem->cv_user_data); + if (retval != 0) return(retval); + } + + retval = pdata->gloc(pdata->n_local, t, ytemp, gy, + cv_mem->cv_user_data); + pdata->nge++; + if (retval != 0) return(retval); + + /* Obtain pointers to the data for various vectors */ + y_data = N_VGetArrayPointer(y); + gy_data = N_VGetArrayPointer(gy); + ewt_data = N_VGetArrayPointer(cv_mem->cv_ewt); + ytemp_data = N_VGetArrayPointer(ytemp); + gtemp_data = N_VGetArrayPointer(gtemp); + if (cv_mem->cv_constraints != NULL) + cns_data = N_VGetArrayPointer(cv_mem->cv_constraints); + + /* Set minimum increment based on uround and norm of g */ + gnorm = N_VWrmsNorm(gy, cv_mem->cv_ewt); + minInc = (gnorm != ZERO) ? + (MIN_INC_MULT * SUNRabs(cv_mem->cv_h) * + cv_mem->cv_uround * pdata->n_local * gnorm) : ONE; + + /* Set bandwidth and number of column groups for band differencing */ + width = pdata->mldq + pdata->mudq + 1; + ngroups = SUNMIN(width, pdata->n_local); + + /* 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) { + 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, + cv_mem->cv_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 = 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]); + + /* Adjust sign(inc) as before. */ + if (cv_mem->cv_constraints != NULL) { + 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); + for (i=i1; i <= i2; i++) + SM_COLUMN_ELEMENT_B(col_j,i,j) = + inc_inv * (gtemp_data[i] - gy_data[i]); + } + } + + return(0); +} + + +/*================================================================ + PART II - Backward Problems + ================================================================*/ + +/*--------------------------------------------------------------- + User-Callable Functions: initialization, reinit and free + ---------------------------------------------------------------*/ +int CVBBDPrecInitB(void *cvode_mem, int which, sunindextype NlocalB, + sunindextype mudqB, sunindextype mldqB, + sunindextype mukeepB, sunindextype mlkeepB, + realtype dqrelyB, CVLocalFnB glocB, CVCommFnB cfnB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + CVBBDPrecDataB cvbbdB_mem; + void *cvodeB_mem; + int flag; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVSBBDPRE", + "CVBBDPrecInitB", MSGBBD_MEM_NULL); + return(CVLS_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CVLS_NO_ADJ, "CVSBBDPRE", + "CVBBDPrecInitB", MSGBBD_NO_ADJ); + return(CVLS_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + /* Check which */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVSBBDPRE", + "CVBBDPrecInitB", MSGBBD_BAD_WHICH); + return(CVLS_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + /* advance */ + cvB_mem = cvB_mem->cv_next; + } + /* cv_mem corresponding to 'which' problem. */ + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + /* Initialize the BBD preconditioner for this backward problem. */ + flag = CVBBDPrecInit(cvodeB_mem, NlocalB, mudqB, mldqB, mukeepB, + mlkeepB, dqrelyB, cvGlocWrapper, cvCfnWrapper); + if (flag != CV_SUCCESS) return(flag); + + /* Allocate memory for CVBBDPrecDataB to store the user-provided + functions which will be called from the wrappers */ + cvbbdB_mem = NULL; + cvbbdB_mem = (CVBBDPrecDataB) malloc(sizeof(* cvbbdB_mem)); + if (cvbbdB_mem == NULL) { + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSBBDPRE", + "CVBBDPrecInitB", MSGBBD_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + + /* set pointers to user-provided functions */ + cvbbdB_mem->glocB = glocB; + cvbbdB_mem->cfnB = cfnB; + + /* Attach pmem and pfree */ + cvB_mem->cv_pmem = cvbbdB_mem; + cvB_mem->cv_pfree = CVBBDPrecFreeB; + + return(CVLS_SUCCESS); +} + + +int CVBBDPrecReInitB(void *cvode_mem, int which, sunindextype mudqB, + sunindextype mldqB, realtype dqrelyB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + int flag; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVSBBDPRE", + "CVBBDPrecReInitB", MSGBBD_MEM_NULL); + return(CVLS_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CVLS_NO_ADJ, "CVSBBDPRE", + "CVBBDPrecReInitB", MSGBBD_NO_ADJ); + return(CVLS_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + /* Check which */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVSBBDPRE", + "CVBBDPrecReInitB", MSGBBD_BAD_WHICH); + return(CVLS_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + /* advance */ + cvB_mem = cvB_mem->cv_next; + } + /* 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); +} + + +static int CVBBDPrecFreeB(CVodeBMem cvB_mem) +{ + free(cvB_mem->cv_pmem); + cvB_mem->cv_pmem = NULL; + return(0); +} + + +/*---------------------------------------------------------------- + Wrapper functions + ----------------------------------------------------------------*/ + +/* cvGlocWrapper interfaces to the CVLocalFnB routine provided by the user */ +static int cvGlocWrapper(sunindextype NlocalB, realtype t, N_Vector yB, + N_Vector gB, void *cvode_mem) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + CVBBDPrecDataB cvbbdB_mem; + int flag; + + cv_mem = (CVodeMem) cvode_mem; + ca_mem = cv_mem->cv_adj_mem; + cvB_mem = ca_mem->ca_bckpbCrt; + cvbbdB_mem = (CVBBDPrecDataB) (cvB_mem->cv_pmem); + + /* Get forward solution from interpolation */ + flag = ca_mem->ca_IMget(cv_mem, t, ca_mem->ca_ytmp, NULL); + if (flag != CV_SUCCESS) { + 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, + gB, cvB_mem->cv_user_data); +} + + +/* cvCfnWrapper interfaces to the CVCommFnB routine provided by the user */ +static int cvCfnWrapper(sunindextype NlocalB, realtype t, + N_Vector yB, void *cvode_mem) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + CVBBDPrecDataB cvbbdB_mem; + int flag; + + cv_mem = (CVodeMem) cvode_mem; + ca_mem = cv_mem->cv_adj_mem; + cvB_mem = ca_mem->ca_bckpbCrt; + cvbbdB_mem = (CVBBDPrecDataB) (cvB_mem->cv_pmem); + if (cvbbdB_mem->cfnB == NULL) return(0); + + /* Get forward solution from interpolation */ + flag = ca_mem->ca_IMget(cv_mem, t, ca_mem->ca_ytmp, NULL); + if (flag != CV_SUCCESS) { + 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, + yB, cvB_mem->cv_user_data); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_bbdpre_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_bbdpre_impl.h new file mode 100644 index 0000000..e6ad589 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_bbdpre_impl.h @@ -0,0 +1,103 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 + * ----------------------------------------------------------------- + * Implementation header file for the CVBBDPRE module. + * ----------------------------------------------------------------- + */ + +#ifndef _CVSBBDPRE_IMPL_H +#define _CVSBBDPRE_IMPL_H + +#include <cvodes/cvodes_bbdpre.h> +#include <sunmatrix/sunmatrix_band.h> +#include <sunlinsol/sunlinsol_band.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*----------------------------------------------------------------- + Type: CVBBDPrecData + -----------------------------------------------------------------*/ + +typedef struct CVBBDPrecDataRec { + + /* passed by user to CVBBDPrecInit and used by PrecSetup/PrecSolve */ + sunindextype mudq, mldq, mukeep, mlkeep; + realtype dqrely; + CVLocalFn gloc; + CVCommFn cfn; + + /* set by CVBBDPrecSetup and used by CVBBDPrecSolve */ + SUNMatrix savedJ; + SUNMatrix savedP; + SUNLinearSolver LS; + N_Vector tmp1; + N_Vector tmp2; + N_Vector tmp3; + N_Vector zlocal; + N_Vector rlocal; + + /* set by CVBBDPrecInit and used by CVBBDPrecSetup */ + sunindextype n_local; + + /* available for optional output */ + long int rpwsize; + long int ipwsize; + long int nge; + + /* pointer to cvode_mem */ + void *cvode_mem; + +} *CVBBDPrecData; + + +/*----------------------------------------------------------------- + Type: CVBBDPrecDataB + -----------------------------------------------------------------*/ + +typedef struct CVBBDPrecDataRecB { + + /* BBD user functions (glocB and cfnB) for backward run */ + CVLocalFnB glocB; + CVCommFnB cfnB; + +} *CVBBDPrecDataB; + + +/*----------------------------------------------------------------- + CVBBDPRE error messages + -----------------------------------------------------------------*/ + +#define MSGBBD_MEM_NULL "Integrator memory is NULL." +#define MSGBBD_LMEM_NULL "Linear solver memory is NULL. One of the SPILS linear solvers must be attached." +#define MSGBBD_MEM_FAIL "A memory request failed." +#define MSGBBD_BAD_NVECTOR "A required vector operation is not implemented." +#define MSGBBD_SUNMAT_FAIL "An error arose from a SUNBandMatrix routine." +#define MSGBBD_SUNLS_FAIL "An error arose from a SUNBandLinearSolver routine." +#define MSGBBD_PMEM_NULL "BBD peconditioner memory is NULL. CVBBDPrecInit must be called." +#define MSGBBD_FUNC_FAILED "The gloc or cfn routine failed in an unrecoverable manner." + +#define MSGBBD_NO_ADJ "Illegal attempt to call before calling CVodeAdjInit." +#define MSGBBD_BAD_WHICH "Illegal value for the which parameter." +#define MSGBBD_PDATAB_NULL "BBD preconditioner memory is NULL for the backward integration." +#define MSGBBD_BAD_TINTERP "Bad t for interpolation." + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_diag.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_diag.c new file mode 100644 index 0000000..cc3ca62 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_diag.c @@ -0,0 +1,509 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): 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 CVDIAG linear solver. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "cvodes_diag_impl.h" +#include "cvodes_impl.h" + +/* Other Constants */ + +#define FRACT RCONST(0.1) +#define ONE RCONST(1.0) + +/* CVDIAG linit, lsetup, lsolve, and lfree routines */ + +static int CVDiagInit(CVodeMem cv_mem); + +static int CVDiagSetup(CVodeMem cv_mem, int convfail, N_Vector ypred, + N_Vector fpred, booleantype *jcurPtr, N_Vector vtemp1, + N_Vector vtemp2, N_Vector vtemp3); + +static int CVDiagSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight, + N_Vector ycur, N_Vector fcur); + +static int CVDiagFree(CVodeMem cv_mem); + + +/* + * ================================================================ + * + * PART I - forward problems + * + * ================================================================ + */ + + +/* Readability Replacements */ + +#define lrw1 (cv_mem->cv_lrw1) +#define liw1 (cv_mem->cv_liw1) +#define f (cv_mem->cv_f) +#define uround (cv_mem->cv_uround) +#define tn (cv_mem->cv_tn) +#define h (cv_mem->cv_h) +#define rl1 (cv_mem->cv_rl1) +#define gamma (cv_mem->cv_gamma) +#define ewt (cv_mem->cv_ewt) +#define nfe (cv_mem->cv_nfe) +#define zn (cv_mem->cv_zn) +#define linit (cv_mem->cv_linit) +#define lsetup (cv_mem->cv_lsetup) +#define lsolve (cv_mem->cv_lsolve) +#define lfree (cv_mem->cv_lfree) +#define lmem (cv_mem->cv_lmem) +#define vec_tmpl (cv_mem->cv_tempv) +#define setupNonNull (cv_mem->cv_setupNonNull) + +#define gammasv (cvdiag_mem->di_gammasv) +#define M (cvdiag_mem->di_M) +#define bit (cvdiag_mem->di_bit) +#define bitcomp (cvdiag_mem->di_bitcomp) +#define nfeDI (cvdiag_mem->di_nfeDI) +#define last_flag (cvdiag_mem->di_last_flag) + + +/* + * ----------------------------------------------------------------- + * CVDiag + * ----------------------------------------------------------------- + * This routine initializes the memory record and sets various function + * fields specific to the diagonal linear solver module. CVDense first + * calls the existing lfree routine if this is not NULL. Then it sets + * the cv_linit, cv_lsetup, cv_lsolve, cv_lfree fields in (*cvode_mem) + * to be CVDiagInit, CVDiagSetup, CVDiagSolve, and CVDiagFree, + * respectively. It allocates memory for a structure of type + * CVDiagMemRec and sets the cv_lmem field in (*cvode_mem) to the + * address of this structure. It sets setupNonNull in (*cvode_mem) to + * SUNTRUE. Finally, it allocates memory for M, bit, and bitcomp. + * The CVDiag return value is SUCCESS = 0, LMEM_FAIL = -1, or + * LIN_ILL_INPUT=-2. + * ----------------------------------------------------------------- + */ + +int CVDiag(void *cvode_mem) +{ + CVodeMem cv_mem; + CVDiagMem cvdiag_mem; + + /* Return immediately if cvode_mem is NULL */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CVDIAG_MEM_NULL, "CVDIAG", "CVDiag", MSGDG_CVMEM_NULL); + return(CVDIAG_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Check if N_VCompare and N_VInvTest are present */ + if(vec_tmpl->ops->nvcompare == NULL || + vec_tmpl->ops->nvinvtest == NULL) { + cvProcessError(cv_mem, CVDIAG_ILL_INPUT, "CVDIAG", "CVDiag", MSGDG_BAD_NVECTOR); + return(CVDIAG_ILL_INPUT); + } + + if (lfree != NULL) lfree(cv_mem); + + /* Set four main function fields in cv_mem */ + linit = CVDiagInit; + lsetup = CVDiagSetup; + lsolve = CVDiagSolve; + lfree = CVDiagFree; + + /* Get memory for CVDiagMemRec */ + cvdiag_mem = NULL; + cvdiag_mem = (CVDiagMem) malloc(sizeof(CVDiagMemRec)); + if (cvdiag_mem == NULL) { + cvProcessError(cv_mem, CVDIAG_MEM_FAIL, "CVDIAG", "CVDiag", MSGDG_MEM_FAIL); + return(CVDIAG_MEM_FAIL); + } + + last_flag = CVDIAG_SUCCESS; + + /* Allocate memory for M, bit, and bitcomp */ + + M = N_VClone(vec_tmpl); + if (M == NULL) { + cvProcessError(cv_mem, CVDIAG_MEM_FAIL, "CVDIAG", "CVDiag", MSGDG_MEM_FAIL); + free(cvdiag_mem); cvdiag_mem = NULL; + return(CVDIAG_MEM_FAIL); + } + bit = N_VClone(vec_tmpl); + if (bit == NULL) { + cvProcessError(cv_mem, CVDIAG_MEM_FAIL, "CVDIAG", "CVDiag", MSGDG_MEM_FAIL); + N_VDestroy(M); + free(cvdiag_mem); cvdiag_mem = NULL; + return(CVDIAG_MEM_FAIL); + } + bitcomp = N_VClone(vec_tmpl); + if (bitcomp == NULL) { + cvProcessError(cv_mem, CVDIAG_MEM_FAIL, "CVDIAG", "CVDiag", MSGDG_MEM_FAIL); + N_VDestroy(M); + N_VDestroy(bit); + free(cvdiag_mem); cvdiag_mem = NULL; + return(CVDIAG_MEM_FAIL); + } + + /* Attach linear solver memory to integrator memory */ + lmem = cvdiag_mem; + + return(CVDIAG_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * CVDiagGetWorkSpace + * ----------------------------------------------------------------- + */ + +int CVDiagGetWorkSpace(void *cvode_mem, long int *lenrwLS, long int *leniwLS) +{ + CVodeMem cv_mem; + + /* Return immediately if cvode_mem is NULL */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CVDIAG_MEM_NULL, "CVDIAG", "CVDiagGetWorkSpace", MSGDG_CVMEM_NULL); + return(CVDIAG_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + *lenrwLS = 3*lrw1; + *leniwLS = 3*liw1; + + return(CVDIAG_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * CVDiagGetNumRhsEvals + * ----------------------------------------------------------------- + */ + +int CVDiagGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS) +{ + CVodeMem cv_mem; + CVDiagMem cvdiag_mem; + + /* Return immediately if cvode_mem is NULL */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CVDIAG_MEM_NULL, "CVDIAG", "CVDiagGetNumRhsEvals", MSGDG_CVMEM_NULL); + return(CVDIAG_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + if (lmem == NULL) { + cvProcessError(cv_mem, CVDIAG_LMEM_NULL, "CVDIAG", "CVDiagGetNumRhsEvals", MSGDG_LMEM_NULL); + return(CVDIAG_LMEM_NULL); + } + cvdiag_mem = (CVDiagMem) lmem; + + *nfevalsLS = nfeDI; + + return(CVDIAG_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * CVDiagGetLastFlag + * ----------------------------------------------------------------- + */ + +int CVDiagGetLastFlag(void *cvode_mem, long int *flag) +{ + CVodeMem cv_mem; + CVDiagMem cvdiag_mem; + + /* Return immediately if cvode_mem is NULL */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CVDIAG_MEM_NULL, "CVDIAG", "CVDiagGetLastFlag", MSGDG_CVMEM_NULL); + return(CVDIAG_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + if (lmem == NULL) { + cvProcessError(cv_mem, CVDIAG_LMEM_NULL, "CVDIAG", "CVDiagGetLastFlag", MSGDG_LMEM_NULL); + return(CVDIAG_LMEM_NULL); + } + cvdiag_mem = (CVDiagMem) lmem; + + *flag = last_flag; + + return(CVDIAG_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * CVDiagGetReturnFlagName + * ----------------------------------------------------------------- + */ + +char *CVDiagGetReturnFlagName(long int flag) +{ + char *name; + + name = (char *)malloc(30*sizeof(char)); + + switch(flag) { + case CVDIAG_SUCCESS: + sprintf(name,"CVDIAG_SUCCESS"); + break; + case CVDIAG_MEM_NULL: + sprintf(name,"CVDIAG_MEM_NULL"); + break; + case CVDIAG_LMEM_NULL: + sprintf(name,"CVDIAG_LMEM_NULL"); + break; + case CVDIAG_ILL_INPUT: + sprintf(name,"CVDIAG_ILL_INPUT"); + break; + case CVDIAG_MEM_FAIL: + sprintf(name,"CVDIAG_MEM_FAIL"); + break; + case CVDIAG_INV_FAIL: + sprintf(name,"CVDIAG_INV_FAIL"); + break; + case CVDIAG_RHSFUNC_UNRECVR: + sprintf(name,"CVDIAG_RHSFUNC_UNRECVR"); + break; + case CVDIAG_RHSFUNC_RECVR: + sprintf(name,"CVDIAG_RHSFUNC_RECVR"); + break; + case CVDIAG_NO_ADJ: + sprintf(name,"CVDIAG_NO_ADJ"); + break; + default: + sprintf(name,"NONE"); + } + + return(name); +} + +/* + * ----------------------------------------------------------------- + * CVDiagInit + * ----------------------------------------------------------------- + * This routine does remaining initializations specific to the diagonal + * linear solver. + * ----------------------------------------------------------------- + */ + +static int CVDiagInit(CVodeMem cv_mem) +{ + CVDiagMem cvdiag_mem; + + cvdiag_mem = (CVDiagMem) lmem; + + nfeDI = 0; + + last_flag = CVDIAG_SUCCESS; + return(0); +} + +/* + * ----------------------------------------------------------------- + * CVDiagSetup + * ----------------------------------------------------------------- + * This routine does the setup operations for the diagonal linear + * solver. It constructs a diagonal approximation to the Newton matrix + * M = I - gamma*J, updates counters, and inverts M. + * ----------------------------------------------------------------- + */ + +static int CVDiagSetup(CVodeMem cv_mem, int convfail, N_Vector ypred, + N_Vector fpred, booleantype *jcurPtr, N_Vector vtemp1, + N_Vector vtemp2, N_Vector vtemp3) +{ + realtype r; + N_Vector ftemp, y; + booleantype invOK; + CVDiagMem cvdiag_mem; + int retval; + + cvdiag_mem = (CVDiagMem) lmem; + + /* Rename work vectors for use as temporary values of y and f */ + ftemp = vtemp1; + y = vtemp2; + + /* Form y with perturbation = FRACT*(func. iter. correction) */ + r = FRACT * rl1; + N_VLinearSum(h, fpred, -ONE, zn[1], ftemp); + N_VLinearSum(r, ftemp, ONE, ypred, y); + + /* Evaluate f at perturbed y */ + retval = f(tn, y, M, cv_mem->cv_user_data); + nfeDI++; + if (retval < 0) { + cvProcessError(cv_mem, CVDIAG_RHSFUNC_UNRECVR, "CVDIAG", "CVDiagSetup", MSGDG_RHSFUNC_FAILED); + last_flag = CVDIAG_RHSFUNC_UNRECVR; + return(-1); + } + if (retval > 0) { + last_flag = CVDIAG_RHSFUNC_RECVR; + return(1); + } + + /* Construct M = I - gamma*J with J = diag(deltaf_i/deltay_i) */ + N_VLinearSum(ONE, M, -ONE, fpred, M); + N_VLinearSum(FRACT, ftemp, -h, M, M); + N_VProd(ftemp, ewt, y); + /* Protect against deltay_i being at roundoff level */ + N_VCompare(uround, y, bit); + N_VAddConst(bit, -ONE, bitcomp); + N_VProd(ftemp, bit, y); + N_VLinearSum(FRACT, y, -ONE, bitcomp, y); + N_VDiv(M, y, M); + N_VProd(M, bit, M); + N_VLinearSum(ONE, M, -ONE, bitcomp, M); + + /* Invert M with test for zero components */ + invOK = N_VInvTest(M, M); + if (!invOK) { + last_flag = CVDIAG_INV_FAIL; + return(1); + } + + /* Set jcur = SUNTRUE, save gamma in gammasv, and return */ + *jcurPtr = SUNTRUE; + gammasv = gamma; + last_flag = CVDIAG_SUCCESS; + return(0); +} + +/* + * ----------------------------------------------------------------- + * CVDiagSolve + * ----------------------------------------------------------------- + * This routine performs the solve operation for the diagonal linear + * solver. If necessary it first updates gamma in M = I - gamma*J. + * ----------------------------------------------------------------- + */ + +static int CVDiagSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight, + N_Vector ycur, N_Vector fcur) +{ + booleantype invOK; + realtype r; + CVDiagMem cvdiag_mem; + + cvdiag_mem = (CVDiagMem) lmem; + + /* If gamma has changed, update factor in M, and save gamma value */ + + if (gammasv != gamma) { + r = gamma / gammasv; + N_VInv(M, M); + N_VAddConst(M, -ONE, M); + N_VScale(r, M, M); + N_VAddConst(M, ONE, M); + invOK = N_VInvTest(M, M); + if (!invOK) { + last_flag = CVDIAG_INV_FAIL; + return (1); + } + gammasv = gamma; + } + + /* Apply M-inverse to b */ + N_VProd(b, M, b); + + last_flag = CVDIAG_SUCCESS; + return(0); +} + +/* + * ----------------------------------------------------------------- + * CVDiagFree + * ----------------------------------------------------------------- + * This routine frees memory specific to the diagonal linear solver. + * ----------------------------------------------------------------- + */ + +static int CVDiagFree(CVodeMem cv_mem) +{ + CVDiagMem cvdiag_mem; + + cvdiag_mem = (CVDiagMem) lmem; + + N_VDestroy(M); + N_VDestroy(bit); + N_VDestroy(bitcomp); + free(cvdiag_mem); + cv_mem->cv_lmem = NULL; + + return(0); +} + + +/* + * ================================================================ + * + * PART II - backward problems + * + * ================================================================ + */ + + +/* + * CVDiagB + * + * Wrappers for the backward phase around the corresponding + * CVODES functions + */ + +int CVDiagB(void *cvode_mem, int which) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + int flag; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CVDIAG_MEM_NULL, "CVSDIAG", "CVDiagB", MSGDG_CVMEM_NULL); + return(CVDIAG_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CVDIAG_NO_ADJ, "CVSDIAG", "CVDiagB", MSGDG_NO_ADJ); + return(CVDIAG_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + /* Check which */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CVDIAG_ILL_INPUT, "CVSDIAG", "CVDiagB", MSGDG_BAD_WHICH); + return(CVDIAG_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + cvodeB_mem = (void *) (cvB_mem->cv_mem); + + flag = CVDiag(cvodeB_mem); + + return(flag); +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_diag_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_diag_impl.h new file mode 100644 index 0000000..799f7cb --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_diag_impl.h @@ -0,0 +1,69 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): 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 + * ----------------------------------------------------------------- + * Implementation header file for the diagonal linear solver, CVDIAG. + * ----------------------------------------------------------------- + */ + +#ifndef _CVSDIAG_IMPL_H +#define _CVSDIAG_IMPL_H + +#include <cvodes/cvodes_diag.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* + * ----------------------------------------------------------------- + * Types: CVDiagMemRec, CVDiagMem + * ----------------------------------------------------------------- + * The type CVDiagMem is pointer to a CVDiagMemRec. + * This structure contains CVDiag solver-specific data. + * ----------------------------------------------------------------- + */ + +typedef struct { + + realtype di_gammasv; /* gammasv = gamma at the last call to setup or solve */ + + N_Vector di_M; /* M = (I - gamma J)^{-1} , gamma = h / l1 */ + + N_Vector di_bit; /* temporary storage vector */ + + N_Vector di_bitcomp; /* temporary storage vector */ + + long int di_nfeDI; /* no. of calls to f due to difference + quotient diagonal Jacobian approximation */ + + long int di_last_flag; /* last error return flag */ + +} CVDiagMemRec, *CVDiagMem; + +/* Error Messages */ + +#define MSGDG_CVMEM_NULL "Integrator memory is NULL." +#define MSGDG_MEM_FAIL "A memory request failed." +#define MSGDG_BAD_NVECTOR "A required vector operation is not implemented." +#define MSGDG_LMEM_NULL "CVDIAG memory is NULL." +#define MSGDG_RHSFUNC_FAILED "The right-hand side routine failed in an unrecoverable manner." + +#define MSGDG_NO_ADJ "Illegal attempt to call before calling CVodeAdjMalloc." +#define MSGDG_BAD_WHICH "Illegal value for which." + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_direct.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_direct.c new file mode 100644 index 0000000..3f172ac --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_direct.c @@ -0,0 +1,66 @@ +/* ----------------------------------------------------------------- + * Programmer(s): 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 + * ----------------------------------------------------------------- + * 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. + * -----------------------------------------------------------------*/ + +#include <cvodes/cvodes_ls.h> +#include <cvodes/cvodes_direct.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*================================================================= + Exported Functions (wrappers for equivalent routines in cvodes_ls.h) + =================================================================*/ + +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)); } + +char *CVDlsGetReturnFlagName(long int flag) +{ return(CVodeGetLinReturnFlagName(flag)); } + +int CVDlsSetLinearSolverB(void *cvode_mem, int which, + SUNLinearSolver LS, SUNMatrix A) +{ return(CVodeSetLinearSolverB(cvode_mem, which, LS, A)); } + +int CVDlsSetJacFnB(void *cvode_mem, int which, CVDlsJacFnB jacB) +{ return(CVodeSetJacFnB(cvode_mem, which, jacB)); } + +int CVDlsSetJacFnBS(void *cvode_mem, int which, CVDlsJacFnBS jacBS) +{ return(CVodeSetJacFnBS(cvode_mem, which, jacBS)); } + +#ifdef __cplusplus +} +#endif + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_impl.h new file mode 100644 index 0000000..233ab03 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_impl.h @@ -0,0 +1,1191 @@ +/* + * ----------------------------------------------------------------- + * $Revision$ + * $Date$ + * ----------------------------------------------------------------- + * Programmer(s): 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 + * ----------------------------------------------------------------- + * Implementation header file for the main CVODES integrator. + * ----------------------------------------------------------------- + */ + +#ifndef _CVODES_IMPL_H +#define _CVODES_IMPL_H + +#include <stdarg.h> + +#include <cvodes/cvodes.h> +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_types.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +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 + * ================================================================= + */ + +/* Basic CVODES constants */ + +#define ADAMS_Q_MAX 12 /* max value of q for lmm == ADAMS */ +#define BDF_Q_MAX 5 /* max value of q for lmm == BDF */ +#define Q_MAX ADAMS_Q_MAX /* max value of q for either lmm */ +#define L_MAX (Q_MAX+1) /* max value of L for either lmm */ +#define NUM_TESTS 5 /* number of error test quantities */ + +#define HMIN_DEFAULT RCONST(0.0) /* hmin default value */ +#define HMAX_INV_DEFAULT RCONST(0.0) /* hmax_inv default value */ +#define MXHNIL_DEFAULT 10 /* mxhnil default value */ +#define MXSTEP_DEFAULT 500 /* mxstep default value */ + +/* Return values for lower level routines used by CVode and functions + provided to the nonlinear solver */ + +#define RHSFUNC_RECVR +9 +#define SRHSFUNC_RECVR +12 + +/* nonlinear solver constants + NLS_MAXCOR maximum no. of corrector iterations for the nonlinear solver + CRDOWN constant used in the estimation of the convergence rate (crate) + of the iterates for the nonlinear equation + RDIV declare divergence if ratio del/delp > RDIV +*/ +#define NLS_MAXCOR 3 +#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 + * ================================================================= + */ + +typedef struct CVadjMemRec *CVadjMem; +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 + * ================================================================= + */ + + +/* + * ----------------------------------------------------------------- + * Types: struct CVodeMemRec, CVodeMem + * ----------------------------------------------------------------- + * The type CVodeMem is type pointer to struct CVodeMemRec. + * This structure contains fields to keep track of problem state. + * ----------------------------------------------------------------- + */ + +typedef struct CVodeMemRec { + + realtype cv_uround; /* machine unit roundoff */ + + /*-------------------------- + Problem Specification Data + --------------------------*/ + + CVRhsFn cv_f; /* y' = f(t,y(t)) */ + void *cv_user_data; /* user pointer passed to f */ + + int cv_lmm; /* lmm = ADAMS or BDF */ + + int cv_itol; /* itol = CV_SS, CV_SV, or CV_WF, or CV_NN */ + realtype cv_reltol; /* relative tolerance */ + realtype cv_Sabstol; /* scalar absolute tolerance */ + N_Vector cv_Vabstol; /* vector absolute tolerance */ + 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 */ + + booleantype cv_constraintsSet; /* constraints vector present: + do constraints calc */ + + /*----------------------- + Quadrature Related Data + -----------------------*/ + + booleantype cv_quadr; /* SUNTRUE if integrating quadratures */ + + CVQuadRhsFn cv_fQ; /* q' = fQ(t, y(t)) */ + + booleantype cv_errconQ; /* SUNTRUE if quadrs. are included in error test */ + + int cv_itolQ; /* itolQ = CV_SS or CV_SV */ + realtype cv_reltolQ; /* relative tolerance for quadratures */ + realtype cv_SabstolQ; /* scalar absolute tolerance for quadratures */ + N_Vector cv_VabstolQ; /* vector absolute tolerance for quadratures */ + + /*------------------------ + Sensitivity Related Data + ------------------------*/ + + booleantype cv_sensi; /* SUNTRUE if computing sensitivities */ + + int cv_Ns; /* Number of sensitivities */ + + int cv_ism; /* ism = SIMULTANEOUS or STAGGERED */ + + CVSensRhsFn cv_fS; /* fS = (df/dy)*yS + (df/dp) */ + CVSensRhs1Fn cv_fS1; /* fS1 = (df/dy)*yS_i + (df/dp) */ + void *cv_fS_data; /* data pointer passed to fS */ + booleantype cv_fSDQ; /* SUNTRUE if using internal DQ functions */ + int cv_ifS; /* ifS = ALLSENS or ONESENS */ + + realtype *cv_p; /* parameters in f(t,y,p) */ + realtype *cv_pbar; /* scale factors for parameters */ + int *cv_plist; /* list of sensitivities */ + int cv_DQtype; /* central/forward finite differences */ + realtype cv_DQrhomax; /* cut-off value for separate/simultaneous FD */ + + booleantype cv_errconS; /* SUNTRUE if yS are considered in err. control */ + + int cv_itolS; + realtype cv_reltolS; /* relative tolerance for sensitivities */ + realtype *cv_SabstolS; /* scalar absolute tolerances for sensi. */ + N_Vector *cv_VabstolS; /* vector absolute tolerances for sensi. */ + + /*----------------------------------- + Quadrature Sensitivity Related Data + -----------------------------------*/ + + booleantype cv_quadr_sensi; /* SUNTRUE if computing sensitivties of quadrs. */ + + CVQuadSensRhsFn cv_fQS; /* fQS = (dfQ/dy)*yS + (dfQ/dp) */ + void *cv_fQS_data; /* data pointer passed to fQS */ + booleantype cv_fQSDQ; /* SUNTRUE if using internal DQ functions */ + + booleantype cv_errconQS; /* SUNTRUE if yQS are considered in err. con. */ + + int cv_itolQS; + realtype cv_reltolQS; /* relative tolerance for yQS */ + realtype *cv_SabstolQS; /* scalar absolute tolerances for yQS */ + N_Vector *cv_VabstolQS; /* vector absolute tolerances for yQS */ + + /*----------------------- + 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 * + (jth derivative of the interpolating poly.) */ + + /*------------------- + 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 + 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). + On return, this vector is scaled to give + the estimated local error in y. */ + N_Vector cv_tempv; /* temporary storage vector */ + N_Vector cv_ftemp; /* temporary storage vector */ + N_Vector cv_vtemp1; /* temporary storage vector */ + 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 + --------------------------*/ + + N_Vector cv_znQ[L_MAX]; /* Nordsieck arrays for quadratures */ + N_Vector cv_ewtQ; /* error weight vector for quadratures */ + N_Vector cv_yQ; /* Unlike y, yQ is not allocated by the user */ + N_Vector cv_acorQ; /* acorQ = yQ_n(m) - yQ_n(0) */ + N_Vector cv_tempvQ; /* temporary storage vector (~ tempv) */ + + /*--------------------------- + Sensitivity Related Vectors + ---------------------------*/ + + N_Vector *cv_znS[L_MAX]; /* Nordsieck arrays for sensitivities */ + N_Vector *cv_ewtS; /* error weight vectors for sensitivities */ + N_Vector *cv_yS; /* yS=yS0 (allocated by the user) */ + N_Vector *cv_acorS; /* acorS = yS_n(m) - yS_n(0) */ + N_Vector *cv_tempvS; /* temporary storage vector (~ tempv) */ + N_Vector *cv_ftempS; /* temporary storage vector (~ ftemp) */ + + booleantype cv_stgr1alloc; /* Did we allocate ncfS1, ncfnS1, and nniS1? */ + + /*-------------------------------------- + Quadrature Sensitivity Related Vectors + --------------------------------------*/ + + N_Vector *cv_znQS[L_MAX]; /* Nordsieck arrays for quadr. sensitivities */ + N_Vector *cv_ewtQS; /* error weight vectors for sensitivities */ + N_Vector *cv_yQS; /* Unlike yS, yQS is not allocated by the user */ + 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 + -----------------*/ + + booleantype cv_tstopset; + realtype cv_tstop; + + /*--------- + Step Data + ---------*/ + + int cv_q; /* current order */ + int cv_qprime; /* order to be used on the next step + * qprime = q-1, q, or q+1 */ + int cv_next_q; /* order to be used on the next step */ + int cv_qwait; /* number of internal steps to wait before + * considering a change in q */ + int cv_L; /* L = q + 1 */ + + 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_eta; /* eta = hprime / h */ + realtype cv_hscale; /* value of h used in zn */ + realtype cv_tn; /* current internal value of t */ + realtype cv_tretlast; /* last value of t returned */ + + realtype cv_tau[L_MAX+1]; /* array of previous q+1 successful step + * sizes indexed from 1 to q+1 */ + realtype cv_tq[NUM_TESTS+1]; /* array of test quantities indexed from + * 1 to NUM_TESTS(=5) */ + realtype cv_l[L_MAX]; /* coefficients of l(x) (degree q poly) */ + + realtype cv_rl1; /* the scalar 1/l[1] */ + realtype cv_gamma; /* gamma = h * rl1 */ + realtype cv_gammap; /* gamma at the last setup call */ + realtype cv_gamrat; /* gamma / gammap */ + + realtype cv_crate; /* est. corrector conv. rate in Nls */ + realtype cv_crateS; /* est. corrector conv. rate in NlsStgr */ + realtype cv_delp; /* norm of previous nonlinear solver update */ + realtype cv_acnrm; /* | acor | */ + realtype cv_acnrmQ; /* | acorQ | */ + realtype cv_acnrmS; /* | acorS | */ + realtype cv_acnrmQS; /* | acorQS | */ + realtype cv_nlscoef; /* coeficient in nonlinear convergence test */ + int *cv_ncfS1; /* Array of Ns local counters for conv. + * failures (used in CVStep for STAGGERED1) */ + + /*------ + Limits + ------*/ + + int cv_qmax; /* q <= qmax */ + 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 + ----------*/ + + long int cv_nst; /* number of internal steps taken */ + + long int cv_nfe; /* number of f calls */ + long int cv_nfQe; /* number of fQ calls */ + long int cv_nfSe; /* number of fS calls */ + long int cv_nfeS; /* number of f calls from sensi DQ */ + long int cv_nfQSe; /* number of fQS calls */ + long int cv_nfQeS; /* number of fQ calls from sensi DQ */ + + + long int cv_ncfn; /* number of corrector convergence failures */ + long int cv_ncfnS; /* number of total sensi. corr. conv. failures */ + long int *cv_ncfnS1; /* number of sensi. corrector conv. failures */ + + long int cv_nni; /* number of nonlinear iterations performed */ + long int cv_nniS; /* number of total sensi. nonlinear iterations */ + long int *cv_nniS1; /* number of sensi. nonlinear iterations */ + + long int cv_netf; /* number of error test failures */ + long int cv_netfQ; /* number of quadr. error test failures */ + long int cv_netfS; /* number of sensi. error test failures */ + long int cv_netfQS; /* number of quadr. sensi. error test failures */ + + long int cv_nsetups; /* number of setup calls */ + long int cv_nsetupsS; /* number of setup calls due to sensitivities */ + + int cv_nhnil; /* number of messages issued to the user that + t + h == t for the next iternal step */ + + /*----------------------------- + 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 */ + long int cv_lrw; /* no. of realtype words in CVODES work vectors */ + long int cv_liw; /* no. of integer words in CVODES work vectors */ + + /*---------------- + Step size ratios + ----------------*/ + + realtype cv_etaqm1; /* ratio of new to old h for order q-1 */ + realtype cv_etaq; /* ratio of new to old h for order q */ + realtype cv_etaqp1; /* ratio of new to old h for order q+1 */ + + /*--------------------- + Nonlinear Solver Data + ---------------------*/ + + SUNNonlinearSolver NLS; /* nonlinear solver object for ODE solves */ + booleantype ownNLS; /* flag indicating NLS ownership */ + + SUNNonlinearSolver NLSsim; /* NLS object for the simultaneous corrector */ + booleantype ownNLSsim; /* flag indicating NLS ownership */ + + SUNNonlinearSolver NLSstg; /* NLS object for the staggered corrector */ + booleantype ownNLSstg; /* flag indicating NLS ownership */ + + SUNNonlinearSolver NLSstg1; /* NLS object for the staggered1 corrector */ + booleantype ownNLSstg1; /* flag indicating NLS ownership */ + int sens_solve_idx; /* index of the current staggered1 solve */ + long int nnip; /* previous total number of iterations */ + + booleantype sens_solve; /* flag indicating if the current solve is a + staggered or staggered1 sensitivity solve */ + int convfail; /* flag to indicate when a Jacobian update may + be needed */ + + /* 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] + + Staggered: ycor0Stg = ida_deltaS + ycorStg = ida_eeS + ewtStg = ida_ewtS + */ + N_Vector ycor0Sim, ycorSim, ewtSim; + N_Vector ycor0Stg, ycorStg, ewtStg; + + /* flags indicating if vector wrappers for the simultaneous and staggered + correctors have been allocated */ + booleantype simMallocDone; + booleantype stgMallocDone; + + + /*------------------ + Linear Solver Data + ------------------*/ + + /* Linear Solver functions to be called */ + + 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_lsolve)(struct CVodeMemRec *cv_mem, N_Vector b, N_Vector weight, + N_Vector ycur, N_Vector fcur); + + int (*cv_lfree)(struct CVodeMemRec *cv_mem); + + /* Linear Solver specific memory */ + + void *cv_lmem; + + /* Flag to request a call to the setup routine */ + + booleantype cv_forceSetup; + + /*------------ + Saved Values + ------------*/ + + int cv_qu; /* last successful q value used */ + long int cv_nstlp; /* step number of last setup call */ + realtype cv_h0u; /* actual initial stepsize */ + realtype cv_hu; /* last successful h value used */ + realtype cv_saved_tq5; /* saved value of tq[5] */ + booleantype cv_jcur; /* is Jacobian info for linear solver current? */ + int cv_convfail; /* flag storing previous solver failure mode */ + realtype cv_tolsf; /* tolerance scale factor */ + int cv_qmax_alloc; /* qmax used when allocating mem */ + int cv_qmax_allocQ; /* qmax used when allocating quad. mem */ + int cv_qmax_allocS; /* qmax used when allocating sensi. mem */ + int cv_qmax_allocQS; /* qmax used when allocating quad. sensi. mem */ + int cv_indx_acor; /* index of zn vector in which acor is saved */ + + /*-------------------------------------------------------------------- + Flags turned ON by CVodeInit, CVodeSensMalloc, and CVodeQuadMalloc + and read by CVodeReInit, CVodeSensReInit, and CVodeQuadReInit + --------------------------------------------------------------------*/ + + booleantype cv_VabstolMallocDone; + booleantype cv_MallocDone; + booleantype cv_constraintsMallocDone; + + booleantype cv_VabstolQMallocDone; + booleantype cv_QuadMallocDone; + + booleantype cv_VabstolSMallocDone; + booleantype cv_SabstolSMallocDone; + booleantype cv_SensMallocDone; + + booleantype cv_VabstolQSMallocDone; + booleantype cv_SabstolQSMallocDone; + booleantype cv_QuadSensMallocDone; + + /*------------------------------------------- + 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 */ + + /*------------------------- + Stability Limit Detection + -------------------------*/ + + booleantype cv_sldeton; /* Is Stability Limit Detection on? */ + realtype cv_ssdat[6][4]; /* scaled data array for STALD */ + int cv_nscon; /* counter for STALD method */ + long int cv_nor; /* counter for number of order reductions */ + + /*---------------- + Rootfinding Data + ----------------*/ + + CVRootFn cv_gfun; /* Function g for roots sought */ + int cv_nrtfn; /* number of components of g */ + int *cv_iroots; /* array for root information */ + int *cv_rootdir; /* array specifying direction of zero-crossing */ + realtype cv_tlo; /* nearest endpoint of interval in root search */ + realtype cv_thi; /* farthest endpoint of interval in root search */ + realtype cv_trout; /* t value returned by rootfinding routine */ + realtype *cv_glo; /* saved array of g values at t = tlo */ + realtype *cv_ghi; /* saved array of g values at t = thi */ + realtype *cv_grout; /* array of g values at t = trout */ + realtype cv_toutc; /* copy of tout (if NORMAL mode) */ + realtype cv_ttol; /* tolerance on root location trout */ + int cv_taskc; /* copy of parameter itask */ + int cv_irfnd; /* flag showing whether last step had a root */ + long int cv_nge; /* counter for g evaluations */ + booleantype *cv_gactive; /* array with active/inactive event functions */ + int cv_mxgnull; /* number of warning messages about possible g==0 */ + + /*----------------------- + Fused Vector Operations + -----------------------*/ + + realtype* cv_cvals; /* array of scalars */ + N_Vector* cv_Xvecs; /* array of vectors */ + N_Vector* cv_Zvecs; /* array of vectors */ + + /*------------------------ + Adjoint sensitivity data + ------------------------*/ + + booleantype cv_adj; /* SUNTRUE if performing ASA */ + + struct CVadjMemRec *cv_adj_mem; /* Pointer to adjoint memory structure */ + + booleantype cv_adjMallocDone; + +} *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 + * ================================================================= + */ + +/* + * ----------------------------------------------------------------- + * Types : struct CkpntMemRec, CkpntMem + * ----------------------------------------------------------------- + * The type CkpntMem is type pointer to struct CkpntMemRec. + * This structure contains fields to store all information at a + * check point that is needed to 'hot' start cvodes. + * ----------------------------------------------------------------- + */ + +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; + + /* number of sensitivities */ + int ck_Ns; + + /* Nordsieck History Array for sensitivities */ + N_Vector *ck_znS[L_MAX]; + + /* Do we need to carry quadrature sensitivities? */ + booleantype ck_quadr_sensi; + + /* 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; + int ck_q; + int ck_qprime; + int ck_qwait; + int ck_L; + realtype ck_gammap; + realtype ck_h; + realtype ck_hprime; + realtype ck_hscale; + realtype ck_eta; + realtype ck_etamax; + 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 + * ----------------------------------------------------------------- + * cvaIMMallocFn: Type for a function that initializes the content + * 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 + * interpolated forward solution. + * cvaIMStorePnt: Type for a function that stores a new + * point in the structure d + * ----------------------------------------------------------------- + */ + +typedef booleantype (*cvaIMMallocFn)(CVodeMem cv_mem); +typedef void (*cvaIMFreeFn)(CVodeMem cv_mem); +typedef int (*cvaIMGetYFn)(CVodeMem cv_mem, realtype t, N_Vector y, N_Vector *yS); +typedef int (*cvaIMStorePntFn)(CVodeMem cv_mem, DtpntMem d); + +/* + * ----------------------------------------------------------------- + * Type : struct DtpntMemRec + * ----------------------------------------------------------------- + * This structure contains fields to store all information at a + * data point that is needed to interpolate solution of forward + * simulations. Its content field depends on IMtype. + * ----------------------------------------------------------------- + */ + +struct DtpntMemRec { + realtype t; /* time */ + void *content; /* IMtype-dependent content */ +}; + +/* Data for cubic Hermite interpolation */ +typedef struct HermiteDataMemRec { + N_Vector y; + N_Vector yd; + N_Vector *yS; + N_Vector *ySd; +} *HermiteDataMem; + +/* Data for polynomial interpolation */ +typedef struct PolynomialDataMemRec { + N_Vector y; + N_Vector *yS; + int order; +} *PolynomialDataMem; + + +/* + * ----------------------------------------------------------------- + * Type : struct CVodeBMemRec + * ----------------------------------------------------------------- + * The type CVodeBMem is a pointer to a structure which stores all + * information for ONE backward problem. + * The CVadjMem structure contains a linked list of CVodeBMem pointers + * ----------------------------------------------------------------- + */ + +struct CVodeBMemRec { + + /* Index of this backward problem */ + int cv_index; + + /* Time at which the backward problem is initialized */ + realtype cv_t0; + + /* CVODES memory for this backward problem */ + CVodeMem cv_mem; + + /* Flags to indicate that this backward problem's RHS or quad RHS + * require forward sensitivities */ + booleantype cv_f_withSensi; + booleantype cv_fQ_withSensi; + + /* Right hand side function for backward run */ + CVRhsFnB cv_f; + CVRhsFnBS cv_fs; + + /* Right hand side quadrature function for backward run */ + CVQuadRhsFnB cv_fQ; + CVQuadRhsFnBS cv_fQs; + + /* 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 */ + void *cv_pmem; + + /* Function to free any memory allocated by the preconditioner module */ + int (*cv_pfree)(CVodeBMem cvB_mem); + + /* Time at which to extract solution / quadratures */ + realtype cv_tout; + + /* Workspace Nvector */ + N_Vector cv_y; + + /* Pointer to next structure in list */ + struct CVodeBMemRec *cv_next; + +}; + +/* + * ----------------------------------------------------------------- + * Type : struct CVadjMemRec + * ----------------------------------------------------------------- + * The type CVadjMem is type pointer to struct CVadjMemRec. + * This structure contins fields to store all information + * necessary for adjoint sensitivity analysis. + * ----------------------------------------------------------------- + */ + +struct CVadjMemRec { + + /* -------------------- + * Forward problem data + * -------------------- */ + + /* Integration interval */ + realtype ca_tinitial, ca_tfinal; + + /* Flag for first call to CVodeF */ + booleantype ca_firstCVodeFcall; + + /* Flag if CVodeF was called with TSTOP */ + booleantype ca_tstopCVodeFcall; + realtype ca_tstopCVodeF; + + /* ---------------------- + * Backward problems data + * ---------------------- */ + + /* Storage for backward problems */ + struct CVodeBMemRec *cvB_mem; + + /* Number of backward problems */ + int ca_nbckpbs; + + /* Address of current backward problem */ + struct CVodeBMemRec *ca_bckpbCrt; + + /* Flag for first call to CVodeB */ + booleantype ca_firstCVodeBcall; + + /* ---------------- + * Check point data + * ---------------- */ + + /* Storage for check point information */ + struct CkpntMemRec *ck_mem; + + /* Number of check points */ + int ca_nckpnts; + + /* address of the check point structure for which data is available */ + struct CkpntMemRec *ca_ckpntData; + + /* ------------------ + * Interpolation data + * ------------------ */ + + /* Number of steps between 2 check points */ + long int ca_nsteps; + + /* 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; + cvaIMFreeFn ca_IMfree; + cvaIMStorePntFn ca_IMstore; /* store a new interpolation point */ + cvaIMGetYFn ca_IMget; /* interpolate forward solution */ + + /* Flags controlling the interpolation module */ + booleantype ca_IMmallocDone; /* IM initialized? */ + booleantype ca_IMnewData; /* new data available in dt_mem?*/ + booleantype ca_IMstoreSensi; /* store sensitivities? */ + booleantype ca_IMinterpSensi; /* interpolate sensitivities? */ + + /* Workspace for the interpolation module */ + N_Vector ca_Y[L_MAX]; /* pointers to zn[i] */ + N_Vector *ca_YS[L_MAX]; /* pointers to znS[i] */ + realtype ca_T[L_MAX]; + + /* ------------------------------- + * Workspace for wrapper functions + * ------------------------------- */ + + N_Vector ca_ytmp; + + N_Vector *ca_yStmp; + +}; + + +/* + * ================================================================= + * I N T E R F A C E T O L I N E A R S O L V E R S + * ================================================================= + */ + +/* + * ----------------------------------------------------------------- + * Communication between CVODE and a CVODE Linear Solver + * ----------------------------------------------------------------- + * convfail (input to cv_lsetup) + * + * CV_NO_FAILURES : Either this is the first cv_setup call for this + * step, or the local error test failed on the + * previous attempt at this step (but the nonlinear + * solver iteration converged). + * + * CV_FAIL_BAD_J : This value is passed to cv_lsetup if + * + * (a) The previous nonlinear solver corrector iteration + * did not converge and the linear solver's + * setup routine indicated that its Jacobian- + * related data is not current + * or + * (b) During the previous nonlinear solver corrector + * iteration, the linear solver's solve routine + * failed in a recoverable manner and the + * linear solver's setup routine indicated that + * its Jacobian-related data is not current. + * + * CV_FAIL_OTHER : During the current internal step try, the + * previous nonlinear solver iteration failed to converge + * even though the linear solver was using current + * Jacobian-related data. + * ----------------------------------------------------------------- + */ + +/* Constants for convfail (input to cv_lsetup) */ + +#define CV_NO_FAILURES 0 +#define CV_FAIL_BAD_J 1 +#define CV_FAIL_OTHER 2 + +/* + * ----------------------------------------------------------------- + * int (*cv_linit)(CVodeMem cv_mem); + * ----------------------------------------------------------------- + * The purpose of cv_linit is to complete initializations for a + * specific linear solver, such as counters and statistics. + * An LInitFn should return 0 if it has successfully initialized the + * CVODE linear solver and a negative value otherwise. + * If an error does occur, an appropriate message should be sent to + * the error handler function. + * ----------------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------- + * int (*cv_lsetup)(CVodeMem cv_mem, int convfail, N_Vector ypred, + * N_Vector fpred, booleantype *jcurPtr, + * N_Vector vtemp1, N_Vector vtemp2, + * N_Vector vtemp3); + * ----------------------------------------------------------------- + * The job of cv_lsetup is to prepare the linear solver for + * subsequent calls to cv_lsolve. It may recompute Jacobian- + * related data is it deems necessary. Its parameters are as + * follows: + * + * cv_mem - problem memory pointer of type CVodeMem. See the + * typedef earlier in this file. + * + * convfail - a flag to indicate any problem that occurred during + * the solution of the nonlinear equation on the + * current time step for which the linear solver is + * being used. This flag can be used to help decide + * whether the Jacobian data kept by a CVODE linear + * solver needs to be updated or not. + * Its possible values have been documented above. + * + * ypred - the predicted y vector for the current CVODE internal + * step. + * + * fpred - f(tn, ypred). + * + * jcurPtr - a pointer to a boolean to be filled in by cv_lsetup. + * The function should set *jcurPtr=SUNTRUE if its Jacobian + * data is current after the call and should set + * *jcurPtr=SUNFALSE if its Jacobian data is not current. + * Note: If cv_lsetup calls for re-evaluation of + * Jacobian data (based on convfail and CVODE state + * data), it should return *jcurPtr=SUNTRUE always; + * otherwise an infinite loop can result. + * + * vtemp1 - temporary N_Vector provided for use by cv_lsetup. + * + * vtemp3 - temporary N_Vector provided for use by cv_lsetup. + * + * vtemp3 - temporary N_Vector provided for use by cv_lsetup. + * + * The cv_lsetup routine should return 0 if successful, a positive + * value for a recoverable error, and a negative value for an + * unrecoverable error. + * ----------------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------- + * int (*cv_lsolve)(CVodeMem cv_mem, N_Vector b, N_Vector weight, + * N_Vector ycur, N_Vector fcur); + * ----------------------------------------------------------------- + * cv_lsolve must solve the linear equation P x = b, where + * P is some approximation to (I - gamma J), J = (df/dy)(tn,ycur) + * and the RHS vector b is input. The N-vector ycur contains + * the solver's current approximation to y(tn) and the vector + * fcur contains the N_Vector f(tn,ycur). The solution is to be + * returned in the vector b. cv_lsolve returns a positive value + * for a recoverable error and a negative value for an + * unrecoverable error. Success is indicated by a 0 return value. + * ----------------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------- + * int (*cv_lfree)(CVodeMem cv_mem); + * ----------------------------------------------------------------- + * 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 + * return 0 upon success, nonzero on failure. + * ----------------------------------------------------------------- + */ + +/* + * ================================================================= + * C V O D E S I N T E R N A L F U N C T I O N S + * ================================================================= + */ + +/* Norm functions */ + +realtype cvSensNorm(CVodeMem cv_mem, N_Vector *xS, N_Vector *wS); + +realtype cvSensUpdateNorm(CVodeMem cv_mem, realtype old_nrm, + N_Vector *xS, N_Vector *wS); + + +/* Prototype of internal ewtSet function */ + +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, + const char *msgfmt, ...); + +/* Prototype of internal errHandler 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, + 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 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, + 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, + void *fS_data, + N_Vector tempv, N_Vector ftemp); + +/* Nonlinear solver functions */ +int cvNlsInit(CVodeMem cv_mem); +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 + * ================================================================= + */ + +#if defined(SUNDIALS_EXTENDED_PRECISION) + +#define MSG_TIME "t = %Lg" +#define MSG_TIME_H "t = %Lg and h = %Lg" +#define MSG_TIME_INT "t = %Lg is not between tcur - hu = %Lg and tcur = %Lg." +#define MSG_TIME_TOUT "tout = %Lg" +#define MSG_TIME_TSTOP "tstop = %Lg" + +#elif defined(SUNDIALS_DOUBLE_PRECISION) + +#define MSG_TIME "t = %lg" +#define MSG_TIME_H "t = %lg and h = %lg" +#define MSG_TIME_INT "t = %lg is not between tcur - hu = %lg and tcur = %lg." +#define MSG_TIME_TOUT "tout = %lg" +#define MSG_TIME_TSTOP "tstop = %lg" + +#else + +#define MSG_TIME "t = %g" +#define MSG_TIME_H "t = %g and h = %g" +#define MSG_TIME_INT "t = %g is not between tcur - hu = %g and tcur = %g." +#define MSG_TIME_TOUT "tout = %g" +#define MSG_TIME_TSTOP "tstop = %g" + +#endif + + +/* Initialization and I/O error messages */ + +#define MSGCV_NO_MEM "cvode_mem = NULL illegal." +#define MSGCV_CVMEM_FAIL "Allocation of cvode_mem failed." +#define MSGCV_MEM_FAIL "A memory request failed." +#define MSGCV_BAD_LMM "Illegal value for lmm. The legal values are CV_ADAMS and CV_BDF." +#define MSGCV_NO_MALLOC "Attempt to call before CVodeInit." +#define MSGCV_NEG_MAXORD "maxord <= 0 illegal." +#define MSGCV_BAD_MAXORD "Illegal attempt to increase maximum method order." +#define MSGCV_SET_SLDET "Attempt to use stability limit detection with the CV_ADAMS method illegal." +#define MSGCV_NEG_HMIN "hmin < 0 illegal." +#define MSGCV_NEG_HMAX "hmax < 0 illegal." +#define MSGCV_BAD_HMIN_HMAX "Inconsistent step size limits: hmin > hmax." +#define MSGCV_BAD_RELTOL "reltol < 0 illegal." +#define MSGCV_BAD_ABSTOL "abstol has negative component(s) (illegal)." +#define MSGCV_NULL_ABSTOL "abstol = NULL illegal." +#define MSGCV_NULL_Y0 "y0 = NULL illegal." +#define MSGCV_Y0_FAIL_CONSTR "y0 fails to satisfy constraints." +#define MSGCV_BAD_ISM_CONSTR "Constraints can not be enforced while forward sensitivity is used with simultaneous method" +#define MSGCV_NULL_F "f = NULL illegal." +#define MSGCV_NULL_G "g = NULL illegal." +#define MSGCV_BAD_NVECTOR "A required vector operation is not implemented." +#define MSGCV_BAD_CONSTR "Illegal values in constraints vector." +#define MSGCV_BAD_K "Illegal value for k." +#define MSGCV_NULL_DKY "dky = NULL illegal." +#define MSGCV_BAD_T "Illegal value for t." MSG_TIME_INT +#define MSGCV_NO_ROOT "Rootfinding was not initialized." +#define MSGCV_NLS_INIT_FAIL "The nonlinear solver's init routine failed." + +#define MSGCV_NO_QUAD "Quadrature integration not activated." +#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_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_PBAR "pbar has zero component(s) (illegal)." +#define MSGCV_BAD_PLIST "plist has negative component(s) (illegal)." +#define MSGCV_BAD_NS "NS <= 0 illegal." +#define MSGCV_NULL_YS0 "yS0 = NULL illegal." +#define MSGCV_BAD_ISM "Illegal value for ism. Legal values are: CV_SIMULTANEOUS, CV_STAGGERED and CV_STAGGERED1." +#define MSGCV_BAD_IFS "Illegal value for ifS. Legal values are: CV_ALLSENS and CV_ONESENS." +#define MSGCV_BAD_ISM_IFS "Illegal ism = CV_STAGGERED1 for CVodeSensInit." +#define MSGCV_BAD_IS "Illegal value for is." +#define MSGCV_NULL_DKYA "dkyA = NULL illegal." +#define MSGCV_BAD_DQTYPE "Illegal value for DQtype. Legal values are: CV_CENTERED and CV_FORWARD." +#define MSGCV_BAD_DQRHO "DQrhomax < 0 illegal." + +#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_NO_QUADSENSI "Forward sensitivity analysis for quadrature variables not activated." +#define MSGCV_NULL_YQS0 "yQS0 = NULL illegal." + +/* CVode Error Messages */ + +#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." +#define MSGCV_BAD_EWT "Initial ewt has component(s) equal to zero (illegal)." +#define MSGCV_EWT_NOW_BAD "At " MSG_TIME ", a component of ewt has become <= 0." +#define MSGCV_BAD_ITASK "Illegal value for itask." +#define MSGCV_BAD_H0 "h0 and tout - t0 inconsistent." +#define MSGCV_BAD_TOUT "Trouble interpolating at " MSG_TIME_TOUT ". tout too far back in direction of integration" +#define MSGCV_EWT_FAIL "The user-provide EwtSet function failed." +#define MSGCV_EWT_NOW_FAIL "At " MSG_TIME ", the user-provide EwtSet function failed." +#define MSGCV_LINIT_FAIL "The linear solver's init routine failed." +#define MSGCV_HNIL_DONE "The above warning has been issued mxhnil times and will not be issued again for this problem." +#define MSGCV_TOO_CLOSE "tout too close to t0 to start integration." +#define MSGCV_MAX_STEPS "At " MSG_TIME ", mxstep steps taken before reaching tout." +#define MSGCV_TOO_MUCH_ACC "At " MSG_TIME ", too much accuracy requested." +#define MSGCV_HNIL "Internal " MSG_TIME_H " are such that t + h = t on the next step. The solver will continue anyway." +#define MSGCV_ERR_FAILS "At " MSG_TIME_H ", the error test failed repeatedly or with |h| = hmin." +#define MSGCV_CONV_FAILS "At " MSG_TIME_H ", the corrector convergence test failed repeatedly or with |h| = hmin." +#define MSGCV_SETUP_FAILED "At " MSG_TIME ", the setup routine failed in an unrecoverable manner." +#define MSGCV_SOLVE_FAILED "At " MSG_TIME ", the solve routine failed in an unrecoverable manner." +#define MSGCV_FAILED_CONSTR "At " MSG_TIME ", unable to satisfy inequality constraints." +#define MSGCV_RHSFUNC_FAILED "At " MSG_TIME ", the right-hand side routine failed in an unrecoverable manner." +#define MSGCV_RHSFUNC_UNREC "At " MSG_TIME ", the right-hand side failed in a recoverable manner, but no recovery is possible." +#define MSGCV_RHSFUNC_REPTD "At " MSG_TIME " repeated recoverable right-hand side function errors." +#define MSGCV_RHSFUNC_FIRST "The right-hand side routine failed at the first call." +#define MSGCV_RTFUNC_FAILED "At " MSG_TIME ", the rootfinding routine failed in an unrecoverable manner." +#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_NO_TOLQ "No integration tolerances for quadrature variables have been specified." +#define MSGCV_BAD_EWTQ "Initial ewtQ has component(s) equal to zero (illegal)." +#define MSGCV_EWTQ_NOW_BAD "At " MSG_TIME ", a component of ewtQ has become <= 0." +#define MSGCV_QRHSFUNC_FAILED "At " MSG_TIME ", the quadrature right-hand side routine failed in an unrecoverable manner." +#define MSGCV_QRHSFUNC_UNREC "At " MSG_TIME ", the quadrature right-hand side failed in a recoverable manner, but no recovery is possible." +#define MSGCV_QRHSFUNC_REPTD "At " MSG_TIME " repeated recoverable quadrature right-hand side function errors." +#define MSGCV_QRHSFUNC_FIRST "The quadrature right-hand side routine failed at the first call." + +#define MSGCV_NO_TOLS "No integration tolerances for sensitivity variables have been specified." +#define MSGCV_NULL_P "p = NULL when using internal DQ for sensitivity RHS illegal." +#define MSGCV_BAD_EWTS "Initial ewtS has component(s) equal to zero (illegal)." +#define MSGCV_EWTS_NOW_BAD "At " MSG_TIME ", a component of ewtS has become <= 0." +#define MSGCV_SRHSFUNC_FAILED "At " MSG_TIME ", the sensitivity right-hand side routine failed in an unrecoverable manner." +#define MSGCV_SRHSFUNC_UNREC "At " MSG_TIME ", the sensitivity right-hand side failed in a recoverable manner, but no recovery is possible." +#define MSGCV_SRHSFUNC_REPTD "At " MSG_TIME " repeated recoverable sensitivity right-hand side function errors." +#define MSGCV_SRHSFUNC_FIRST "The sensitivity right-hand side routine failed at the first call." + +#define MSGCV_NULL_FQ "CVODES is expected to use DQ to evaluate the RHS of quad. sensi., but quadratures were not initialized." +#define MSGCV_NO_TOLQS "No integration tolerances for quadrature sensitivity variables have been specified." +#define MSGCV_BAD_EWTQS "Initial ewtQS has component(s) equal to zero (illegal)." +#define MSGCV_EWTQS_NOW_BAD "At " MSG_TIME ", a component of ewtQS has become <= 0." +#define MSGCV_QSRHSFUNC_FAILED "At " MSG_TIME ", the quadrature sensitivity right-hand side routine failed in an unrecoverable manner." +#define MSGCV_QSRHSFUNC_UNREC "At " MSG_TIME ", the quadrature sensitivity right-hand side failed in a recoverable manner, but no recovery is possible." +#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 + * ================================================================= + */ + +#define MSGCV_NO_ADJ "Illegal attempt to call before calling CVodeAdjMalloc." +#define MSGCV_BAD_STEPS "Steps nonpositive illegal." +#define MSGCV_BAD_INTERP "Illegal value for interp." +#define MSGCV_BAD_WHICH "Illegal value for which." +#define MSGCV_NO_BCK "No backward problems have been defined yet." +#define MSGCV_NO_FWD "Illegal attempt to call before calling CVodeF." +#define MSGCV_BAD_TB0 "The initial time tB0 for problem %d is outside the interval over which the forward problem was solved." +#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_BAD_TINTERP "Bad t = %g for interpolation." +#define MSGCV_WRONG_INTERP "This function cannot be called for the specified interp type." + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_io.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_io.c new file mode 100644 index 0000000..cb40f8e --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_io.c @@ -0,0 +1,2017 @@ +/* + * ----------------------------------------------------------------- + * $Revision$ + * $Date$ + * ----------------------------------------------------------------- + * Programmer(s): 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 optional input and output + * functions for the CVODES solver. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "cvodes_impl.h" + +#include <sundials/sundials_math.h> +#include <sundials/sundials_types.h> + +#define ZERO RCONST(0.0) +#define HALF RCONST(0.5) +#define ONE RCONST(1.0) +#define TWOPT5 RCONST(2.5) + +/* + * ================================================================= + * CVODES optional input functions + * ================================================================= + */ + +/* + * CVodeSetErrHandlerFn + * + * Specifies the error handler function + */ + +int CVodeSetErrHandlerFn(void *cvode_mem, CVErrHandlerFn ehfun, void *eh_data) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetErrHandlerFn", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + cv_mem->cv_ehfun = ehfun; + cv_mem->cv_eh_data = eh_data; + + return(CV_SUCCESS); +} + +/* + * CVodeSetErrFile + * + * Specifies the FILE pointer for output (NULL means no messages) + */ + +int CVodeSetErrFile(void *cvode_mem, FILE *errfp) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetErrFile", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + cv_mem->cv_errfp = errfp; + + return(CV_SUCCESS); +} + +/* + * CVodeSetUserData + * + * Specifies the user data pointer for f + */ + +int CVodeSetUserData(void *cvode_mem, void *user_data) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetUserData", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + cv_mem->cv_user_data = user_data; + + return(CV_SUCCESS); +} + +/* + * CVodeSetMaxOrd + * + * Specifies the maximum method order + */ + +int CVodeSetMaxOrd(void *cvode_mem, int maxord) +{ + CVodeMem cv_mem; + int qmax_alloc; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetMaxOrd", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + if (maxord <= 0) { + 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; + qmax_alloc = SUNMIN(qmax_alloc, cv_mem->cv_qmax_allocQ); + qmax_alloc = SUNMIN(qmax_alloc, cv_mem->cv_qmax_allocS); + + if (maxord > qmax_alloc) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetMaxOrd", MSGCV_BAD_MAXORD); + return(CV_ILL_INPUT); + } + + cv_mem->cv_qmax = maxord; + + return(CV_SUCCESS); +} + +/* + * CVodeSetMaxNumSteps + * + * Specifies the maximum number of integration steps + */ + +int CVodeSetMaxNumSteps(void *cvode_mem, long int mxsteps) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetMaxNumSteps", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + /* Passing mxsteps=0 sets the default. Passing mxsteps<0 disables the test. */ + if (mxsteps == 0) + cv_mem->cv_mxstep = MXSTEP_DEFAULT; + else + cv_mem->cv_mxstep = mxsteps; + + return(CV_SUCCESS); +} + +/* + * CVodeSetMaxHnilWarns + * + * Specifies the maximum number of warnings for small h + */ + +int CVodeSetMaxHnilWarns(void *cvode_mem, int mxhnil) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetMaxHnilWarns", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + cv_mem->cv_mxhnil = mxhnil; + + return(CV_SUCCESS); +} + +/* + *CVodeSetStabLimDet + * + * Turns on/off the stability limit detection algorithm + */ + +int CVodeSetStabLimDet(void *cvode_mem, booleantype sldet) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetStabLimDet", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + if( sldet && (cv_mem->cv_lmm != CV_BDF) ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetStabLimDet", MSGCV_SET_SLDET); + return(CV_ILL_INPUT); + } + + cv_mem->cv_sldeton = sldet; + + return(CV_SUCCESS); +} + +/* + * CVodeSetInitStep + * + * Specifies the initial step size + */ + +int CVodeSetInitStep(void *cvode_mem, realtype hin) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetInitStep", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + cv_mem->cv_hin = hin; + + return(CV_SUCCESS); +} + +/* + * CVodeSetMinStep + * + * Specifies the minimum step size + */ + +int CVodeSetMinStep(void *cvode_mem, realtype hmin) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetMinStep", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + if (hmin<0) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetMinStep", MSGCV_NEG_HMIN); + return(CV_ILL_INPUT); + } + + /* Passing 0 sets hmin = zero */ + if (hmin == ZERO) { + cv_mem->cv_hmin = HMIN_DEFAULT; + return(CV_SUCCESS); + } + + if (hmin * cv_mem->cv_hmax_inv > ONE) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetMinStep", MSGCV_BAD_HMIN_HMAX); + return(CV_ILL_INPUT); + } + + cv_mem->cv_hmin = hmin; + + return(CV_SUCCESS); +} + +/* + * CVodeSetMaxStep + * + * Specifies the maximum step size + */ + +int CVodeSetMaxStep(void *cvode_mem, realtype hmax) +{ + realtype hmax_inv; + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetMaxStep", MSGCV_NO_MEM); + return (CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + if (hmax < 0) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetMaxStep", MSGCV_NEG_HMAX); + return(CV_ILL_INPUT); + } + + /* Passing 0 sets hmax = infinity */ + if (hmax == ZERO) { + cv_mem->cv_hmax_inv = HMAX_INV_DEFAULT; + return(CV_SUCCESS); + } + + hmax_inv = ONE/hmax; + if (hmax_inv * cv_mem->cv_hmin > ONE) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetMaxStep", MSGCV_BAD_HMIN_HMAX); + return(CV_ILL_INPUT); + } + + cv_mem->cv_hmax_inv = hmax_inv; + + return(CV_SUCCESS); +} + +/* + * CVodeSetStopTime + * + * Specifies the time beyond which the integration is not to proceed. + */ + +int CVodeSetStopTime(void *cvode_mem, realtype tstop) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetStopTime", MSGCV_NO_MEM); + return (CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* If CVode was called at least once, test if tstop is legal + * (i.e. if it was not already passed). + * If CVodeSetStopTime is called before the first call to CVode, + * tstop will be checked in CVode. */ + if (cv_mem->cv_nst > 0) { + + if ( (tstop - cv_mem->cv_tn) * cv_mem->cv_h < ZERO ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetStopTime", MSGCV_BAD_TSTOP, tstop, cv_mem->cv_tn); + return(CV_ILL_INPUT); + } + + } + + cv_mem->cv_tstop = tstop; + cv_mem->cv_tstopset = SUNTRUE; + + return(CV_SUCCESS); +} + +/* + * CVodeSetMaxErrTestFails + * + * Specifies the maximum number of error test failures during one + * step try. + */ + +int CVodeSetMaxErrTestFails(void *cvode_mem, int maxnef) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetMaxErrTestFails", MSGCV_NO_MEM); + return (CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + cv_mem->cv_maxnef = maxnef; + + return(CV_SUCCESS); +} + +/* + * CVodeSetMaxConvFails + * + * Specifies the maximum number of nonlinear convergence failures + * during one step try. + */ + +int CVodeSetMaxConvFails(void *cvode_mem, int maxncf) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetMaxConvFails", MSGCV_NO_MEM); + return (CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + cv_mem->cv_maxncf = maxncf; + + return(CV_SUCCESS); +} + +/* + * CVodeSetMaxNonlinIters + * + * Specifies the maximum number of nonlinear iterations during + * one solve. + */ + +int CVodeSetMaxNonlinIters(void *cvode_mem, int maxcor) +{ + CVodeMem cv_mem; + booleantype sensi_sim; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "CVodeSetMaxNonlinIters", MSGCV_NO_MEM); + return (CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + /* Are we computing sensitivities with the simultaneous approach? */ + sensi_sim = (cv_mem->cv_sensi && (cv_mem->cv_ism==CV_SIMULTANEOUS)); + + if (sensi_sim) { + + /* check that the NLS is non-NULL */ + if (cv_mem->NLSsim == NULL) { + cvProcessError(NULL, CV_MEM_FAIL, "CVODES", + "CVodeSetMaxNonlinIters", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + return(SUNNonlinSolSetMaxIters(cv_mem->NLSsim, maxcor)); + + } else { + + /* check that the NLS is non-NULL */ + if (cv_mem->NLS == NULL) { + cvProcessError(NULL, CV_MEM_FAIL, "CVODES", + "CVodeSetMaxNonlinIters", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + return(SUNNonlinSolSetMaxIters(cv_mem->NLS, maxcor)); + } + + return(CV_SUCCESS); +} + +/* + * CVodeSetNonlinConvCoef + * + * Specifies the coeficient in the nonlinear solver convergence + * test + */ + +int CVodeSetNonlinConvCoef(void *cvode_mem, realtype nlscoef) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetNonlinConvCoef", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + cv_mem->cv_nlscoef = nlscoef; + + return(CV_SUCCESS); +} + +/* + * CVodeSetRootDirection + * + * Specifies the direction of zero-crossings to be monitored. + * The default is to monitor both crossings. + */ + +int CVodeSetRootDirection(void *cvode_mem, int *rootdir) +{ + CVodeMem cv_mem; + int i, nrt; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetRootDirection", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + nrt = cv_mem->cv_nrtfn; + if (nrt==0) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetRootDirection", MSGCV_NO_ROOT); + return(CV_ILL_INPUT); + } + + for(i=0; i<nrt; i++) cv_mem->cv_rootdir[i] = rootdir[i]; + + return(CV_SUCCESS); +} + + +/* + * CVodeSetNoInactiveRootWarn + * + * Disables issuing a warning if some root function appears + * to be identically zero at the beginning of the integration + */ + +int CVodeSetNoInactiveRootWarn(void *cvode_mem) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetNoInactiveRootWarn", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + cv_mem->cv_mxgnull = 0; + + return(CV_SUCCESS); +} + +/* + * CVodeSetConstraints + * + * Setup for constraint handling feature + */ + +int CVodeSetConstraints(void *cvode_mem, N_Vector constraints) +{ + CVodeMem cv_mem; + realtype temptest; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetConstraints", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + /* If there are no constraints, destroy data structures */ + if (constraints == NULL) { + if (cv_mem->cv_constraintsMallocDone) { + N_VDestroy(cv_mem->cv_constraints); + cv_mem->cv_lrw -= cv_mem->cv_lrw1; + cv_mem->cv_liw -= cv_mem->cv_liw1; + } + cv_mem->cv_constraintsMallocDone = SUNFALSE; + cv_mem->cv_constraintsSet = SUNFALSE; + return(CV_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) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetConstraints", MSGCV_BAD_NVECTOR); + return(CV_ILL_INPUT); + } + + /* Check the constraints vector */ + temptest = N_VMaxNorm(constraints); + if ((temptest > TWOPT5) || (temptest < HALF)) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetConstraints", MSGCV_BAD_CONSTR); + return(CV_ILL_INPUT); + } + + if ( !(cv_mem->cv_constraintsMallocDone) ) { + cv_mem->cv_constraints = N_VClone(constraints); + cv_mem->cv_lrw += cv_mem->cv_lrw1; + cv_mem->cv_liw += cv_mem->cv_liw1; + cv_mem->cv_constraintsMallocDone = SUNTRUE; + } + + /* Load the constraints vector */ + N_VScale(ONE, constraints, cv_mem->cv_constraints); + + cv_mem->cv_constraintsSet = SUNTRUE; + + return(CV_SUCCESS); +} + +/* + * ================================================================= + * Quadrature optional input functions + * ================================================================= + */ + +int CVodeSetQuadErrCon(void *cvode_mem, booleantype errconQ) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetQuadErrCon", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + cv_mem->cv_errconQ = errconQ; + + return(CV_SUCCESS); +} + +/* + * ================================================================= + * FSA optional input functions + * ================================================================= + */ + +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); + 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); + return(CV_ILL_INPUT); + } + + if (DQrhomax < ZERO ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetSensDQMethod", MSGCV_BAD_DQRHO); + return(CV_ILL_INPUT); + } + + cv_mem->cv_DQtype = DQtype; + cv_mem->cv_DQrhomax = DQrhomax; + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int CVodeSetSensErrCon(void *cvode_mem, booleantype errconS) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetSensErrCon", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + cv_mem->cv_errconS = errconS; + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int CVodeSetSensMaxNonlinIters(void *cvode_mem, int maxcorS) +{ + CVodeMem cv_mem; + booleantype sensi_stg; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "CVodeSetSensMaxNonlinIters", MSGCV_NO_MEM); + return (CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + /* Are we computing sensitivities with a staggered approach? */ + sensi_stg = (cv_mem->cv_sensi && (cv_mem->cv_ism==CV_STAGGERED)); + + if (sensi_stg) { + + /* check that the NLS is non-NULL */ + if (cv_mem->NLSstg == NULL) { + cvProcessError(NULL, CV_MEM_FAIL, "CVODES", + "CVodeSetSensMaxNonlinIters", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + return(SUNNonlinSolSetMaxIters(cv_mem->NLSstg, maxcorS)); + + } else { + + /* check that the NLS is non-NULL */ + if (cv_mem->NLSstg1 == NULL) { + cvProcessError(NULL, CV_MEM_FAIL, "CVODES", + "CVodeSetMaxNonlinIters", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + return(SUNNonlinSolSetMaxIters(cv_mem->NLSstg1, maxcorS)); + } + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int CVodeSetSensParams(void *cvode_mem, realtype *p, realtype *pbar, int *plist) +{ + CVodeMem cv_mem; + int is, Ns; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetSensParams", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + /* Was sensitivity initialized? */ + + if (cv_mem->cv_SensMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeSetSensParams", MSGCV_NO_SENSI); + return(CV_NO_SENS); + } + + Ns = cv_mem->cv_Ns; + + /* Parameters */ + + cv_mem->cv_p = p; + + /* pbar */ + + if (pbar != NULL) + for (is=0; is<Ns; is++) { + if (pbar[is] == ZERO) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetSensParams", MSGCV_BAD_PBAR); + return(CV_ILL_INPUT); + } + cv_mem->cv_pbar[is] = SUNRabs(pbar[is]); + } + else + for (is=0; is<Ns; is++) + cv_mem->cv_pbar[is] = ONE; + + /* plist */ + + if (plist != NULL) + for (is=0; is<Ns; is++) { + if ( plist[is] < 0 ) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetSensParams", MSGCV_BAD_PLIST); + return(CV_ILL_INPUT); + } + cv_mem->cv_plist[is] = plist[is]; + } + else + for (is=0; is<Ns; is++) + cv_mem->cv_plist[is] = is; + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int CVodeSetQuadSensErrCon(void *cvode_mem, booleantype errconQS) +{ + CVodeMem cv_mem; + + 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? */ + + 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); + return(CV_NO_QUAD); + } + + cv_mem->cv_errconQS = errconQS; + + return(CV_SUCCESS); +} + +/* + * ================================================================= + * CVODES optional output functions + * ================================================================= + */ + +/* + * CVodeGetNumSteps + * + * Returns the current number of integration steps + */ + +int CVodeGetNumSteps(void *cvode_mem, long int *nsteps) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumSteps", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *nsteps = cv_mem->cv_nst; + + return(CV_SUCCESS); +} + +/* + * CVodeGetNumRhsEvals + * + * Returns the current number of calls to f + */ + +int CVodeGetNumRhsEvals(void *cvode_mem, long int *nfevals) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumRhsEvals", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *nfevals = cv_mem->cv_nfe; + + return(CV_SUCCESS); +} + +/* + * CVodeGetNumLinSolvSetups + * + * Returns the current number of calls to the linear solver setup routine + */ + +int CVodeGetNumLinSolvSetups(void *cvode_mem, long int *nlinsetups) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumLinSolvSetups", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *nlinsetups = cv_mem->cv_nsetups; + + return(CV_SUCCESS); +} + +/* + * CVodeGetNumErrTestFails + * + * Returns the current number of error test failures + */ + +int CVodeGetNumErrTestFails(void *cvode_mem, long int *netfails) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumErrTestFails", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *netfails = cv_mem->cv_netf; + + return(CV_SUCCESS); +} + +/* + * CVodeGetLastOrder + * + * Returns the order on the last succesful step + */ + +int CVodeGetLastOrder(void *cvode_mem, int *qlast) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetLastOrder", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *qlast = cv_mem->cv_qu; + + return(CV_SUCCESS); +} + +/* + * CVodeGetCurrentOrder + * + * Returns the order to be attempted on the next step + */ + +int CVodeGetCurrentOrder(void *cvode_mem, int *qcur) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetCurrentOrder", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *qcur = cv_mem->cv_next_q; + + return(CV_SUCCESS); +} + +/* + * CVodeGetNumStabLimOrderReds + * + * Returns the number of order reductions triggered by the stability + * limit detection algorithm + */ + +int CVodeGetNumStabLimOrderReds(void *cvode_mem, long int *nslred) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumStabLimOrderReds", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + if (cv_mem->cv_sldeton==SUNFALSE) + *nslred = 0; + else + *nslred = cv_mem->cv_nor; + + return(CV_SUCCESS); +} + +/* + * CVodeGetActualInitStep + * + * Returns the step size used on the first step + */ + +int CVodeGetActualInitStep(void *cvode_mem, realtype *hinused) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetActualInitStep", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *hinused = cv_mem->cv_h0u; + + return(CV_SUCCESS); +} + +/* + * CVodeGetLastStep + * + * Returns the step size used on the last successful step + */ + +int CVodeGetLastStep(void *cvode_mem, realtype *hlast) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetLastStep", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *hlast = cv_mem->cv_hu; + + return(CV_SUCCESS); +} + +/* + * CVodeGetCurrentStep + * + * Returns the step size to be attempted on the next step + */ + +int CVodeGetCurrentStep(void *cvode_mem, realtype *hcur) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetCurrentStep", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *hcur = cv_mem->cv_next_h; + + return(CV_SUCCESS); +} + +/* + * CVodeGetCurrentTime + * + * Returns the current value of the independent variable + */ + +int CVodeGetCurrentTime(void *cvode_mem, realtype *tcur) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetCurrentTime", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *tcur = cv_mem->cv_tn; + + return(CV_SUCCESS); +} + +/* + * CVodeGetTolScaleFactor + * + * Returns a suggested factor for scaling tolerances + */ + +int CVodeGetTolScaleFactor(void *cvode_mem, realtype *tolsfact) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetTolScaleFactor", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *tolsfact = cv_mem->cv_tolsf; + + return(CV_SUCCESS); +} + +/* + * CVodeGetErrWeights + * + * This routine returns the current weight vector. + */ + +int CVodeGetErrWeights(void *cvode_mem, N_Vector eweight) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetErrWeights", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + N_VScale(ONE, cv_mem->cv_ewt, eweight); + + return(CV_SUCCESS); +} + +/* + * CVodeGetEstLocalErrors + * + * Returns an estimate of the local error + */ + +int CVodeGetEstLocalErrors(void *cvode_mem, N_Vector ele) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetEstLocalErrors", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + N_VScale(ONE, cv_mem->cv_acor, ele); + + return(CV_SUCCESS); +} + +/* + * CVodeGetWorkSpace + * + * Returns integrator work space requirements + */ + +int CVodeGetWorkSpace(void *cvode_mem, long int *lenrw, long int *leniw) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetWorkSpace", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *leniw = cv_mem->cv_liw; + *lenrw = cv_mem->cv_lrw; + + 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, + realtype *hcur, realtype *tcur) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetIntegratorStats", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *nsteps = cv_mem->cv_nst; + *nfevals = cv_mem->cv_nfe; + *nlinsetups = cv_mem->cv_nsetups; + *netfails = cv_mem->cv_netf; + *qlast = cv_mem->cv_qu; + *qcur = cv_mem->cv_next_q; + *hinused = cv_mem->cv_h0u; + *hlast = cv_mem->cv_hu; + *hcur = cv_mem->cv_next_h; + *tcur = cv_mem->cv_tn; + + return(CV_SUCCESS); +} + +/* + * CVodeGetNumGEvals + * + * Returns the current number of calls to g (for rootfinding) + */ + +int CVodeGetNumGEvals(void *cvode_mem, long int *ngevals) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumGEvals", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *ngevals = cv_mem->cv_nge; + + return(CV_SUCCESS); +} + +/* + * CVodeGetRootInfo + * + * Returns pointer to array rootsfound showing roots found + */ + +int CVodeGetRootInfo(void *cvode_mem, int *rootsfound) +{ + CVodeMem cv_mem; + int i, nrt; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetRootInfo", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + nrt = cv_mem->cv_nrtfn; + + for (i=0; i<nrt; i++) rootsfound[i] = cv_mem->cv_iroots[i]; + + return(CV_SUCCESS); +} + + +/* + * CVodeGetNumNonlinSolvIters + * + * Returns the current number of iterations in the nonlinear solver + */ + +int CVodeGetNumNonlinSolvIters(void *cvode_mem, long int *nniters) +{ + CVodeMem cv_mem; + booleantype sensi_sim; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "CVodeGetNumNonlinSolvIters", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + /* are we computing sensitivities with the simultaneous approach? */ + sensi_sim = (cv_mem->cv_sensi && (cv_mem->cv_ism==CV_SIMULTANEOUS)); + + /* get number of iterations from the NLS */ + if (sensi_sim) { + + /* check that the NLS is non-NULL */ + if (cv_mem->NLSsim == NULL) { + cvProcessError(NULL, CV_MEM_FAIL, "CVODES", + "CVodeGetNumNonlinSolvIters", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + return(SUNNonlinSolGetNumIters(cv_mem->NLSsim, nniters)); + + } else { + + /* check that the NLS is non-NULL */ + if (cv_mem->NLS == NULL) { + cvProcessError(NULL, CV_MEM_FAIL, "CVODES", + "CVodeGetNumNonlinSolvIters", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + return(SUNNonlinSolGetNumIters(cv_mem->NLS, nniters)); + } + + return(CV_SUCCESS); +} + +/* + * CVodeGetNumNonlinSolvConvFails + * + * Returns the current number of convergence failures in the + * nonlinear solver + */ + +int CVodeGetNumNonlinSolvConvFails(void *cvode_mem, long int *nncfails) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumNonlinSolvConvFails", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *nncfails = cv_mem->cv_ncfn; + + return(CV_SUCCESS); +} + +/* + * CVodeGetNonlinSolvStats + * + * Returns nonlinear solver statistics + */ + +int CVodeGetNonlinSolvStats(void *cvode_mem, long int *nniters, + long int *nncfails) +{ + CVodeMem cv_mem; + booleantype sensi_sim; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "CVodeGetNonlinSolvStats", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + *nncfails = cv_mem->cv_ncfn; + + /* are we computing sensitivities with the simultaneous approach? */ + sensi_sim = (cv_mem->cv_sensi && (cv_mem->cv_ism==CV_SIMULTANEOUS)); + + /* get number of iterations from the NLS */ + if (sensi_sim) { + + /* check that the NLS is non-NULL */ + if (cv_mem->NLSsim == NULL) { + cvProcessError(NULL, CV_MEM_FAIL, "CVODES", + "CVodeGetNumNonlinSolvIters", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + return(SUNNonlinSolGetNumIters(cv_mem->NLSsim, nniters)); + + } else { + + /* check that the NLS is non-NULL */ + if (cv_mem->NLS == NULL) { + cvProcessError(NULL, CV_MEM_FAIL, "CVODES", + "CVodeGetNumNonlinSolvIters", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + return(SUNNonlinSolGetNumIters(cv_mem->NLS, nniters)); + } + + return(CV_SUCCESS); +} + + +/* + * ================================================================= + * Quadrature optional output functions + * ================================================================= + */ + +/*-----------------------------------------------------------------*/ + +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); + 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); + return(CV_NO_QUAD); + } + + *nfQevals = cv_mem->cv_nfQe; + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +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); + 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); + return(CV_NO_QUAD); + } + + *nQetfails = cv_mem->cv_netfQ; + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +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); + 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); + return(CV_NO_QUAD); + } + + if(cv_mem->cv_errconQ) N_VScale(ONE, cv_mem->cv_ewtQ, eQweight); + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +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); + 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); + return(CV_NO_QUAD); + } + + *nfQevals = cv_mem->cv_nfQe; + *nQetfails = cv_mem->cv_netfQ; + + return(CV_SUCCESS); +} + +/* + * ================================================================= + * Quadrature FSA optional output functions + * ================================================================= + */ + +/*-----------------------------------------------------------------*/ + +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); + 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); + return(CV_NO_QUADSENS); + } + + *nfQSevals = cv_mem->cv_nfQSe; + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +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); + 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); + return(CV_NO_QUADSENS); + } + + *nQSetfails = cv_mem->cv_netfQS; + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int CVodeGetQuadSensErrWeights(void *cvode_mem, N_Vector *eQSweight) +{ + CVodeMem cv_mem; + int is, Ns; + + if (cvode_mem==NULL) { + 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); + return(CV_NO_QUADSENS); + } + Ns = cv_mem->cv_Ns; + + if (cv_mem->cv_errconQS) + for (is=0; is<Ns; is++) + N_VScale(ONE, cv_mem->cv_ewtQS[is], eQSweight[is]); + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int CVodeGetQuadSensStats(void *cvode_mem, long int *nfQSevals, long int *nQSetfails) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + 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); + return(CV_NO_QUADSENS); + } + + *nfQSevals = cv_mem->cv_nfQSe; + *nQSetfails = cv_mem->cv_netfQS; + + return(CV_SUCCESS); +} + + +/* + * ================================================================= + * FSA optional output functions + * ================================================================= + */ + +/*-----------------------------------------------------------------*/ + +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); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + if (cv_mem->cv_sensi==SUNFALSE) { + cvProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetSensNumRhsEvals", MSGCV_NO_SENSI); + return(CV_NO_SENS); + } + + *nfSevals = cv_mem->cv_nfSe; + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +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); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + if (cv_mem->cv_sensi==SUNFALSE) { + cvProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetNumRhsEvalsSens", MSGCV_NO_SENSI); + return(CV_NO_SENS); + } + + *nfevalsS = cv_mem->cv_nfeS; + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +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); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + if (cv_mem->cv_sensi==SUNFALSE) { + cvProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetSensNumErrTestFails", MSGCV_NO_SENSI); + return(CV_NO_SENS); + } + + *nSetfails = cv_mem->cv_netfS; + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +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); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + if (cv_mem->cv_sensi==SUNFALSE) { + cvProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetSensNumLinSolvSetups", MSGCV_NO_SENSI); + return(CV_NO_SENS); + } + + *nlinsetupsS = cv_mem->cv_nsetupsS; + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int CVodeGetSensErrWeights(void *cvode_mem, N_Vector *eSweight) +{ + CVodeMem cv_mem; + int is, Ns; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetSensErrWeights", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + if (cv_mem->cv_sensi==SUNFALSE) { + cvProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetSensErrWeights", MSGCV_NO_SENSI); + return(CV_NO_SENS); + } + + Ns = cv_mem->cv_Ns; + + for (is=0; is<Ns; is++) + N_VScale(ONE, cv_mem->cv_ewtS[is], eSweight[is]); + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int CVodeGetSensStats(void *cvode_mem, long int *nfSevals, long int *nfevalsS, + long int *nSetfails, long int *nlinsetupsS) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetSensStats", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + if (cv_mem->cv_sensi==SUNFALSE) { + cvProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetSensStats", MSGCV_NO_SENSI); + return(CV_NO_SENS); + } + + *nfSevals = cv_mem->cv_nfSe; + *nfevalsS = cv_mem->cv_nfeS; + *nSetfails = cv_mem->cv_netfS; + *nlinsetupsS = cv_mem->cv_nsetupsS; + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int CVodeGetSensNumNonlinSolvIters(void *cvode_mem, long int *nSniters) +{ + CVodeMem cv_mem; + booleantype sensi_stg; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "CVodeGetSensNumNonlinSolvIters", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + if (cv_mem->cv_sensi==SUNFALSE) { + cvProcessError(cv_mem, CV_NO_SENS, "CVODES", + "CVodeGetSensNumNonlinSolvIters", MSGCV_NO_SENSI); + return(CV_NO_SENS); + } + + /* Are we computing sensitivities with a staggered approach? */ + sensi_stg = (cv_mem->cv_sensi && (cv_mem->cv_ism==CV_STAGGERED)); + + if (sensi_stg) { + + /* check that the NLS is non-NULL */ + if (cv_mem->NLSstg == NULL) { + cvProcessError(NULL, CV_MEM_FAIL, "CVODES", + "CVodeGetSensNumNonlinSolvIters", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + return(SUNNonlinSolGetNumIters(cv_mem->NLSstg, nSniters)); + + } else { + + /* check that the NLS is non-NULL */ + if (cv_mem->NLSstg1 == NULL) { + cvProcessError(NULL, CV_MEM_FAIL, "CVODES", + "CVodeGetSensNumNonlinSolvIters", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + return(SUNNonlinSolGetNumIters(cv_mem->NLSstg1, nSniters)); + } + +} + +/*-----------------------------------------------------------------*/ + +int CVodeGetSensNumNonlinSolvConvFails(void *cvode_mem, long int *nSncfails) +{ + CVodeMem cv_mem; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetSensNumNonlinSolvConvFails", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + if (cv_mem->cv_sensi==SUNFALSE) { + cvProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetSensNumNonlinSolvConvFails", MSGCV_NO_SENSI); + return(CV_NO_SENS); + } + + *nSncfails = cv_mem->cv_ncfnS; + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int CVodeGetStgrSensNumNonlinSolvIters(void *cvode_mem, long int *nSTGR1niters) +{ + CVodeMem cv_mem; + int is, Ns; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetStgrSensNumNonlinSolvIters", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + Ns = cv_mem->cv_Ns; + + if (cv_mem->cv_sensi==SUNFALSE) { + cvProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetStgrSensNumNonlinSolvIters", MSGCV_NO_SENSI); + return(CV_NO_SENS); + } + + if(cv_mem->cv_ism==CV_STAGGERED1) + for(is=0; is<Ns; is++) nSTGR1niters[is] = cv_mem->cv_nniS1[is]; + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int CVodeGetStgrSensNumNonlinSolvConvFails(void *cvode_mem, long int *nSTGR1ncfails) +{ + CVodeMem cv_mem; + int is, Ns; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetStgrSensNumNonlinSolvConvFails", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + Ns = cv_mem->cv_Ns; + + if (cv_mem->cv_sensi==SUNFALSE) { + cvProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetStgrSensNumNonlinSolvConvFails", MSGCV_NO_SENSI); + return(CV_NO_SENS); + } + + if(cv_mem->cv_ism==CV_STAGGERED1) + for(is=0; is<Ns; is++) nSTGR1ncfails[is] = cv_mem->cv_ncfnS1[is]; + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int CVodeGetSensNonlinSolvStats(void *cvode_mem, long int *nSniters, + long int *nSncfails) +{ + CVodeMem cv_mem; + booleantype sensi_stg; + + if (cvode_mem==NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "CVodeGetSensNonlinSolvstats", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + + cv_mem = (CVodeMem) cvode_mem; + + if (cv_mem->cv_sensi==SUNFALSE) { + cvProcessError(cv_mem, CV_NO_SENS, "CVODES", + "CVodeGetSensNonlinSolvStats", MSGCV_NO_SENSI); + return(CV_NO_SENS); + } + + *nSncfails = cv_mem->cv_ncfnS; + + /* Are we computing sensitivities with a staggered approach? */ + sensi_stg = (cv_mem->cv_sensi && (cv_mem->cv_ism==CV_STAGGERED)); + + if (sensi_stg) { + + /* check that the NLS is non-NULL */ + if (cv_mem->NLSstg == NULL) { + cvProcessError(NULL, CV_MEM_FAIL, "CVODES", + "CVodeGetSensNumNonlinSolvStats", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + return(SUNNonlinSolGetNumIters(cv_mem->NLSstg, nSniters)); + + } else { + + /* check that the NLS is non-NULL */ + if (cv_mem->NLSstg1 == NULL) { + cvProcessError(NULL, CV_MEM_FAIL, "CVODES", + "CVodeGetSensNumNonlinSolvStats", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + return(SUNNonlinSolGetNumIters(cv_mem->NLSstg1, nSniters)); + } + + return(CV_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +char *CVodeGetReturnFlagName(long int flag) +{ + char *name; + + name = (char *)malloc(24*sizeof(char)); + + switch(flag) { + case CV_SUCCESS: + sprintf(name,"CV_SUCCESS"); + break; + case CV_TSTOP_RETURN: + sprintf(name,"CV_TSTOP_RETURN"); + break; + case CV_ROOT_RETURN: + sprintf(name,"CV_ROOT_RETURN"); + break; + case CV_TOO_MUCH_WORK: + sprintf(name,"CV_TOO_MUCH_WORK"); + break; + case CV_TOO_MUCH_ACC: + sprintf(name,"CV_TOO_MUCH_ACC"); + break; + case CV_ERR_FAILURE: + sprintf(name,"CV_ERR_FAILURE"); + break; + case CV_CONV_FAILURE: + sprintf(name,"CV_CONV_FAILURE"); + break; + case CV_LINIT_FAIL: + sprintf(name,"CV_LINIT_FAIL"); + break; + case CV_LSETUP_FAIL: + sprintf(name,"CV_LSETUP_FAIL"); + break; + case CV_LSOLVE_FAIL: + sprintf(name,"CV_LSOLVE_FAIL"); + break; + case CV_RHSFUNC_FAIL: + sprintf(name,"CV_RHSFUNC_FAIL"); + break; + case CV_FIRST_RHSFUNC_ERR: + sprintf(name,"CV_FIRST_RHSFUNC_ERR"); + break; + case CV_REPTD_RHSFUNC_ERR: + sprintf(name,"CV_REPTD_RHSFUNC_ERR"); + break; + case CV_UNREC_RHSFUNC_ERR: + sprintf(name,"CV_UNREC_RHSFUNC_ERR"); + break; + case CV_RTFUNC_FAIL: + sprintf(name,"CV_RTFUNC_FAIL"); + break; + case CV_MEM_FAIL: + sprintf(name,"CV_MEM_FAIL"); + break; + case CV_MEM_NULL: + sprintf(name,"CV_MEM_NULL"); + break; + case CV_ILL_INPUT: + sprintf(name,"CV_ILL_INPUT"); + break; + case CV_NO_MALLOC: + sprintf(name,"CV_NO_MALLOC"); + break; + case CV_BAD_K: + sprintf(name,"CV_BAD_K"); + break; + case CV_BAD_T: + sprintf(name,"CV_BAD_T"); + break; + case CV_BAD_DKY: + sprintf(name,"CV_BAD_DKY"); + break; + case CV_NO_QUAD: + sprintf(name,"CV_NO_QUAD"); + break; + case CV_QRHSFUNC_FAIL: + sprintf(name,"CV_QRHSFUNC_FAIL"); + break; + case CV_FIRST_QRHSFUNC_ERR: + sprintf(name,"CV_FIRST_QRHSFUNC_ERR"); + break; + case CV_REPTD_QRHSFUNC_ERR: + sprintf(name,"CV_REPTD_QRHSFUNC_ERR"); + break; + case CV_UNREC_QRHSFUNC_ERR: + sprintf(name,"CV_UNREC_QRHSFUNC_ERR"); + break; + case CV_BAD_IS: + sprintf(name,"CV_BAD_IS"); + break; + case CV_NO_SENS: + sprintf(name,"CV_NO_SENS"); + break; + case CV_SRHSFUNC_FAIL: + sprintf(name,"CV_SRHSFUNC_FAIL"); + break; + case CV_FIRST_SRHSFUNC_ERR: + sprintf(name,"CV_FIRST_SRHSFUNC_ERR"); + break; + case CV_REPTD_SRHSFUNC_ERR: + sprintf(name,"CV_REPTD_SRHSFUNC_ERR"); + break; + case CV_UNREC_SRHSFUNC_ERR: + sprintf(name,"CV_UNREC_SRHSFUNC_ERR"); + break; + case CV_TOO_CLOSE: + sprintf(name,"CV_TOO_CLOSE"); + break; + case CV_NO_ADJ: + sprintf(name,"CV_NO_ADJ"); + break; + case CV_NO_FWD: + sprintf(name,"CV_NO_FWD"); + break; + case CV_NO_BCK: + sprintf(name,"CV_NO_BCK"); + break; + case CV_BAD_TB0: + sprintf(name,"CV_BAD_TB0"); + break; + case CV_REIFWD_FAIL: + sprintf(name,"CV_REIFWD_FAIL"); + break; + case CV_FWD_FAIL: + sprintf(name,"CV_FWD_FAIL"); + break; + case CV_GETY_BADT: + sprintf(name,"CV_GETY_BADT"); + break; + default: + sprintf(name,"NONE"); + } + + return(name); +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_ls.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_ls.c new file mode 100644 index 0000000..0a5c9ac --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_ls.c @@ -0,0 +1,2346 @@ +/*----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 + *----------------------------------------------------------------- + * Implementation file for CVODES' linear solver interface. + * + * Part I contains routines for using CVSLS on forward problems. + * + * Part II contains wrappers for using CVSLS on adjoint + * (backward) problems. + *-----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "cvodes_impl.h" +#include "cvodes_ls_impl.h" +#include <sundials/sundials_math.h> +#include <sunmatrix/sunmatrix_band.h> +#include <sunmatrix/sunmatrix_dense.h> +#include <sunmatrix/sunmatrix_sparse.h> + +/* Private constants */ +#define MIN_INC_MULT RCONST(1000.0) +#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 + =================================================================*/ + +/* cvLsJacBWrapper and cvLsJacBSWrapper have type CVLsJacFn, and + wrap around user-provided functions of type CVLsJacFnB and + CVLsJacFnBS, respectively */ +static int cvLsJacBWrapper(realtype t, N_Vector yB, N_Vector fyB, + SUNMatrix JB, void *cvode_mem, + N_Vector tmp1B, N_Vector tmp2B, + N_Vector tmp3B); + +static int cvLsJacBSWrapper(realtype t, N_Vector yB, N_Vector fyB, + SUNMatrix JB, void *cvode_mem, + N_Vector tmp1B, N_Vector tmp2B, + N_Vector tmp3B); + +/* cvLsPrecSetupBWrapper and cvLsPrecSetupBSWrapper have type + CVLsPrecSetupFn, and wrap around user-provided functions of + type CVLsPrecSetupFnB and CVLsPrecSetupFnBS, respectively */ +static int cvLsPrecSetupBWrapper(realtype t, N_Vector yB, N_Vector fyB, + booleantype jokB, booleantype *jcurPtrB, + realtype gammaB, void *cvode_mem); +static int cvLsPrecSetupBSWrapper(realtype t, N_Vector yB, N_Vector fyB, + booleantype jokB, booleantype *jcurPtrB, + realtype gammaB, void *cvode_mem); + +/* cvLsPrecSolveBWrapper and cvLsPrecSolveBSWrapper have type + CVLsPrecSolveFn, and wrap around user-provided functions of + type CVLsPrecSolveFnB and CVLsPrecSolveFnBS, respectively */ +static int cvLsPrecSolveBWrapper(realtype t, N_Vector yB, N_Vector fyB, + N_Vector rB, N_Vector zB, + realtype gammaB, realtype deltaB, + int lrB, void *cvode_mem); +static int cvLsPrecSolveBSWrapper(realtype t, N_Vector yB, N_Vector fyB, + N_Vector rB, N_Vector zB, + realtype gammaB, realtype deltaB, + int lrB, void *cvode_mem); + +/* cvLsJacTimesSetupBWrapper and cvLsJacTimesSetupBSWrapper have type + CVLsJacTimesSetupFn, and wrap around user-provided functions of + type CVLsJacTimesSetupFnB and CVLsJacTimesSetupFnBS, respectively */ +static int cvLsJacTimesSetupBWrapper(realtype t, N_Vector yB, + N_Vector fyB, void *cvode_mem); +static int cvLsJacTimesSetupBSWrapper(realtype t, N_Vector yB, + N_Vector fyB, void *cvode_mem); + +/* cvLsJacTimesVecBWrapper and cvLsJacTimesVecBSWrapper have type + CVLsJacTimesVecFn, and wrap around user-provided functions of + type CVLsJacTimesVecFnB and CVLsJacTimesVecFnBS, respectively */ +static int cvLsJacTimesVecBWrapper(N_Vector vB, N_Vector JvB, realtype t, + N_Vector yB, N_Vector fyB, + void *cvode_mem, N_Vector tmpB); +static int cvLsJacTimesVecBSWrapper(N_Vector vB, N_Vector JvB, realtype t, + N_Vector yB, N_Vector fyB, + void *cvode_mem, N_Vector tmpB); + + +/*================================================================ + PART I - forward problems + ================================================================*/ + +/*----------------------------------------------------------------- + CVSLS Exported functions -- Required + -----------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + CVodeSetLinearSolver specifies the linear solver + ---------------------------------------------------------------*/ +int CVodeSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, + SUNMatrix A) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval, LSType; + + /* Return immediately if either cvode_mem or LS inputs are NULL */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVSLS", + "CVodeSetLinearSolver", MSG_LS_CVMEM_NULL); + return(CVLS_MEM_NULL); + } + if (LS == NULL) { + cvProcessError(NULL, CVLS_ILL_INPUT, "CVSLS", + "CVodeSetLinearSolver", + "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) ) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVSLS", + "CVodeSetLinearSolver", + "LS object is missing a required operation"); + return(CVLS_ILL_INPUT); + } + + /* Test if vector is compatible with LS interface */ + if ( (cv_mem->cv_tempv->ops->nvconst == NULL) || + (cv_mem->cv_tempv->ops->nvdotprod == 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"); + return(CVLS_ILL_INPUT); + } + + /* free any existing system solver attached to CVode */ + if (cv_mem->cv_lfree) cv_mem->cv_lfree(cv_mem); + + /* Set four main system linear solver function fields in cv_mem */ + cv_mem->cv_linit = cvLsInitialize; + cv_mem->cv_lsetup = cvLsSetup; + cv_mem->cv_lsolve = cvLsSolve; + cv_mem->cv_lfree = cvLsFree; + + /* Allocate memory for CVLsMemRec */ + cvls_mem = NULL; + cvls_mem = (CVLsMem) malloc(sizeof(struct CVLsMemRec)); + if (cvls_mem == NULL) { + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSLS", + "CVodeSetLinearSolver", MSG_LS_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + memset(cvls_mem, 0, sizeof(struct CVLsMemRec)); + + /* set SUNLinearSolver pointer */ + cvls_mem->LS = LS; + + /* Set defaults for Jacobian-related fields */ + if (A != NULL) { + cvls_mem->jacDQ = SUNTRUE; + cvls_mem->jac = cvLsDQJac; + cvls_mem->J_data = cv_mem; + } else { + cvls_mem->jacDQ = SUNFALSE; + 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; + + /* Set defaults for preconditioner-related fields */ + cvls_mem->pset = NULL; + cvls_mem->psolve = NULL; + cvls_mem->pfree = NULL; + cvls_mem->P_data = cv_mem->cv_user_data; + + /* Initialize counters */ + cvLsInitializeCounters(cvls_mem); + + /* Set default values for the rest of the LS parameters */ + cvls_mem->msbj = CVLS_MSBJ; + cvls_mem->jbad = SUNTRUE; + cvls_mem->eplifac = CVLS_EPLIN; + cvls_mem->last_flag = CVLS_SUCCESS; + + /* If LS supports ATimes, attach CVLs routine */ + if (LS->ops->setatimes) { + retval = SUNLinSolSetATimes(LS, cv_mem, cvLsATimes); + if (retval != SUNLS_SUCCESS) { + cvProcessError(cv_mem, CVLS_SUNLS_FAIL, "CVSLS", + "CVodeSetLinearSolver", + "Error in calling SUNLinSolSetATimes"); + free(cvls_mem); cvls_mem = NULL; + return(CVLS_SUNLS_FAIL); + } + } + + /* If LS supports preconditioning, initialize pset/psol to NULL */ + if (LS->ops->setpreconditioner) { + retval = SUNLinSolSetPreconditioner(LS, cv_mem, NULL, NULL); + if (retval != SUNLS_SUCCESS) { + cvProcessError(cv_mem, CVLS_SUNLS_FAIL, "CVSLS", + "CVodeSetLinearSolver", + "Error in calling SUNLinSolSetPreconditioner"); + free(cvls_mem); cvls_mem = NULL; + return(CVLS_SUNLS_FAIL); + } + } + + /* When using a non-NULL SUNMatrix object, store pointer to A and create saved_J */ + 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); + } + } + /* 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); + } + + cvls_mem->x = N_VClone(cv_mem->cv_tempv); + 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) ); + } + + /* Attach linear solver memory to integrator memory */ + cv_mem->cv_lmem = cvls_mem; + + return(CVLS_SUCCESS); +} + + +/*----------------------------------------------------------------- + CVSLS Exported functions -- Optional input/output + -----------------------------------------------------------------*/ + + +/* CVodeSetJacFn specifies the Jacobian function. */ +int CVodeSetJacFn(void *cvode_mem, CVLsJacFn jac) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeSetJacFn", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* return with failure if jac cannot be used */ + if ((jac != NULL) && (cvls_mem->A == NULL)) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVSLS", "CVodeSetJacFn", + "Jacobian routine cannot be supplied for NULL SUNMatrix"); + return(CVLS_ILL_INPUT); + } + + /* set Jacobian routine pointer, and update relevant flags */ + if (jac != NULL) { + cvls_mem->jacDQ = SUNFALSE; + cvls_mem->jac = jac; + cvls_mem->J_data = cv_mem->cv_user_data; + } else { + cvls_mem->jacDQ = SUNTRUE; + cvls_mem->jac = cvLsDQJac; + cvls_mem->J_data = cv_mem; + } + + return(CVLS_SUCCESS); +} + + +/* CVodeSetEpsLin specifies the nonlinear -> linear tolerance scale factor */ +int CVodeSetEpsLin(void *cvode_mem, realtype eplifac) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeSetEpsLin", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* Check for legal eplifac */ + if(eplifac < ZERO) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVSLS", + "CVodeSetEpsLin", MSG_LS_BAD_EPLIN); + return(CVLS_ILL_INPUT); + } + + cvls_mem->eplifac = (eplifac == ZERO) ? CVLS_EPLIN : eplifac; + + return(CVLS_SUCCESS); +} + + +/* CVodeSetMaxStepsBetweenJac specifies the maximum number of + time steps to wait before recomputing the Jacobian matrix + and/or preconditioner */ +int CVodeSetMaxStepsBetweenJac(void *cvode_mem, long int msbj) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure; store input and return */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeSetMaxStepsBetweenJac", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + cvls_mem->msbj = (msbj <= ZERO) ? CVLS_MSBJ : msbj; + + return(CVLS_SUCCESS); +} + + +/* CVodeSetPreconditioner specifies the user-supplied preconditioner + setup and solve routines */ +int CVodeSetPreconditioner(void *cvode_mem, CVLsPrecSetupFn psetup, + CVLsPrecSolveFn psolve) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + PSetupFn cvls_psetup; + PSolveFn cvls_psolve; + int retval; + + /* access CVLsMem structure */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeSetPreconditioner", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* store function pointers for user-supplied routines in CVLs interface */ + cvls_mem->pset = psetup; + cvls_mem->psolve = psolve; + + /* issue error if LS object does not allow user-supplied preconditioning */ + if (cvls_mem->LS->ops->setpreconditioner == NULL) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVSLS", + "CVodeSetPreconditioner", + "SUNLinearSolver object does not support user-supplied preconditioning"); + return(CVLS_ILL_INPUT); + } + + /* notify iterative linear solver to call CVLs interface routines */ + cvls_psetup = (psetup == NULL) ? NULL : cvLsPSetup; + cvls_psolve = (psolve == NULL) ? NULL : cvLsPSolve; + retval = SUNLinSolSetPreconditioner(cvls_mem->LS, cv_mem, + cvls_psetup, cvls_psolve); + if (retval != SUNLS_SUCCESS) { + cvProcessError(cv_mem, CVLS_SUNLS_FAIL, "CVSLS", + "CVLsSetPreconditioner", + "Error in calling SUNLinSolSetPreconditioner"); + return(CVLS_SUNLS_FAIL); + } + + return(CVLS_SUCCESS); +} + + +/* CVodeSetJacTimes specifies the user-supplied Jacobian-vector product + setup and multiply routines */ +int CVodeSetJacTimes(void *cvode_mem, CVLsJacTimesSetupFn jtsetup, + CVLsJacTimesVecFn jtimes) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeSetJacTimes", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* issue error if LS object does not allow user-supplied ATimes */ + if (cvls_mem->LS->ops->setatimes == NULL) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVSLS", + "CVodeSetJacTimes", + "SUNLinearSolver object does not support user-supplied ATimes routine"); + return(CVLS_ILL_INPUT); + } + + /* store function pointers for user-supplied routines in CVLs + interface (NULL jtimes implies use of DQ default) */ + if (jtimes != NULL) { + cvls_mem->jtimesDQ = SUNFALSE; + cvls_mem->jtsetup = jtsetup; + cvls_mem->jtimes = jtimes; + cvls_mem->jt_data = cv_mem->cv_user_data; + } else { + cvls_mem->jtimesDQ = SUNTRUE; + cvls_mem->jtsetup = NULL; + cvls_mem->jtimes = cvLsDQJtimes; + cvls_mem->jt_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, + long int *leniwLS) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + sunindextype lrw1, liw1; + long int lrw, liw; + int retval; + + /* access CVLsMem structure */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeGetLinWorkSpace", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* start with fixed sizes plus vector/matrix pointers */ + *lenrwLS = 2; + *leniwLS = 30; + + /* add NVector sizes */ + if (cv_mem->cv_tempv->ops->nvspace) { + N_VSpace(cv_mem->cv_tempv, &lrw1, &liw1); + *lenrwLS += 2*lrw1; + *leniwLS += 2*liw1; + } + + /* add SUNMatrix size (only account for the one owned by Ls interface) */ + if (cvls_mem->savedJ) + if (cvls_mem->savedJ->ops->space) { + retval = SUNMatSpace(cvls_mem->savedJ, &lrw, &liw); + if (retval == 0) { + *lenrwLS += lrw; + *leniwLS += liw; + } + } + + /* add LS sizes */ + if (cvls_mem->LS->ops->space) { + retval = SUNLinSolSpace(cvls_mem->LS, &lrw, &liw); + if (retval == 0) { + *lenrwLS += lrw; + *leniwLS += liw; + } + } + + return(CVLS_SUCCESS); +} + + +/* CVodeGetNumJacEvals returns the number of Jacobian evaluations */ +int CVodeGetNumJacEvals(void *cvode_mem, long int *njevals) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure; set output value and return */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeGetNumJacEvals", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + *njevals = cvls_mem->nje; + return(CVLS_SUCCESS); +} + + +/* CVodeGetNumLinRhsEvals returns the number of calls to the ODE + function needed for the DQ Jacobian approximation or J*v product + approximation */ +int CVodeGetNumLinRhsEvals(void *cvode_mem, long int *nfevalsLS) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure; set output value and return */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeGetNumLinRhsEvals", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + *nfevalsLS = cvls_mem->nfeDQ; + return(CVLS_SUCCESS); +} + + +/* CVodeGetNumPrecEvals returns the number of calls to the + user- or CVode-supplied preconditioner setup routine */ +int CVodeGetNumPrecEvals(void *cvode_mem, long int *npevals) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure; set output value and return */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeGetNumPrecEvals", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + *npevals = cvls_mem->npe; + return(CVLS_SUCCESS); +} + + +/* CVodeGetNumPrecSolves returns the number of calls to the + user- or CVode-supplied preconditioner solve routine */ +int CVodeGetNumPrecSolves(void *cvode_mem, long int *npsolves) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure; set output value and return */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeGetNumPrecSolves", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + *npsolves = cvls_mem->nps; + return(CVLS_SUCCESS); +} + + +/* CVodeGetNumLinIters returns the number of linear iterations + (if accessible from the LS object) */ +int CVodeGetNumLinIters(void *cvode_mem, long int *nliters) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure; set output value and return */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeGetNumLinIters", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + *nliters = cvls_mem->nli; + return(CVLS_SUCCESS); +} + + +/* CVodeGetNumLinConvFails returns the number of linear solver + convergence failures (as reported by the LS object) */ +int CVodeGetNumLinConvFails(void *cvode_mem, long int *nlcfails) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure; set output value and return */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeGetNumLinConvFails", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + *nlcfails = cvls_mem->ncfl; + return(CVLS_SUCCESS); +} + + +/* CVodeGetNumJTSetupEvals returns the number of calls to the + user-supplied Jacobian-vector product setup routine */ +int CVodeGetNumJTSetupEvals(void *cvode_mem, long int *njtsetups) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure; set output value and return */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeGetNumJTSetupEvals", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + *njtsetups = cvls_mem->njtsetup; + return(CVLS_SUCCESS); +} + + +/* CVodeGetNumJtimesEvals returns the number of calls to the + Jacobian-vector product multiply routine */ +int CVodeGetNumJtimesEvals(void *cvode_mem, long int *njvevals) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure; set output value and return */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeGetNumJtimesEvals", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + *njvevals = cvls_mem->njtimes; + return(CVLS_SUCCESS); +} + + +/* CVodeGetLastLinFlag returns the last flag set in a CVLS function */ +int CVodeGetLastLinFlag(void *cvode_mem, long int *flag) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure; set output value and return */ + retval = cvLs_AccessLMem(cvode_mem, "CVodeGetLastLinFlag", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + *flag = cvls_mem->last_flag; + return(CVLS_SUCCESS); +} + + +/* CVodeGetLinReturnFlagName translates from the integer error code + returned by an CVLs routine to the corresponding string + equivalent for that flag */ +char *CVodeGetLinReturnFlagName(long int flag) +{ + char *name = (char *)malloc(30*sizeof(char)); + + switch(flag) { + case CVLS_SUCCESS: + sprintf(name,"CVLS_SUCCESS"); + break; + case CVLS_MEM_NULL: + sprintf(name,"CVLS_MEM_NULL"); + break; + case CVLS_LMEM_NULL: + sprintf(name,"CVLS_LMEM_NULL"); + break; + case CVLS_ILL_INPUT: + sprintf(name,"CVLS_ILL_INPUT"); + break; + case CVLS_MEM_FAIL: + sprintf(name,"CVLS_MEM_FAIL"); + break; + case CVLS_PMEM_NULL: + sprintf(name,"CVLS_PMEM_NULL"); + break; + case CVLS_JACFUNC_UNRECVR: + sprintf(name,"CVLS_JACFUNC_UNRECVR"); + break; + case CVLS_JACFUNC_RECVR: + sprintf(name,"CVLS_JACFUNC_RECVR"); + break; + case CVLS_SUNMAT_FAIL: + sprintf(name,"CVLS_SUNMAT_FAIL"); + break; + case CVLS_SUNLS_FAIL: + sprintf(name,"CVLS_SUNLS_FAIL"); + break; + case CVLS_NO_ADJ: + sprintf(name,"CVLS_NO_ADJ"); + break; + case CVLS_LMEMB_NULL: + sprintf(name,"CVLS_LMEMB_NULL"); + break; + default: + sprintf(name,"NONE"); + } + + return(name); +} + + +/*----------------------------------------------------------------- + CVSLS private functions + -----------------------------------------------------------------*/ + +/*----------------------------------------------------------------- + cvLsATimes + + This routine generates the matrix-vector product z = Mv, where + M = I - gamma*J. The product J*v is obtained by calling the jtimes + routine. It is then scaled by -gamma and added to v to obtain M*v. + The return value is the same as the value returned by jtimes -- + 0 if successful, nonzero otherwise. + -----------------------------------------------------------------*/ +int cvLsATimes(void *cvode_mem, N_Vector v, N_Vector z) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure */ + retval = cvLs_AccessLMem(cvode_mem, "cvLsATimes", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* call Jacobian-times-vector product routine + (either user-supplied or internal DQ) */ + retval = cvls_mem->jtimes(v, z, cv_mem->cv_tn, + cvls_mem->ycur, + cvls_mem->fcur, + cvls_mem->jt_data, + cvls_mem->ytemp); + cvls_mem->njtimes++; + if (retval != 0) return(retval); + + /* add contribution from identity matrix */ + N_VLinearSum(ONE, v, -cv_mem->cv_gamma, z, z); + + return(0); +} + + +/*--------------------------------------------------------------- + cvLsPSetup: + + This routine interfaces between the generic iterative linear + solvers and the user's psetup routine. It passes to psetup all + required state information from cvode_mem. Its return value + is the same as that returned by psetup. Note that the generic + iterative linear solvers guarantee that cvLsPSetup will only + be called in the case that the user's psetup routine is non-NULL. + ---------------------------------------------------------------*/ +int cvLsPSetup(void *cvode_mem) +{ + int retval; + CVodeMem cv_mem; + CVLsMem cvls_mem; + + /* access CVLsMem structure */ + retval = cvLs_AccessLMem(cvode_mem, "cvLsPSetup", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* Call user pset routine to update preconditioner and possibly + reset jcur (pass !jbad as update suggestion) */ + retval = cvls_mem->pset(cv_mem->cv_tn, cvls_mem->ycur, + cvls_mem->fcur, !(cvls_mem->jbad), + &cv_mem->cv_jcur, cv_mem->cv_gamma, + cvls_mem->P_data); + return(retval); +} + + +/*----------------------------------------------------------------- + cvLsPSolve + + This routine interfaces between the generic SUNLinSolSolve + routine and the user's psolve routine. It passes to psolve all + required state information from cvode_mem. Its return value is + the same as that returned by psolve. Note that the generic + SUNLinSol solver guarantees that cvLsPSolve will not be called + in the case in which preconditioning is not done. This is the + only case in which the user's psolve routine is allowed to be + NULL. + -----------------------------------------------------------------*/ +int cvLsPSolve(void *cvode_mem, N_Vector r, N_Vector z, realtype tol, int lr) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure */ + retval = cvLs_AccessLMem(cvode_mem, "cvLsPSolve", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* call the user-supplied psolve routine, and accumulate count */ + retval = cvls_mem->psolve(cv_mem->cv_tn, cvls_mem->ycur, + cvls_mem->fcur, r, z, + cv_mem->cv_gamma, tol, lr, + cvls_mem->P_data); + cvls_mem->nps++; + return(retval); +} + + +/*----------------------------------------------------------------- + cvLsDQJac + + This routine is a wrapper for the Dense and Band + implementations of the difference quotient Jacobian + approximation routines. + ---------------------------------------------------------------*/ +int cvLsDQJac(realtype t, N_Vector y, N_Vector fy, + SUNMatrix Jac, void *cvode_mem, N_Vector tmp1, + N_Vector tmp2, N_Vector tmp3) +{ + CVodeMem cv_mem; + int retval; + + /* access CVodeMem structure */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVSLS", + "cvLsDQJac", MSG_LS_CVMEM_NULL); + return(CVLS_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* verify that Jac is non-NULL */ + if (Jac == NULL) { + cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVSLS", + "cvLsDQJac", MSG_LS_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + + /* Verify that N_Vector supports required operations */ + if (cv_mem->cv_tempv->ops->nvcloneempty == NULL || + cv_mem->cv_tempv->ops->nvwrmsnorm == NULL || + cv_mem->cv_tempv->ops->nvlinearsum == NULL || + cv_mem->cv_tempv->ops->nvdestroy == NULL || + cv_mem->cv_tempv->ops->nvscale == NULL || + cv_mem->cv_tempv->ops->nvgetarraypointer == NULL || + cv_mem->cv_tempv->ops->nvsetarraypointer == NULL) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVSLS", + "cvLsDQJac", MSG_LS_BAD_NVECTOR); + return(CVLS_ILL_INPUT); + } + + /* Call the matrix-structure-specific DQ approximation routine */ + if (SUNMatGetID(Jac) == SUNMATRIX_DENSE) { + retval = cvLsDenseDQJac(t, y, fy, Jac, cv_mem, tmp1); + } else if (SUNMatGetID(Jac) == SUNMATRIX_BAND) { + retval = cvLsBandDQJac(t, y, fy, Jac, cv_mem, tmp1, tmp2); + } else { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVSLS", "cvLsDQJac", + "unrecognized matrix type for cvLsDQJac"); + retval = CVLS_ILL_INPUT; + } + return(retval); +} + + +/*----------------------------------------------------------------- + cvLsDenseDQJac + + This routine generates a dense difference quotient approximation + to the Jacobian of f(t,y). It assumes that a dense SUNMatrix is + stored column-wise, and that elements within each column are + contiguous. The address of the jth column of J is obtained via + the accessor function SUNDenseMatrix_Column, and this pointer + is associated with an N_Vector using the N_VSetArrayPointer + function. Finally, the actual computation of the jth column of + the Jacobian is done with a call to N_VLinearSum. + -----------------------------------------------------------------*/ +int cvLsDenseDQJac(realtype t, N_Vector y, N_Vector fy, + SUNMatrix Jac, CVodeMem cv_mem, N_Vector tmp1) +{ + realtype fnorm, minInc, inc, inc_inv, yjsaved, srur, conj; + realtype *y_data, *ewt_data, *cns_data; + N_Vector ftemp, jthCol; + sunindextype j, N; + CVLsMem cvls_mem; + int retval = 0; + + /* access LsMem interface structure */ + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + /* access matrix dimension */ + N = SUNDenseMatrix_Rows(Jac); + + /* Rename work vector for readibility */ + ftemp = tmp1; + + /* Create an empty vector for matrix column calculations */ + jthCol = N_VCloneEmpty(tmp1); + + /* 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) + cns_data = N_VGetArrayPointer(cv_mem->cv_constraints); + + /* Set minimum increment based on uround and norm of f */ + srur = SUNRsqrt(cv_mem->cv_uround); + fnorm = N_VWrmsNorm(fy, cv_mem->cv_ewt); + minInc = (fnorm != ZERO) ? + (MIN_INC_MULT * SUNRabs(cv_mem->cv_h) * cv_mem->cv_uround * N * fnorm) : ONE; + + for (j = 0; j < N; j++) { + + /* Generate the jth col of J(tn,y) */ + N_VSetArrayPointer(SUNDenseMatrix_Column(Jac,j), jthCol); + + yjsaved = y_data[j]; + 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) { + 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 = cv_mem->cv_f(t, y, ftemp, cv_mem->cv_user_data); + cvls_mem->nfeDQ++; + if (retval != 0) break; + + y_data[j] = yjsaved; + + inc_inv = ONE/inc; + N_VLinearSum(inc_inv, ftemp, -inc_inv, fy, jthCol); + + } + + /* Destroy jthCol vector */ + N_VSetArrayPointer(NULL, jthCol); /* SHOULDN'T BE NEEDED */ + N_VDestroy(jthCol); + + return(retval); +} + + +/*----------------------------------------------------------------- + cvLsBandDQJac + + 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 in + succession. + -----------------------------------------------------------------*/ +int cvLsBandDQJac(realtype t, N_Vector y, N_Vector fy, SUNMatrix Jac, + CVodeMem cv_mem, N_Vector tmp1, N_Vector tmp2) +{ + N_Vector ftemp, ytemp; + realtype fnorm, minInc, inc, inc_inv, srur, conj; + realtype *col_j, *ewt_data, *fy_data, *ftemp_data; + realtype *y_data, *ytemp_data, *cns_data; + sunindextype group, i, j, width, ngroups, i1, i2; + sunindextype N, mupper, mlower; + CVLsMem cvls_mem; + int retval = 0; + + /* access LsMem interface structure */ + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + /* access matrix dimensions */ + N = SUNBandMatrix_Columns(Jac); + mupper = SUNBandMatrix_UpperBandwidth(Jac); + mlower = SUNBandMatrix_LowerBandwidth(Jac); + + /* Rename work vectors for use as temporary values of y and f */ + ftemp = tmp1; + ytemp = tmp2; + + /* Obtain pointers to the data for ewt, fy, ftemp, y, ytemp */ + ewt_data = N_VGetArrayPointer(cv_mem->cv_ewt); + fy_data = N_VGetArrayPointer(fy); + 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); + + /* Load ytemp with y = predicted y vector */ + N_VScale(ONE, y, ytemp); + + /* Set minimum increment based on uround and norm of f */ + srur = SUNRsqrt(cv_mem->cv_uround); + fnorm = N_VWrmsNorm(fy, cv_mem->cv_ewt); + minInc = (fnorm != ZERO) ? + (MIN_INC_MULT * SUNRabs(cv_mem->cv_h) * cv_mem->cv_uround * N * fnorm) : ONE; + + /* Set bandwidth and number of column groups for band differencing */ + width = mlower + mupper + 1; + ngroups = SUNMIN(width, N); + + /* Loop over column groups. */ + for (group=1; group <= ngroups; group++) { + + /* 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 (cv_mem->cv_constraints != NULL) { + 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; + } + + /* Evaluate f with incremented y */ + retval = cv_mem->cv_f(cv_mem->cv_tn, ytemp, ftemp, cv_mem->cv_user_data); + cvls_mem->nfeDQ++; + if (retval != 0) break; + + /* Restore ytemp, then form and load difference quotients */ + for (j=group-1; j < N; j+=width) { + 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 (cv_mem->cv_constraints != NULL) { + 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); + for (i=i1; i <= i2; i++) + SM_COLUMN_ELEMENT_B(col_j,i,j) = inc_inv * (ftemp_data[i] - fy_data[i]); + } + } + + return(retval); +} + + +/*----------------------------------------------------------------- + cvLsDQJtimes + + This routine generates a difference quotient approximation to + the Jacobian times vector f_y(t,y) * v. The approximation is + Jv = [f(y + v*sig) - f(y)]/sig, where sig = 1 / ||v||_WRMS, + i.e. the WRMS norm of v*sig is 1. + -----------------------------------------------------------------*/ +int cvLsDQJtimes(N_Vector v, N_Vector Jv, realtype t, + N_Vector y, N_Vector fy, void *cvode_mem, + N_Vector work) +{ + CVodeMem cv_mem; + CVLsMem cvls_mem; + realtype sig, siginv; + int iter, retval; + + /* access CVLsMem structure */ + retval = cvLs_AccessLMem(cvode_mem, "cvLsDQJtimes", + &cv_mem, &cvls_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* Initialize perturbation to 1/||v|| */ + sig = ONE/N_VWrmsNorm(v, cv_mem->cv_ewt); + + for (iter=0; iter<MAX_DQITERS; iter++) { + + /* Set work = y + sig*v */ + N_VLinearSum(sig, v, ONE, y, work); + + /* Set Jv = f(tn, y+sig*v) */ + retval = cv_mem->cv_f(t, work, Jv, cv_mem->cv_user_data); + cvls_mem->nfeDQ++; + if (retval == 0) break; + if (retval < 0) return(-1); + + /* If f failed recoverably, shrink sig and retry */ + sig *= PT25; + } + + /* If retval still isn't 0, return with a recoverable failure */ + if (retval > 0) return(+1); + + /* Replace Jv by (Jv - fy)/sig */ + siginv = ONE/sig; + N_VLinearSum(siginv, Jv, -siginv, fy, Jv); + + return(0); +} + + +/*----------------------------------------------------------------- + cvLsInitialize + + This routine performs remaining initializations specific + to the iterative linear solver interface (and solver itself) + -----------------------------------------------------------------*/ +int cvLsInitialize(CVodeMem cv_mem) +{ + CVLsMem cvls_mem; + int retval; + + /* access CVLsMem structure */ + if (cv_mem->cv_lmem==NULL) { + cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVSLS", + "cvLsInitialize", MSG_LS_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + /* Test for valid combinations of matrix & Jacobian routines: */ + 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; + + } else if (cvls_mem->jacDQ) { + + /* 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) { + + 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); + } + + } 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; + } + + /* reset counters */ + cvLsInitializeCounters(cvls_mem); + + /* Set Jacobian-related fields, based on jtimesDQ */ + if (cvls_mem->jtimesDQ) { + cvls_mem->jtsetup = NULL; + cvls_mem->jtimes = cvLsDQJtimes; + cvls_mem->jt_data = cv_mem; + } else { + cvls_mem->jt_data = cv_mem->cv_user_data; + } + + /* if A is NULL and psetup is not present, then cvLsSetup does + not need to be called, so set the lsetup function to NULL */ + if ( (cvls_mem->A == NULL) && (cvls_mem->pset == NULL) ) + cv_mem->cv_lsetup = NULL; + + /* Call LS initialize routine, and return result */ + cvls_mem->last_flag = SUNLinSolInitialize(cvls_mem->LS); + return(cvls_mem->last_flag); +} + + +/*----------------------------------------------------------------- + cvLsSetup + + This conditionally calls the LS 'setup' routine. + + When using a SUNMatrix object, this determines whether + to update a Jacobian matrix (or use a stored version), based + on heuristics regarding previous convergence issues, the number + of time steps since it was last updated, etc.; it then creates + the system matrix from this, the 'gamma' factor and the + identity matrix, A = I-gamma*J. + + This routine then calls the LS 'setup' routine with A. + -----------------------------------------------------------------*/ +int cvLsSetup(CVodeMem cv_mem, int convfail, N_Vector ypred, + N_Vector fpred, booleantype *jcurPtr, + N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3) +{ + CVLsMem cvls_mem; + realtype dgamma; + int retval; + + /* access CVLsMem structure */ + if (cv_mem->cv_lmem==NULL) { + cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVSLS", + "cvLsSetup", MSG_LS_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + /* Set CVLs N_Vector pointers to current solution and rhs */ + cvls_mem->ycur = ypred; + cvls_mem->fcur = fpred; + + /* Use nst, gamma/gammap, and convfail to set J/P eval. flag jok */ + dgamma = SUNRabs((cv_mem->cv_gamma/cv_mem->cv_gammap) - ONE); + cvls_mem->jbad = (cv_mem->cv_nst == 0) || + (cv_mem->cv_nst > cvls_mem->nstlj + cvls_mem->msbj) || + ((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); + } + + /* If jbad = SUNTRUE, call jac routine for new J value */ + } else { + + 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); + } + + } + + /* 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); + } + + } + + /* Call LS setup routine -- the LS may call cvLsPSetup, who will + 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 (cvls_mem->A == NULL) { + + /* If user set jcur to SUNTRUE, increment npe and save nst value */ + if (*jcurPtr) { + cvls_mem->npe++; + cvls_mem->nstlj = cv_mem->cv_nst; + } + + /* Update jcur flag if we suggested an update */ + if (cvls_mem->jbad) *jcurPtr = SUNTRUE; + } + + return(cvls_mem->last_flag); +} + + +/*----------------------------------------------------------------- + cvLsSolve + + This routine interfaces between CVode and the generic + SUNLinearSolver object LS, by setting the appropriate tolerance + and scaling vectors, calling the solver, and accumulating + statistics from the solve for use/reporting by CVode. + -----------------------------------------------------------------*/ +int cvLsSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight, + N_Vector ynow, N_Vector fnow) +{ + CVLsMem cvls_mem; + realtype bnorm, deltar, delta, w_mean; + int curiter, nli_inc, retval, LSType; + booleantype do_sensi_sim, do_sensi_stg, do_sensi_stg1; + + /* access CVLsMem structure */ + if (cv_mem->cv_lmem==NULL) { + cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVSLS", + "cvLsSolve", MSG_LS_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + 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)); + do_sensi_stg1 = (cv_mem->cv_sensi && (cv_mem->cv_ism==CV_STAGGERED1)); + + /* get current nonlinear solver iteration */ + if (do_sensi_sim) + retval = SUNNonlinSolGetCurIter(cv_mem->NLSsim, &curiter); + else if (do_sensi_stg && cv_mem->sens_solve) + retval = SUNNonlinSolGetCurIter(cv_mem->NLSstg, &curiter); + else if (do_sensi_stg1 && cv_mem->sens_solve) + retval = SUNNonlinSolGetCurIter(cv_mem->NLSstg1, &curiter); + else + 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) ) { + deltar = cvls_mem->eplifac * cv_mem->cv_tq[4]; + bnorm = N_VWrmsNorm(b, weight); + if (bnorm <= deltar) { + if (curiter > 0) N_VConst(ZERO, b); + cvls_mem->last_flag = CVLS_SUCCESS; + return(cvls_mem->last_flag); + } + delta = deltar * cvls_mem->sqrtN; + } else { + delta = ZERO; + } + + /* Set vectors ycur and fcur for use by the Atimes and Psolve + interface routines */ + 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, + weight, + weight); + if (retval != SUNLS_SUCCESS) { + cvProcessError(cv_mem, CVLS_SUNLS_FAIL, "CVSLS", "cvLsSolve", + "Error in calling SUNLinSolSetScalingVectors"); + cvls_mem->last_flag = CVLS_SUNLS_FAIL; + return(cvls_mem->last_flag); + } + + /* If solver is iterative and does not support scaling vectors, update the + tolerance in an attempt to account for weight vector. We make the + following assumptions: + 1. w_i = w_mean, for i=0,...,n-1 (i.e. the weights are homogeneous) + 2. the linear solver uses a basic 2-norm to measure convergence + Hence (using the notation from sunlinsol_spgmr.h, with S = diag(w)), + || bbar - Abar xbar ||_2 < tol + <=> || S b - S A x ||_2 < tol + <=> || S (b - A x) ||_2 < tol + <=> \sum_{i=0}^{n-1} (w_i (b - A x)_i)^2 < tol^2 + <=> 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) ) { + + w_mean = SUNRsqrt( N_VDotProd(weight, weight) ) / cvls_mem->sqrtN; + delta /= w_mean; + + } + + /* 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, + cvls_mem->jt_data); + cvls_mem->njtsetup++; + if (cvls_mem->last_flag != 0) { + cvProcessError(cv_mem, retval, "CVSLS", + "cvLsSolve", MSG_LS_JTSETUP_FAILED); + return(cvls_mem->last_flag); + } + } + + /* Call solver, and copy x to b */ + retval = SUNLinSolSolve(cvls_mem->LS, cvls_mem->A, cvls_mem->x, b, delta); + N_VScale(ONE, cvls_mem->x, b); + + /* 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) ) + 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) ) + nli_inc = SUNLinSolNumIters(cvls_mem->LS); + + /* Increment counters nli and ncfl */ + cvls_mem->nli += nli_inc; + if (retval != SUNLS_SUCCESS) cvls_mem->ncfl++; + + /* Interpret solver return value */ + cvls_mem->last_flag = retval; + + switch(retval) { + + case SUNLS_SUCCESS: + return(0); + break; + case SUNLS_RES_REDUCED: + /* allow reduction but not solution on first Newton iteration, + otherwise return with a recoverable failure */ + if (curiter == 0) return(0); + else return(1); + break; + case SUNLS_CONV_FAIL: + case SUNLS_ATIMES_FAIL_REC: + case SUNLS_PSOLVE_FAIL_REC: + case SUNLS_PACKAGE_FAIL_REC: + case SUNLS_QRFACT_FAIL: + case SUNLS_LUFACT_FAIL: + return(1); + break; + case SUNLS_MEM_NULL: + case SUNLS_ILL_INPUT: + case SUNLS_MEM_FAIL: + case SUNLS_GS_FAIL: + case SUNLS_QRSOL_FAIL: + return(-1); + break; + case SUNLS_PACKAGE_FAIL_UNREC: + cvProcessError(cv_mem, SUNLS_PACKAGE_FAIL_UNREC, "CVSLS", + "cvLsSolve", + "Failure in SUNLinSol external package"); + return(-1); + break; + case SUNLS_ATIMES_FAIL_UNREC: + cvProcessError(cv_mem, SUNLS_ATIMES_FAIL_UNREC, "CVSLS", + "cvLsSolve", MSG_LS_JTIMES_FAILED); + return(-1); + break; + case SUNLS_PSOLVE_FAIL_UNREC: + cvProcessError(cv_mem, SUNLS_PSOLVE_FAIL_UNREC, "CVSLS", + "cvLsSolve", MSG_LS_PSOLVE_FAILED); + return(-1); + break; + } + + return(0); +} + + +/*----------------------------------------------------------------- + cvLsFree + + This routine frees memory associates with the CVLs system + solver interface. + -----------------------------------------------------------------*/ +int cvLsFree(CVodeMem cv_mem) +{ + CVLsMem cvls_mem; + + /* Return immediately if CVodeMem or CVLsMem are NULL */ + if (cv_mem == NULL) return (CVLS_SUCCESS); + if (cv_mem->cv_lmem == NULL) return(CVLS_SUCCESS); + cvls_mem = (CVLsMem) cv_mem->cv_lmem; + + /* Free N_Vector memory */ + if (cvls_mem->ytemp) { + N_VDestroy(cvls_mem->ytemp); + cvls_mem->ytemp = NULL; + } + if (cvls_mem->x) { + N_VDestroy(cvls_mem->x); + cvls_mem->x = NULL; + } + + /* Free savedJ memory */ + if (cvls_mem->savedJ) { + SUNMatDestroy(cvls_mem->savedJ); + cvls_mem->savedJ = NULL; + } + + /* Nullify other N_Vector pointers */ + cvls_mem->ycur = NULL; + cvls_mem->fcur = NULL; + + /* Nullify other SUNMatrix pointer */ + cvls_mem->A = NULL; + + /* Free preconditioner memory (if applicable) */ + if (cvls_mem->pfree) cvls_mem->pfree(cv_mem); + + /* free CVLs interface structure */ + free(cv_mem->cv_lmem); + + return(CVLS_SUCCESS); +} + + +/*----------------------------------------------------------------- + cvLsInitializeCounters + + This routine resets all counters from an CVLsMem structure. + -----------------------------------------------------------------*/ +int cvLsInitializeCounters(CVLsMem cvls_mem) +{ + cvls_mem->nje = 0; + cvls_mem->nfeDQ = 0; + cvls_mem->nstlj = 0; + cvls_mem->npe = 0; + cvls_mem->nli = 0; + cvls_mem->nps = 0; + cvls_mem->ncfl = 0; + cvls_mem->njtsetup = 0; + cvls_mem->njtimes = 0; + return(0); +} + + +/*--------------------------------------------------------------- + cvLs_AccessLMem + + This routine unpacks the cv_mem and ls_mem structures from + void* pointer. If either is missing it returns CVLS_MEM_NULL + or CVLS_LMEM_NULL. + ---------------------------------------------------------------*/ +int cvLs_AccessLMem(void* cvode_mem, const char *fname, + CVodeMem *cv_mem, CVLsMem *cvls_mem) +{ + if (cvode_mem==NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVSLS", + fname, MSG_LS_CVMEM_NULL); + return(CVLS_MEM_NULL); + } + *cv_mem = (CVodeMem) cvode_mem; + if ((*cv_mem)->cv_lmem==NULL) { + cvProcessError(*cv_mem, CVLS_LMEM_NULL, "CVSLS", + fname, MSG_LS_LMEM_NULL); + return(CVLS_LMEM_NULL); + } + *cvls_mem = (CVLsMem) (*cv_mem)->cv_lmem; + return(CVLS_SUCCESS); +} + + +/*================================================================ + PART II - backward problems + ================================================================*/ + +/*--------------------------------------------------------------- + CVSLS Exported functions -- Required + ---------------------------------------------------------------*/ + +/* CVodeSetLinearSolverB specifies the iterative linear solver + for backward integration */ +int CVodeSetLinearSolverB(void *cvode_mem, int which, + SUNLinearSolver LS, SUNMatrix A) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + CVLsMemB cvlsB_mem; + int retval; + + /* Check if cvode_mem exists */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVSLS", + "CVodeSetLinearSolverB", MSG_LS_CVMEM_NULL); + return(CVLS_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Was ASA initialized? */ + if (cv_mem->cv_adjMallocDone == SUNFALSE) { + cvProcessError(cv_mem, CVLS_NO_ADJ, "CVSLS", + "CVodeSetLinearSolverB", MSG_LS_NO_ADJ); + return(CVLS_NO_ADJ); + } + ca_mem = cv_mem->cv_adj_mem; + + /* Check which */ + if ( which >= ca_mem->ca_nbckpbs ) { + cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVSLS", + "CVodeSetLinearSolverB", MSG_LS_BAD_WHICH); + return(CVLS_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + cvB_mem = ca_mem->cvB_mem; + while (cvB_mem != NULL) { + if ( which == cvB_mem->cv_index ) break; + cvB_mem = cvB_mem->cv_next; + } + + /* Get memory for CVLsMemRecB */ + cvlsB_mem = NULL; + cvlsB_mem = (CVLsMemB) malloc(sizeof(struct CVLsMemRecB)); + if (cvlsB_mem == NULL) { + cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVSLS", + "CVodeSetLinearSolverB", MSG_LS_MEM_FAIL); + return(CVLS_MEM_FAIL); + } + + /* initialize Jacobian and preconditioner functions */ + cvlsB_mem->jacB = NULL; + cvlsB_mem->jacBS = NULL; + cvlsB_mem->jtsetupB = NULL; + cvlsB_mem->jtsetupBS = NULL; + cvlsB_mem->jtimesB = NULL; + cvlsB_mem->jtimesBS = NULL; + cvlsB_mem->psetB = NULL; + cvlsB_mem->psetBS = NULL; + cvlsB_mem->psolveB = NULL; + cvlsB_mem->psolveBS = NULL; + cvlsB_mem->P_dataB = NULL; + + /* free any existing system solver attached to cvB */ + if (cvB_mem->cv_lfree) cvB_mem->cv_lfree(cvB_mem); + + /* Attach lmemB data and lfreeB function. */ + cvB_mem->cv_lmem = cvlsB_mem; + cvB_mem->cv_lfree = cvLsFreeB; + + /* set the linear solver for this backward problem */ + cvodeB_mem = (void *) (cvB_mem->cv_mem); + retval = CVodeSetLinearSolver(cvodeB_mem, LS, A); + if (retval != CVLS_SUCCESS) { + free(cvlsB_mem); + cvlsB_mem = NULL; + } + + return(retval); +} + + +/*--------------------------------------------------------------- + CVSLS Exported functions -- Optional input/output + ---------------------------------------------------------------*/ + +int CVodeSetJacFnB(void *cvode_mem, int which, CVLsJacFnB jacB) +{ + 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, "CVodeSetJacFnB", + &cv_mem, &ca_mem, &cvB_mem, &cvlsB_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* set jacB function pointer */ + cvlsB_mem->jacB = jacB; + + /* call corresponding routine for cvodeB_mem structure */ + cvodeB_mem = (void *) (cvB_mem->cv_mem); + if (jacB != NULL) { + retval = CVodeSetJacFn(cvodeB_mem, cvLsJacBWrapper); + } else { + retval = CVodeSetJacFn(cvodeB_mem, NULL); + } + + return(retval); +} + + +int CVodeSetJacFnBS(void *cvode_mem, int which, CVLsJacFnBS jacBS) +{ + 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, "CVodeSetJacFnBS", + &cv_mem, &ca_mem, &cvB_mem, &cvlsB_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* set jacBS function pointer */ + cvlsB_mem->jacBS = jacBS; + + /* call corresponding routine for cvodeB_mem structure */ + cvodeB_mem = (void *) (cvB_mem->cv_mem); + if (jacBS != NULL) { + retval = CVodeSetJacFn(cvodeB_mem, cvLsJacBSWrapper); + } else { + retval = CVodeSetJacFn(cvodeB_mem, NULL); + } + + return(retval); +} + + +int CVodeSetEpsLinB(void *cvode_mem, int which, realtype eplifacB) +{ + 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, "CVodeSetEpsLinB", + &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(CVodeSetEpsLin(cvodeB_mem, eplifacB)); +} + + +int CVodeSetPreconditionerB(void *cvode_mem, int which, + CVLsPrecSetupFnB psetupB, + CVLsPrecSolveFnB psolveB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + CVLsMemB cvlsB_mem; + CVLsPrecSetupFn cvls_psetup; + CVLsPrecSolveFn cvls_psolve; + int retval; + + /* access relevant memory structures */ + retval = cvLs_AccessLMemB(cvode_mem, which, "CVodeSetPreconditionerB", + &cv_mem, &ca_mem, &cvB_mem, &cvlsB_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* Set preconditioners for the backward problem. */ + cvlsB_mem->psetB = psetupB; + cvlsB_mem->psolveB = psolveB; + + /* Call the corresponding "set" routine for the backward problem */ + cvodeB_mem = (void *) (cvB_mem->cv_mem); + cvls_psetup = (psetupB == NULL) ? NULL : cvLsPrecSetupBWrapper; + cvls_psolve = (psolveB == NULL) ? NULL : cvLsPrecSolveBWrapper; + return(CVodeSetPreconditioner(cvodeB_mem, cvls_psetup, cvls_psolve)); +} + + +int CVodeSetPreconditionerBS(void *cvode_mem, int which, + CVLsPrecSetupFnBS psetupBS, + CVLsPrecSolveFnBS psolveBS) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + CVLsMemB cvlsB_mem; + CVLsPrecSetupFn cvls_psetup; + CVLsPrecSolveFn cvls_psolve; + int retval; + + /* access relevant memory structures */ + retval = cvLs_AccessLMemB(cvode_mem, which, "CVodeSetPreconditionerBS", + &cv_mem, &ca_mem, &cvB_mem, &cvlsB_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* Set preconditioners for the backward problem. */ + cvlsB_mem->psetBS = psetupBS; + cvlsB_mem->psolveBS = psolveBS; + + /* Call the corresponding "set" routine for the backward problem */ + cvodeB_mem = (void *) (cvB_mem->cv_mem); + cvls_psetup = (psetupBS == NULL) ? NULL : cvLsPrecSetupBSWrapper; + cvls_psolve = (psolveBS == NULL) ? NULL : cvLsPrecSolveBSWrapper; + return(CVodeSetPreconditioner(cvodeB_mem, cvls_psetup, cvls_psolve)); +} + + +int CVodeSetJacTimesB(void *cvode_mem, int which, + CVLsJacTimesSetupFnB jtsetupB, + CVLsJacTimesVecFnB jtimesB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + CVLsMemB cvlsB_mem; + CVLsJacTimesSetupFn cvls_jtsetup; + CVLsJacTimesVecFn cvls_jtimes; + int retval; + + /* access relevant memory structures */ + retval = cvLs_AccessLMemB(cvode_mem, which, "CVodeSetJacTimesB", + &cv_mem, &ca_mem, &cvB_mem, &cvlsB_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* Set jacobian routines for the backward problem. */ + cvlsB_mem->jtsetupB = jtsetupB; + cvlsB_mem->jtimesB = jtimesB; + + /* Call the corresponding "set" routine for the backward problem */ + cvodeB_mem = (void *) (cvB_mem->cv_mem); + cvls_jtsetup = (jtsetupB == NULL) ? NULL : cvLsJacTimesSetupBWrapper; + cvls_jtimes = (jtimesB == NULL) ? NULL : cvLsJacTimesVecBWrapper; + return(CVodeSetJacTimes(cvodeB_mem, cvls_jtsetup, cvls_jtimes)); +} + + +int CVodeSetJacTimesBS(void *cvode_mem, int which, + CVLsJacTimesSetupFnBS jtsetupBS, + CVLsJacTimesVecFnBS jtimesBS) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + void *cvodeB_mem; + CVLsMemB cvlsB_mem; + CVLsJacTimesSetupFn cvls_jtsetup; + CVLsJacTimesVecFn cvls_jtimes; + int retval; + + /* access relevant memory structures */ + retval = cvLs_AccessLMemB(cvode_mem, which, "CVodeSetJacTimesBS", + &cv_mem, &ca_mem, &cvB_mem, &cvlsB_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* Set jacobian routines for the backward problem. */ + cvlsB_mem->jtsetupBS = jtsetupBS; + cvlsB_mem->jtimesBS = jtimesBS; + + /* Call the corresponding "set" routine for the backward problem */ + cvodeB_mem = (void *) (cvB_mem->cv_mem); + cvls_jtsetup = (jtsetupBS == NULL) ? NULL : cvLsJacTimesSetupBSWrapper; + cvls_jtimes = (jtimesBS == NULL) ? NULL : cvLsJacTimesVecBSWrapper; + return(CVodeSetJacTimes(cvodeB_mem, cvls_jtsetup, cvls_jtimes)); +} + + + +/*----------------------------------------------------------------- + CVSLS private functions for backwards problems + -----------------------------------------------------------------*/ + +/* cvLsJacBWrapper interfaces to the CVLsJacFnB routine provided + by the user. cvLsJacBWrapper is of type CVLsJacFn. */ +static int cvLsJacBWrapper(realtype t, N_Vector yB, N_Vector fyB, + SUNMatrix JB, 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, "cvLsJacBWrapper", + &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", "cvLsJacBWrapper", + MSG_LS_BAD_TINTERP); + return(-1); + } + + /* Call user's adjoint jacB routine (of type CVLsJacFnB) */ + return(cvlsB_mem->jacB(t, ca_mem->ca_ytmp, yB, fyB, JB, + cvB_mem->cv_user_data, tmp1B, tmp2B, tmp3B)); +} + +/* cvLsJacBSWrapper interfaces to the CVLsJacFnBS routine provided + by the user. cvLsJacBSWrapper is of type CVLsJacFn. */ +static int cvLsJacBSWrapper(realtype t, N_Vector yB, N_Vector fyB, + SUNMatrix JB, 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, "cvLsJacBSWrapper", + &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", "cvLsJacBSWrapper", + MSG_LS_BAD_TINTERP); + return(-1); + } + + /* Call user's adjoint dense djacBS routine (of type CVLsDenseJacFnBS) */ + return(cvlsB_mem->jacBS(t, ca_mem->ca_ytmp, ca_mem->ca_yStmp, yB, fyB, + JB, cvB_mem->cv_user_data, tmp1B, tmp2B, tmp3B)); +} + + +/* cvLsPrecSetupBWrapper interfaces to the CVLsPrecSetupFnB + routine provided by the user */ +static int cvLsPrecSetupBWrapper(realtype t, N_Vector yB, N_Vector fyB, + booleantype jokB, booleantype *jcurPtrB, + realtype gammaB, void *cvode_mem) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + CVLsMemB cvlsB_mem; + int retval; + + /* access relevant memory structures */ + retval = cvLs_AccessLMemBCur(cvode_mem, "cvLsPrecSetupBWrapper", + &cv_mem, &ca_mem, &cvB_mem, &cvlsB_mem); + if (retval != CVLS_SUCCESS) return(retval); + + /* Get 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", "cvLsPrecSetupBWrapper", + MSG_LS_BAD_TINTERP); + return(-1); + } + + /* Call user's adjoint precondB routine */ + return(cvlsB_mem->psetB(t, ca_mem->ca_ytmp, yB, fyB, jokB, + jcurPtrB, gammaB, cvB_mem->cv_user_data)); +} + +/* cvLsPrecSetupBSWrapper interfaces to the CVLsPrecSetupFnBS routine + provided by the user */ +static int cvLsPrecSetupBSWrapper(realtype t, N_Vector yB, N_Vector fyB, + booleantype jokB, booleantype *jcurPtrB, + realtype gammaB, void *cvode_mem) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + CVLsMemB cvlsB_mem; + int retval; + + /* access relevant memory structures */ + retval = cvLs_AccessLMemBCur(cvode_mem, "cvLsPrecSetupBSWrapper", + &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", "cvLsPrecSetupBSWrapper", + MSG_LS_BAD_TINTERP); + return(-1); + } + + /* Call user's adjoint precondB routine */ + return(cvlsB_mem->psetBS(t, ca_mem->ca_ytmp, ca_mem->ca_yStmp, + yB, fyB, jokB, jcurPtrB, gammaB, + cvB_mem->cv_user_data)); +} + + +/* cvLsPrecSolveBWrapper interfaces to the CVLsPrecSolveFnB routine + provided by the user */ +static int cvLsPrecSolveBWrapper(realtype t, N_Vector yB, N_Vector fyB, + N_Vector rB, N_Vector zB, + realtype gammaB, realtype deltaB, + int lrB, void *cvode_mem) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + CVLsMemB cvlsB_mem; + int retval; + + /* access relevant memory structures */ + retval = cvLs_AccessLMemBCur(cvode_mem, "cvLsPrecSolveBWrapper", + &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", "cvLsPrecSolveBWrapper", + MSG_LS_BAD_TINTERP); + return(-1); + } + + /* Call user's adjoint psolveB routine */ + return(cvlsB_mem->psolveB(t, ca_mem->ca_ytmp, yB, fyB, rB, zB, + gammaB, deltaB, lrB, cvB_mem->cv_user_data)); +} + + +/* cvLsPrecSolveBSWrapper interfaces to the CVLsPrecSolveFnBS routine + provided by the user */ +static int cvLsPrecSolveBSWrapper(realtype t, N_Vector yB, N_Vector fyB, + N_Vector rB, N_Vector zB, + realtype gammaB, realtype deltaB, + int lrB, void *cvode_mem) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + CVLsMemB cvlsB_mem; + int retval; + + /* access relevant memory structures */ + retval = cvLs_AccessLMemBCur(cvode_mem, "cvLsPrecSolveBSWrapper", + &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", "cvLsPrecSolveBSWrapper", + MSG_LS_BAD_TINTERP); + return(-1); + } + + /* Call user's adjoint psolveBS routine */ + return(cvlsB_mem->psolveBS(t, ca_mem->ca_ytmp, ca_mem->ca_yStmp, + yB, fyB, rB, zB, gammaB, deltaB, + lrB, cvB_mem->cv_user_data)); +} + + +/* cvLsJacTimesSetupBWrapper interfaces to the CVLsJacTimesSetupFnB + routine provided by the user */ +static int cvLsJacTimesSetupBWrapper(realtype t, N_Vector yB, + N_Vector fyB, void *cvode_mem) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + CVLsMemB cvlsB_mem; + int retval; + + /* access relevant memory structures */ + retval = cvLs_AccessLMemBCur(cvode_mem, "cvLsJacTimesSetupBWrapper", + &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", "cvLsJacTimesVecBWrapper", + MSG_LS_BAD_TINTERP); + return(-1); + } + + /* Call user's adjoint jtsetupB routine */ + return(cvlsB_mem->jtsetupB(t, ca_mem->ca_ytmp, yB, + fyB, cvB_mem->cv_user_data)); +} + + +/* cvLsJacTimesSetupBSWrapper interfaces to the CVLsJacTimesSetupFnBS + routine provided by the user */ +static int cvLsJacTimesSetupBSWrapper(realtype t, N_Vector yB, + N_Vector fyB, void *cvode_mem) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + CVLsMemB cvlsB_mem; + int retval; + + /* access relevant memory structures */ + retval = cvLs_AccessLMemBCur(cvode_mem, "cvLsJacTimesSetupBSWrapper", + &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", "cvLsJacTimesVecBSWrapper", + MSG_LS_BAD_TINTERP); + return(-1); + } + + /* Call user's adjoint jtsetupBS routine */ + return(cvlsB_mem->jtsetupBS(t, ca_mem->ca_ytmp, + ca_mem->ca_yStmp, yB, fyB, + cvB_mem->cv_user_data)); +} + + +/* cvLsJacTimesVecBWrapper interfaces to the CVLsJacTimesVecFnB routine + provided by the user */ +static int cvLsJacTimesVecBWrapper(N_Vector vB, N_Vector JvB, realtype t, + N_Vector yB, N_Vector fyB, + void *cvode_mem, N_Vector tmpB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + CVLsMemB cvlsB_mem; + int retval; + + /* access relevant memory structures */ + retval = cvLs_AccessLMemBCur(cvode_mem, "cvLsJacTimesVecBWrapper", + &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", "cvLsJacTimesVecBWrapper", + MSG_LS_BAD_TINTERP); + return(-1); + } + + /* Call user's adjoint jtimesB routine */ + return(cvlsB_mem->jtimesB(vB, JvB, t, ca_mem->ca_ytmp, yB, + fyB, cvB_mem->cv_user_data, tmpB)); +} + + +/* cvLsJacTimesVecBSWrapper interfaces to the CVLsJacTimesVecFnBS + routine provided by the user */ +static int cvLsJacTimesVecBSWrapper(N_Vector vB, N_Vector JvB, realtype t, + N_Vector yB, N_Vector fyB, + void *cvode_mem, N_Vector tmpB) +{ + CVodeMem cv_mem; + CVadjMem ca_mem; + CVodeBMem cvB_mem; + CVLsMemB cvlsB_mem; + int retval; + + /* access relevant memory structures */ + retval = cvLs_AccessLMemBCur(cvode_mem, "cvLsJacTimesVecBSWrapper", + &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", "cvLsJacTimesVecBSWrapper", + MSG_LS_BAD_TINTERP); + return(-1); + } + + /* Call user's adjoint jtimesBS routine */ + return(cvlsB_mem->jtimesBS(vB, JvB, t, ca_mem->ca_ytmp, + ca_mem->ca_yStmp, yB, fyB, + cvB_mem->cv_user_data, tmpB)); +} + + +/* cvLsFreeB frees memory associated with the CVSLS wrapper */ +int cvLsFreeB(CVodeBMem cvB_mem) +{ + CVLsMemB cvlsB_mem; + + /* Return immediately if cvB_mem or cvB_mem->cv_lmem are NULL */ + if (cvB_mem == NULL) return(CVLS_SUCCESS); + if (cvB_mem->cv_lmem == NULL) return(CVLS_SUCCESS); + cvlsB_mem = (CVLsMemB) (cvB_mem->cv_lmem); + + /* free CVLsMemB interface structure */ + free(cvlsB_mem); + + return(CVLS_SUCCESS); +} + + +/* cvLs_AccessLMemB unpacks the cv_mem, ca_mem, cvB_mem and + cvlsB_mem structures from the void* cvode_mem pointer. + If any are missing it returns CVLS_MEM_NULL, CVLS_NO_ADJ, + CVS_ILL_INPUT, or CVLS_LMEMB_NULL. */ +int cvLs_AccessLMemB(void *cvode_mem, int which, const char *fname, + CVodeMem *cv_mem, CVadjMem *ca_mem, + CVodeBMem *cvB_mem, CVLsMemB *cvlsB_mem) +{ + + /* access CVodeMem structure */ + if (cvode_mem==NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVSLS", + fname, MSG_LS_CVMEM_NULL); + return(CVLS_MEM_NULL); + } + *cv_mem = (CVodeMem) cvode_mem; + + /* access CVadjMem structure */ + if ((*cv_mem)->cv_adjMallocDone == SUNFALSE) { + cvProcessError(*cv_mem, CVLS_NO_ADJ, "CVSLS", + fname, MSG_LS_NO_ADJ); + return(CVLS_NO_ADJ); + } + *ca_mem = (*cv_mem)->cv_adj_mem; + + /* Check which */ + if ( which >= (*ca_mem)->ca_nbckpbs ) { + cvProcessError(*cv_mem, CVLS_ILL_INPUT, "CVSLS", + fname, MSG_LS_BAD_WHICH); + return(CVLS_ILL_INPUT); + } + + /* Find the CVodeBMem entry in the linked list corresponding to which */ + *cvB_mem = (*ca_mem)->cvB_mem; + while ((*cvB_mem) != NULL) { + if ( which == (*cvB_mem)->cv_index ) break; + *cvB_mem = (*cvB_mem)->cv_next; + } + + /* access CVLsMemB structure */ + if ((*cvB_mem)->cv_lmem == NULL) { + cvProcessError(*cv_mem, CVLS_LMEMB_NULL, "CVSLS", + fname, MSG_LS_LMEMB_NULL); + return(CVLS_LMEMB_NULL); + } + *cvlsB_mem = (CVLsMemB) ((*cvB_mem)->cv_lmem); + + return(CVLS_SUCCESS); +} + + +/* cvLs_AccessLMemBCur unpacks the cv_mem, ca_mem, cvB_mem and + cvlsB_mem structures from the void* cvode_mem pointer. + If any are missing it returns CVLS_MEM_NULL, CVLS_NO_ADJ, + or CVLS_LMEMB_NULL. */ +int cvLs_AccessLMemBCur(void *cvode_mem, const char *fname, + CVodeMem *cv_mem, CVadjMem *ca_mem, + CVodeBMem *cvB_mem, CVLsMemB *cvlsB_mem) +{ + + /* access CVodeMem structure */ + if (cvode_mem==NULL) { + cvProcessError(NULL, CVLS_MEM_NULL, "CVSLS", + fname, MSG_LS_CVMEM_NULL); + return(CVLS_MEM_NULL); + } + *cv_mem = (CVodeMem) cvode_mem; + + /* access CVadjMem structure */ + if ((*cv_mem)->cv_adjMallocDone == SUNFALSE) { + cvProcessError(*cv_mem, CVLS_NO_ADJ, "CVSLS", + fname, MSG_LS_NO_ADJ); + return(CVLS_NO_ADJ); + } + *ca_mem = (*cv_mem)->cv_adj_mem; + + /* get current backward problem */ + if ((*ca_mem)->ca_bckpbCrt == NULL) { + cvProcessError(*cv_mem, CVLS_LMEMB_NULL, "CVSLS", + fname, MSG_LS_LMEMB_NULL); + return(CVLS_LMEMB_NULL); + } + *cvB_mem = (*ca_mem)->ca_bckpbCrt; + + /* access CVLsMemB structure */ + if ((*cvB_mem)->cv_lmem == NULL) { + cvProcessError(*cv_mem, CVLS_LMEMB_NULL, "CVSLS", + fname, MSG_LS_LMEMB_NULL); + return(CVLS_LMEMB_NULL); + } + *cvlsB_mem = (CVLsMemB) ((*cvB_mem)->cv_lmem); + + return(CVLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + EOF + ---------------------------------------------------------------*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_ls_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_ls_impl.h new file mode 100644 index 0000000..14a9227 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_ls_impl.h @@ -0,0 +1,226 @@ +/*----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 + *----------------------------------------------------------------- + * Implementation header file for the scaled, preconditioned + * linear solver interface. + *-----------------------------------------------------------------*/ + +#ifndef _CVSLS_IMPL_H +#define _CVSLS_IMPL_H + +#include <cvodes/cvodes_ls.h> +#include "cvodes_impl.h" + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*----------------------------------------------------------------- + CVSLS solver constants + + CVLS_MSBJ maximum number of steps between Jacobian and/or + preconditioner evaluations + CVLS_DGMAX maximum change in gamma between Jacobian and/or + preconditioner evaluations + CVLS_EPLIN default value for factor by which the tolerance on + the nonlinear iteration is multiplied to get a + tolerance on the linear iteration + -----------------------------------------------------------------*/ +#define CVLS_MSBJ 50 +#define CVLS_DGMAX RCONST(0.2) +#define CVLS_EPLIN RCONST(0.05) + + +/*================================================================= + PART I: Forward Problems + =================================================================*/ + +/*----------------------------------------------------------------- + Types : CVLsMemRec, CVLsMem + + The type CVLsMem is pointer to a CVLsMemRec. + -----------------------------------------------------------------*/ +typedef struct CVLsMemRec { + + /* 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 */ + + /* Iterative solver tolerance */ + realtype sqrtN; /* sqrt(N) */ + realtype eplifac; /* eplifac = user specified or EPLIN_DEFAULT */ + + /* Linear solver, matrix and vector objects/pointers */ + SUNLinearSolver LS; /* generic linear solver object */ + 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 ycur; /* CVODE current y vector in Newton Iteration */ + N_Vector fcur; /* fcur = f(tn, ycur) */ + + /* Statistics and associated parameters */ + long int msbj; /* max num steps between jac/pset calls */ + long int nje; /* nje = no. of calls to jac */ + long int nfeDQ; /* no. of calls to f due to DQ Jacobian or J*v + approximations */ + long int nstlj; /* nstlj = nst at last jac/pset call */ + long int npe; /* npe = total number of pset calls */ + long int nli; /* nli = total number of linear iterations */ + long int nps; /* nps = total number of psolve calls */ + long int ncfl; /* ncfl = total number of convergence failures */ + long int njtsetup; /* njtsetup = total number of calls to jtsetup */ + long int njtimes; /* njtimes = total number of calls to jtimes */ + + /* Preconditioner computation + * (a) user-provided: + * - P_data == user_data + * - pfree == NULL (the user dealocates memory for user_data) + * (b) internal preconditioner module + * - P_data == cvode_mem + * - pfree == set by the prec. module and called in CVodeFree */ + CVLsPrecSetupFn pset; + CVLsPrecSolveFn psolve; + int (*pfree)(CVodeMem cv_mem); + void *P_data; + + /* Jacobian times vector compuation + * (a) jtimes function provided by the user: + * - jt_data == user_data + * - jtimesDQ == SUNFALSE + * (b) internal jtimes + * - jt_data == cvode_mem + * - jtimesDQ == SUNTRUE */ + booleantype jtimesDQ; + CVLsJacTimesSetupFn jtsetup; + CVLsJacTimesVecFn jtimes; + void *jt_data; + + long int last_flag; /* last error flag returned by any function */ + +} *CVLsMem; + +/*----------------------------------------------------------------- + Prototypes of internal functions + -----------------------------------------------------------------*/ + +/* Interface routines called by system SUNLinearSolver */ +int cvLsATimes(void* cvode_mem, N_Vector v, N_Vector z); +int cvLsPSetup(void* cvode_mem); +int cvLsPSolve(void* cvode_mem, N_Vector r, N_Vector z, + realtype tol, int lr); + +/* Difference quotient approximation for Jac times vector */ +int cvLsDQJtimes(N_Vector v, N_Vector Jv, realtype t, + N_Vector y, N_Vector fy, void *data, + N_Vector work); + +/* Difference-quotient Jacobian approximation routines */ +int cvLsDQJac(realtype t, N_Vector y, N_Vector fy, SUNMatrix Jac, + void *data, N_Vector tmp1, N_Vector tmp2, N_Vector tmp3); +int cvLsDenseDQJac(realtype t, N_Vector y, N_Vector fy, + SUNMatrix Jac, CVodeMem cv_mem, N_Vector tmp1); +int cvLsBandDQJac(realtype t, N_Vector y, N_Vector fy, + SUNMatrix Jac, CVodeMem cv_mem, N_Vector tmp1, + N_Vector tmp2); + +/* Generic linit/lsetup/lsolve/lfree interface routines for CVode to call */ +int cvLsInitialize(CVodeMem cv_mem); +int cvLsSetup(CVodeMem cv_mem, int convfail, N_Vector ypred, + N_Vector fpred, booleantype *jcurPtr, + N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3); +int cvLsSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight, + N_Vector ycur, N_Vector fcur); +int cvLsFree(CVodeMem cv_mem); + +/* Auxilliary functions */ +int cvLsInitializeCounters(CVLsMem cvls_mem); +int cvLs_AccessLMem(void* cvode_mem, const char* fname, + CVodeMem* cv_mem, CVLsMem* cvls_mem); + +/*================================================================= + PART II: Backward Problems + =================================================================*/ + +/*----------------------------------------------------------------- + Types : CVLsMemRecB, CVLsMemB + + CVodeSetLinearSolverB attaches such a structure to the lmemB + field of CVodeBMem + -----------------------------------------------------------------*/ +typedef struct CVLsMemRecB { + + CVLsJacFnB jacB; + CVLsJacFnBS jacBS; + CVLsJacTimesSetupFnB jtsetupB; + CVLsJacTimesSetupFnBS jtsetupBS; + CVLsJacTimesVecFnB jtimesB; + CVLsJacTimesVecFnBS jtimesBS; + CVLsPrecSetupFnB psetB; + CVLsPrecSetupFnBS psetBS; + CVLsPrecSolveFnB psolveB; + CVLsPrecSolveFnBS psolveBS; + void *P_dataB; + +} *CVLsMemB; + + +/*----------------------------------------------------------------- + Prototypes of internal functions + -----------------------------------------------------------------*/ + +int cvLsFreeB(CVodeBMem cvb_mem); +int cvLs_AccessLMemB(void *cvode_mem, int which, const char *fname, + CVodeMem *cv_mem, CVadjMem *ca_mem, + CVodeBMem *cvB_mem, CVLsMemB *cvlsB_mem); +int cvLs_AccessLMemBCur(void *cvode_mem, const char *fname, + CVodeMem *cv_mem, CVadjMem *ca_mem, + CVodeBMem *cvB_mem, CVLsMemB *cvlsB_mem); + + +/*================================================================= + Error Messages + =================================================================*/ + +#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_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." +#define MSG_LS_JTSETUP_FAILED "The Jacobian x vector setup routine failed in an unrecoverable manner." +#define MSG_LS_JTIMES_FAILED "The Jacobian x vector routine failed in an unrecoverable manner." +#define MSG_LS_JACFUNC_FAILED "The Jacobian routine failed in an unrecoverable manner." +#define MSG_LS_SUNMAT_FAILED "A SUNMatrix routine failed in an unrecoverable manner." + +#define MSG_LS_NO_ADJ "Illegal attempt to call before calling CVodeAdjMalloc." +#define MSG_LS_BAD_WHICH "Illegal value for which." +#define MSG_LS_LMEMB_NULL "Linear solver memory is NULL for the backward integration." +#define MSG_LS_BAD_TINTERP "Bad t for interpolation." + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_nls.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_nls.c new file mode 100644 index 0000000..6275530 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_nls.c @@ -0,0 +1,319 @@ +/* ----------------------------------------------------------------------------- + * 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 the implementation file for the CVODES nonlinear solver interface. + * ---------------------------------------------------------------------------*/ + +#include "cvodes_impl.h" +#include "sundials/sundials_math.h" + +/* constant macros */ +#define ONE RCONST(1.0) + +/* private functions */ +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 cvNlsConvTest(SUNNonlinearSolver NLS, N_Vector ycor, N_Vector del, + realtype tol, N_Vector ewt, void* cvode_mem); + +/* ----------------------------------------------------------------------------- + * Exported functions + * ---------------------------------------------------------------------------*/ + +int CVodeSetNonlinearSolver(void *cvode_mem, SUNNonlinearSolver NLS) +{ + CVodeMem cv_mem; + int retval; + + /* Return immediately if CVode memory is NULL */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetNonlinearSolver", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Return immediately if NLS memory is NULL */ + if (NLS == NULL) { + cvProcessError(NULL, CV_ILL_INPUT, "CVODES", "CVodeSetNonlinearSolver", + "NLS must be non-NULL"); + return (CV_ILL_INPUT); + } + + /* 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"); + return(CV_ILL_INPUT); + } + + /* free any existing nonlinear solver */ + if ((cv_mem->NLS != NULL) && (cv_mem->ownNLS)) + retval = SUNNonlinSolFree(cv_mem->NLS); + + /* set SUNNonlinearSolver pointer */ + cv_mem->NLS = NLS; + + /* Set NLS ownership flag. If this function was called to attach the default + NLS, CVODE will set the flag to SUNTRUE after this function returns. */ + cv_mem->ownNLS = SUNFALSE; + + /* set the nonlinear system function */ + if (SUNNonlinSolGetType(NLS) == SUNNONLINEARSOLVER_ROOTFIND) { + retval = SUNNonlinSolSetSysFn(cv_mem->NLS, cvNlsResidual); + } else if (SUNNonlinSolGetType(NLS) == SUNNONLINEARSOLVER_FIXEDPOINT) { + retval = SUNNonlinSolSetSysFn(cv_mem->NLS, cvNlsFPFunction); + } else { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetNonlinearSolver", + "Invalid nonlinear solver type"); + return(CV_ILL_INPUT); + } + + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetNonlinearSolver", + "Setting nonlinear system function failed"); + return(CV_ILL_INPUT); + } + + /* set convergence test function */ + retval = SUNNonlinSolSetConvTestFn(cv_mem->NLS, cvNlsConvTest); + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetNonlinearSolver", + "Setting convergence test function failed"); + return(CV_ILL_INPUT); + } + + /* set max allowed nonlinear iterations */ + retval = SUNNonlinSolSetMaxIters(cv_mem->NLS, NLS_MAXCOR); + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetNonlinearSolver", + "Setting maximum number of nonlinear iterations failed"); + return(CV_ILL_INPUT); + } + + return(CV_SUCCESS); +} + + +/* ----------------------------------------------------------------------------- + * Private functions + * ---------------------------------------------------------------------------*/ + + +int cvNlsInit(CVodeMem cvode_mem) +{ + int retval; + + /* set the linear solver setup wrapper function */ + if (cvode_mem->cv_lsetup) + retval = SUNNonlinSolSetLSetupFn(cvode_mem->NLS, cvNlsLSetup); + else + retval = SUNNonlinSolSetLSetupFn(cvode_mem->NLS, NULL); + + if (retval != CV_SUCCESS) { + cvProcessError(cvode_mem, CV_ILL_INPUT, "CVODE", "cvNlsInit", + "Setting the linear solver setup function failed"); + return(CV_NLS_INIT_FAIL); + } + + /* set the linear solver solve wrapper function */ + if (cvode_mem->cv_lsolve) + retval = SUNNonlinSolSetLSolveFn(cvode_mem->NLS, cvNlsLSolve); + else + retval = SUNNonlinSolSetLSolveFn(cvode_mem->NLS, NULL); + + if (retval != CV_SUCCESS) { + cvProcessError(cvode_mem, CV_ILL_INPUT, "CVODE", "cvNlsInit", + "Setting linear solver solve function failed"); + return(CV_NLS_INIT_FAIL); + } + + /* initialize nonlinear solver */ + retval = SUNNonlinSolInitialize(cvode_mem->NLS); + + if (retval != CV_SUCCESS) { + cvProcessError(cvode_mem, CV_ILL_INPUT, "CVODE", "cvNlsInit", + MSGCV_NLS_INIT_FAIL); + return(CV_NLS_INIT_FAIL); + } + + return(CV_SUCCESS); +} + + +static int cvNlsLSetup(N_Vector ycor, N_Vector res, booleantype jbad, + booleantype* jcur, void* cvode_mem) +{ + CVodeMem cv_mem; + int retval; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "cvNlsLSetup", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* if the nonlinear solver marked the Jacobian as bad update convfail */ + if (jbad) + cv_mem->convfail = CV_FAIL_BAD_J; + + /* setup the linear solver */ + retval = cv_mem->cv_lsetup(cv_mem, cv_mem->convfail, cv_mem->cv_y, cv_mem->cv_ftemp, + &(cv_mem->cv_jcur), cv_mem->cv_vtemp1, cv_mem->cv_vtemp2, + cv_mem->cv_vtemp3); + cv_mem->cv_nsetups++; + + /* update Jacobian status */ + *jcur = cv_mem->cv_jcur; + + cv_mem->cv_forceSetup = SUNFALSE; + cv_mem->cv_gamrat = ONE; + cv_mem->cv_gammap = cv_mem->cv_gamma; + cv_mem->cv_crate = ONE; + cv_mem->cv_crateS = ONE; + cv_mem->cv_nstlp = cv_mem->cv_nst; + + if (retval < 0) return(CV_LSETUP_FAIL); + if (retval > 0) return(SUN_NLS_CONV_RECVR); + + return(CV_SUCCESS); +} + + +static int cvNlsLSolve(N_Vector ycor, N_Vector delta, void* cvode_mem) +{ + CVodeMem cv_mem; + int retval; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "cvNlsLSolve", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + retval = cv_mem->cv_lsolve(cv_mem, delta, cv_mem->cv_ewt, cv_mem->cv_y, cv_mem->cv_ftemp); + + if (retval < 0) return(CV_LSOLVE_FAIL); + if (retval > 0) return(SUN_NLS_CONV_RECVR); + + return(CV_SUCCESS); +} + + +static int cvNlsConvTest(SUNNonlinearSolver NLS, N_Vector ycor, N_Vector delta, + realtype tol, N_Vector ewt, void* cvode_mem) +{ + CVodeMem cv_mem; + int m, retval; + realtype del; + realtype dcon; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "cvNlsConvTest", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* compute the norm of the correction */ + del = N_VWrmsNorm(delta, ewt); + + /* get the current nonlinear solver iteration count */ + retval = SUNNonlinSolGetCurIter(NLS, &m); + if (retval != CV_SUCCESS) return(CV_MEM_NULL); + + /* Test for convergence. If m > 0, an estimate of the convergence + rate constant is stored in crate, and used in the test. */ + if (m > 0) { + cv_mem->cv_crate = SUNMAX(CRDOWN * cv_mem->cv_crate, del/cv_mem->cv_delp); + } + dcon = del * SUNMIN(ONE, cv_mem->cv_crate) / tol; + + if (dcon <= ONE) { + cv_mem->cv_acnrm = (m==0) ? del : N_VWrmsNorm(ycor, cv_mem->cv_ewt); + return(CV_SUCCESS); /* Nonlinear system was solved successfully */ + } + + /* check if the iteration seems to be diverging */ + if ((m >= 1) && (del > RDIV*cv_mem->cv_delp)) return(SUN_NLS_CONV_RECVR); + + /* Save norm of correction and loop again */ + cv_mem->cv_delp = del; + + /* Not yet converged */ + return(SUN_NLS_CONTINUE); +} + + +static int cvNlsResidual(N_Vector ycor, N_Vector res, void* cvode_mem) +{ + CVodeMem cv_mem; + int retval; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", + "cvNlsResidual", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* update the state based on the current correction */ + N_VLinearSum(ONE, cv_mem->cv_zn[0], ONE, ycor, cv_mem->cv_y); + + /* evaluate the rhs function */ + 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) return(RHSFUNC_RECVR); + + /* compute the resiudal */ + N_VLinearSum(cv_mem->cv_rl1, cv_mem->cv_zn[1], ONE, ycor, res); + N_VLinearSum(-cv_mem->cv_gamma, cv_mem->cv_ftemp, ONE, res, res); + + return(CV_SUCCESS); +} + + +static int cvNlsFPFunction(N_Vector ycor, N_Vector res, void* cvode_mem) +{ + CVodeMem cv_mem; + int retval; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODE", "cvNlsFPFunction", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* update the state based on the current correction */ + N_VLinearSum(ONE, cv_mem->cv_zn[0], ONE, ycor, cv_mem->cv_y); + + /* evaluate the rhs function */ + retval = cv_mem->cv_f(cv_mem->cv_tn, cv_mem->cv_y, res, + cv_mem->cv_user_data); + cv_mem->cv_nfe++; + if (retval < 0) return(CV_RHSFUNC_FAIL); + if (retval > 0) return(RHSFUNC_RECVR); + + N_VLinearSum(cv_mem->cv_h, res, -ONE, cv_mem->cv_zn[1], res); + N_VScale(cv_mem->cv_rl1, res, res); + + return(CV_SUCCESS); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_nls_sim.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_nls_sim.c new file mode 100644 index 0000000..54437f9 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_nls_sim.c @@ -0,0 +1,520 @@ +/* ----------------------------------------------------------------------------- + * 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 the implementation file for the CVODES nonlinear solver interface. + * ---------------------------------------------------------------------------*/ + +/* + * When sensitivities are computed using the CV_SIMULTANEOUS approach and the + * Newton solver is selected the iteraiton is a quasi-Newton method on the + * combined system (by approximating the Jacobian matrix by its block diagonal) + * and thus only solve linear systems with multiple right hand sides (all + * sharing the same coefficient matrix - whatever iteration matrix we decide on) + * we set-up the linear solver to handle N equations at a time. + */ + +#include "cvodes_impl.h" +#include "sundials/sundials_math.h" +#include "sundials/sundials_nvector_senswrapper.h" + +/* constant macros */ +#define ONE RCONST(1.0) + +/* private functions */ +static int cvNlsResidualSensSim(N_Vector ycorSim, N_Vector resSim, + void* cvode_mem); +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, + void* cvode_mem); +static int cvNlsConvTestSensSim(SUNNonlinearSolver NLS, + N_Vector ycorSim, N_Vector delSim, + realtype tol, N_Vector ewtSim, void* cvode_mem); + +/* ----------------------------------------------------------------------------- + * Exported functions + * ---------------------------------------------------------------------------*/ + +int CVodeSetNonlinearSolverSensSim(void *cvode_mem, SUNNonlinearSolver NLS) +{ + CVodeMem cv_mem; + int retval, is; + + /* Return immediately if CVode memory is NULL */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "CVodeSetNonlinearSolverSensSim", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Return immediately if NLS memory is NULL */ + if (NLS == NULL) { + cvProcessError(NULL, CV_ILL_INPUT, "CVODES", + "CVodeSetNonlinearSolverSensSim", + "NLS must be non-NULL"); + return (CV_ILL_INPUT); + } + + /* 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", + "NLS does not support required operations"); + return(CV_ILL_INPUT); + } + + /* check that sensitivities were initialized */ + if (!(cv_mem->cv_sensi)) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSetNonlinearSolverSensSim", + MSGCV_NO_SENSI); + return(CV_ILL_INPUT); + } + + /* check that simultaneous corrector was selected */ + if (cv_mem->cv_ism != CV_SIMULTANEOUS) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSetNonlinearSolverSensStg", + "Sensitivity solution method is not CV_SIMULTANEOUS"); + return(CV_ILL_INPUT); + } + + /* free any existing nonlinear solver */ + if ((cv_mem->NLSsim != NULL) && (cv_mem->ownNLSsim)) + retval = SUNNonlinSolFree(cv_mem->NLSsim); + + /* set SUNNonlinearSolver pointer */ + cv_mem->NLSsim = NLS; + + /* Set NLS ownership flag. If this function was called to attach the default + NLS, CVODE will set the flag to SUNTRUE after this function returns. */ + cv_mem->ownNLSsim = SUNFALSE; + + /* set the nonlinear system function */ + if (SUNNonlinSolGetType(NLS) == SUNNONLINEARSOLVER_ROOTFIND) { + retval = SUNNonlinSolSetSysFn(cv_mem->NLSsim, cvNlsResidualSensSim); + } else if (SUNNonlinSolGetType(NLS) == SUNNONLINEARSOLVER_FIXEDPOINT) { + retval = SUNNonlinSolSetSysFn(cv_mem->NLSsim, cvNlsFPFunctionSensSim); + } else { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSetNonlinearSolverSensSim", + "Invalid nonlinear solver type"); + return(CV_ILL_INPUT); + } + + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSetNonlinearSolverSensSim", + "Setting nonlinear system function failed"); + return(CV_ILL_INPUT); + } + + /* set convergence test function */ + retval = SUNNonlinSolSetConvTestFn(cv_mem->NLSsim, cvNlsConvTestSensSim); + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSetNonlinearSolverSensSim", + "Setting convergence test function failed"); + return(CV_ILL_INPUT); + } + + /* set max allowed nonlinear iterations */ + retval = SUNNonlinSolSetMaxIters(cv_mem->NLSsim, NLS_MAXCOR); + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSetNonlinearSolverSensSim", + "Setting maximum number of nonlinear iterations failed"); + return(CV_ILL_INPUT); + } + + /* 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) { + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", + "CVodeSetNonlinearSolverSensSim", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + cv_mem->ycorSim = N_VNewEmpty_SensWrapper(cv_mem->cv_Ns+1); + if (cv_mem->ycorSim == NULL) { + N_VDestroy(cv_mem->ycor0Sim); + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", + "CVodeSetNonlinearSolverSensSim", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + 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->ycorSim); + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", + "CVodeSetNonlinearSolverSensSim", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + cv_mem->simMallocDone = SUNTRUE; + } + + /* 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; + + 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]; + } + + return(CV_SUCCESS); +} + + +/* ----------------------------------------------------------------------------- + * Private functions + * ---------------------------------------------------------------------------*/ + + +int cvNlsInitSensSim(CVodeMem cvode_mem) +{ + int retval; + + /* set the linear solver setup wrapper function */ + if (cvode_mem->cv_lsetup) + retval = SUNNonlinSolSetLSetupFn(cvode_mem->NLSsim, cvNlsLSetupSensSim); + else + retval = SUNNonlinSolSetLSetupFn(cvode_mem->NLSsim, NULL); + + if (retval != CV_SUCCESS) { + cvProcessError(cvode_mem, CV_ILL_INPUT, "CVODES", "cvNlsInitSensSim", + "Setting the linear solver setup function failed"); + return(CV_NLS_INIT_FAIL); + } + + /* set the linear solver solve wrapper function */ + if (cvode_mem->cv_lsolve) + retval = SUNNonlinSolSetLSolveFn(cvode_mem->NLSsim, cvNlsLSolveSensSim); + else + retval = SUNNonlinSolSetLSolveFn(cvode_mem->NLSsim, NULL); + + if (retval != CV_SUCCESS) { + cvProcessError(cvode_mem, CV_ILL_INPUT, "CVODES", "cvNlsInitSensSim", + "Setting linear solver solve function failed"); + return(CV_NLS_INIT_FAIL); + } + + /* initialize nonlinear solver */ + retval = SUNNonlinSolInitialize(cvode_mem->NLSsim); + + if (retval != CV_SUCCESS) { + cvProcessError(cvode_mem, CV_ILL_INPUT, "CVODES", "cvNlsInitSensSim", + MSGCV_NLS_INIT_FAIL); + return(CV_NLS_INIT_FAIL); + } + + return(CV_SUCCESS); +} + + +static int cvNlsLSetupSensSim(N_Vector ycorSim, N_Vector resSim, + booleantype jbad, booleantype* jcur, + void* cvode_mem) +{ + CVodeMem cv_mem; + int retval; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "cvNlsLSetupSensSim", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* if the nonlinear solver marked the Jacobian as bad update convfail */ + if (jbad) + cv_mem->convfail = CV_FAIL_BAD_J; + + /* setup the linear solver */ + retval = cv_mem->cv_lsetup(cv_mem, cv_mem->convfail, cv_mem->cv_y, + cv_mem->cv_ftemp, &(cv_mem->cv_jcur), + cv_mem->cv_vtemp1, cv_mem->cv_vtemp2, + cv_mem->cv_vtemp3); + cv_mem->cv_nsetups++; + + /* update Jacobian status */ + *jcur = cv_mem->cv_jcur; + + cv_mem->cv_forceSetup = SUNFALSE; + cv_mem->cv_gamrat = ONE; + cv_mem->cv_gammap = cv_mem->cv_gamma; + cv_mem->cv_crate = ONE; + cv_mem->cv_crateS = ONE; + cv_mem->cv_nstlp = cv_mem->cv_nst; + + if (retval < 0) return(CV_LSETUP_FAIL); + if (retval > 0) return(SUN_NLS_CONV_RECVR); + + return(CV_SUCCESS); +} + + +static int cvNlsLSolveSensSim(N_Vector ycorSim, N_Vector deltaSim, void* cvode_mem) +{ + CVodeMem cv_mem; + int retval, is; + N_Vector delta; + N_Vector *deltaS; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "cvNlsLSolveSensSim", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* extract state delta from the vector wrapper */ + delta = NV_VEC_SW(deltaSim,0); + + /* solve the state linear system */ + retval = cv_mem->cv_lsolve(cv_mem, delta, cv_mem->cv_ewt, cv_mem->cv_y, + cv_mem->cv_ftemp); + + if (retval < 0) return(CV_LSOLVE_FAIL); + if (retval > 0) return(SUN_NLS_CONV_RECVR); + + /* extract sensitivity deltas from the vector wrapper */ + deltaS = NV_VECS_SW(deltaSim)+1; + + /* solve the sensitivity linear systems */ + for (is=0; is<cv_mem->cv_Ns; is++) { + retval = cv_mem->cv_lsolve(cv_mem, deltaS[is], cv_mem->cv_ewtS[is], + cv_mem->cv_y, cv_mem->cv_ftemp); + + if (retval < 0) return(CV_LSOLVE_FAIL); + if (retval > 0) return(SUN_NLS_CONV_RECVR); + } + + return(CV_SUCCESS); +} + + +static int cvNlsConvTestSensSim(SUNNonlinearSolver NLS, + N_Vector ycorSim, N_Vector deltaSim, + realtype tol, N_Vector ewtSim, void* cvode_mem) +{ + CVodeMem cv_mem; + int m, retval; + realtype del, delS, Del; + realtype dcon; + N_Vector ycor, delta, ewt; + N_Vector *deltaS, *ewtS; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "cvNlsConvTestSensSim", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* extract the current state and sensitivity corrections */ + ycor = NV_VEC_SW(ycorSim,0); + + /* extract state and sensitivity deltas */ + delta = NV_VEC_SW(deltaSim,0); + deltaS = NV_VECS_SW(deltaSim)+1; + + /* extract state and sensitivity error weights */ + ewt = NV_VEC_SW(ewtSim,0); + ewtS = NV_VECS_SW(ewtSim)+1; + + /* compute the norm of the state and sensitivity corrections */ + del = N_VWrmsNorm(delta, ewt); + delS = cvSensUpdateNorm(cv_mem, del, deltaS, ewtS); + + /* norm used in error test */ + Del = delS; + + /* get the current nonlinear solver iteration count */ + retval = SUNNonlinSolGetCurIter(NLS, &m); + if (retval != CV_SUCCESS) return(CV_MEM_NULL); + + /* Test for convergence. If m > 0, an estimate of the convergence + rate constant is stored in crate, and used in the test. + + Recall that, even when errconS=SUNFALSE, all variables are used in the + convergence test. Hence, we use Del (and not del). However, acnrm is used + in the error test and thus it has different forms depending on errconS + (and this explains why we have to carry around del and delS). + */ + if (m > 0) { + cv_mem->cv_crate = SUNMAX(CRDOWN * cv_mem->cv_crate, Del/cv_mem->cv_delp); + } + dcon = Del * SUNMIN(ONE, cv_mem->cv_crate) / tol; + + /* check if nonlinear system was solved successfully */ + if (dcon <= ONE) { + if (m == 0) { + cv_mem->cv_acnrm = (cv_mem->cv_errconS) ? delS : del; + } else { + cv_mem->cv_acnrm = (cv_mem->cv_errconS) ? + N_VWrmsNorm(ycorSim, ewtSim) : N_VWrmsNorm(ycor, ewt); + } + return(CV_SUCCESS); + } + + /* check if the iteration seems to be diverging */ + if ((m >= 1) && (Del > RDIV*cv_mem->cv_delp)) return(SUN_NLS_CONV_RECVR); + + /* Save norm of correction and loop again */ + cv_mem->cv_delp = Del; + + /* Not yet converged */ + return(SUN_NLS_CONTINUE); +} + + +static int cvNlsResidualSensSim(N_Vector ycorSim, N_Vector resSim, void* cvode_mem) +{ + CVodeMem cv_mem; + int retval; + N_Vector ycor, res; + N_Vector *ycorS, *resS; + realtype cvals[3]; + N_Vector* XXvecs[3]; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "cvNlsResidualSensSim", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* extract state and residual vectors from the vector wrapper */ + ycor = NV_VEC_SW(ycorSim,0); + res = NV_VEC_SW(resSim,0); + + /* update the state based on the current correction */ + N_VLinearSum(ONE, cv_mem->cv_zn[0], ONE, ycor, cv_mem->cv_y); + + /* evaluate the rhs function */ + 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) return(RHSFUNC_RECVR); + + /* compute the resiudal */ + N_VLinearSum(cv_mem->cv_rl1, cv_mem->cv_zn[1], ONE, ycor, res); + N_VLinearSum(-cv_mem->cv_gamma, cv_mem->cv_ftemp, ONE, res, res); + + /* extract sensitivity and residual vectors from the vector wrapper */ + ycorS = NV_VECS_SW(ycorSim)+1; + resS = NV_VECS_SW(resSim)+1; + + /* update sensitivities based on the current correction */ + retval = N_VLinearSumVectorArray(cv_mem->cv_Ns, + ONE, cv_mem->cv_znS[0], + ONE, ycorS, cv_mem->cv_yS); + if (retval != CV_SUCCESS) return(CV_VECTOROP_ERR); + + /* evaluate the sensitivity rhs function */ + retval = cvSensRhsWrapper(cv_mem, cv_mem->cv_tn, + cv_mem->cv_y, cv_mem->cv_ftemp, + cv_mem->cv_yS, cv_mem->cv_ftempS, + cv_mem->cv_vtemp1, cv_mem->cv_vtemp2); + + if (retval < 0) return(CV_SRHSFUNC_FAIL); + if (retval > 0) return(SRHSFUNC_RECVR); + + /* compute the sensitivity resiudal */ + cvals[0] = cv_mem->cv_rl1; XXvecs[0] = cv_mem->cv_znS[1]; + cvals[1] = ONE; XXvecs[1] = ycorS; + cvals[2] = -cv_mem->cv_gamma; XXvecs[2] = cv_mem->cv_ftempS; + + retval = N_VLinearCombinationVectorArray(cv_mem->cv_Ns, + 3, cvals, XXvecs, resS); + if (retval != CV_SUCCESS) return(CV_VECTOROP_ERR); + + return(CV_SUCCESS); +} + + +static int cvNlsFPFunctionSensSim(N_Vector ycorSim, N_Vector resSim, void* cvode_mem) +{ + CVodeMem cv_mem; + int retval, is; + N_Vector ycor, res; + N_Vector *ycorS, *resS; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "cvNlsFPFunctionSensSim", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* extract state and residual vectors from the vector wrapper */ + ycor = NV_VEC_SW(ycorSim,0); + res = NV_VEC_SW(resSim,0); + + /* update the state based on the current correction */ + N_VLinearSum(ONE, cv_mem->cv_zn[0], ONE, ycor, cv_mem->cv_y); + + /* evaluate the rhs function */ + retval = cv_mem->cv_f(cv_mem->cv_tn, cv_mem->cv_y, res, + cv_mem->cv_user_data); + cv_mem->cv_nfe++; + if (retval < 0) return(CV_RHSFUNC_FAIL); + if (retval > 0) return(RHSFUNC_RECVR); + + /* evaluate fixed point function */ + N_VLinearSum(cv_mem->cv_h, res, -ONE, cv_mem->cv_zn[1], res); + N_VScale(cv_mem->cv_rl1, res, res); + + /* extract sensitivity and residual vectors from the vector wrapper */ + ycorS = NV_VECS_SW(ycorSim)+1; + resS = NV_VECS_SW(resSim)+1; + + /* update the sensitivities based on the current correction */ + N_VLinearSumVectorArray(cv_mem->cv_Ns, + ONE, cv_mem->cv_znS[0], + ONE, ycorS, cv_mem->cv_yS); + + /* evaluate the sensitivity rhs function */ + retval = cvSensRhsWrapper(cv_mem, cv_mem->cv_tn, + cv_mem->cv_y, res, + cv_mem->cv_yS, resS, + cv_mem->cv_vtemp1, cv_mem->cv_vtemp2); + + if (retval < 0) return(CV_SRHSFUNC_FAIL); + if (retval > 0) return(SRHSFUNC_RECVR); + + /* evaluate sensitivity fixed point function */ + for (is=0; is<cv_mem->cv_Ns; is++) { + N_VLinearSum(cv_mem->cv_h, resS[is], -ONE, cv_mem->cv_znS[1][is], resS[is]); + N_VScale(cv_mem->cv_rl1, resS[is], resS[is]); + } + + return(CV_SUCCESS); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_nls_stg.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_nls_stg.c new file mode 100644 index 0000000..8df4030 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_nls_stg.c @@ -0,0 +1,448 @@ +/* ----------------------------------------------------------------------------- + * 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 the implementation file for the CVODES nonlinear solver interface. + * ---------------------------------------------------------------------------*/ + +#include "cvodes_impl.h" +#include "sundials/sundials_math.h" +#include "sundials/sundials_nvector_senswrapper.h" + +/* constant macros */ +#define ONE RCONST(1.0) + +/* private functions */ +static int cvNlsResidualSensStg(N_Vector ycorStg, N_Vector resStg, + void* cvode_mem); +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, + void* cvode_mem); +static int cvNlsConvTestSensStg(SUNNonlinearSolver NLS, + N_Vector ycorStg, N_Vector delStg, + realtype tol, N_Vector ewtStg, void* cvode_mem); + +/* ----------------------------------------------------------------------------- + * Exported functions + * ---------------------------------------------------------------------------*/ + +int CVodeSetNonlinearSolverSensStg(void *cvode_mem, SUNNonlinearSolver NLS) +{ + CVodeMem cv_mem; + int retval, is; + + /* Return immediately if CVode memory is NULL */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "CVodeSetNonlinearSolverSensStg", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Return immediately if NLS memory is NULL */ + if (NLS == NULL) { + cvProcessError(NULL, CV_ILL_INPUT, "CVODES", + "CVodeSetNonlinearSolverSensStg", + "NLS must be non-NULL"); + return (CV_ILL_INPUT); + } + + /* 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", + "NLS does not support required operations"); + return(CV_ILL_INPUT); + } + + /* check that sensitivities were initialized */ + if (!(cv_mem->cv_sensi)) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSetNonlinearSolverSensStg", + MSGCV_NO_SENSI); + return(CV_ILL_INPUT); + } + + /* check that staggered corrector was selected */ + if (cv_mem->cv_ism != CV_STAGGERED) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSetNonlinearSolverSensStg", + "Sensitivity solution method is not CV_STAGGERED"); + return(CV_ILL_INPUT); + } + + /* free any existing nonlinear solver */ + if ((cv_mem->NLSstg != NULL) && (cv_mem->ownNLSstg)) + retval = SUNNonlinSolFree(cv_mem->NLSstg); + + /* set SUNNonlinearSolver pointer */ + cv_mem->NLSstg = NLS; + + /* Set NLS ownership flag. If this function was called to attach the default + NLS, CVODE will set the flag to SUNTRUE after this function returns. */ + cv_mem->ownNLSstg = SUNFALSE; + + /* set the nonlinear system function */ + if (SUNNonlinSolGetType(NLS) == SUNNONLINEARSOLVER_ROOTFIND) { + retval = SUNNonlinSolSetSysFn(cv_mem->NLSstg, cvNlsResidualSensStg); + } else if (SUNNonlinSolGetType(NLS) == SUNNONLINEARSOLVER_FIXEDPOINT) { + retval = SUNNonlinSolSetSysFn(cv_mem->NLSstg, cvNlsFPFunctionSensStg); + } else { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSetNonlinearSolverSensStg", + "Invalid nonlinear solver type"); + return(CV_ILL_INPUT); + } + + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSetNonlinearSolverSensStg", + "Setting nonlinear system function failed"); + return(CV_ILL_INPUT); + } + + /* set convergence test function */ + retval = SUNNonlinSolSetConvTestFn(cv_mem->NLSstg, cvNlsConvTestSensStg); + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSetNonlinearSolverSensStg", + "Setting convergence test function failed"); + return(CV_ILL_INPUT); + } + + /* set max allowed nonlinear iterations */ + retval = SUNNonlinSolSetMaxIters(cv_mem->NLSstg, NLS_MAXCOR); + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSetNonlinearSolverSensStg", + "Setting maximum number of nonlinear iterations failed"); + return(CV_ILL_INPUT); + } + + /* 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) { + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", + "CVodeSetNonlinearSolverSensStg", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + cv_mem->ycorStg = N_VNewEmpty_SensWrapper(cv_mem->cv_Ns); + if (cv_mem->ycorStg == NULL) { + N_VDestroy(cv_mem->ycor0Stg); + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", + "CVodeSetNonlinearSolverSensStg", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + cv_mem->ewtStg = N_VNewEmpty_SensWrapper(cv_mem->cv_Ns); + if (cv_mem->ewtStg == NULL) { + N_VDestroy(cv_mem->ycor0Stg); + N_VDestroy(cv_mem->ycorStg); + cvProcessError(cv_mem, CV_MEM_FAIL, "CVODES", + "CVodeSetNonlinearSolverSensStg", MSGCV_MEM_FAIL); + return(CV_MEM_FAIL); + } + + cv_mem->stgMallocDone = SUNTRUE; + } + + /* 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]; + } + + return(CV_SUCCESS); +} + + +/* ----------------------------------------------------------------------------- + * Private functions + * ---------------------------------------------------------------------------*/ + + +int cvNlsInitSensStg(CVodeMem cvode_mem) +{ + int retval; + + /* set the linear solver setup wrapper function */ + if (cvode_mem->cv_lsetup) + retval = SUNNonlinSolSetLSetupFn(cvode_mem->NLSstg, cvNlsLSetupSensStg); + else + retval = SUNNonlinSolSetLSetupFn(cvode_mem->NLSstg, NULL); + + if (retval != CV_SUCCESS) { + cvProcessError(cvode_mem, CV_ILL_INPUT, "CVODES", "cvNlsInitSensStg", + "Setting the linear solver setup function failed"); + return(CV_NLS_INIT_FAIL); + } + + /* set the linear solver solve wrapper function */ + if (cvode_mem->cv_lsolve) + retval = SUNNonlinSolSetLSolveFn(cvode_mem->NLSstg, cvNlsLSolveSensStg); + else + retval = SUNNonlinSolSetLSolveFn(cvode_mem->NLSstg, NULL); + + if (retval != CV_SUCCESS) { + cvProcessError(cvode_mem, CV_ILL_INPUT, "CVODES", "cvNlsInitSensStg", + "Setting linear solver solve function failed"); + return(CV_NLS_INIT_FAIL); + } + + /* initialize nonlinear solver */ + retval = SUNNonlinSolInitialize(cvode_mem->NLSstg); + + if (retval != CV_SUCCESS) { + cvProcessError(cvode_mem, CV_ILL_INPUT, "CVODES", "cvNlsInitSensStg", + MSGCV_NLS_INIT_FAIL); + return(CV_NLS_INIT_FAIL); + } + + return(CV_SUCCESS); +} + + +static int cvNlsLSetupSensStg(N_Vector ycorStg, N_Vector resStg, + booleantype jbad, booleantype* jcur, + void* cvode_mem) +{ + CVodeMem cv_mem; + int retval; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "cvNlsLSetupSensStg", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* if the nonlinear solver marked the Jacobian as bad update convfail */ + if (jbad) + cv_mem->convfail = CV_FAIL_BAD_J; + + /* setup the linear solver */ + retval = cv_mem->cv_lsetup(cv_mem, cv_mem->convfail, cv_mem->cv_y, + cv_mem->cv_ftemp, &(cv_mem->cv_jcur), + cv_mem->cv_vtemp1, cv_mem->cv_vtemp2, + cv_mem->cv_vtemp3); + cv_mem->cv_nsetups++; + cv_mem->cv_nsetupsS++; + + /* update Jacobian status */ + *jcur = cv_mem->cv_jcur; + + cv_mem->cv_gamrat = ONE; + cv_mem->cv_gammap = cv_mem->cv_gamma; + cv_mem->cv_crate = ONE; + cv_mem->cv_crateS = ONE; + cv_mem->cv_nstlp = cv_mem->cv_nst; + + if (retval < 0) return(CV_LSETUP_FAIL); + if (retval > 0) return(SUN_NLS_CONV_RECVR); + + return(CV_SUCCESS); +} + + +static int cvNlsLSolveSensStg(N_Vector ycorStg, N_Vector deltaStg, void* cvode_mem) +{ + CVodeMem cv_mem; + int retval, is; + N_Vector *deltaS; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "cvNlsLSolveSensStg", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* extract sensitivity deltas from the vector wrapper */ + deltaS = NV_VECS_SW(deltaStg); + + /* solve the sensitivity linear systems */ + for (is=0; is<cv_mem->cv_Ns; is++) { + retval = cv_mem->cv_lsolve(cv_mem, deltaS[is], cv_mem->cv_ewtS[is], + cv_mem->cv_y, cv_mem->cv_ftemp); + + if (retval < 0) return(CV_LSOLVE_FAIL); + if (retval > 0) return(SUN_NLS_CONV_RECVR); + } + + return(CV_SUCCESS); +} + + +static int cvNlsConvTestSensStg(SUNNonlinearSolver NLS, + N_Vector ycorStg, N_Vector deltaStg, + realtype tol, N_Vector ewtStg, void* cvode_mem) +{ + CVodeMem cv_mem; + int m, retval; + realtype Del; + realtype dcon; + N_Vector *ycorS, *deltaS, *ewtS; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "cvNlsConvTestSensStg", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* extract the current sensitivity corrections */ + ycorS = NV_VECS_SW(ycorStg); + + /* extract the sensitivity deltas */ + deltaS = NV_VECS_SW(deltaStg); + + /* extract the sensitivity error weights */ + ewtS = NV_VECS_SW(ewtStg); + + /* compute the norm of the state and sensitivity corrections */ + Del = cvSensNorm(cv_mem, deltaS, ewtS); + + /* get the current nonlinear solver iteration count */ + retval = SUNNonlinSolGetCurIter(NLS, &m); + if (retval != CV_SUCCESS) return(CV_MEM_NULL); + + /* Test for convergence. If m > 0, an estimate of the convergence + rate constant is stored in crate, and used in the test. + + Recall that, even when errconS=SUNFALSE, all variables are used in the + convergence test. Hence, we use Del (and not del). However, acnrm is used + in the error test and thus it has different forms depending on errconS + (and this explains why we have to carry around del and delS). + */ + if (m > 0) { + cv_mem->cv_crateS = SUNMAX(CRDOWN * cv_mem->cv_crateS, Del/cv_mem->cv_delp); + } + dcon = Del * SUNMIN(ONE, cv_mem->cv_crateS) / tol; + + /* check if nonlinear system was solved successfully */ + if (dcon <= ONE) { + if (cv_mem->cv_errconS) + cv_mem->cv_acnrmS = (m==0) ? Del : cvSensNorm(cv_mem, ycorS, ewtS); + return(CV_SUCCESS); + } + + /* check if the iteration seems to be diverging */ + if ((m >= 1) && (Del > RDIV*cv_mem->cv_delp)) return(SUN_NLS_CONV_RECVR); + + /* Save norm of correction and loop again */ + cv_mem->cv_delp = Del; + + /* Not yet converged */ + return(SUN_NLS_CONTINUE); +} + + +static int cvNlsResidualSensStg(N_Vector ycorStg, N_Vector resStg, void* cvode_mem) +{ + CVodeMem cv_mem; + int retval; + N_Vector *ycorS, *resS; + realtype cvals[3]; + N_Vector* XXvecs[3]; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "cvNlsResidualSensStg", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* extract sensitivity and residual vectors from the vector wrapper */ + ycorS = NV_VECS_SW(ycorStg); + resS = NV_VECS_SW(resStg); + + /* update sensitivities based on the current correction */ + retval = N_VLinearSumVectorArray(cv_mem->cv_Ns, + ONE, cv_mem->cv_znS[0], + ONE, ycorS, cv_mem->cv_yS); + if (retval != CV_SUCCESS) return(CV_VECTOROP_ERR); + + /* evaluate the sensitivity rhs function */ + retval = cvSensRhsWrapper(cv_mem, cv_mem->cv_tn, + cv_mem->cv_y, cv_mem->cv_ftemp, + cv_mem->cv_yS, cv_mem->cv_ftempS, + cv_mem->cv_vtemp1, cv_mem->cv_vtemp2); + + if (retval < 0) return(CV_SRHSFUNC_FAIL); + if (retval > 0) return(SRHSFUNC_RECVR); + + /* compute the sensitivity resiudal */ + cvals[0] = cv_mem->cv_rl1; XXvecs[0] = cv_mem->cv_znS[1]; + cvals[1] = ONE; XXvecs[1] = ycorS; + cvals[2] = -cv_mem->cv_gamma; XXvecs[2] = cv_mem->cv_ftempS; + + retval = N_VLinearCombinationVectorArray(cv_mem->cv_Ns, + 3, cvals, XXvecs, resS); + if (retval != CV_SUCCESS) return(CV_VECTOROP_ERR); + + return(CV_SUCCESS); +} + + +static int cvNlsFPFunctionSensStg(N_Vector ycorStg, N_Vector resStg, void* cvode_mem) +{ + CVodeMem cv_mem; + int retval, is; + N_Vector *ycorS, *resS; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "cvNlsFPFunctionSensStg", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* extract sensitivity and residual vectors from the vector wrapper */ + ycorS = NV_VECS_SW(ycorStg); + resS = NV_VECS_SW(resStg); + + /* update the sensitivities based on the current correction */ + retval = N_VLinearSumVectorArray(cv_mem->cv_Ns, + ONE, cv_mem->cv_znS[0], + ONE, ycorS, cv_mem->cv_yS); + if (retval != CV_SUCCESS) return(CV_VECTOROP_ERR); + + /* evaluate the sensitivity rhs function */ + retval = cvSensRhsWrapper(cv_mem, cv_mem->cv_tn, + cv_mem->cv_y, cv_mem->cv_ftemp, + cv_mem->cv_yS, resS, + cv_mem->cv_vtemp1, cv_mem->cv_vtemp2); + + if (retval < 0) return(CV_SRHSFUNC_FAIL); + if (retval > 0) return(SRHSFUNC_RECVR); + + /* evaluate sensitivity fixed point function */ + for (is=0; is<cv_mem->cv_Ns; is++) { + N_VLinearSum(cv_mem->cv_h, resS[is], -ONE, cv_mem->cv_znS[1][is], resS[is]); + N_VScale(cv_mem->cv_rl1, resS[is], resS[is]); + } + + return(CV_SUCCESS); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_nls_stg1.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_nls_stg1.c new file mode 100644 index 0000000..aeed096 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_nls_stg1.c @@ -0,0 +1,372 @@ +/* ----------------------------------------------------------------------------- + * 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 the implementation file for the CVODES nonlinear solver interface. + * ---------------------------------------------------------------------------*/ + +#include "cvodes_impl.h" +#include "sundials/sundials_math.h" + +/* constant macros */ +#define ONE RCONST(1.0) + +/* private functions */ +static int cvNlsResidualSensStg1(N_Vector ycor, N_Vector res, + void* cvode_mem); +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, + void* cvode_mem); +static int cvNlsConvTestSensStg1(SUNNonlinearSolver NLS, + N_Vector ycor, N_Vector del, + realtype tol, N_Vector ewt, void* cvode_mem); + +/* ----------------------------------------------------------------------------- + * Exported functions + * ---------------------------------------------------------------------------*/ + +int CVodeSetNonlinearSolverSensStg1(void *cvode_mem, SUNNonlinearSolver NLS) +{ + CVodeMem cv_mem; + int retval; + + /* Return immediately if CVode memory is NULL */ + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "CVodeSetNonlinearSolverSensStg1", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* Return immediately if NLS memory is NULL */ + if (NLS == NULL) { + cvProcessError(NULL, CV_ILL_INPUT, "CVODES", + "CVodeSetNonlinearSolverSensStg1", + "NLS must be non-NULL"); + return (CV_ILL_INPUT); + } + + /* 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", + "NLS does not support required operations"); + return(CV_ILL_INPUT); + } + + /* check that sensitivities were initialized */ + if (!(cv_mem->cv_sensi)) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSetNonlinearSolverSensStg1", + MSGCV_NO_SENSI); + return(CV_ILL_INPUT); + } + + /* check that staggered corrector was selected */ + if (cv_mem->cv_ism != CV_STAGGERED1) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSetNonlinearSolverSensStg1", + "Sensitivity solution method is not CV_STAGGERED1"); + return(CV_ILL_INPUT); + } + + /* free any existing nonlinear solver */ + if ((cv_mem->NLSstg1 != NULL) && (cv_mem->ownNLSstg1)) + retval = SUNNonlinSolFree(cv_mem->NLSstg1); + + /* set SUNNonlinearSolver pointer */ + cv_mem->NLSstg1 = NLS; + + /* Set NLS ownership flag. If this function was called to attach the default + NLS, CVODE will set the flag to SUNTRUE after this function returns. */ + cv_mem->ownNLSstg1 = SUNFALSE; + + /* set the nonlinear system function */ + if (SUNNonlinSolGetType(NLS) == SUNNONLINEARSOLVER_ROOTFIND) { + retval = SUNNonlinSolSetSysFn(cv_mem->NLSstg1, cvNlsResidualSensStg1); + } else if (SUNNonlinSolGetType(NLS) == SUNNONLINEARSOLVER_FIXEDPOINT) { + retval = SUNNonlinSolSetSysFn(cv_mem->NLSstg1, cvNlsFPFunctionSensStg1); + } else { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSetNonlinearSolverSensStg1", + "Invalid nonlinear solver type"); + return(CV_ILL_INPUT); + } + + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSetNonlinearSolverSensStg1", + "Setting nonlinear system function failed"); + return(CV_ILL_INPUT); + } + + /* set convergence test function */ + retval = SUNNonlinSolSetConvTestFn(cv_mem->NLSstg1, cvNlsConvTestSensStg1); + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSetNonlinearSolverSensStg1", + "Setting convergence test function failed"); + return(CV_ILL_INPUT); + } + + /* set max allowed nonlinear iterations */ + retval = SUNNonlinSolSetMaxIters(cv_mem->NLSstg1, NLS_MAXCOR); + if (retval != CV_SUCCESS) { + cvProcessError(cv_mem, CV_ILL_INPUT, "CVODES", + "CVodeSetNonlinearSolverSensStg1", + "Setting maximum number of nonlinear iterations failed"); + return(CV_ILL_INPUT); + } + + return(CV_SUCCESS); +} + + +/* ----------------------------------------------------------------------------- + * Private functions + * ---------------------------------------------------------------------------*/ + + +int cvNlsInitSensStg1(CVodeMem cvode_mem) +{ + int retval; + + /* set the linear solver setup wrapper function */ + if (cvode_mem->cv_lsetup) + retval = SUNNonlinSolSetLSetupFn(cvode_mem->NLSstg1, cvNlsLSetupSensStg1); + else + retval = SUNNonlinSolSetLSetupFn(cvode_mem->NLSstg1, NULL); + + if (retval != CV_SUCCESS) { + cvProcessError(cvode_mem, CV_ILL_INPUT, "CVODES", "cvNlsInitSensStg1", + "Setting the linear solver setup function failed"); + return(CV_NLS_INIT_FAIL); + } + + /* set the linear solver solve wrapper function */ + if (cvode_mem->cv_lsolve) + retval = SUNNonlinSolSetLSolveFn(cvode_mem->NLSstg1, cvNlsLSolveSensStg1); + else + retval = SUNNonlinSolSetLSolveFn(cvode_mem->NLSstg1, NULL); + + if (retval != CV_SUCCESS) { + cvProcessError(cvode_mem, CV_ILL_INPUT, "CVODES", "cvNlsInitSensStg1", + "Setting linear solver solve function failed"); + return(CV_NLS_INIT_FAIL); + } + + /* initialize nonlinear solver */ + retval = SUNNonlinSolInitialize(cvode_mem->NLSstg1); + + if (retval != CV_SUCCESS) { + cvProcessError(cvode_mem, CV_ILL_INPUT, "CVODES", "cvNlsInitSensStg1", + MSGCV_NLS_INIT_FAIL); + return(CV_NLS_INIT_FAIL); + } + + /* reset previous iteration count for updating nniS1 */ + cvode_mem->nnip = 0; + + return(CV_SUCCESS); +} + + +static int cvNlsLSetupSensStg1(N_Vector ycor, N_Vector res, + booleantype jbad, booleantype* jcur, + void* cvode_mem) +{ + CVodeMem cv_mem; + int retval; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "cvNlsLSetupSensStg1", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* if the nonlinear solver marked the Jacobian as bad update convfail */ + if (jbad) + cv_mem->convfail = CV_FAIL_BAD_J; + + /* setup the linear solver */ + retval = cv_mem->cv_lsetup(cv_mem, cv_mem->convfail, cv_mem->cv_y, + cv_mem->cv_ftemp, &(cv_mem->cv_jcur), + cv_mem->cv_vtemp1, cv_mem->cv_vtemp2, + cv_mem->cv_vtemp3); + cv_mem->cv_nsetups++; + cv_mem->cv_nsetupsS++; + + /* update Jacobian status */ + *jcur = cv_mem->cv_jcur; + + cv_mem->cv_gamrat = ONE; + cv_mem->cv_gammap = cv_mem->cv_gamma; + cv_mem->cv_crate = ONE; + cv_mem->cv_crateS = ONE; + cv_mem->cv_nstlp = cv_mem->cv_nst; + + if (retval < 0) return(CV_LSETUP_FAIL); + if (retval > 0) return(SUN_NLS_CONV_RECVR); + + return(CV_SUCCESS); +} + + +static int cvNlsLSolveSensStg1(N_Vector ycor, N_Vector delta, void* cvode_mem) +{ + CVodeMem cv_mem; + int retval, is; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "cvNlsLSolveSensStg1", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* get index of current sensitivity solve */ + is = cv_mem->sens_solve_idx; + + /* solve the sensitivity linear systems */ + retval = cv_mem->cv_lsolve(cv_mem, delta, cv_mem->cv_ewtS[is], + cv_mem->cv_y, cv_mem->cv_ftemp); + + if (retval < 0) return(CV_LSOLVE_FAIL); + if (retval > 0) return(SUN_NLS_CONV_RECVR); + + return(CV_SUCCESS); +} + + +static int cvNlsConvTestSensStg1(SUNNonlinearSolver NLS, + N_Vector ycor, N_Vector delta, + realtype tol, N_Vector ewt, void* cvode_mem) +{ + CVodeMem cv_mem; + int m, retval; + realtype del; + realtype dcon; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "cvNlsConvTestSensStg1", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* compute the norm of the state and sensitivity corrections */ + del = N_VWrmsNorm(delta, ewt); + + /* get the current nonlinear solver iteration count */ + retval = SUNNonlinSolGetCurIter(NLS, &m); + if (retval != CV_SUCCESS) return(CV_MEM_NULL); + + /* Test for convergence. If m > 0, an estimate of the convergence + rate constant is stored in crate, and used in the test. + */ + if (m > 0) { + cv_mem->cv_crateS = SUNMAX(CRDOWN * cv_mem->cv_crateS, del/cv_mem->cv_delp); + } + dcon = del * SUNMIN(ONE, cv_mem->cv_crateS) / tol; + + /* check if nonlinear system was solved successfully */ + if (dcon <= ONE) return(CV_SUCCESS); + + /* check if the iteration seems to be diverging */ + if ((m >= 1) && (del > RDIV*cv_mem->cv_delp)) return(SUN_NLS_CONV_RECVR); + + /* Save norm of correction and loop again */ + cv_mem->cv_delp = del; + + /* Not yet converged */ + return(SUN_NLS_CONTINUE); +} + + +static int cvNlsResidualSensStg1(N_Vector ycor, N_Vector res, void* cvode_mem) +{ + CVodeMem cv_mem; + int retval, is; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "cvNlsResidualSensStg1", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* get index of current sensitivity solve */ + is = cv_mem->sens_solve_idx; + + /* update sensitivity based on the current correction */ + N_VLinearSum(ONE, cv_mem->cv_znS[0][is], ONE, ycor, cv_mem->cv_yS[is]); + + /* evaluate the sensitivity rhs function */ + retval = cvSensRhs1Wrapper(cv_mem, cv_mem->cv_tn, + cv_mem->cv_y, cv_mem->cv_ftemp, + is, cv_mem->cv_yS[is], cv_mem->cv_ftempS[is], + cv_mem->cv_vtemp1, cv_mem->cv_vtemp2); + + if (retval < 0) return(CV_SRHSFUNC_FAIL); + if (retval > 0) return(SRHSFUNC_RECVR); + + /* compute the sensitivity resiudal */ + N_VLinearSum(cv_mem->cv_rl1, cv_mem->cv_znS[1][is], ONE, ycor, res); + N_VLinearSum(-cv_mem->cv_gamma, cv_mem->cv_ftempS[is], ONE, res, res); + + return(CV_SUCCESS); +} + + +static int cvNlsFPFunctionSensStg1(N_Vector ycor, N_Vector res, void* cvode_mem) +{ + CVodeMem cv_mem; + int retval, is; + + if (cvode_mem == NULL) { + cvProcessError(NULL, CV_MEM_NULL, "CVODES", + "cvNlsFPFunctionSensStg1", MSGCV_NO_MEM); + return(CV_MEM_NULL); + } + cv_mem = (CVodeMem) cvode_mem; + + /* get index of current sensitivity solve */ + is = cv_mem->sens_solve_idx; + + /* update the sensitivities based on the current correction */ + N_VLinearSum(ONE, cv_mem->cv_znS[0][is], ONE, ycor, cv_mem->cv_yS[is]); + + /* evaluate the sensitivity rhs function */ + retval = cvSensRhs1Wrapper(cv_mem, cv_mem->cv_tn, + cv_mem->cv_y, cv_mem->cv_ftemp, + is, cv_mem->cv_yS[is], res, + cv_mem->cv_vtemp1, cv_mem->cv_vtemp2); + + if (retval < 0) return(CV_SRHSFUNC_FAIL); + if (retval > 0) return(SRHSFUNC_RECVR); + + /* evaluate sensitivity fixed point function */ + N_VLinearSum(cv_mem->cv_h, res, -ONE, cv_mem->cv_znS[1][is], res); + N_VScale(cv_mem->cv_rl1, res, res); + + return(CV_SUCCESS); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_spils.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_spils.c new file mode 100644 index 0000000..0ce3a9a --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/cvodes/cvodes_spils.c @@ -0,0 +1,107 @@ +/*----------------------------------------------------------------- + * Programmer(s): 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 + * ----------------------------------------------------------------- + * Header file for the deprecated Scaled, Preconditioned Iterative + * Linear Solver interface in CVODES; these routines now just wrap + * the updated CVODES generic linear solver interface in cvodes_ls.h. + * -----------------------------------------------------------------*/ + +#include <cvodes/cvodes_ls.h> +#include <cvodes/cvodes_spils.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*================================================================= + CVSSPILS Exported functions (wrappers for equivalent routines in + cvodes_ls.h) + =================================================================*/ + +int CVSpilsSetLinearSolver(void *cvode_mem, SUNLinearSolver LS) +{ return(CVodeSetLinearSolver(cvode_mem, LS, NULL)); } + +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)); } + +int CVSpilsSetLinearSolverB(void *cvode_mem, int which, + SUNLinearSolver LS) +{ return(CVodeSetLinearSolverB(cvode_mem, which, LS, NULL)); } + +int CVSpilsSetEpsLinB(void *cvode_mem, int which, realtype eplifacB) +{ return(CVodeSetEpsLinB(cvode_mem, which, eplifacB)); } + +int CVSpilsSetPreconditionerB(void *cvode_mem, int which, + CVSpilsPrecSetupFnB psetB, + CVSpilsPrecSolveFnB psolveB) +{ return(CVodeSetPreconditionerB(cvode_mem, which, psetB, psolveB)); } + +int CVSpilsSetPreconditionerBS(void *cvode_mem, int which, + CVSpilsPrecSetupFnBS psetBS, + CVSpilsPrecSolveFnBS psolveBS) +{ return(CVodeSetPreconditionerBS(cvode_mem, which, psetBS, psolveBS)); } + +int CVSpilsSetJacTimesB(void *cvode_mem, int which, + CVSpilsJacTimesSetupFnB jtsetupB, + CVSpilsJacTimesVecFnB jtimesB) +{ return(CVodeSetJacTimesB(cvode_mem, which, jtsetupB, jtimesB)); } + +int CVSpilsSetJacTimesBS(void *cvode_mem, int which, + CVSpilsJacTimesSetupFnBS jtsetupBS, + CVSpilsJacTimesVecFnBS jtimesBS) +{ return(CVodeSetJacTimesBS(cvode_mem, which, jtsetupBS, jtimesBS)); } + + +#ifdef __cplusplus +} +#endif + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fida.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fida.c new file mode 100644 index 0000000..0bdec85 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fida.c @@ -0,0 +1,617 @@ +/*----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * Aaron Collier 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 Fortran interface to + * the IDA package. See fida.h for usage. + * NOTE: Some routines are necessarily stored elsewhere to avoid + * linking problems. + *-----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "fida.h" /* function names, prototypes, global variables */ +#include "ida_impl.h" /* definition of IDAMem type */ +#include <ida/ida_ls.h> /* prototypes for IDALS interface routines */ + +/*************************************************/ + +/* Definitions for global variables shared amongst various routines */ + +N_Vector F2C_IDA_ypvec, F2C_IDA_ewtvec; + +void *IDA_idamem; +long int *IDA_iout; +realtype *IDA_rout; +int IDA_nrtfn; + +/*************************************************/ + +/* private constant(s) */ +#define ZERO RCONST(0.0) + +/*************************************************/ + +/* Prototype of user-supplied Fortran routine (IDAResFn) */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FIDA_RESFUN(realtype*, /* T */ + realtype*, /* Y */ + realtype*, /* YP */ + realtype*, /* R */ + long int*, /* IPAR */ + realtype*, /* RPAR */ + int*); /* IER */ + +#ifdef __cplusplus +} +#endif + +/*************************************************/ + +void FIDA_MALLOC(realtype *t0, realtype *yy0, realtype *yp0, + int *iatol, realtype *rtol, realtype *atol, + long int *iout, realtype *rout, + long int *ipar, realtype *rpar, int *ier) +{ + N_Vector Vatol; + FIDAUserData IDA_userdata; + + *ier = 0; + + /* Check for required vector operations */ + if ((F2C_IDA_vec->ops->nvgetarraypointer == NULL) || + (F2C_IDA_vec->ops->nvsetarraypointer == NULL)) { + *ier = -1; + fprintf(stderr, "A required vector operation is not implemented.\n\n"); + return; + } + + /* Initialize all pointers to NULL */ + IDA_idamem = NULL; + Vatol = NULL; + F2C_IDA_ypvec = F2C_IDA_ewtvec = NULL; + FIDANullNonlinSol(); + + /* Create IDA object */ + IDA_idamem = IDACreate(); + if (IDA_idamem == NULL) { + *ier = -1; + return; + } + + /* Set and attach user data */ + IDA_userdata = NULL; + IDA_userdata = (FIDAUserData) malloc(sizeof *IDA_userdata); + if (IDA_userdata == NULL) { + *ier = -1; + return; + } + IDA_userdata->rpar = rpar; + IDA_userdata->ipar = ipar; + + *ier = IDASetUserData(IDA_idamem, IDA_userdata); + if(*ier != IDA_SUCCESS) { + free(IDA_userdata); IDA_userdata = NULL; + *ier = -1; + return; + } + + /* Attach user's yy0 to F2C_IDA_vec */ + N_VSetArrayPointer(yy0, F2C_IDA_vec); + + /* Create F2C_IDA_ypvec and attach user's yp0 to it */ + F2C_IDA_ypvec = NULL; + F2C_IDA_ypvec = N_VCloneEmpty(F2C_IDA_vec); + if (F2C_IDA_ypvec == NULL) { + free(IDA_userdata); IDA_userdata = NULL; + *ier = -1; + } + N_VSetArrayPointer(yp0, F2C_IDA_ypvec); + + /* Call IDAInit */ + *ier = IDAInit(IDA_idamem, FIDAresfn, *t0, F2C_IDA_vec, F2C_IDA_ypvec); + + /* Reset data pointers */ + N_VSetArrayPointer(NULL, F2C_IDA_vec); + N_VSetArrayPointer(NULL, F2C_IDA_ypvec); + + /* On failure, clean-up and exit */ + if (*ier != IDA_SUCCESS) { + N_VDestroy(F2C_IDA_ypvec); + free(IDA_userdata); IDA_userdata = NULL; + *ier = -1; + return; + } + + /* Set tolerances */ + switch (*iatol) { + case 1: + *ier = IDASStolerances(IDA_idamem, *rtol, *atol); + break; + case 2: + Vatol = NULL; + Vatol= N_VCloneEmpty(F2C_IDA_vec); + if (Vatol == NULL) { + free(IDA_userdata); IDA_userdata = NULL; + *ier = -1; + return; + } + N_VSetArrayPointer(atol, Vatol); + *ier = IDASVtolerances(IDA_idamem, *rtol, Vatol); + N_VDestroy(Vatol); + break; + } + + /* On failure, clean-up and exit */ + if (*ier != IDA_SUCCESS) { + free(IDA_userdata); IDA_userdata = NULL; + *ier = -1; + return; + } + + /* Grab optional output arrays and store them in global variables */ + IDA_iout = iout; + IDA_rout = rout; + + /* Store the unit roundoff in rout for user access */ + IDA_rout[5] = UNIT_ROUNDOFF; + + /* Set F2C_IDA_ewtvec on NULL */ + F2C_IDA_ewtvec = NULL; + + return; +} + +/*************************************************/ + +void FIDA_REINIT(realtype *t0, realtype *yy0, realtype *yp0, + int *iatol, realtype *rtol, realtype *atol, + int *ier) +{ + N_Vector Vatol; + + *ier = 0; + + /* Initialize all pointers to NULL */ + Vatol = NULL; + + /* Attach user's yy0 to F2C_IDA_vec */ + N_VSetArrayPointer(yy0, F2C_IDA_vec); + + /* Attach user's yp0 to F2C_IDA_ypvec */ + N_VSetArrayPointer(yp0, F2C_IDA_ypvec); + + /* Call IDAReInit */ + *ier = IDAReInit(IDA_idamem, *t0, F2C_IDA_vec, F2C_IDA_ypvec); + + /* Reset data pointers */ + N_VSetArrayPointer(NULL, F2C_IDA_vec); + N_VSetArrayPointer(NULL, F2C_IDA_ypvec); + + /* On failure, exit */ + if (*ier != IDA_SUCCESS) { + *ier = -1; + return; + } + + /* Set tolerances */ + switch (*iatol) { + case 1: + *ier = IDASStolerances(IDA_idamem, *rtol, *atol); + break; + case 2: + Vatol = NULL; + Vatol= N_VCloneEmpty(F2C_IDA_vec); + if (Vatol == NULL) { + *ier = -1; + return; + } + N_VSetArrayPointer(atol, Vatol); + *ier = IDASVtolerances(IDA_idamem, *rtol, Vatol); + N_VDestroy(Vatol); + break; + } + + /* On failure, exit */ + if (*ier != IDA_SUCCESS) { + *ier = -1; + return; + } + + return; +} + +/*************************************************/ + +void FIDA_SETIIN(char key_name[], long int *ival, int *ier) +{ + if (!strncmp(key_name,"MAX_ORD",7)) + *ier = IDASetMaxOrd(IDA_idamem, (int) *ival); + else if (!strncmp(key_name,"MAX_NSTEPS",10)) + *ier = IDASetMaxNumSteps(IDA_idamem, (long int) *ival); + else if (!strncmp(key_name,"MAX_ERRFAIL",11)) + *ier = IDASetMaxErrTestFails(IDA_idamem, (int) *ival); + else if (!strncmp(key_name,"MAX_NITERS",10)) + *ier = IDASetMaxNonlinIters(IDA_idamem, (int) *ival); + else if (!strncmp(key_name,"MAX_CONVFAIL",12)) + *ier = IDASetMaxConvFails(IDA_idamem, (int) *ival); + else if (!strncmp(key_name,"SUPPRESS_ALG",12)) + *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)) + *ier = IDASetMaxNumItersIC(IDA_idamem, (int) *ival); + else if (!strncmp(key_name,"MAX_NJE_IC",10)) + *ier = IDASetMaxNumJacsIC(IDA_idamem, (int) *ival); + else if (!strncmp(key_name,"LS_OFF_IC",9)) + *ier = IDASetLineSearchOffIC(IDA_idamem, (booleantype) *ival); + else { + *ier = -99; + fprintf(stderr, "FIDASETIIN: Unrecognized key.\n\n"); + } + +} + +/***************************************************************************/ + +void FIDA_SETRIN(char key_name[], realtype *rval, int *ier) +{ + + if (!strncmp(key_name,"INIT_STEP",9)) + *ier = IDASetInitStep(IDA_idamem, *rval); + else if (!strncmp(key_name,"MAX_STEP",8)) + *ier = IDASetMaxStep(IDA_idamem, *rval); + else if (!strncmp(key_name,"STOP_TIME",9)) + *ier = IDASetStopTime(IDA_idamem, *rval); + else if (!strncmp(key_name,"NLCONV_COEF_IC",14)) + *ier = IDASetNonlinConvCoefIC(IDA_idamem, *rval); + else if (!strncmp(key_name,"NLCONV_COEF",11)) + *ier = IDASetNonlinConvCoef(IDA_idamem, *rval); + else if (!strncmp(key_name,"STEP_TOL_IC",11)) + *ier = IDASetStepToleranceIC(IDA_idamem, *rval); + else { + *ier = -99; + fprintf(stderr, "FIDASETRIN: Unrecognized key.\n\n"); + } + +} + +/*************************************************/ + +void FIDA_SETVIN(char key_name[], realtype *vval, int *ier) +{ + N_Vector Vec; + + *ier = 0; + + if (!strncmp(key_name,"ID_VEC",6)) { + Vec = NULL; + Vec = N_VCloneEmpty(F2C_IDA_vec); + if (Vec == NULL) { + *ier = -1; + return; + } + N_VSetArrayPointer(vval, Vec); + IDASetId(IDA_idamem, Vec); + N_VDestroy(Vec); + } else if (!strncmp(key_name,"CONSTR_VEC",10)) { + Vec = NULL; + Vec = N_VCloneEmpty(F2C_IDA_vec); + if (Vec == NULL) { + *ier = -1; + return; + } + N_VSetArrayPointer(vval, Vec); + IDASetConstraints(IDA_idamem, Vec); + N_VDestroy(Vec); + } else { + *ier = -99; + fprintf(stderr, "FIDASETVIN: Unrecognized key.\n\n"); + } + +} + +/*************************************************/ + +void FIDA_TOLREINIT(int *iatol, realtype *rtol, realtype *atol, int *ier) +{ + N_Vector Vatol=NULL; + + *ier = 0; + + if (*iatol == 1) { + *ier = IDASStolerances(IDA_idamem, *rtol, *atol); + } else { + Vatol = NULL; + Vatol = N_VCloneEmpty(F2C_IDA_vec); + if (Vatol == NULL) { + *ier = -1; + return; + } + N_VSetArrayPointer(atol, Vatol); + *ier = IDASVtolerances(IDA_idamem, *rtol, Vatol); + N_VDestroy(Vatol); + } + + return; +} + +/*************************************************/ + +void FIDA_CALCIC(int *icopt, realtype *tout1, int *ier) +{ + *ier = 0; + *ier = IDACalcIC(IDA_idamem, *icopt, *tout1); + return; +} + +/*************************************************/ + +/* 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, + F2C_IDA_matrix); + return; +} + + +/*************************************************/ + +/*** DEPRECATED ***/ +void FIDA_DLSINIT(int *ier) +{ FIDA_LSINIT(ier); } + +/*************************************************/ + +/*** DEPRECATED ***/ +void FIDA_SPILSINIT(int *ier) { + FIDANullMatrix(); + FIDA_LSINIT(ier); +} + +/*************************************************/ + +/* 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); + return; +} + +void FIDA_LSSETINCREMENTFACTOR(realtype *dqincfac, int *ier) { + *ier = IDASetIncrementFactor(IDA_idamem, *dqincfac); + return; +} + +/*** DEPRECATED ***/ +void FIDA_SPILSSETEPSLIN(realtype *eplifac, int *ier) +{ FIDA_LSSETEPSLIN(eplifac, ier); } + +/*** DEPRECATED ***/ +void FIDA_SPILSSETINCREMENTFACTOR(realtype *dqincfac, int *ier) +{ FIDA_LSSETINCREMENTFACTOR(dqincfac, ier); } + + +/*************************************************/ + +void FIDA_SOLVE(realtype *tout, realtype *tret, realtype *yret, + realtype *ypret, int *itask, int *ier) +{ + int klast, kcur; + + *ier = 0; + + /* Attach user data to vectors */ + N_VSetArrayPointer(yret, F2C_IDA_vec); + N_VSetArrayPointer(ypret, F2C_IDA_ypvec); + + *ier = IDASolve(IDA_idamem, *tout, tret, F2C_IDA_vec, F2C_IDA_ypvec, *itask); + + /* Reset data pointers */ + N_VSetArrayPointer(NULL, F2C_IDA_vec); + N_VSetArrayPointer(NULL, F2C_IDA_ypvec); + + /* Set optional outputs */ + + IDAGetWorkSpace(IDA_idamem, + &IDA_iout[0], /* LENRW */ + &IDA_iout[1]); /* LENIW */ + + IDAGetIntegratorStats(IDA_idamem, + &IDA_iout[2], /* NST */ + &IDA_iout[3], /* NRE */ + &IDA_iout[7], /* NSETUPS */ + &IDA_iout[4], /* NETF */ + &klast, /* KLAST */ + &kcur, /* KCUR */ + &IDA_rout[0], /* HINUSED */ + &IDA_rout[1], /* HLAST */ + &IDA_rout[2], /* HCUR */ + &IDA_rout[3]); /* TCUR */ + IDA_iout[8] = (long int) klast; + IDA_iout[9] = (long int) kcur; + IDAGetNonlinSolvStats(IDA_idamem, + &IDA_iout[6], /* NNI */ + &IDA_iout[5]); /* NCFN */ + IDAGetNumBacktrackOps(IDA_idamem, + &IDA_iout[10]); /* NBCKTRK */ + IDAGetTolScaleFactor(IDA_idamem, + &IDA_rout[4]); /* TOLSFAC */ + + /* Root finding is on */ + if (IDA_nrtfn != 0) + IDAGetNumGEvals(IDA_idamem, &IDA_iout[11]); /* NGE */ + + /* Linear solver optional outputs */ + IDAGetLinWorkSpace(IDA_idamem, &IDA_iout[12], &IDA_iout[13]); /* LENRWLS, LENIWLS */ + IDAGetLastLinFlag(IDA_idamem, &IDA_iout[14]); /* LSTF */ + IDAGetNumLinResEvals(IDA_idamem, &IDA_iout[15]); /* NRE */ + IDAGetNumJacEvals(IDA_idamem, &IDA_iout[16]); /* NJE */ + IDAGetNumJTSetupEvals(IDA_idamem, &IDA_iout[17]); /* NJTS */ + IDAGetNumJtimesEvals(IDA_idamem, &IDA_iout[18]); /* NJT */ + IDAGetNumPrecEvals(IDA_idamem, &IDA_iout[19]); /* NPE */ + IDAGetNumPrecSolves(IDA_idamem, &IDA_iout[20]); /* NPS */ + IDAGetNumLinIters(IDA_idamem, &IDA_iout[21]); /* NLI */ + IDAGetNumLinConvFails(IDA_idamem, &IDA_iout[22]); /* NCFL */ + + return; +} + +/*************************************************/ + +void FIDA_GETDKY(realtype *t, int *k, realtype *dky, int *ier) +{ + /* Store existing F2C_IDA_vec data pointer */ + realtype *f2c_data = N_VGetArrayPointer(F2C_IDA_vec); + + /* Attach user data to vectors */ + N_VSetArrayPointer(dky, F2C_IDA_vec); + + *ier = 0; + *ier = IDAGetDky(IDA_idamem, *t, *k, F2C_IDA_vec); + + /* Reset data pointers */ + N_VSetArrayPointer(f2c_data, F2C_IDA_vec); + + return; +} + +/*************************************************/ + +void FIDA_GETERRWEIGHTS(realtype *eweight, int *ier) +{ + /* Store existing F2C_IDA_vec data pointer */ + realtype *f2c_data = N_VGetArrayPointer(F2C_IDA_vec); + + /* Attach user data to vector */ + N_VSetArrayPointer(eweight, F2C_IDA_vec); + + *ier = 0; + *ier = IDAGetErrWeights(IDA_idamem, F2C_IDA_vec); + + /* Reset data pointer */ + N_VSetArrayPointer(f2c_data, F2C_IDA_vec); + + return; +} + +/*************************************************/ + +void FIDA_GETESTLOCALERR(realtype *ele, int *ier) +{ + /* Store existing F2C_IDA_vec data pointer */ + realtype *f2c_data = N_VGetArrayPointer(F2C_IDA_vec); + + /* Attach user data to vector */ + N_VSetArrayPointer(ele, F2C_IDA_vec); + + *ier = 0; + *ier = IDAGetEstLocalErrors(IDA_idamem, F2C_IDA_vec); + + /* Reset data pointers */ + N_VSetArrayPointer(f2c_data, F2C_IDA_vec); + + return; +} + +/*************************************************/ + +void FIDA_FREE(void) +{ + IDAMem ida_mem; + + ida_mem = (IDAMem) IDA_idamem; + + /* free IDALS interface */ + if (ida_mem->ida_lfree) + ida_mem->ida_lfree(ida_mem); + ida_mem->ida_lmem = NULL; + + /* free user_data structure */ + if (ida_mem->ida_user_data) + free(ida_mem->ida_user_data); + ida_mem->ida_user_data = NULL; + + /* free main integrator memory structure */ + IDAFree(&IDA_idamem); + + /* free interface vectors / matrices / linear solvers / nonlinear solver */ + N_VSetArrayPointer(NULL, F2C_IDA_vec); + N_VDestroy(F2C_IDA_vec); + 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; + return; +} + +/*************************************************/ + +int FIDAresfn(realtype t, N_Vector yy, N_Vector yp, + N_Vector rr, void *user_data) +{ + int ier; + realtype *yy_data, *yp_data, *rr_data; + FIDAUserData IDA_userdata; + + /* NOTE: The user-supplied routine should set ier to an + appropriate value, but we preset the value to zero + (meaning SUCCESS) so the user need only reset the + value if an error occurred */ + ier = 0; + + /* Get pointers to vector data */ + yy_data = N_VGetArrayPointer(yy); + yp_data = N_VGetArrayPointer(yp); + rr_data = N_VGetArrayPointer(rr); + + IDA_userdata = (FIDAUserData) user_data; + + /* Call user-supplied routine */ + FIDA_RESFUN(&t, yy_data, yp_data, rr_data, + IDA_userdata->ipar, IDA_userdata->rpar, &ier); + + return(ier); +} + +/*************************************************/ + +/* 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) ) { + *ier = -1; + return; + } + *ier = IDASetNonlinearSolver(IDA_idamem, F2C_IDA_nonlinsol); + return; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fida.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fida.h new file mode 100644 index 0000000..b545c10 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fida.h @@ -0,0 +1,1107 @@ +/*--------------------------------------------------------------- + * Programmer(s): Aaron Collier and Radu Serban @ 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 header file for FIDA, the Fortran interface to + * the IDA package. + *--------------------------------------------------------------*/ + +/*============================================================================= + FIDA Interface Package + + The FIDA Interface Package is a package of C functions which support + the use of the IDA solver, for the solution of DAE systems, in a + mixed Fortran/C setting. While IDA 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 IDA for any acceptable NVECTOR implementation. + + A summary of the user-callable functions, with the corresponding + IDA functions, are as follows: + + Fortran IDA + --------------------- -------------------------------- + FNVINITS N_VNew_Serial + FNVINITP N_VNew_Parallel + FNVINITOMP N_VNew_OpenMP + FNVINITPTS N_VNew_Pthreads + + FSUNBANDMATINIT SUNBandMatrix + FSUNDENSEMATINIT SUNDenseMatrix + FSUNSPARSEMATINIT SUNSparseMatrix + + FSUNBANDLINSOLINIT SUNBandLinearSolver + FSUNDENSELINSOLINIT SUNDenseLinearSolver + FSUNKLUINIT SUNKLU + FSUNKLUREINIT SUNKLUReinit + FSUNLAPACKBANDINIT SUNLapackBand + FSUNLAPACKDENSEINIT SUNLapackDense + FSUNPCGINIT SUNPCG + FSUNSPBCGSINIT SUNSPBCGS + FSUNSPFGMRINIT SUNSPFGMR + FSUNSPGMRINIT SUNSPGMR + FSUNSPTFQMRINIT SUNSPTFQMR + FSUNSUPERLUMTINIT SUNSuperLUMT + + FIDAMALLOC IDACreate, IDASetUserData and IDAInit + FIDAREINIT IDAReInit + + FIDASETIIN IDASet* (integer arguments) + FIDASETRIN IDASet* (real arguments) + FIDASETVIN IDASet* (vector arguments) + + FIDATOLREINIT IDASetTolerances + + FIDACALCIC IDACalcIC + + FIDAEWTSET IDAWFtolerances + + FIDALSINIT IDASetLinearSolver + FIDALSSETEPSLIN IDASetEpsLin + FIDALSSETINCREMENTFACTOR IDASetIncrementFactor + FIDALSSETJAC IDASetJacTimes + FIDALSSETPREC IDASetPreconditioner + FIDADENSESETJAC IDASetJacFn + FIDABANDSETJAC IDASetJacFn + FIDASPARSESETJAC IDASetJacFn + + FIDANLSINIT IDASetNonlinearSolver + + FIDASOLVE IDASolve, IDAGet*, and IDA*Get* + + FIDAGETDKY IDAGetDky + + FIDAGETERRWEIGHTS IDAGetErrWeights + + FIDAGETESTLOCALERR IDAGetEstLocalErrors + + FIDAFREE IDAFree + --------------------- -------------------------------- + + The user-supplied functions, each listed with the corresponding interface + function which calls it (and its type within IDA), are as follows: + + Fortran: Interface Fcn: IDA Type: + ------------- ------------------ ----------------------- + FIDARESFUN FIDAresfn IDAResFn + FIDADJAC FIDADenseJac IDALsJacFn + FIDABJAC FIDABandJac IDALsJacFn + FIDASPJAC FIDASparseJac IDALsJacFn + FIDAPSET FIDAPSet IDALsPrecSetupFn + FIDAPSOL FIDAPSol IDALsPrecSolveFn + FIDAJTSETUP FIDAJTSetup IDALsJacTimesSetupFn + FIDAJTIMES FIDAJtimes IDALsJacTimesVecFn + FIDAEWT FIDAEwtSet IDAEwtFn + ------------- ------------------ ----------------------- + + In contrast to the case of direct use of IDA, the names of all user-supplied + routines here are fixed, in order to maximize portability for the resulting + mixed-language program. + + Important note on portability: + In this package, the names of the interface functions, and the names of + the Fortran user routines called by them, appear as dummy names + which are mapped to actual values by a series of definitions, in this + and other header files. + + ============================================================================= + + Usage of the FIDA Interface Package + + The usage of FIDA requires calls to a few different interface + functions, depending on the method options selected, and one or more + user-supplied routines which define the problem to be solved. These + function calls and user routines are summarized separately below. + + Some details are omitted, and the user is referred to the user documents + on IDA for more complete documentation. Information on the + arguments of any given user-callable interface routine, or of a given + user-supplied function called by an interface function, can be found in + the documentation on the corresponding function in the IDA package. + + The number labels on the instructions below end with s for instructions + that are specific to use with the serial/OpenMP/PThreads NVector package, + and end with p are specific to use with the N_VParallel package. + + ----------------------------------------------------------------------------- + + Data Types + + Throughout this documentation, we will refer to data types according to + their usage in SUNDIALS. The equivalent types to these may vary, + depending on your computer architecture and on how SUNDIALS was compiled. + A Fortran user should take care that all arguments passed through this + Fortran/C interface are declared of the appropriate type. + + Integers: SUNDIALS uses 'int', 'long int' and 'sunindextype' types. At + compilation, SUNDIALS allows the configuration of the 'index' type, that + accepts values of 32-bit signed and 64-bit signed. This choice dictates + the size of a SUNDIALS 'sunindextype' variable. + int -- equivalent to an INTEGER or INTEGER*4 in Fortran + long int -- equivalent to an INTEGER*8 in Fortran (Linux/UNIX/OSX), or + equivalent to an INTEGER in Windows + sunindextype -- this will depend on the SUNDIALS configuration: + 32-bit -- equivalent to an INTEGER or INTEGER*4 in Fortran + 64-bit -- equivalent to an INTEGER*8 in Fortran + + Real numbers: At compilation, SUNDIALS allows the configuration option + '--with-precision', that accepts values of 'single', 'double' or + 'extended' (the default is 'double'). This choice dictates the size of a + SUNDIALS 'realtype' variable. The corresponding Fortran types for these + 'realtype' sizes are: + single -- equivalent to a REAL or REAL*4 in Fortran + double -- equivalent to a DOUBLE PRECISION or REAL*8 in Fortran + extended -- equivalent to a REAL*16 in Fortran + + ----------------------------------------------------------------------------- + + (1) User-supplied residual routine: FIDARESFUN + + The user must in all cases supply the following Fortran routine + + SUBROUTINE FIDARESFUN(T, Y, YP, R, IPAR, RPAR, IER) + + It must set the R array to F(t,y,y'), the residual of the DAE system. + + The arguments are: + T -- current time [realtype, input] + Y -- array containing state variables [realtype, input] + YP -- array containing state variable derivatives [realtype, input] + R -- array containing DAE residuals [realtype, output] + IPAR -- array containing integer user data that was passed to + FIDAMALLOC [long int, input] + RPAR -- array containing real user data that was passed to + FIDAMALLOC [realtype, input] + IER -- return flag [int, output]: + 0 if successful, + >0 if a recoverable error occurred, + <0 if an unrecoverable error ocurred. + + (2s) Optional user-supplied dense Jacobian approximation routine: FIDADJAC + + As an option when using the Dense or LapackDense linear solvers, the + user may supply a routine that computes a dense approximation of the + system Jacobian J = dF/dy' + c_j*dF/dy. If supplied, it must have the + following form: + + SUBROUTINE FIDADJAC(NEQ, T, Y, YP, R, DJAC, CJ, EWT, H, + 1 IPAR, RPAR, WK1, WK2, WK3, IER) + + This routine must compute the Jacobian and store it columnwise in DJAC. + + The arguments are: + NEQ -- number of rows in the matrix [long int, input] + T -- current time [realtype, input] + Y -- array containing state variables [realtype, input] + YP -- array containing state variable derivatives [realtype, input] + R -- array containing DAE residuals [realtype, input] + DJAC -- 2D array containing the jacobian entries [realtype of size + (NEQ,NEQ), output] + CJ -- scalar in the system Jacobian proportional to inverse step + size [realtype, input] + EWT -- array containing error weight vector [realtype, input] + H -- current step size [realtype, input] + IPAR -- array containing integer user data that was passed to + FIDAMALLOC [long int, input] + RPAR -- array containing real user data that was passed to + FIDAMALLOC [realtype, input] + WK* -- array containing temporary workspace of same size as Y + [realtype, input] + IER -- return flag [int, output]: + 0 if successful, + >0 if a recoverable error occurred, + <0 if an unrecoverable error ocurred. + + (2s) Optional user-supplied band Jacobian approximation routine: FIDABJAC + + As an option when using the Band or LapackBand linear solvers, the + user may supply a routine that computes a band approximation of the + system Jacobian J = dF/dy' + c_j*dF/dy. If supplied, it must have the + following form: + + SUBROUTINE FIDABJAC(NEQ, MU, ML, MDIM, T, Y, YP, R, CJ, BJAC, + 1 EWT, H, IPAR, RPAR, WK1, WK2, WK3, IER) + + This routine must load the MDIM by N array BJAC with the Jacobian + matrix at the current (t,y,y') in band form. Store in BJAC(k,j) + the Jacobian element J(i,j) with k = i - j + MU + 1 + (k = 1 ... ML+MU+1) and j = 1 ... N. + + The arguments are: + NEQ -- number of rows in the matrix [long int, input] + MU -- upper half-bandwidth of the matrix [long int, input] + ML -- lower half-bandwidth of the matrix [long int, input] + MDIM -- leading dimension of BJAC array [long int, input] + T -- current time [realtype, input] + Y -- array containing state variables [realtype, input] + YP -- array containing state variable derivatives [realtype, input] + R -- array containing DAE residuals [realtype, input] + DJAC -- 2D array containing the jacobian entries [realtype of size + (NEQ,NEQ), output] + CJ -- scalar in the system Jacobian proportional to inverse step + size [realtype, input] + EWT -- array containing error weight vector [realtype, input] + H -- current step size [realtype, input] + IPAR -- array containing integer user data that was passed to + FIDAMALLOC [long int, input] + RPAR -- array containing real user data that was passed to + FIDAMALLOC [realtype, input] + WK* -- array containing temporary workspace of same size as Y + [realtype, input] + IER -- return flag [int, output]: + 0 if successful, + >0 if a recoverable error occurred, + <0 if an unrecoverable error ocurred. + + (2s) User-supplied sparse Jacobian approximation routine: FIDASPJAC + + When using the KLU or SuperLUMT linear solvers, the user *must* supply + a routine that computes a compressed-sparse-column [or + compressed-sparse-row] approximation of the system Jacobian + J = dF/dy' + c_j*dF/dy. If supplied, it must have the following form: + + SUBROUTINE FIDASPJAC(T, CJ, Y, YP, R, N, NNZ, JDATA, JRVALS, + 1 JCPTRS, H, IPAR, RPAR, WK1, WK2, WK3, IER) + + It must load the N by N compressed sparse column [row] matrix with + storage for NNZ nonzeros, stored in the arrays JDATA (nonzero values), + JRVALS (row [column] indices for each nonzero), JCOLPTRS (indices for + start of each column [row]), with the Jacobian matrix in CSC [CSR] + form (see sunmatrix_sparse.h for more information). + + The arguments are: + T -- current time [realtype, input] + CJ -- scalar in the system Jacobian proportional + to inverse step size [realtype, input] + Y -- array containing state variables [realtype, input] + YP -- array containing state derivatives [realtype, input] + R -- array containing system residual F(T, Y, YP) [realtype, input] + N -- number of matrix rows/columns in Jacobian [int, input] + NNZ -- allocated length of nonzero storage [int, input] + JDATA -- nonzero values in Jacobian + [realtype of length NNZ, output] + JRVALS -- row [column] indices for each nonzero in Jacobian + [int of length NNZ, output] + JCPTRS -- pointers to each Jacobian column [row] in preceding arrays + [int of length N+1, output] + H -- current step size [realtype, input] + IPAR -- array containing integer user data that was passed to + FIDAMALLOC [long int, input] + RPAR -- array containing real user data that was passed to + FIDAMALLOC [realtype, input] + WK* -- array containing temporary workspace of same size as Y + [realtype, input] + IER -- return flag [int, output]: + 0 if successful, + >0 if a recoverable error occurred, + <0 if an unrecoverable error ocurred. + + NOTE: this may ONLY be used if SUNDIALS has been configured with + sunindextype set to 64-bit integers. + + (2) Optional user-supplied Jacobian-vector product setup routine: + FIDAJTSETUP + + As an option when using the IDALS linear solver interface with a + matrix-free linear solver module, the user may supply a routine that + computes the product of the system Jacobian J = dF/dy' + c_j*dF/dy + and a given vector v, as well as a routine to set up any user data + structures in preparation for the matrix-vector product. If a + 'setup' routine is supplied, it must have the following form: + + SUBROUTINE FIDAJTSETUP(T, Y, YP, R, CJ, EWT, H, IPAR, RPAR, IER) + + It must perform any relevant preparations for subsequent calls to the + user-provided FIDAJTIMES routine (see below). + + The arguments are: + T -- current time [realtype, input] + Y -- array containing state variables [realtype, input] + YP -- array containing state variable derivatives [realtype, input] + R -- array containing DAE residuals [realtype, input] + CJ -- scalar in the system Jacobian proportional to inverse step + size [realtype, input] + EWT -- array containing error weight vector [realtype, input] + H -- current step size [realtype, input] + IPAR -- array containing integer user data that was passed to + FIDAMALLOC [long int, input] + RPAR -- array containing real user data that was passed to + FIDAMALLOC [realtype, input] + IER -- return flag [int, output]: + 0 if successful, + nonzero if an error. + + (2) Optional user-supplied Jacobian-vector product routine: FIDAJTIMES + + As an option when using the IDALS linear solver interface with a + matrix-free linear solver module, the user may supply a routine + that computes the product of the system Jacobian + J = dF/dy' + c_j*dF/dy and a given vector v. If supplied, it must + have the following form: + + SUBROUTINE FIDAJTIMES(T, Y, YP, R, V, FJV, CJ, EWT, H, + 1 IPAR, RPAR, WK1, WK2, IER) + + This routine must compute the product vector Jv, where the vector v + is stored in V, and store the product in FJV. + + The arguments are: + T -- current time [realtype, input] + Y -- array containing state variables [realtype, input] + YP -- array containing state variable derivatives [realtype, input] + R -- array containing DAE residuals [realtype, input] + V -- array containing vector to multiply [realtype, input] + FJV -- array containing product vector [realtype, output] + CJ -- scalar in the system Jacobian proportional to inverse step + size [realtype, input] + EWT -- array containing error weight vector [realtype, input] + H -- current step size [realtype, input] + IPAR -- array containing integer user data that was passed to + FIDAMALLOC [long int, input] + RPAR -- array containing real user data that was passed to + FIDAMALLOC [realtype, input] + IER -- return flag [int, output]: + 0 if successful, + nonzero if an error. + + (3) Optional user-supplied preconditioner setup/solve routines: FIDAPSET + and FIDAPSOL + + As an option when using the IDALS linear solver interface and an + iterative linear solver module, the user may supply routines to + setup and apply the preconditioner. If supplied, these must have + the following form: + + SUBROUTINE FIDAPSET(T, Y, YP, R, CJ, EWT, H, IPAR, RPAR, IER) + + This routine must perform any evaluation of Jacobian-related data and + preprocessing needed for the solution of the preconditioner linear + systems by FIDAPSOL. + + The arguments are: + T -- current time [realtype, input] + Y -- array containing state variables [realtype, input] + YP -- array containing state variable derivatives [realtype, input] + R -- array containing DAE residuals [realtype, input] + CJ -- scalar in the system Jacobian proportional to inverse step + size [realtype, input] + EWT -- array containing error weight vector [realtype, input] + H -- current step size [realtype, input] + IPAR -- array containing integer user data that was passed to + FIDAMALLOC [long int, input] + RPAR -- array containing real user data that was passed to + FIDAMALLOC [realtype, input] + IER -- return flag [int, output]: + 0 if successful, + nonzero if an error. + + The user-supplied routine FIDAPSOL must have the form: + + SUBROUTINE FIDAPSOL(T, Y, YP, R, RV, ZV, CJ, DELTA, EWT, + 1 IPAR, RPAR, IER) + + This routine must solve the preconditioner linear system Pz = r, + where r = RV is input, and store the solution z in ZV. + + The arguments are: + T -- current time [realtype, input] + Y -- array containing state variables [realtype, input] + YP -- array containing state variable derivatives [realtype, input] + R -- array containing DAE residuals [realtype, input] + RV -- right-hand side array [realtype, input] + ZV -- solution array [realtype, output] + CJ -- scalar in the system Jacobian proportional to inverse step + size [realtype, input] + DELTA -- desired residual tolerance [realtype, input] + EWT -- array containing error weight vector [realtype, input] + IPAR -- array containing integer user data that was passed to + FIDAMALLOC [long int, input] + RPAR -- array containing real user data that was passed to + FIDAMALLOC [realtype, input] + IER -- return flag [int, output]: + 0 if successful, + nonzero if an error. + + (4) Optional user-supplied error weight vector routine: FIDAEWT + + As an option to providing the relative and absolute tolerances, the + user may supply a routine that computes the weights used in the WRMS + norms. If supplied, it must have the following form: + + SUBROUTINE FIDAEWT(Y, EWT, IPAR, RPAR, IER) + + It must store the error weights in EWT, given the current solution + vector Y. + + The arguments are: + Y -- array containing state variables [realtype, input] + EWT -- array containing the error weight vector [realtype, output] + IPAR -- array containing integer user data that was passed to + FIDAMALLOC [long int, input] + RPAR -- array containing real user data that was passed to + FIDAMALLOC [realtype, input] + IER -- return flag [int, output]: + 0 if successful, + nonzero if an error. + + ----------------------------------------------------------------------------- + + (5) Initialization: FNVINITS / FNVINITP / FNVINITOMP / FNVINITPTS, + FSUNBANDMATINIT / FSUNDENSEMATINIT / + FSUNSPARSEMATINIT, + FSUNBANDLINSOLINIT / FSUNDENSELINSOLINIT / + FSUNKLUINIT / FSUNKLUREINIT / FSUNKLUSETORDERING / + FSUNLAPACKBANDINIT / FSUNLAPACKDENSEINIT / + FSUNPCGINIT / FSUNSPBCGSINIT / FSUNSPFGMRINIT / + FSUNSPGMRINIT / FSUNSPTFQMRINIT / FSUNSUPERLUMTINIT / + FSUNSUPERLUMTSETORDERING, + FIDAMALLOC, + FIDALSINIT + FIDAREINIT, + FIDATOLREINIT, + FIDACALCIC, + + NOTE: the initialization order is important! It *must* proceed as + shown: vector, matrix (if used), linear solver (if used), IDA, + IDALS, reinit. + + (5.1) To initialize the a vector specification for storing the solution + data, the user must make one of the following calls: + + (serial) + CALL FNVINITS(2, NEQ, IER) + (MPI parallel) + CALL FNVINITP(COMM, 2, NLOCAL, NGLOBAL, IER) + (OpenMP threaded) + CALL FNVINITOMP(2, NEQ, NUM_THREADS, IER) + (PThreads threaded) + CALL FNVINITPTS(2, NEQ, NUM_THREADS, IER) + + In each of these, one argument is an int containing the IDA solver + ID (2). + + The other arguments are: + NEQ = size of vectors [long int, input] + COMM = the MPI communicator [int, input] + NLOCAL = local size of vectors on this processor + [long int, input] + NGLOBAL = the system size, and the global size of vectors (the sum + of all values of NLOCAL) [long int, input] + NUM_THREADS = number of threads + IER = return completion flag [int, output]: + 0 = success, + -1 = failure. + + (5.2) To initialize a band/dense/sparse matrix structure for + storing the system Jacobian and for use within a direct linear solver, + the user must make one of the following calls: + + CALL FSUNBANDMATINIT(2, N, MU, ML, SMU, IER) + CALL FSUNDENSEMATINIT(2, M, N, IER) + CALL FSUNSPARSEMATINIT(2, M, N, NNZ, SPARSETYPE, IER) + + In each of these, one argument is an int containing the IDA solver + ID (2). + + The other arguments are: + + M = the number of rows of the matrix [long int, input] + N = the number of columns of the matrix [long int, input] + MU = the number of upper bands (diagonal not included) in a banded + matrix [long int, input] + ML = the number of lower bands (diagonal not included) in a banded + matrix [long int, input] + SMU = the number of upper bands to store (diagonal not included) + for factorization of a banded matrix [long int, input] + NNZ = the storage size (upper bound on the number of nonzeros) for + a sparse matrix [long int, input] + SPARSETYPE = integer denoting use of CSC (0) vs CSR (1) storage + for a sparse matrix [int, input] + IER = return completion flag [int, output]: + 0 = success, + -1 = failure. + + (5.3) To initialize a linear solver structure for solving linear systems + arising from solution to the DAE, the user must make one of the + following calls: + + CALL FSUNBANDLINSOLINIT(2, IER) + CALL FSUNDENSELINSOLINIT(2, IER) + CALL FSUNKLUINIT(2, IER) + CALL FSUNLAPACKBANDINIT(2, IER) + CALL FSUNLAPACKDENSEINIT(2, IER) + CALL FSUNPCGINIT(2, PRETYPE, MAXL, IER) + CALL FSUNSPBCGSINIT(2, PRETYPE, MAXL, IER) + CALL FSUNSPFGMRINIT(2, PRETYPE, MAXL, IER) + CALL FSUNSPGMRINIT(2, PRETYPE, MAXL, IER) + CALL FSUNSPTFQMRINIT(2, PRETYPE, MAXL, IER) + CALL FSUNSUPERLUMTINIT(2, NUM_THREADS, IER) + + Or once these have been initialized, their solver parameters may be + modified via calls to the functions + + CALL FSUNKLUSETORDERING(2, ORD_CHOICE, IER) + CALL FSUNSUPERLUMTSETORDERING(2, ORD_CHOICE, IER) + + CALL FSUNPCGSETPRECTYPE(2, PRETYPE, IER) + CALL FSUNPCGSETMAXL(2, MAXL, IER) + CALL FSUNSPBCGSSETPRECTYPE(2, PRETYPE, IER) + CALL FSUNSPBCGSSETMAXL(2, MAXL, IER) + CALL FSUNSPFGMRSETGSTYPE(2, GSTYPE, IER) + CALL FSUNSPFGMRSETPRECTYPE(2, PRETYPE, IER) + CALL FSUNSPGMRSETGSTYPE(2, GSTYPE, IER) + CALL FSUNSPGMRSETPRECTYPE(2, PRETYPE, IER) + CALL FSUNSPTFQMRSETPRECTYPE(2, PRETYPE, IER) + CALL FSUNSPTFQMRSETMAXL(2, MAXL, IER) + + In all of the above, one argument is an int containing the IDA solver + ID (2). + + The other arguments are: + + NNZ = the storage size (upper bound on the number of nonzeros) for + a sparse matrix [long int, input] + ORD_CHOICE = integer denoting ordering choice (see + SUNKLUSetOrdering and SUNSuperLUMTSetOrdering documentation + for details) [int, input] + PRETYPE = type of preconditioning to perform (0=none, 1=left, + 2=right, 3=both) [int, input] + MAXL = maximum Krylov subspace dimension [int, input] + GSTYPE = choice of Gram-Schmidt orthogonalization algorithm + (0=modified, 1=classical) [int, input] + IER = return completion flag [int, output]: + 0 = success, + -1 = failure. + + (5.4) To set various problem and solution parameters and allocate + internal memory, make the following call: + + CALL FIDAMALLOC(T0, Y0, YP0, IATOL, RTOL, ATOL, + 1 IOUT, ROUT, IPAR, RPAR, IER) + + The arguments are: + T0 = initial value of t [realtype, input] + Y0 = array of initial conditions for y(t0) [realtype, input] + YP0 = array of initial conditions for y'(t0) [realtype, input] + IATOL = type for absolute tolerance ATOL [int, input]: + 1 = scalar, + 2 = array, + 3 = user-supplied function; the user must supply a routine + FIDAEWT to compute the error weight vector. + RTOL = scalar relative tolerance [realtype, input] + ATOL = scalar or array absolute tolerance [realtype, input] + IOUT = array of length at least 21 for integer optional outputs + [long int, output] + ROUT = array of length at least 6 for real optional outputs + [realtype, output] + IPAR = array of user integer data [long int, input/output] + RPAR = array with user real data [realtype, input/output] + IER = return completion flag [int, output]: + 0 = SUCCESS, + -1 = failure (see printed message for failure details). + + The user data arrays IPAR and RPAR are passed unmodified to all + subsequent calls to user-provided routines. Modifications to either + array inside a user-provided routine will be propagated. Using these + two arrays, the user can dispense with Common blocks to pass data + betwen user-provided routines. + + The optional outputs are: + LENRW = IOUT( 1) -> IDAGetWorkSpace + LENIW = IOUT( 2) -> IDAGetWorkSpace + NST = IOUT( 3) -> IDAGetNumSteps + NRE = IOUT( 4) -> IDAGetNumResEvals + NETF = IOUT( 5) -> IDAGetNumErrTestFails + NCFN = IOUT( 6) -> IDAGetNumNonlinSolvConvFails + NNI = IOUT( 7) -> IDAGetNumNonlinSolvIters + NSETUPS = IOUT( 8) -> IDAGetNumLinSolvSetups + KLAST = IOUT( 9) -> IDAGetLastOrder + KCUR = IOUT(10) -> IDAGetCurrentOrder + NBCKTRK = IOUT(11) -> IDAGetNumBacktrackOps + NGE = IOUT(12) -> IDAGetNumGEvals + + HINUSED = ROUT( 1) -> IDAGetActualInitStep + HLAST = ROUT( 2) -> IDAGetLastStep + HCUR = ROUT( 3) -> IDAGetCurrentStep + TCUR = ROUT( 4) -> IDAGetCurrentTime + TOLSFAC = ROUT( 5) -> IDAGetTolScaleFactor + UNITRND = ROUT( 6) -> UNIT_ROUNDOFF + See the IDA manual for details. + + (5.5) To attach the linear solver created in step (5.3) to the + IDALS interface, using the command: + + CALL FIDALSINIT(IER) + + The arguments are: + IER = return completion flag [int, output]: + 0 = SUCCESS, + -1 = failure (see printed message for failure details). + + (5.6) If the user program includes the FIDAEWT routine for the evaluation + of the error weights, the following call must be made + + CALL FIDAEWTSET(FLAG, IER) + + with FLAG = 1 to specify that FIDAEWT is provided and should be used; + FLAG = 0 resets to the default EWT formulation. + The return flag IER is 0 if successful, and nonzero otherwise. + + (5.7) If the user program includes the FIDABJAC routine for the + evaluation of the band approximation to the Jacobian, then following + the call to FIDALSINIT, the following call must be made + + CALL FIDABANDSETJAC(FLAG, IER) + + with the int FLAG=1 to specify that FIDABJAC is provided and should be + used; FLAG=0 specifies a reset to the internal finite difference + Jacobian approximation. The int return flag IER=0 if successful, + nonzero otherwise. + + If the user program includes the FIDADJAC routine for the evaluation + of the dense approximation to the Jacobian, then after the call to + FIDALSINIT, the following call must be made + + CALL FIDADENSESETJAC(FLAG, IER) + + with the int FLAG=1 to specify that FIDADJAC is provided and should be + used; FLAG=0 specifies a reset to the internal finite difference + Jacobian approximation. The int return flag IER=0 if successful, and + nonzero otherwise. + + When using a sparse matrix and linear solver the user must provide the + FIDASPJAC routine for the evaluation of the sparse approximation to + the Jacobian. To indicate that this routine has been provided, after + the call to FIDALSINIT, the following call must be made + + CALL FIDASPARSESETJAC(IER) + + The int return flag IER=0 if successful, and nonzero otherwise. + + (5.8) If the user program includes the FIDAJTSETUP and FIDAJTIMES + routines for setup of a Jacobian-times-vector product, then after + creating the IDALS interface, the following call must be made: + + CALL FIDALSSETJAC(FLAG, IER) + + with the int FLAG=1 to specify that FIDAJTSETUP and FIDAJTIMES are + provided and should be used; FLAG=0 specifies a reset to the internal + finite difference approximation to this product). The int return + flag IER=0 if successful, and nonzero otherwise. + + (5.9) If the user program includes the FIDAPSET and FIDAPSOL routines + for supplying a preconditioner to an iterative linear solver, then + after creating the IDALS interface, the following call must be made + + CALL FIDALSSETPREC(FLAG, IER) + + with the int FLAG=1. If FLAG=0 then preconditioning with these + routines will be disabled. The return flag IER=0 if successful, + nonzero otherwise. + + (5.10) If the user wishes to use one of IDA's built-in preconditioning + module, FIDABBD, then that should be initialized after creating the + IDALS interface using the call + + CALL FIDABBDINIT(NLOCAL, MUDQ, MLDQ, MU, ML, DQRELY, IER) + + Detailed explanation of the inputs to these functions, as well as any + requirements of user-supplied functions on which these preconditioning + modules rely, may be found in the header file fidabbd.h. + + (5.11) To set various integer optional inputs, make the folowing call: + + CALL FIDASETIIN(KEY, VALUE, IER) + + to set the integer input VALUE to the optional input specified by the + quoted character string KEY. VALUE must be a Fortran integer of size + commensurate with a C "long int". KEY must be one of the following: + MAX_ORD, MAX_NSTEPS, MAX_ERRFAIL, MAX_NITERS, MAX_CONVFAIL, + SUPPRESS_ALG, MAX_NSTEPS_IC, MAX_NITERS_IC, MAX_NJE_IC, LS_OFF_IC. + The int return flag IER is 0 if successful, and nonzero otherwise. + + (5.12) To set various real optional inputs, make the folowing call: + + CALL FIDASETRIN(KEY, VALUE, IER) + + to set the realtype value VALUE to the optional input specified by the + quoted character string KEY. VALUE must be a Fortran real-valued + number of size commensurate with the SUNDIALS "realtype". KEY must + one of the following: INIT_STEP, MAX_STEP, MIIN_STEP, STOP_TIME, + NLCONV_COEF. The int return flag IER is 0 if successful, and nonzero + otherwise. + + (5.13) To set the vector of variable IDs or the vector of constraints, + make the following call: + + CALL FIDASETVIN(KEY, ARRAY, IER) + + where ARRAY is an array of realtype and the quoted character string + KEY is one of: ID_VEC or CONSTR_VEC. The int return flag IER is 0 + if successful, and nonzero otherwise. + + (5.14) To re-initialize the FIDA solver for the solution of a new problem + of the same size as one already solved, make the following call: + + CALL FIDAREINIT(T0, Y0, YP0, IATOL, RTOL, ATOL, ID, CONSTR, IER) + + The arguments have the same names and meanings as those of FIDAMALLOC. + FIDAREINIT performs the same initializations as FIDAMALLOC, but does + no memory allocation for IDA data structures, using instead the + existing internal memory created by the previous FIDAMALLOC call. + The subsequent calls to attach the linear system solver is only needed + if the matrix or linear solver objects have been re-created. + + (5.15) To modify the tolerance parameters, make the following call: + + CALL FIDATOLREINIT(IATOL, RTOL, ATOL, IER) + + The arguments have the same names and meanings as those of FIDAMALLOC. + FIDATOLREINIT simply calls IDASetTolerances with the given arguments. + + (5.16) To compute consistent initial conditions for an index-one DAE system, + make the following call: + + CALL FIDACALCIC(ICOPT, TOUT, IER) + + The arguments are: + ICOPT = specifies the option [int, input]: + 1 = IDA_YP_YDP_INIT + 2 = IDA_Y_INIT + (See user guide for additional details) + TOUT = the first value of t at which a solution will + be requested from FIDASOLVE [realtype, input]. + IER = return completion flag [int, output]. + + (5.17) The FSUNKLU solver will reuse much of the factorization information + from one solve to the next. If at any time the user wants to force a + full refactorization or if the number of nonzeros in the Jacobian + matrix changes, the user should make the call + + CALL FSUNKLUREINIT(2, NNZ, REINIT_TYPE, IER) + + The arguments are: + NNZ = the maximum number of nonzeros [int; input] + REINIT_TYPE = 1 or 2. For a value of 1, the matrix will be + destroyed and a new one will be allocated with NNZ nonzeros. + For a value of 2, only symbolic and numeric factorizations will + be completed. + + ----------------------------------------------------------------------------- + + (6) Optional outputs from the IDALS linear solver interface (stored in the + IOUT array that was passed to FIDAMALLOC) + + LENRWLS = IOUT(13) -> IDAGetLinWorkSpace + LENIWLS = IOUT(14) -> IDAGetLinWorkSpace + LSTF = IOUT(15) -> IDAGetLastLinFlag + NRELS = IOUT(16) -> IDAGetNumLinResEvals + NJE = IOUT(17) -> IDAGetNumJacEvals + NJTS = IOUT(18) -> IDAGetJTSetupEvals + NJT = IOUT(19) -> IDAGetJtimesEvals + NPE = IOUT(20) -> IDAGetPrecEvals + NPS = IOUT(21) -> IDAGetPrecSolves + NLI = IOUT(22) -> IDAGetLinIters + NLCF = IOUT(23) -> IDAGetLinConvFails + + See the IDA manual for more detailed descriptions of any of the + above. + + ----------------------------------------------------------------------------- + + (7) The solver: FIDASOLVE + + To solve the DAE system, make the following call: + + CALL FIDASOLVE(TOUT, TRET, Y, YP, ITASK, IER) + + The arguments are: + TOUT = next value of t at which a solution is desired [realtype, input] + TRET = value of t reached by the solver [realtype, output] + Y = array containing state variables on output [realtype, output] + YP = array containing state derivatives on output [realtype, output] + ITASK = task indicator [int, input]: + 1 = normal mode (overshoot TOUT and interpolate) + 2 = one-step mode (return after each internal step taken) + 3 = normal tstop mode (like 1, but integration never + proceeds past TSTOP, which must be specified through a + call to FIDASETRIN using the key 'STOP_TIME') + 4 = one step tstop (like 2, but integration never goes + past TSTOP) + IER = completion flag [int, output]: + 0 = success, + 1 = tstop return, + 2 = root return, + negative values are failure modes (see IDA manual). + The current values of the optional outputs are immediately available in + the IOUT and ROUT arrays. + + ----------------------------------------------------------------------------- + + (8) Getting current solution derivative: FIDAGETDKY + + To obtain interpolated values of y and y' for any value of t in the + last internal step taken by IDA, make the following call: + + CALL FIDAGETDKY(T, K, DKY, IER) + + The arguments are: + T = time at which solution derivative is desired, within the interval + [TCUR-HU,TCUR], [realtype, input]. + K = derivative order (0 .le. K .le. QU) [int, input] + DKY = array containing computed K-th derivative of y [realtype, output] + IER = return flag [int, output]: 0=success, <0 = illegal argument. + + ----------------------------------------------------------------------------- + + (9) Get the current error weight vector: FIDAGETERRWEIGHTS + + To obtain the current error weight vector, make the following call: + + CALL FIDAGETERRWEIGHTS(EWT, IER) + + The arguments are: + EWT = array containing the error weight vector [realtype, output] + IER = return flag [int, output]: 0=success, nonzero if an error. + + ----------------------------------------------------------------------------- + + (10) Get an estimate of the local error: FIDAGETESTLOCALERR + + To obtain the current error estimate vector, make the following call: + + CALL FIDAGETESTLOCALERR(ELE, IER) + + The arguments are: + ELE = array with the estimated local error vector [realtype, output] + IER = return flag [int, output]: 0=success, nonzero if an error. + + ----------------------------------------------------------------------------- + + (11) Memory freeing: FIDAFREE + + To the free the internal memory created by the calls to FIDAMALLOC, + FIDALSINIT, the generic linear solver and matrix modules, + and FNVINIT*, make the following call: + + CALL FIDAFREE + + =============================================================================*/ + +#ifndef _FIDA_H +#define _FIDA_H + +#include <ida/ida.h> /* definition of type IDAResFn */ +#include <sundials/sundials_linearsolver.h> /* definition of type SUNLinearSolver */ +#include <sundials/sundials_matrix.h> /* definition of type SUNMatrix */ +#include <sundials/sundials_nvector.h> /* definition of type N_Vector */ +#include <sundials/sundials_types.h> /* definition of type realtype */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +#if defined(SUNDIALS_F77_FUNC) + +#define FIDA_MALLOC SUNDIALS_F77_FUNC(fidamalloc, FIDAMALLOC) +#define FIDA_REINIT SUNDIALS_F77_FUNC(fidareinit, FIDAREINIT) +#define FIDA_SETIIN SUNDIALS_F77_FUNC(fidasetiin, FIDASETIIN) +#define FIDA_SETRIN SUNDIALS_F77_FUNC(fidasetrin, FIDASETRIN) +#define FIDA_SETVIN SUNDIALS_F77_FUNC(fidasetvin, FIDASETVIN) +#define FIDA_TOLREINIT SUNDIALS_F77_FUNC(fidatolreinit, FIDATOLREINIT) +#define FIDA_SOLVE SUNDIALS_F77_FUNC(fidasolve, FIDASOLVE) +#define FIDA_FREE SUNDIALS_F77_FUNC(fidafree, FIDAFREE) +#define FIDA_CALCIC SUNDIALS_F77_FUNC(fidacalcic, FIDACALCIC) +#define FIDA_LSINIT SUNDIALS_F77_FUNC(fidalsinit, FIDALSINIT) +#define FIDA_LSSETEPSLIN SUNDIALS_F77_FUNC(fidalssetepslin, FIDALSSETEPSLIN) +#define FIDA_LSSETINCREMENTFACTOR SUNDIALS_F77_FUNC(fidalssetincrementfactor, FIDALSSETINCREMENTFACTOR) +#define FIDA_BANDSETJAC SUNDIALS_F77_FUNC(fidabandsetjac, FIDABANDSETJAC) +#define FIDA_BJAC SUNDIALS_F77_FUNC(fidabjac, FIDABJAC) +#define FIDA_DENSESETJAC SUNDIALS_F77_FUNC(fidadensesetjac, FIDADENSESETJAC) +#define FIDA_DJAC SUNDIALS_F77_FUNC(fidadjac, FIDADJAC) +#define FIDA_SPARSESETJAC SUNDIALS_F77_FUNC(fidasparsesetjac, FIDASPARSESETJAC) +#define FIDA_SPJAC SUNDIALS_F77_FUNC(fidaspjac, FIDASPJAC) +#define FIDA_LSSETJAC SUNDIALS_F77_FUNC(fidalssetjac, FIDALSSETJAC) +#define FIDA_JTSETUP SUNDIALS_F77_FUNC(fidajtsetup, FIDAJTSETUP) +#define FIDA_JTIMES SUNDIALS_F77_FUNC(fidajtimes, FIDAJTIMES) +#define FIDA_LSSETPREC SUNDIALS_F77_FUNC(fidalssetprec, FIDALSSETPREC) +#define FIDA_PSET SUNDIALS_F77_FUNC(fidapset, FIDAPSET) +#define FIDA_PSOL SUNDIALS_F77_FUNC(fidapsol, FIDAPSOL) +#define FIDA_RESFUN SUNDIALS_F77_FUNC(fidaresfun, FIDARESFUN) +#define FIDA_EWTSET SUNDIALS_F77_FUNC(fidaewtset, FIDAEWTSET) +#define FIDA_EWT SUNDIALS_F77_FUNC(fidaewt, FIDAEWT) +#define FIDA_GETDKY SUNDIALS_F77_FUNC(fidagetdky, FIDAGETDKY) +#define FIDA_GETERRWEIGHTS SUNDIALS_F77_FUNC(fidageterrweights, FIDAGETERRWEIGHTS) +#define FIDA_GETESTLOCALERR SUNDIALS_F77_FUNC(fidagetestlocalerr, FIDAGETESTLOCALERR) +#define FIDA_NLSINIT SUNDIALS_F77_FUNC(fidanlsinit, FIDANLSINIT) + +/*** DEPRECATED ***/ +#define FIDA_DLSINIT SUNDIALS_F77_FUNC(fidadlsinit, FIDADLSINIT) +#define FIDA_SPILSINIT SUNDIALS_F77_FUNC(fidaspilsinit,FIDASPILSINIT) +#define FIDA_SPILSSETEPSLIN SUNDIALS_F77_FUNC(fidaspilssetepslin, FIDASPILSSETEPSLIN) +#define FIDA_SPILSSETINCREMENTFACTOR SUNDIALS_F77_FUNC(fidaspilssetincrementfactor, FIDASPILSSETINCREMENTFACTOR) +#define FIDA_SPILSSETJAC SUNDIALS_F77_FUNC(fidaspilssetjac, FIDASPILSSETJAC) +#define FIDA_SPILSSETPREC SUNDIALS_F77_FUNC(fidaspilssetprec, FIDASPILSSETPREC) +/******************/ + +#else + +#define FIDA_MALLOC fidamalloc_ +#define FIDA_REINIT fidareinit_ +#define FIDA_SETIIN fidasetiin_ +#define FIDA_SETRIN fidasetrin_ +#define FIDA_SETVIN fidasetvin_ +#define FIDA_TOLREINIT fidatolreinit_ +#define FIDA_SOLVE fidasolve_ +#define FIDA_FREE fidafree_ +#define FIDA_CALCIC fidacalcic_ +#define FIDA_LSINIT fidalsinit_ +#define FIDA_LSSETEPSLIN fidalssetepslin_ +#define FIDA_LSSETINCREMENTFACTOR fidalssetincrementfactor_ +#define FIDA_BANDSETJAC fidabandsetjac_ +#define FIDA_BJAC fidabjac_ +#define FIDA_DENSESETJAC fidadensesetjac_ +#define FIDA_DJAC fidadjac_ +#define FIDA_SPARSESETJAC fidasparsesetjac_ +#define FIDA_SPJAC fidaspjac_ +#define FIDA_LSSETJAC fidalssetjac_ +#define FIDA_JTSETUP fidajtsetup_ +#define FIDA_JTIMES fidajtimes_ +#define FIDA_LSSETPREC fidalssetprec_ +#define FIDA_PSET fidapset_ +#define FIDA_PSOL fidapsol_ +#define FIDA_RESFUN fidaresfun_ +#define FIDA_EWTSET fidaewtset_ +#define FIDA_EWT fidaewt_ +#define FIDA_GETDKY fidagetdky_ +#define FIDA_GETERRWEIGHTS fidageterrweights_ +#define FIDA_GETESTLOCALERR fidagetestlocalerr_ +#define FIDA_NLSINIT fidanlsinit_ + +/*** DEPRECATED ***/ +#define FIDA_DLSINIT fidadlsinit_ +#define FIDA_SPILSINIT fidaspilsinit_ +#define FIDA_SPILSSETEPSLIN fidaspilssetepslin_ +#define FIDA_SPILSSETINCREMENTFACTOR fidaspilssetincrementfactor_ +#define FIDA_SPILSSETJAC fidaspilssetjac_ +#define FIDA_SPILSSETPREC fidaspilssetprec_ +/******************/ + +#endif + +/* Type for user data */ + +typedef struct { + realtype *rpar; + long int *ipar; +} *FIDAUserData; + +/* Prototypes of exported functions */ + +void FIDA_MALLOC(realtype *t0, realtype *yy0, realtype *yp0, + int *iatol, realtype *rtol, realtype *atol, + long int *iout, realtype *rout, + long int *ipar, realtype *rpar, int *ier); +void FIDA_REINIT(realtype *t0, realtype *yy0, realtype *yp0, + int *iatol, realtype *rtol, realtype *atol, + int *ier); + +void FIDA_SETIIN(char key_name[], long int *ival, int *ier); +void FIDA_SETRIN(char key_name[], realtype *rval, int *ier); +void FIDA_SETVIN(char key_name[], realtype *vval, int *ier); + +void FIDA_TOLREINIT(int *iatol, realtype *rtol, realtype *atol, int *ier); +void FIDA_CALCIC(int *icopt, realtype *tout1, int *ier); + +void FIDA_LSINIT(int *ier); +void FIDA_LSSETEPSLIN(realtype *eplifac, int *ier); +void FIDA_LSSETINCREMENTFACTOR(realtype *dqincfac, int *ier); +void FIDA_LSSETJAC(int *flag, int *ier); +void FIDA_LSSETPREC(int *flag, int *ier); +void FIDA_DENSESETJAC(int *flag, int *ier); +void FIDA_BANDSETJAC(int *flag, int *ier); +void FIDA_SPARSESETJAC(int *ier); + +/*** DEPRECATED ***/ +void FIDA_DLSINIT(int *ier); +void FIDA_SPILSINIT(int *ier); +void FIDA_SPILSSETEPSLIN(realtype *eplifac, int *ier); +void FIDA_SPILSSETINCREMENTFACTOR(realtype *dqincfac, int *ier); +void FIDA_SPILSSETJAC(int *flag, int *ier); +void FIDA_SPILSSETPREC(int *flag, int *ier); +/******************/ + +void FIDA_NLSINIT(int *ier); + +void FIDA_SOLVE(realtype *tout, realtype *tret, realtype *yret, + realtype *ypret, int *itask, int *ier); + +void FIDA_FREE(void); +void FIDA_EWTSET(int *flag, int *ier); +void FIDA_GETDKY(realtype *t, int *k, realtype *dky, int *ier); +void FIDA_GETERRWEIGHTS(realtype *eweight, int *ier); +void FIDA_GETESTLOCALERR(realtype *ele, int *ier); + +/* Prototypes: Functions Called by the IDA Solver */ + +int FIDAresfn(realtype t, N_Vector yy, N_Vector yp, N_Vector rr, void *user_data); + +int FIDADenseJac(realtype t, realtype c_j, N_Vector yy, N_Vector yp, + N_Vector rr, SUNMatrix Jac, void *user_data, + N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3); + +int FIDABandJac(realtype t, realtype c_j, N_Vector yy, N_Vector yp, + N_Vector rr, SUNMatrix Jac, void *user_data, + N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3); + +int FIDASparseJac(realtype t, realtype c_j, N_Vector y, N_Vector yp, + N_Vector rr, SUNMatrix Jac, void *user_data, + N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3); + +int FIDAJTSetup(realtype t, N_Vector y, N_Vector yp, N_Vector r, + realtype c_j, void *user_data); + +int FIDAJtimes(realtype t, N_Vector yy, N_Vector yp, N_Vector rr, + N_Vector v, N_Vector Jv, + realtype c_j, void *user_data, + N_Vector vtemp1, N_Vector vtemp2); + +int FIDAPSet(realtype t, N_Vector yy, N_Vector yp, N_Vector rr, + realtype c_j, void *user_data); + +int FIDAPSol(realtype t, N_Vector yy, N_Vector yp, N_Vector rr, + N_Vector rvec, N_Vector zvec, + realtype c_j, realtype delta, void *user_data); + +int FIDAEwtSet(N_Vector yy, N_Vector ewt, void *user_data); + +void FIDANullMatrix(); +void FIDANullNonlinSol(); + +/* Declarations for global variables shared amongst various routines */ +extern N_Vector F2C_IDA_vec; /* defined in FNVECTOR module */ +extern N_Vector F2C_IDA_ypvec; /* defined in fida.c */ +extern N_Vector F2C_IDA_ewtvec; /* defined in fida.c */ +extern SUNMatrix F2C_IDA_matrix; /* defined in FSUNMATRIX module */ +extern SUNLinearSolver F2C_IDA_linsol; /* defined in FSUNLINSOL module */ +extern SUNNonlinearSolver F2C_IDA_nonlinsol; /* defined in FSUNNONLINSOL module */ +extern void *IDA_idamem; /* defined in fida.c */ +extern long int *IDA_iout; /* defined in fida.c */ +extern realtype *IDA_rout; /* defined in fida.c */ +extern int IDA_nrtfn; /* defined in fida.c */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidaband.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidaband.c new file mode 100644 index 0000000..dc5001f --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidaband.c @@ -0,0 +1,114 @@ +/*----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 + *----------------------------------------------------------------- + * Fortran/C interface routines for IDA/IDALS, for the case of + * a user-supplied Jacobian approximation routine. + *-----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "fida.h" /* function names, prototypes, global vars.*/ +#include "ida_impl.h" /* definition of IDAMem type */ + +#include <ida/ida_ls.h> +#include <sunmatrix/sunmatrix_band.h> + +/*************************************************/ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FIDA_BJAC(long int* N, long int* MU, long int* ML, + long int* EBAND, realtype* T, realtype* Y, + realtype* YP, realtype* R, realtype* CJ, + realtype* J, realtype* EWT, realtype* H, + long int* IPAR, realtype* RPAR, realtype* V1, + realtype* V2, realtype* V3, int* IER); +#ifdef __cplusplus +} +#endif + +/*************************************************/ + +void FIDA_BANDSETJAC(int *flag, int *ier) +{ + if (*flag == 0) { + *ier = IDASetJacFn(IDA_idamem, NULL); + } else { + if (F2C_IDA_ewtvec == NULL) { + F2C_IDA_ewtvec = N_VClone(F2C_IDA_vec); + if (F2C_IDA_ewtvec == NULL) { + *ier = -1; + return; + } + } + *ier = IDASetJacFn(IDA_idamem, FIDABandJac); + } + return; +} + +/*************************************************/ + +int FIDABandJac(realtype t, realtype c_j, N_Vector yy, + N_Vector yp, N_Vector rr, SUNMatrix J, + void *user_data, N_Vector vtemp1, + N_Vector vtemp2, N_Vector vtemp3) +{ + realtype *yy_data, *yp_data, *rr_data, *jacdata, *ewtdata, *v1data, *v2data, *v3data; + realtype h; + long int N, mupper, mlower, smu, eband; + int ier; + FIDAUserData IDA_userdata; + + /* Initialize all pointers to NULL */ + yy_data = yp_data = rr_data = jacdata = ewtdata = NULL; + v1data = v2data = v3data = NULL; + + /* NOTE: The user-supplied routine should set ier to an + appropriate value, but we preset the value to zero + (meaning SUCCESS) so the user need only reset the + value if an error occurred */ + ier = 0; + + IDAGetErrWeights(IDA_idamem, F2C_IDA_ewtvec); + IDAGetLastStep(IDA_idamem, &h); + + /* Get pointers to vector data */ + yy_data = N_VGetArrayPointer(yy); + yp_data = N_VGetArrayPointer(yp); + rr_data = N_VGetArrayPointer(rr); + ewtdata = N_VGetArrayPointer(F2C_IDA_ewtvec); + v1data = N_VGetArrayPointer(vtemp1); + v2data = N_VGetArrayPointer(vtemp2); + v3data = N_VGetArrayPointer(vtemp3); + + N = SUNBandMatrix_Columns(J); + mupper = SUNBandMatrix_UpperBandwidth(J); + mlower = SUNBandMatrix_LowerBandwidth(J); + smu = SUNBandMatrix_StoredUpperBandwidth(J); + eband = smu + mlower + 1; + jacdata = SUNBandMatrix_Column(J,0) - mupper; + + IDA_userdata = (FIDAUserData) user_data; + + /* Call user-supplied routine */ + FIDA_BJAC(&N, &mupper, &mlower, &eband, &t, yy_data, yp_data, + rr_data, &c_j, jacdata, ewtdata, &h, + IDA_userdata->ipar, IDA_userdata->rpar, + v1data, v2data, v3data, &ier); + + return(ier); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidabbd.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidabbd.c new file mode 100644 index 0000000..57a6584 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidabbd.c @@ -0,0 +1,147 @@ +/*----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 module contains the routines necessary to interface with the + * IDABBDPRE module and user-supplied Fortran routines. + * The routines here call the generically named routines and provide + * a standard interface to the C code of the IDABBDPRE package. + *-----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "fida.h" /* function names, prototypes, global variables */ +#include "fidabbd.h" /* prototypes of interfaces to IDABBD */ + +#include <ida/ida_bbdpre.h> /* prototypes of IDABBDPRE functions and macros */ + +/*************************************************/ + +/* private constant(s) */ + +#define ZERO RCONST(0.0) + +/*************************************************/ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FIDA_GLOCFN(long int* NLOC, realtype* Y, + realtype* YLOC, realtype* YPLOC, + realtype* GLOC, long int* IPAR, + realtype* RPAR, int* IER); + extern void FIDA_COMMFN(long int* NLOC, realtype* T, + realtype* Y, realtype* YP, + long int* IPAR, realtype* RPAR, + int* IER); + +#ifdef __cplusplus +} +#endif + +/*************************************************/ + +void FIDA_BBDINIT(long int *Nloc, long int *mudq, + long int *mldq, long int *mu, + long int *ml, realtype *dqrely, + int *ier) +{ + *ier = IDABBDPrecInit(IDA_idamem, *Nloc, *mudq, + *mldq, *mu, *ml, *dqrely, + (IDABBDLocalFn) FIDAgloc, + (IDABBDCommFn) FIDAcfn); + return; +} + +/*************************************************/ + +void FIDA_BBDREINIT(long int *Nloc, long int *mudq, + long int *mldq, realtype *dqrely, + int *ier) +{ + *ier = IDABBDPrecReInit(IDA_idamem, *mudq, *mldq, *dqrely); + return; +} + +/*************************************************/ + +int FIDAgloc(long int Nloc, realtype t, N_Vector yy, + N_Vector yp, N_Vector gval, void *user_data) +{ + realtype *yy_data, *yp_data, *gval_data; + int ier; + FIDAUserData IDA_userdata; + + /* Initialize all pointers to NULL */ + yy_data = yp_data = gval_data = NULL; + + /* NOTE: The user-supplied routine should set ier to an + appropriate value, but we preset the value to zero + (meaning SUCCESS) so the user need only reset the + value if an error occurred */ + ier = 0; + + /* Get pointers to vector data */ + yy_data = N_VGetArrayPointer(yy); + yp_data = N_VGetArrayPointer(yp); + gval_data = N_VGetArrayPointer(gval); + + IDA_userdata = (FIDAUserData) user_data; + + /* Call user-supplied routine */ + FIDA_GLOCFN(&Nloc, &t, yy_data, yp_data, gval_data, + IDA_userdata->ipar, IDA_userdata->rpar, &ier); + return(ier); +} + +/*************************************************/ + +int FIDAcfn(long int Nloc, realtype t, N_Vector yy, N_Vector yp, + void *user_data) +{ + realtype *yy_data, *yp_data; + int ier; + FIDAUserData IDA_userdata; + + /* Initialize all pointers to NULL */ + yy_data = yp_data = NULL; + + /* NOTE: The user-supplied routine should set ier to an + appropriate value, but we preset the value to zero + (meaning SUCCESS) so the user need only reset the + value if an error occurred */ + ier = 0; + + /* Get pointers to vector data */ + yy_data = N_VGetArrayPointer(yy); + yp_data = N_VGetArrayPointer(yp); + + IDA_userdata = (FIDAUserData) user_data; + + /* Call user-supplied routine */ + FIDA_COMMFN(&Nloc, &t, yy_data, yp_data, + IDA_userdata->ipar, IDA_userdata->rpar, &ier); + return(ier); +} + +/*************************************************/ + +void FIDA_BBDOPT(long int *lenrwbbd, long int *leniwbbd, + long int *ngebbd) +{ + IDABBDPrecGetWorkSpace(IDA_idamem, lenrwbbd, leniwbbd); + IDABBDPrecGetNumGfnEvals(IDA_idamem, ngebbd); + return; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidabbd.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidabbd.h new file mode 100644 index 0000000..6832f6a --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidabbd.h @@ -0,0 +1,549 @@ +/*----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 Fortran interface include file for the BBD + * preconditioner (IDABBDPRE) + *-----------------------------------------------------------------*/ + +/*============================================================================== + FIDABBD Interface Package + + The FIDABBD Interface Package is a package of C functions which, together with + the FIDA Interface Package, support the use of the IDA solver and MPI-parallel + N_Vector module, along with the IDABBDPRE preconditioner module, for the + solution of DAE systems in a mixed Fortran/C setting. The combination of IDA + and IDABBDPRE solves the linear systems arising from the solution of DAE + systems using a Krylov iterative linear solver via the IDASPILS interface, + and with a preconditioner that is block-diagonal with banded blocks. While + IDA and IDABBDPRE are written in C, it is assumed here that the user's + calling program and user-supplied problem-defining routines are written in + Fortran. + + The user-callable functions in this package, with the corresponding + IDA and IDABBDPRE functions, are as follows: + + Fortran IDA + -------------- --------------------------- + FIDABBDININT IDABBDPrecInit + FIDABBDREINIT IDABBDPrecReInit + FIDABBDOPT (accesses optional outputs) + FIDABBDFREE IDABBDPrecFree + -------------- --------------------------- + + In addition to the Fortran residual function FIDARESFUN, the + user-supplied functions used by this package, are listed below, + each with the corresponding interface function which calls it (and its + type within IDABBDPRE or IDA): + + Fortran IDA Type + -------------- ----------- ----------------- + FIDAGLOCFN FIDAgloc IDABBDLocalFn + FIDACOMMFN FIDAcfn IDABBDCommFn + FIDAJTSETUP(*) FIDAJTSetup IDASpilsJTSetupFn + FIDAJTIMES(*) FIDAJtimes IDASpilsJacTimesVecFn + -------------- ----------- ----------------- + (*) = optional + + Important notes on portability: + + The names of all user-supplied routines here are fixed, in + order to maximize portability for the resulting mixed-language + program. + + Additionally, the names of the interface functions, and the names of + the Fortran user routines called by them, appear as dummy names + which are mapped to actual values by a series of definitions in the + header file fidabbd.h. + + ============================================================================== + + Usage of the FIDA/FIDABBD Interface Packages + + The usage of the combined interface packages FIDA and FIDABBD requires + calls to several interface functions, and a few different user-supplied + routines which define the problem to be solved and indirectly define + the preconditioner. These function calls and user routines are + summarized separately below. + + Some details are omitted, and the user is referred to the IDA user + document for more complete information. + + (1) User-supplied residual routine: FIDARESFUN + + The user must in all cases supply the following Fortran routine + + SUBROUTINE FIDARESFUN(T, Y, YP, R, IPAR, RPAR, IER) + + It must set the R array to F(t,y,y'), the residual of the DAE + system, as a function of T, Y and YP. + + The arguments are: + T -- scalar value of the independent variable [realtype, input] + Y -- array containing state variables [realtype, input] + YP -- array containing state derivatives [realtype, input] + R -- array containing DAE residuals [realtype, output] + IPAR -- array containing integer user data that was passed + to FIDAMALLOC [long int, input] + RPAR -- array containing real user data that was passed to + FIDAMALLOC [realtype, input] + IER -- return flag [int, output]: + 0 if successful, + >0 if a recoverable error occurred, + <0 if an unrecoverable error ocurred. + + (2) User-supplied routines to define preconditoner: FIDAGLOCFN + and FIDACOMMFN + + The routines in the IDABBDPRE module provide a preconditioner matrix + for IDA that is block-diagonal with banded blocks. The blocking + corresponds to the distribution of the dependent variable vectors y + and y' among the processes. Each preconditioner block is generated + from the Jacobian of the local part (associated with the current + process) of a given function G(t,y,y') approximating F(t,y,y'). The + blocks are generated by a difference quotient scheme independently + by each process, utilizing an assumed banded structure with given + half-bandwidths. A separate pair of half-bandwidths defines the + band matrix retained. + + (2.1) Local approximate function FIDAGLOCFN. + + The user must supply a subroutine of the form + + SUBROUTINE FIDAGLOCFN(NLOC, T, YLOC, YPLOC, GLOC, IPAR, RPAR, IER) + + Computes the function G(t,y,y') which approximates the residual + function F(t,y,y'). This function is to be computed locally, i.e., + without interprocess communication. (The case where G is + mathematically identical to F is allowed.) + + + The arguments are: + NLOC -- local problem size [long int, input] + T -- current time [realtype, input] + YLOC -- array containing local state variables + [realtype, input] + YPLOC -- array containing local state variable derivatives + [realtype, input] + GLOC -- array containing local DAE residuals [realtype, output] + IPAR -- array containing integer user data that was passed + to FIDAMALLOC [long int, input] + RPAR -- array containing real user data that was passed to + FIDAMALLOC [realtype, input] + IER -- return flag [int, output]: + 0 if successful, + >0 if a recoverable error occurred, + <0 if an unrecoverable error ocurred. + + (2.2) Communication function FIDACOMMF. + + The user must also supply a subroutine of the form + + SUBROUTINE FIDACOMMFN(NLOC, T, YLOC, YPLOC, IPAR, RPAR, IER) + + Performs all interprocess communication necessary to evaluate the + approximate residual function G described above. It is expected to + save communicated data in work space defined by the user, and made + available to FIDAGLOCFN. Each call to the FIDACOMMFN is preceded + by a call to FIDARESFUN with the same (t,y,y') arguments. Thus + FIDACOMMFN can omit any communications done by FIDARESFUN if + relevant to the evaluation of G. + + The arguments are: + NLOC -- local problem size [long int, input] + T -- current time [realtype, input] + YLOC -- array containing local state variables + [realtype, input] + YPLOC -- array containing local state variable derivatives + [realtype, input] + IPAR -- array containing integer user data that was passed + to FIDAMALLOC [long int, input] + RPAR -- array containing real user data that was passed to + FIDAMALLOC [realtype, input] + IER -- return flag [int, output]: + 0 if successful, + >0 if a recoverable error occurred, + <0 if an unrecoverable error ocurred. + + + (3) Optional user-supplied Jacobian-vector setup and product + functions: FIDAJTSETUP and FIDAJTIMSE + + As an option, the user may supply a routine that computes the + product of the system Jacobian J = dF/dy and a given vector v. + If supplied, a 'setup' routine to prepare any user data + structures must exist, and have the form: + + SUBROUTINE FIDAJTSETUP(T, Y, YP, R, CJ, EWT, H, IPAR, RPAR, IER) + + It must perform any relevant preparations for subsequent calls to + the user-provided FIDAJTIMES routine (see below). + + The arguments are: + T -- current time [realtype, input] + Y -- array containing state variables [realtype, input] + YP -- array containing state variable derivatives + [realtype, input] + R -- array containing DAE residuals [realtype, input] + CJ -- current value of scalar in Jacobian [realtype, input] + EWT -- array containing error weight vector [realtype, input] + H -- current step size [realtype, input] + IPAR -- array containing integer user data that was passed to + FIDAMALLOC [long int, input] + RPAR -- array containing real user data that was passed to + FIDAMALLOC [realtype, input] + IER -- return flag [int, output]: + 0 if successful, + nonzero if an error. + + The accompanying Jacobian matrix-vector product routine must + have the following form: + + SUBROUTINE FIDAJTIMES(T, Y, YP, R, V, FJV, CJ, EWT, H, + 1 IPAR, RPAR, WK1, WK2, IER) + + This routine must compute the product vector J*v, and store + the product in FJV. + + The arguments are: + T -- current time [realtype, input] + Y -- array containing state variables [realtype, input] + YP -- array containing state variable derivatives + [realtype, input] + R -- array containing DAE residuals [realtype, input] + V -- vector to multiply [realtype, input] + FJV -- product vector [realtype, output] + CJ -- current value of scalar in Jacobian [realtype, input] + EWT -- array containing error weight vector [realtype, input] + H -- current step size [realtype, input] + IPAR -- array containing integer user data that was passed to + FIDAMALLOC [long int, input] + RPAR -- array containing real user data that was passed to + FIDAMALLOC [realtype, input] + WK1, WK2 -- arrays containing temporary workspace of same size + as Y [realtype, input] + IER -- return flag [int, output]: + 0 if successful, + nonzero if an error. + + (4) Initialization: FNVINITP, generic iterative linear solver initialization, + FIDAMALLOC, FIDASPILSINIT, and FIDABBDINIT. + + (4.1) To initialize the parallel machine environment, the user must make + the following call: + + CALL FNVINITP(COMM, 2, NLOCAL, NGLOBAL, IER) + + where the second argument is an int containing the IDA + solver ID (2). The other arguments are: + COMM = the MPI communicator [int, input] + NLOCAL = local vector size on this processor + [long int, input] + NGLOBAL = system size, and the global size of vectors + (the sum of all values of NLOCAL) [long int, input] + IER = return completion flag [int, ouptut]. + 0 = success, + -1 = failure. + + NOTE: The COMM argument passed to the FNVINITP routine is only supported + if the MPI implementation used to build SUNDIALS includes the MPI_Comm_f2c + function from the MPI-2 specification. To check if the function is + supported look for the line "#define SUNDIALS_MPI_COMM_F2C 1" in the + sundials_config.h header file. + + (4.2) To initialize a generic iterative linear solver structure for + solving linear systems within the Newton solver, the user must make one + of the following calls: + + CALL FSUNPCGINIT(2, PRETYPE, MAXL, IER) + CALL FSUNSPBCGSINIT(2, PRETYPE, MAXL, IER) + CALL FSUNSPFGMRINIT(2, PRETYPE, MAXL, IER) + CALL FSUNSPGMRINIT(2, PRETYPE, MAXL, IER) + CALL FSUNSPTFQMRINIT(2, PRETYPE, MAXL, IER) + + In each of these, one argument is an int containing the IDA solver + ID (2). + + The other arguments are: + + PRETYPE = type of preconditioning to perform (0=none, 1=left, + 2=right, 3=both) [int, input] + MAXL = maximum Krylov subspace dimension [int, input] + IER = return completion flag [int, output]: + 0 = success, + -1 = failure. + + (4.3) To set various problem and solution parameters and allocate + internal memory, make the following call: + + CALL FIDAMALLOC(T0, Y0, YP0, IATOL, RTOL, ATOL, ID, CONSTR, + 1 IOUT, ROUT, IPAR, RPAR, IER) + + The arguments are: + T0 = initial value of t [realtype, input] + Y0 = array of initial conditions, y(t0) [realtype, input] + YP0 = value of y'(t0) [realtype, input] + IATOL = type for absolute tolerance ATOL [int, input]: + 1 = scalar, + 2 = array, + 3 = user-supplied function; the user must + supply a routine FIDAEWT to compute the + error weight vector. + RTOL = scalar relative tolerance [realtype, input] + ATOL = scalar/array absolute tolerance [realtype, input] + IOUT = array of length at least 21 for integer optional + inputs and outputs [long int, output] + ROUT = array of length 6 for real optional inputs and + outputs [realtype, output] + IPAR = array of user integer data [long int, in/out] + RPAR = array with user real data [realtype, in/out] + IER = return completion flag [int, output]: + 0 = SUCCESS, + -1 = failure (see printed message for details). + + The optional outputs are: + + LENRW = IOUT( 1) -> IDAGetWorkSpace + LENIW = IOUT( 2) -> IDAGetWorkSpace + NST = IOUT( 3) -> IDAGetNumSteps + NRE = IOUT( 4) -> IDAGetNumResEvals + NETF = IOUT( 5) -> IDAGetNumErrTestFails + NCFN = IOUT( 6) -> IDAGetNumNonlinSolvConvFails + NNI = IOUT( 7) -> IDAGetNumNonlinSolvIters + NSETUPS = IOUT( 8) -> IDAGetNumLinSolvSetups + KLAST = IOUT( 9) -> IDAGetLastOrder + KCUR = IOUT(10) -> IDAGetCurrentOrder + NBCKTRK = IOUT(11) -> IDAGetNumBacktrackOps + NGE = IOUT(12) -> IDAGetNumGEvals + + HINUSED = ROUT( 1) -> IDAGetActualInitStep + HLAST = ROUT( 2) -> IDAGetLastStep + HCUR = ROUT( 3) -> IDAGetCurrentStep + TCUR = ROUT( 4) -> IDAGetCurrentTime + TOLSFAC = ROUT( 5) -> IDAGetTolScaleFactor + UNITRND = ROUT( 6) -> UNIT_ROUNDOFF + + The user data arrays IPAR and RPAR are passed unmodified to + all subsequent calls to user-provided routines. Changes to + either array inside a user-provided routine will be + propagated. Using these two arrays, the user can dispense + with COMMON blocks to pass data betwen user-provided + routines. + + If the user program includes the FIDAEWT routine for the + evaluation of the error weights, the following call must be made + + CALL FIDAEWTSET (FLAG, IER) + + with FLAG = 1 to specify that FIDAEWT is provided. + The return flag IER is 0 if successful, and nonzero otherwise. + + (4.4) Create the IDASPILS interface to attach the generic + iterative linear solver to IDA, by making the following call: + + CALL FIDASPILSINIT(IER) + + The arguments are: + IER = error return flag [int, output]: + 0 = success; + <0 = an error occured + + (4.5) To allocate memory and initialize data associated with the + IDABBDPRE preconditioner, make the following call: + + CALL FIDABBDINIT(NLOCAL, MUDQ, MLDQ, MU, ML, DQRELY, IER) + + The arguments are: + NLOCAL = local vector size on this process + [long int, input] + MUDQ = upper half-bandwidth to be used in the computation + of the local Jacobian blocks by difference + quotients. These may be smaller than the true + half-bandwidths of the Jacobian of the local block + of g, when smaller values may provide greater + efficiency [long int, input] + MLDQ = lower half-bandwidth to be used in the computation + of the local Jacobian blocks by difference + quotients [long int, input] + MU = upper half-bandwidth of the band matrix that is + retained as an approximation of the local Jacobian + block (may be smaller than MUDQ) [long int, input] + ML = lower half-bandwidth of the band matrix that is + retained as an approximation of the local Jacobian + block (may be smaller than MLDQ) [long int, input] + DQRELY = relative increment factor in y for difference + quotients [realtype, input] + 0.0 = default (sqrt(unit roundoff)) + IER = return completion flag [int, output]: + 0 = success + <0 = an error occurred + + (4.6) To specify whether the Krylov linear solver should use the + supplied FIDAJTSETUP and FIDAJTIMES routines, or the internal + finite difference approximation, make the call + + CALL FIDASPILSSETJAC(FLAG, IER) + + with the int FLAG=1 to specify that FIDAJTSETUP and FIDAJTIMES + are provided (FLAG=0 specifies to use and internal finite + difference approximation to this product). The int return + flag IER=0 if successful, and nonzero otherwise. + + (5) Re-initialization: FIDAREINIT, FIDABBDREINIT + + If a sequence of problems of the same size is being solved using + the Krylov linear solver in combination with the IDABBDPRE + preconditioner, then the IDA package can be reinitialized for + the second and subsequent problems so as to avoid further memory + allocation. First, in place of the call to FIDAMALLOC, make the + following call: + + CALL FIDAREINIT(T0, Y0, YP0, IATOL, RTOL, ATOL, ID, CONSTR, IER) + + The arguments have the same names and meanings as those of + FIDAMALLOC. FIDAREINIT performs the same initializations as + FIDAMALLOC, but does no memory allocation for IDA data structures, + using instead the existing internal memory created by the previous + FIDAMALLOC call. + + Following the call to FIDAREINIT, if there is no change in any of + the linear solver arguments, but the user wishes to modify the + values of MUDQ, MLDQ or DQRELY from the previous call to + FIDABBDINIT, then a user may call: + + CALL FIDABBDREINIT(MUDQ, MLDQ, DQRELY, IER) + + The arguments have the same names and meanings as those of + FIDABBDINIT. + + However, if there is a change in any of the linear solver + arguments or other preconditioner arguments, then a call to + FSUNPCGINIT, FSUNSPBCGSINIT, FSUNSPFGMRINIT, FSUNSPGMRINIT, + or FSUNSPTFQMRINIT is required; in this case the linear + solver memory is reallocated. Following this call, the + IDASPILS interface must also be reconstructed using another + call to FIDASPILSINIT (interface memory is freed and + reallocated), as well as a subsequent call to FIDABBDINIT. + + (6) The solver: FIDASOLVE + + To solve the DAE system, make the following call: + + CALL FIDASOLVE(TOUT, TRET, Y, YP, ITASK, IER) + + The arguments are: + TOUT = next value of t at which a solution is desired + [realtype, input] + TRET = value of t reached by the solver [realtype, output] + Y = state variable array [realtype, output] + YP = state variable derivative array [realtype, output] + ITASK = task indicator [int, input]: + 1 = normal mode (overshoot TOUT and interpolate) + 2 = one-step mode (return after each internal + step taken) + 3 = normal tstop mode (like 1, but integration + never proceeds past TSTOP, which must be + specified through a call to FIDASETRIN using + the key 'STOP_TIME') + 4 = one step tstop (like 2, but integration + never goes past TSTOP) + IER = completion flag [int, output]: + 0 = success, + 1 = tstop return, + 2 = root return, + values -1 ... -10 are failure modes (see + IDA manual). + The current values of the optional outputs are immediately + available in the IOUT and ROUT arrays. + + (7) Optional outputs: FIDABBDOPT + + Optional outputs specific to the IDASpils linear solver are + available in IOUT(13)...IOUT(21) + + To obtain the optional outputs associated with the IDABBDPRE + module, make the following call: + + CALL FIDABBDOPT (LENRWBBD, LENIWBBD, NGEBBD) + + The arguments returned are: + LENRWBBD = length of real preconditioner work space, in + realtype words (this size is local to the current + process if run in parallel) [long int, output] + LENIWBBD = length of integer preconditioner work space, in + integer words (this size is local to the current + process if run in parallel) [long int, output] + NGEBBD = number of G(t,y,y') evaluations (calls to + FIDAGLOCFN) so far [long int, output] + + (8) Memory freeing: FIDAFREE + + To the free the internal memory created by the calls to + FNVINITP, FIDAMALLOC, FIDASPILSINIT and FIDABBDINIT, make + the following call: + + CALL FIDAFREE + +==============================================================================*/ + +#ifndef _FIDABBD_H +#define _FIDABBD_H + +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_types.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +#if defined(SUNDIALS_F77_FUNC) + +#define FIDA_BBDINIT SUNDIALS_F77_FUNC(fidabbdinit, FIDABBDINIT) +#define FIDA_BBDREINIT SUNDIALS_F77_FUNC(fidabbdreinit, FIDABBDREINIT) +#define FIDA_BBDOPT SUNDIALS_F77_FUNC(fidabbdopt, FIDABBDOPT) +#define FIDA_GLOCFN SUNDIALS_F77_FUNC(fidaglocfn, FIDAGLOCFN) +#define FIDA_COMMFN SUNDIALS_F77_FUNC(fidacommfn, FIDACOMMFN) + +#else + +#define FIDA_BBDINIT fidabbdinit_ +#define FIDA_BBDREINIT fidabbdreinit_ +#define FIDA_BBDOPT fidabbdopt_ +#define FIDA_GLOCFN fidaglocfn_ +#define FIDA_COMMFN fidacommfn_ + +#endif + +/* Prototypes of exported functions */ + +void FIDA_BBDINIT(long int *Nloc, long int *mudq, long int *mldq, + long int *mu, long int *ml, realtype *dqrely, int *ier); + +void FIDA_BBDREINIT(long int *Nloc, long int *mudq, long int *mldq, + realtype *dqrely, int *ier); + +void FIDA_BBDOPT(long int *lenrwbbd, long int *leniwbbd, + long int *ngebbd); + +/* Prototypes: Functions Called by the IDABBD Module */ + +int FIDAgloc(long int Nloc, realtype t, N_Vector yy, N_Vector yp, + N_Vector gval, void *user_data); +int FIDAcfn(long int Nloc, realtype t, N_Vector yy, N_Vector yp, + void *user_data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidadense.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidadense.c new file mode 100644 index 0000000..11203ab --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidadense.c @@ -0,0 +1,110 @@ +/*----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 + *----------------------------------------------------------------- + * Fortran/C interface routines for IDA/IDALS, for the case + * of a user-supplied Jacobian approximation routine. + *-----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "fida.h" /* actual function names, prototypes and global vars.*/ +#include "ida_impl.h" /* definition of IDAMem type */ + +#include <ida/ida_ls.h> +#include <sunmatrix/sunmatrix_dense.h> + +/*************************************************/ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FIDA_DJAC(long int* N, realtype* T, realtype* Y, + realtype* YP, realtype* R, realtype* J, + realtype* CJ, realtype* EWT, realtype* H, + long int* IPAR, realtype* RPAR, + realtype* V1, realtype* V2, realtype* V3, + int* IER); + +#ifdef __cplusplus +} +#endif + +/*************************************************/ + +void FIDA_DENSESETJAC(int *flag, int *ier) +{ + if (*flag == 0) { + *ier = IDASetJacFn(IDA_idamem, NULL); + } else { + if (F2C_IDA_ewtvec == NULL) { + F2C_IDA_ewtvec = N_VClone(F2C_IDA_vec); + if (F2C_IDA_ewtvec == NULL) { + *ier = -1; + return; + } + } + *ier = IDASetJacFn(IDA_idamem, FIDADenseJac); + } + return; +} + +/*************************************************/ + +int FIDADenseJac(realtype t, realtype c_j, N_Vector yy, N_Vector yp, + N_Vector rr, SUNMatrix J, void *user_data, + N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3) +{ + realtype *yy_data, *yp_data, *rr_data, *jacdata, *ewtdata, *v1data, *v2data, *v3data; + realtype h; + long int N; + int ier; + FIDAUserData IDA_userdata; + + /* Initialize all pointers to NULL */ + yy_data = yp_data = rr_data = jacdata = ewtdata = NULL; + v1data = v2data = v3data = NULL; + + /* NOTE: The user-supplied routine should set ier to an + appropriate value, but we preset the value to zero + (meaning SUCCESS) so the user need only reset the + value if an error occurred */ + ier = 0; + + IDAGetErrWeights(IDA_idamem, F2C_IDA_ewtvec); + IDAGetLastStep(IDA_idamem, &h); + + /* Get pointers to vector data */ + yy_data = N_VGetArrayPointer(yy); + yp_data = N_VGetArrayPointer(yp); + rr_data = N_VGetArrayPointer(rr); + ewtdata = N_VGetArrayPointer(F2C_IDA_ewtvec); + v1data = N_VGetArrayPointer(vtemp1); + v2data = N_VGetArrayPointer(vtemp2); + v3data = N_VGetArrayPointer(vtemp3); + + N = SUNDenseMatrix_Columns(J); + jacdata = SUNDenseMatrix_Column(J,0); + + IDA_userdata = (FIDAUserData) user_data; + + /* Call user-supplied routine*/ + FIDA_DJAC(&N, &t, yy_data, yp_data, rr_data, + jacdata, &c_j, ewtdata, &h, + IDA_userdata->ipar, IDA_userdata->rpar, + v1data, v2data, v3data, &ier); + + return(ier); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidaewt.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidaewt.c new file mode 100644 index 0000000..dcfdadc --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidaewt.c @@ -0,0 +1,89 @@ +/* + * ----------------------------------------------------------------- + * 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 + * ----------------------------------------------------------------- + * Fortran/C interface routines for IDA, for the case of a + * user-supplied error weight calculation routine. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fida.h" /* actual function names, prototypes and global vars.*/ +#include "ida_impl.h" /* definition of IDAMem type */ + +/*************************************************/ + +/* Prototype of user-supplied Fortran routine */ + +#ifdef __cplusplus /* wrapper to enable C++ usage (IDAEwtFn) */ +extern "C" { +#endif + + extern void FIDA_EWT(realtype*, realtype*, /* Y, EWT */ + long int*, realtype*, /* IPAR, RPAR */ + int*); /* IER */ + +#ifdef __cplusplus +} +#endif + +/*************************************************/ + +/* + * User-callable function to interface to IDASetEwtFn. + */ + +void FIDA_EWTSET(int *flag, int *ier) +{ + *ier = 0; + + if (*flag != 0) { + *ier = IDAWFtolerances(IDA_idamem, FIDAEwtSet); + } + + return; +} + +/*************************************************/ + +/* + * C function to interface between IDA and a Fortran subroutine FIDAVEWT. + */ + +int FIDAEwtSet(N_Vector y, N_Vector ewt, void *user_data) +{ + int ier; + realtype *y_data, *ewt_data; + FIDAUserData IDA_userdata; + + /* Initialize all pointers to NULL */ + y_data = ewt_data = NULL; + + /* NOTE: The user-supplied routine should set ier to an + appropriate value, but we preset the value to zero + (meaning SUCCESS) so the user need only reset the + value if an error occurred */ + ier = 0; + + y_data = N_VGetArrayPointer(y); + ewt_data = N_VGetArrayPointer(ewt); + + IDA_userdata = (FIDAUserData) user_data; + + /* Call user-supplied routine */ + FIDA_EWT(y_data, ewt_data, IDA_userdata->ipar, IDA_userdata->rpar, &ier); + + return(ier); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidajtimes.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidajtimes.c new file mode 100644 index 0000000..35cd0dd --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidajtimes.c @@ -0,0 +1,156 @@ +/*----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * Aaron Collier 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 + *----------------------------------------------------------------- + * The C functions FIDAJTSetup and FIDAJtimes are to interface + * between the IDALS module and the user-supplied + * Jacobian-vector product routines FIDAJTSETUP and FIDAJTIMES. + * Note the use of the generic names FIDA_JTSETUP and FIDA_JTIMES + * below. + *-----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "fida.h" /* actual fn. names, prototypes and global vars.*/ +#include "ida_impl.h" /* definition of IDAMem type */ + +#include <ida/ida_ls.h> + +/*************************************************/ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FIDA_JTSETUP(realtype *T, realtype *Y, realtype *YP, + realtype *R, realtype *CJ, realtype *EWT, + realtype *H, long int *IPAR, + realtype *RPAR, int *IER); + + extern void FIDA_JTIMES(realtype *T, realtype *Y, realtype *YP, + realtype *R, realtype *V, realtype *FJV, + realtype *CJ, realtype *EWT, realtype *H, + long int *IPAR, realtype *RPAR, + realtype *WK1, realtype *WK2, int *IER); + +#ifdef __cplusplus +} +#endif + +/*************************************************/ + +/*** DEPRECATED ***/ +void FIDA_SPILSSETJAC(int *flag, int *ier) +{ FIDA_LSSETJAC(flag, ier); } + + +/* Fortran interface to C routine IDASetJacTimes; see + fida.h for further information */ +void FIDA_LSSETJAC(int *flag, int *ier) +{ + if (*flag == 0) { + *ier = IDASetJacTimes(IDA_idamem, NULL, NULL); + } else { + if (F2C_IDA_ewtvec == NULL) { + F2C_IDA_ewtvec = N_VClone(F2C_IDA_vec); + if (F2C_IDA_ewtvec == NULL) { + *ier = -1; + return; + } + } + *ier = IDASetJacTimes(IDA_idamem, FIDAJTSetup, FIDAJtimes); + } + return; +} + +/*************************************************/ + +/* C interface to user-supplied Fortran routine FIDAJTSETUP; see + fida.h for further information */ +int FIDAJTSetup(realtype t, N_Vector y, N_Vector yp, + N_Vector r, realtype cj, void *user_data) +{ + realtype *ydata, *ypdata, *rdata, *ewtdata; + realtype h; + FIDAUserData IDA_userdata; + int ier = 0; + + /* Initialize all pointers to NULL */ + ydata = ypdata = rdata = ewtdata = NULL; + + /* NOTE: The user-supplied routine should set ier to an + appropriate value, but we preset the value to zero + (meaning SUCCESS) so the user need only reset the + value if an error occurred */ + ier = 0; + + IDAGetErrWeights(IDA_idamem, F2C_IDA_ewtvec); + IDAGetLastStep(IDA_idamem, &h); + ydata = N_VGetArrayPointer(y); + ypdata = N_VGetArrayPointer(yp); + rdata = N_VGetArrayPointer(r); + ewtdata = N_VGetArrayPointer(F2C_IDA_ewtvec); + + IDA_userdata = (FIDAUserData) user_data; + + /* Call user-supplied routine */ + FIDA_JTSETUP(&t, ydata, ypdata, rdata, &cj, ewtdata, &h, + IDA_userdata->ipar, IDA_userdata->rpar, &ier); + return(ier); +} + +/* C interface to user-supplied Fortran routine FIDAJTIMES; see + fida.h for further information */ +int FIDAJtimes(realtype t, N_Vector yy, N_Vector yp, N_Vector rr, + N_Vector v, N_Vector Jv, realtype c_j, + void *user_data, N_Vector vtemp1, N_Vector vtemp2) +{ + realtype *yy_data, *yp_data, *rr_data, *vdata, *Jvdata, *ewtdata; + realtype *v1data, *v2data; + realtype h; + FIDAUserData IDA_userdata; + int ier; + + /* Initialize all pointers to NULL */ + yy_data = yp_data = rr_data = vdata = Jvdata = ewtdata = NULL; + + /* NOTE: The user-supplied routine should set ier to an + appropriate value, but we preset the value to zero + (meaning SUCCESS) so the user need only reset the + value if an error occurred */ + ier = 0; + + IDAGetErrWeights(IDA_idamem, F2C_IDA_ewtvec); + IDAGetLastStep(IDA_idamem, &h); + + /* Get pointers to vector data */ + yy_data = N_VGetArrayPointer(yy); + yp_data = N_VGetArrayPointer(yp); + rr_data = N_VGetArrayPointer(rr); + ewtdata = N_VGetArrayPointer(F2C_IDA_ewtvec); + vdata = N_VGetArrayPointer(v); + Jvdata = N_VGetArrayPointer(Jv); + v1data = N_VGetArrayPointer(vtemp1); + v2data = N_VGetArrayPointer(vtemp2); + + IDA_userdata = (FIDAUserData) user_data; + + /* Call user-supplied routine */ + FIDA_JTIMES(&t, yy_data, yp_data, rr_data, vdata, Jvdata, + &c_j, ewtdata, &h, + IDA_userdata->ipar, IDA_userdata->rpar, + v1data, v2data, &ier); + + return(ier); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidanullmatrix.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidanullmatrix.c new file mode 100644 index 0000000..ee87d7f --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidanullmatrix.c @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * File that provides a globally-defined, but NULL-valued, + * SUNMatrix object, to ensure that F2C_IDA_matrix is defined + * for cases when no matrix object is linked in with the main + * executable. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "fida.h" +#include "ida_impl.h" + +/*=============================================================*/ + +/* Define global matrix variable */ + +SUNMatrix F2C_IDA_matrix; + +/*=============================================================*/ + +/* C routine that is called when using matrix-free linear solvers */ +void FIDANullMatrix() +{ + F2C_IDA_matrix = NULL; +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidanullnonlinsol.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidanullnonlinsol.c new file mode 100644 index 0000000..8db385b --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidanullnonlinsol.c @@ -0,0 +1,41 @@ +/* ----------------------------------------------------------------------------- + * 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 + * ----------------------------------------------------------------------------- + * File that provides a globally-defined, but NULL-valued, SUNNonlinearSolver + * object, to ensure that F2C_IDA_nonlinsol is defined for cases when the + * default nonlinear solver is used and thus no Fortran nonlinear solver object + * is linked in with the main executable. + *----------------------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "fida.h" +#include "ida_impl.h" + +/*=============================================================*/ + +/* Define global linear solver variable */ + +SUNNonlinearSolver F2C_IDA_nonlinsol; + +/*=============================================================*/ + +/* C routine that is called when using the default nonlinear solver */ +void FIDANullNonlinSol() +{ + F2C_IDA_nonlinsol = NULL; +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidapreco.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidapreco.c new file mode 100644 index 0000000..0b50d7d --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidapreco.c @@ -0,0 +1,151 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Aaron Collier 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 + * ----------------------------------------------------------------- + * The C function FIDAPSet is to interface between the IDALS + * module and the user-supplied preconditioner setup routine FIDAPSET. + * Note the use of the generic name FIDA_PSET below. + * -----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "fida.h" /* actual fn. names, prototypes and global vars.*/ +#include "ida_impl.h" /* definition of IDAMem type */ + +#include <ida/ida_ls.h> + +/*************************************************/ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + extern void FIDA_PSET(realtype* t, realtype* yy, realtype* yp, + realtype* rr, realtype* c_j, realtype* ewt, + realtype* h, long int* ipar, realtype* rpar, + int* ier); + + extern void FIDA_PSOL(realtype* t, realtype* yy, realtype* yp, + realtype* rr, realtype* r, realtype* z, + realtype* c_j, realtype* delta, realtype* ewt, + long int* ipar, realtype* rpar, int* ier); + +#ifdef __cplusplus +} +#endif + +/*************************************************/ + +/*** DEPRECATED ***/ +void FIDA_SPILSSETPREC(int *flag, int *ier) +{ FIDA_LSSETPREC(flag, ier); } + +void FIDA_LSSETPREC(int *flag, int *ier) +{ + *ier = 0; + + if (*flag == 0) { + + *ier = IDASetPreconditioner(IDA_idamem, NULL, NULL); + + } else { + + if (F2C_IDA_ewtvec == NULL) { + F2C_IDA_ewtvec = N_VClone(F2C_IDA_vec); + if (F2C_IDA_ewtvec == NULL) { + *ier = -1; + return; + } + } + + *ier = IDASetPreconditioner(IDA_idamem, FIDAPSet, FIDAPSol); + } + + return; +} + +/*************************************************/ + +int FIDAPSet(realtype t, N_Vector yy, N_Vector yp, N_Vector rr, + realtype c_j, void *user_data) +{ + realtype *yy_data, *yp_data, *rr_data, *ewtdata; + realtype h; + int ier; + FIDAUserData IDA_userdata; + + /* Initialize all pointers to NULL */ + yy_data = yp_data = rr_data = ewtdata = NULL; + + /* NOTE: The user-supplied routine should set ier to an + appropriate value, but we preset the value to zero + (meaning SUCCESS) so the user need only reset the + value if an error occurred */ + ier = 0; + + IDAGetErrWeights(IDA_idamem, F2C_IDA_ewtvec); + IDAGetLastStep(IDA_idamem, &h); + + /* Get pointers to vector data */ + yy_data = N_VGetArrayPointer(yy); + yp_data = N_VGetArrayPointer(yp); + rr_data = N_VGetArrayPointer(rr); + ewtdata = N_VGetArrayPointer(F2C_IDA_ewtvec); + + IDA_userdata = (FIDAUserData) user_data; + + /* Call user-supplied routine */ + FIDA_PSET(&t, yy_data, yp_data, rr_data, &c_j, ewtdata, &h, + IDA_userdata->ipar, IDA_userdata->rpar, &ier); + + return(ier); +} + +/*************************************************/ + +int FIDAPSol(realtype t, N_Vector yy, N_Vector yp, N_Vector rr, + N_Vector rvec, N_Vector zvec, + realtype c_j, realtype delta, void *user_data) +{ + realtype *yy_data, *yp_data, *rr_data, *ewtdata, *rdata, *zdata; + int ier; + FIDAUserData IDA_userdata; + + /* Initialize all pointers to NULL */ + yy_data = yp_data = rr_data = ewtdata = zdata = NULL; + + /* NOTE: The user-supplied routine should set ier to an + appropriate value, but we preset the value to zero + (meaning SUCCESS) so the user need only reset the + value if an error occurred */ + ier = 0; + + IDAGetErrWeights(IDA_idamem, F2C_IDA_ewtvec); + + /* Get pointers to vector data */ + yy_data = N_VGetArrayPointer(yy); + yp_data = N_VGetArrayPointer(yp); + rr_data = N_VGetArrayPointer(rr); + ewtdata = N_VGetArrayPointer(F2C_IDA_ewtvec); + rdata = N_VGetArrayPointer(rvec); + zdata = N_VGetArrayPointer(zvec); + + IDA_userdata = (FIDAUserData) user_data; + + /* Call user-supplied routine */ + FIDA_PSOL(&t, yy_data, yp_data, rr_data, rdata, zdata, + &c_j, &delta, ewtdata, + IDA_userdata->ipar, IDA_userdata->rpar, &ier); + + return(ier); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidaroot.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidaroot.c new file mode 100644 index 0000000..2cce74b --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidaroot.c @@ -0,0 +1,90 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Aaron Collier and Alan C. Hindmarsh @ 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 + * ----------------------------------------------------------------- + * The FIDAROOT module contains the routines necessary to use + * the rootfinding feature of the IDA module and to interface + * with the user-supplied Fortran subroutine. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fida.h" /* actual function names, prototypes and global vars.*/ +#include "fidaroot.h" /* prototypes of interfaces to IDA */ +#include "ida_impl.h" /* definition of IDAMeme type */ + +/***************************************************************************/ + +/* Prototype of the Fortran routine */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + extern void FIDA_ROOTFN(realtype*, /* T */ + realtype*, /* Y */ + realtype*, /* YP */ + realtype*, /* G */ + long int*, /* IPAR */ + realtype*, /* RPAR */ + int*); /* IER */ +#ifdef __cplusplus +} +#endif + +/***************************************************************************/ + +void FIDA_ROOTINIT(int *nrtfn, int *ier) +{ + *ier = IDARootInit(IDA_idamem, *nrtfn, (IDARootFn) FIDArootfunc); + IDA_nrtfn = *nrtfn; + + return; +} + +/***************************************************************************/ + +void FIDA_ROOTINFO(int *nrtfn, int *info, int *ier) +{ + *ier = IDAGetRootInfo(IDA_idamem, info); + return; +} + +/***************************************************************************/ + +void FIDA_ROOTFREE(void) +{ + IDARootInit(IDA_idamem, 0, NULL); + + return; +} + +/***************************************************************************/ + +int FIDArootfunc(realtype t, N_Vector y, N_Vector yp, realtype *gout, + void *user_data) +{ + int ier; + realtype *ydata, *ypdata; + FIDAUserData IDA_userdata; + + ydata = N_VGetArrayPointer(y); + ypdata = N_VGetArrayPointer(yp); + + IDA_userdata = (FIDAUserData) user_data; + + FIDA_ROOTFN(&t, ydata, ypdata, gout, IDA_userdata->ipar, IDA_userdata->rpar, &ier); + + return(ier); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidaroot.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidaroot.h new file mode 100644 index 0000000..7d1d39d --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidaroot.h @@ -0,0 +1,143 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Aaron Collier and Alan C. Hindmarsh @ 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 Fortran interface include file for the rootfinding + * feature of IDA. + * ----------------------------------------------------------------- + */ + +/* + * ============================================================================== + * + * FIDAROOT Interface Package + * + * The FIDAROOT interface package allows programs written in FORTRAN to + * use the rootfinding feature of the IDA solver module. + * + * The user-callable functions constituting the FIDAROOT package are the + * following: FIDAROOTINIT, FIDAROOTINFO, and FIDAROOTFREE. The corresponding + * IDA subroutine called by each interface function is given below. + * + * ------------------ --------------------- + * | FIDAROOT routine | | IDA function called | + * ------------------ --------------------- + * FIDAROOTINIT -> IDARootInit + * FIDAROOTINFO -> IDAGetRootInfo + * FIDAROOTFREE -> IDARootInit + * + * FIDAROOTFN is a user-supplied subroutine defining the functions whose + * roots are sought. + * + * ============================================================================== + * + * Usage of the FIDAROOT Interface Package + * + * 1. In order to use the rootfinding feature of the IDA package the user must + * define the following subroutine: + * + * SUBROUTINE FIDAROOTFN (T, Y, YP, G, IPAR, RPAR, IER) + * DIMENSION Y(*), YP(*), G(*) + * + * The arguments are: + * T = independent variable value t [input] + * Y = dependent variable vector y [input] + * YP = dependent variable derivative vector y' [input] + * G = function values g(t,y,y') [output] + * IPAR, RPAR = user (long int and realtype) data [input/output] + * IER = return flag (set on 0 if successful, non-zero if an error occurred) + * + * 2. After calling FIDAMALLOC but prior to calling FIDASOLVE, the user must + * allocate and initialize memory for the FIDAROOT module by making the + * following call: + * + * CALL FIDAROOTINIT (NRTFN, IER) + * + * The arguments are: + * NRTFN = total number of root functions [input] + * IER = return completion flag (0 = success, -1 = IDA memory NULL and + * -14 = memory allocation error) [output] + * + * 3. After calling FIDA, to see whether a root was found, test the FIDA + * return flag IER. The value IER = 2 means one or more roots were found. + * + * 4. If a root was found, and if NRTFN > 1, then to determine which root + * functions G(*) were found to have a root, make the following call: + * CALL FIDAROOTINFO (NRTFN, INFO, IER) + * The arguments are: + * NRTFN = total number of root functions [input] + * INFO = integer array of length NRTFN, with values 0 or 1 [output] + * For i = 1,...,NRTFN, G(i) was found to have a root if INFO(i) = 1. + * IER = completion flag (0 = success, negative = failure) + * + * 5. The total number of calls made to the root function (FIDAROOTFN), + * NGE, can be obtained from IOUT(12). + * + * If the FIDA/IDA memory block is reinitialized to solve a different + * problem via a call to FIDAREINIT, then the counter variable NGE is cleared + * (reset to zero). + * + * 6. To free the memory resources allocated by a prior call to FIDAROOTINIT, + * make the following call: + * CALL FIDAROOTFREE + * See the IDA documentation for additional information. + * + * ============================================================================== + */ + +#ifndef _FIDAROOT_H +#define _FIDAROOT_H + +/* header files */ +#include <sundials/sundials_nvector.h> /* definition of type N_Vector */ +#include <sundials/sundials_types.h> /* definition of SUNDIALS type realtype */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* Definitions of interface function names */ + +#if defined(SUNDIALS_F77_FUNC) + +#define FIDA_ROOTINIT SUNDIALS_F77_FUNC(fidarootinit, FIDAROOTINIT) +#define FIDA_ROOTINFO SUNDIALS_F77_FUNC(fidarootinfo, FIDAROOTINFO) +#define FIDA_ROOTFREE SUNDIALS_F77_FUNC(fidarootfree, FIDAROOTFREE) +#define FIDA_ROOTFN SUNDIALS_F77_FUNC(fidarootfn, FIDAROOTFN) + +#else + +#define FIDA_ROOTINIT fidarootinit_ +#define FIDA_ROOTINFO fidarootinfo_ +#define FIDA_ROOTFREE fidarootfree_ +#define FIDA_ROOTFN fidarootfn_ + +#endif + +/* Prototypes of exported function */ + +void FIDA_ROOTINIT(int *nrtfn, int *ier); +void FIDA_ROOTINFO(int *nrtfn, int *info, int *ier); +void FIDA_ROOTFREE(void); + +/* Prototype of function called by IDA module */ + +int FIDArootfunc(realtype t, N_Vector y, N_Vector yp, realtype *gout, + void *user_data); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidasparse.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidasparse.c new file mode 100644 index 0000000..afd74eb --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/fcmix/fidasparse.c @@ -0,0 +1,94 @@ +/*----------------------------------------------------------------- + * Programmer(s): Carol Woodward @ 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 + *-----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "fida.h" +#include "ida_impl.h" +#include <ida/ida_ls.h> +#include <sunmatrix/sunmatrix_sparse.h> + +/*=============================================================*/ + +/* Prototype of the Fortran routine */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +extern void FIDA_SPJAC(realtype *T, realtype *CJ, realtype *Y, + realtype *YP, realtype *R, long int *N, + long int *NNZ, realtype *JDATA, + sunindextype *JRVALS, sunindextype *JCPTRS, + realtype *H, long int *IPAR, realtype *RPAR, + realtype *V1, realtype *V2, + realtype *V3, int *ier); + +#ifdef __cplusplus +} +#endif + +/*=============================================================*/ + +/* Fortran interface to C routine IDASlsSetSparseJacFn; see + fida.h for further information */ +void FIDA_SPARSESETJAC(int *ier) +{ +#if defined(SUNDIALS_INT32_T) + IDAProcessError((IDAMem) IDA_idamem, IDA_ILL_INPUT, "IDA", + "FIDASPARSESETJAC", + "Sparse Fortran users must configure SUNDIALS with 64-bit integers."); + *ier = 1; +#else + *ier = IDASetJacFn(IDA_idamem, FIDASparseJac); +#endif +} + +/*=============================================================*/ + +/* C interface to user-supplied Fortran routine FIDASPJAC; see + fida.h for additional information */ +int FIDASparseJac(realtype t, realtype cj, N_Vector y, N_Vector yp, + N_Vector fval, SUNMatrix J, void *user_data, + N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3) +{ + int ier; + realtype *ydata, *ypdata, *rdata, *v1data, *v2data, *v3data, *Jdata; + realtype h; + long int NP, NNZ; + sunindextype *indexvals, *indexptrs; + FIDAUserData IDA_userdata; + + IDAGetLastStep(IDA_idamem, &h); + ydata = N_VGetArrayPointer(y); + ypdata = N_VGetArrayPointer(yp); + rdata = N_VGetArrayPointer(fval); + v1data = N_VGetArrayPointer(vtemp1); + v2data = N_VGetArrayPointer(vtemp2); + v3data = N_VGetArrayPointer(vtemp3); + IDA_userdata = (FIDAUserData) user_data; + NP = SUNSparseMatrix_NP(J); + NNZ = SUNSparseMatrix_NNZ(J); + Jdata = SUNSparseMatrix_Data(J); + indexvals = SUNSparseMatrix_IndexValues(J); + indexptrs = SUNSparseMatrix_IndexPointers(J); + + FIDA_SPJAC(&t, &cj, ydata, ypdata, rdata, &NP, &NNZ, + Jdata, indexvals, indexptrs, &h, + IDA_userdata->ipar, IDA_userdata->rpar, v1data, + v2data, v3data, &ier); + return(ier); +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida.c new file mode 100644 index 0000000..c950af8 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida.c @@ -0,0 +1,3384 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Alan Hindmarsh, Radu Serban 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 implementation file for the main IDA solver. + * It is independent of the linear solver in use. + * ----------------------------------------------------------------- + * + * EXPORTED FUNCTIONS + * ------------------ + * Creation, allocation and re-initialization functions + * IDACreate + * IDAInit + * IDAReInit + * IDARootInit + * Main solver function + * IDASolve + * Interpolated output and extraction functions + * IDAGetDky + * Deallocation functions + * IDAFree + * + * PRIVATE FUNCTIONS + * ----------------- + * IDACheckNvector + * Memory allocation/deallocation + * IDAAllocVectors + * IDAFreeVectors + * Initial setup + * IDAInitialSetup + * IDAEwtSet + * IDAEwtSetSS + * IDAEwtSetSV + * Stopping tests + * IDAStopTest1 + * IDAStopTest2 + * Error handler + * IDAHandleFailure + * Main IDAStep function + * IDAStep + * IDASetCoeffs + * Nonlinear solver functions + * IDANls + * IDAPredict + * Error test + * IDATestError + * IDARestore + * Handler for convergence and/or error test failures + * IDAHandleNFlag + * IDAReset + * Function called after a successful step + * IDACompleteStep + * Get solution + * IDAGetSolution + * Norm functions + * IDAWrmsNorm + * Functions for rootfinding + * IDARcheck1 + * IDARcheck2 + * IDARcheck3 + * IDARootfind + * IDA Error message handling functions + * IDAProcessError + * IDAErrHandler + * ----------------------------------------------------------------- + */ + +/* + * ================================================================= + * IMPORTED HEADER FILES + * ================================================================= + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> + +#include "ida_impl.h" +#include <sundials/sundials_math.h> +#include "sunnonlinsol/sunnonlinsol_newton.h" + +/* + * ================================================================= + * IDAS PRIVATE CONSTANTS + * ================================================================= + */ + +#define ZERO RCONST(0.0) /* real 0.0 */ +#define HALF RCONST(0.5) /* real 0.5 */ +#define QUARTER RCONST(0.25) /* real 0.25 */ +#define TWOTHIRDS RCONST(0.667) /* real 2/3 */ +#define ONE RCONST(1.0) /* real 1.0 */ +#define ONEPT5 RCONST(1.5) /* real 1.5 */ +#define TWO RCONST(2.0) /* real 2.0 */ +#define FOUR RCONST(4.0) /* real 4.0 */ +#define FIVE RCONST(5.0) /* real 5.0 */ +#define TEN RCONST(10.0) /* real 10.0 */ +#define TWELVE RCONST(12.0) /* real 12.0 */ +#define TWENTY RCONST(20.0) /* real 20.0 */ +#define HUNDRED RCONST(100.0) /* real 100.0 */ +#define PT9 RCONST(0.9) /* real 0.9 */ +#define PT99 RCONST(0.99) /* real 0.99 */ +#define PT1 RCONST(0.1) /* real 0.1 */ +#define PT01 RCONST(0.01) /* real 0.01 */ +#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 + * ------------------------------------------------------------ + */ + +/* IDAStep control constants */ + +#define PREDICT_AGAIN 20 + +/* Return values for lower level routines used by IDASolve */ + +#define CONTINUE_STEPS +99 + +/* IDACompleteStep constants */ + +#define UNSET -1 +#define LOWER +1 +#define RAISE +2 +#define MAINTAIN +3 + +/* IDATestError constants */ + +#define ERROR_TEST_FAIL +7 + +/* + * Control constants for lower-level rootfinding functions + * ------------------------------------------------------- + */ + +#define RTFOUND +1 +#define CLOSERT +3 + +/* + * Control constants for tolerances + * -------------------------------- + */ + +#define IDA_NN 0 +#define IDA_SS 1 +#define IDA_SV 2 +#define IDA_WF 3 + +/* + * Algorithmic constants + * --------------------- + */ + +#define MXNCF 10 /* max number of convergence failures allowed */ +#define MXNEF 10 /* max number of error test failures allowed */ +#define MAXNH 5 /* max. number of h tries in IC calc. */ +#define MAXNJ 4 /* max. number of J tries in IC calc. */ +#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 */ + +/* + * ================================================================= + * PRIVATE FUNCTION PROTOTYPES + * ================================================================= + */ + +static booleantype IDACheckNvector(N_Vector tmpl); + +/* Memory allocation/deallocation */ + +static booleantype IDAAllocVectors(IDAMem IDA_mem, N_Vector tmpl); +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); + +/* Main IDAStep function */ + +static int IDAStep(IDAMem IDA_mem); + +/* Function called at beginning of step */ + +static void IDASetCoeffs(IDAMem IDA_mem, realtype *ck); + +/* Nonlinear solver functions */ + +static void IDAPredict(IDAMem IDA_mem); +static int IDANls(IDAMem IDA_mem); + +/* Error test */ + +static int IDATestError(IDAMem IDA_mem, realtype ck, + realtype *err_k, realtype *err_km1); + +/* Handling of convergence and/or error test failures */ + +static void IDARestore(IDAMem IDA_mem, realtype saved_t); +static int IDAHandleNFlag(IDAMem IDA_mem, int nflag, realtype err_k, realtype err_km1, + long int *ncfnPtr, int *ncfPtr, long int *netfPtr, int *nefPtr); +static void IDAReset(IDAMem IDA_mem); + +/* Function called after a successful step */ + +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 */ + +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, + N_Vector yret, N_Vector ypret, int itask); +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); + +/* Functions for rootfinding */ + +static int IDARcheck1(IDAMem IDA_mem); +static int IDARcheck2(IDAMem IDA_mem); +static int IDARcheck3(IDAMem IDA_mem); +static int IDARootfind(IDAMem IDA_mem); + +/* + * ================================================================= + * EXPORTED FUNCTIONS IMPLEMENTATION + * ================================================================= + */ + +/* + * ----------------------------------------------------------------- + * Creation, allocation and re-initialization functions + * ----------------------------------------------------------------- + */ + +/* + * IDACreate + * + * 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. + */ + +void *IDACreate(void) +{ + IDAMem IDA_mem; + + IDA_mem = NULL; + IDA_mem = (IDAMem) malloc(sizeof(struct IDAMemRec)); + if (IDA_mem == NULL) { + IDAProcessError(NULL, 0, "IDA", "IDACreate", MSG_MEM_FAIL); + return (NULL); + } + + /* Zero out ida_mem */ + memset(IDA_mem, 0, sizeof(struct IDAMemRec)); + + /* Set unit roundoff in IDA_mem */ + IDA_mem->ida_uround = UNIT_ROUNDOFF; + + /* Set default values for integrator optional inputs */ + IDA_mem->ida_res = NULL; + IDA_mem->ida_user_data = NULL; + IDA_mem->ida_itol = IDA_NN; + IDA_mem->ida_user_efun = SUNFALSE; + IDA_mem->ida_efun = NULL; + IDA_mem->ida_edata = NULL; + IDA_mem->ida_ehfun = IDAErrHandler; + IDA_mem->ida_eh_data = IDA_mem; + IDA_mem->ida_errfp = stderr; + IDA_mem->ida_maxord = MAXORD_DEFAULT; + IDA_mem->ida_mxstep = MXSTEP_DEFAULT; + IDA_mem->ida_hmax_inv = HMAX_INV_DEFAULT; + IDA_mem->ida_hin = ZERO; + IDA_mem->ida_epcon = EPCON; + IDA_mem->ida_maxnef = MXNEF; + IDA_mem->ida_maxncf = MXNCF; + IDA_mem->ida_suppressalg = SUNFALSE; + IDA_mem->ida_id = NULL; + IDA_mem->ida_constraints = NULL; + IDA_mem->ida_constraintsSet = SUNFALSE; + IDA_mem->ida_tstopset = SUNFALSE; + + /* set the saved value maxord_alloc */ + IDA_mem->ida_maxord_alloc = MAXORD_DEFAULT; + + /* Set default values for IC optional inputs */ + IDA_mem->ida_epiccon = PT01 * EPCON; + IDA_mem->ida_maxnh = MAXNH; + IDA_mem->ida_maxnj = MAXNJ; + IDA_mem->ida_maxnit = MAXNI; + IDA_mem->ida_maxbacks = MAXBACKS; + IDA_mem->ida_lsoff = SUNFALSE; + IDA_mem->ida_steptol = SUNRpowerR(IDA_mem->ida_uround, TWOTHIRDS); + + /* Initialize lrw and liw */ + IDA_mem->ida_lrw = 25 + 5*MXORDP1; + 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; + IDA_mem->ida_MallocDone = SUNFALSE; + + /* Initialize nonlinear solver pointer */ + IDA_mem->NLS = NULL; + IDA_mem->ownNLS = SUNFALSE; + + /* Return pointer to IDA memory block */ + return((void *)IDA_mem); +} + +/*-----------------------------------------------------------------*/ + +/* + * IDAInit + * + * 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 handler function. + */ + +int IDAInit(void *ida_mem, IDAResFn res, + realtype t0, N_Vector yy0, N_Vector yp0) +{ + int retval; + IDAMem IDA_mem; + booleantype nvectorOK, allocOK; + sunindextype lrw1, liw1; + SUNNonlinearSolver NLS; + + /* Check ida_mem */ + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAInit", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Check for legal input parameters */ + + if (yy0 == NULL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAInit", MSG_Y0_NULL); + return(IDA_ILL_INPUT); + } + + if (yp0 == NULL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAInit", MSG_YP0_NULL); + return(IDA_ILL_INPUT); + } + + if (res == NULL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAInit", MSG_RES_NULL); + return(IDA_ILL_INPUT); + } + + /* Test if all required vector operations are implemented */ + + nvectorOK = IDACheckNvector(yy0); + if (!nvectorOK) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAInit", MSG_BAD_NVECTOR); + return(IDA_ILL_INPUT); + } + + /* Set space requirements for one N_Vector */ + + if (yy0->ops->nvspace != NULL) { + N_VSpace(yy0, &lrw1, &liw1); + } else { + lrw1 = 0; + liw1 = 0; + } + IDA_mem->ida_lrw1 = lrw1; + IDA_mem->ida_liw1 = liw1; + + /* Allocate the vectors (using yy0 as a template) */ + + allocOK = IDAAllocVectors(IDA_mem, yy0); + if (!allocOK) { + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDA", "IDAInit", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + /* create a Newton nonlinear solver object by default */ + NLS = SUNNonlinSol_Newton(yy0); + + /* check that nonlinear solver is non-NULL */ + if (NLS == NULL) { + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDA", "IDAInit", MSG_MEM_FAIL); + IDAFreeVectors(IDA_mem); + return(IDA_MEM_FAIL); + } + + /* attach the nonlinear solver to the IDA memory */ + retval = IDASetNonlinearSolver(IDA_mem, NLS); + + /* check that the nonlinear solver was successfully attached */ + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, retval, "IDA", "IDAInit", + "Setting the nonlinear solver failed"); + IDAFreeVectors(IDA_mem); + SUNNonlinSolFree(NLS); + return(IDA_MEM_FAIL); + } + + /* set ownership flag */ + IDA_mem->ownNLS = SUNTRUE; + + /* All error checking is complete at this point */ + + /* Copy the input parameters into IDA memory block */ + + IDA_mem->ida_res = res; + IDA_mem->ida_tn = t0; + + /* Set the linear solver addresses to NULL */ + + IDA_mem->ida_linit = NULL; + IDA_mem->ida_lsetup = NULL; + IDA_mem->ida_lsolve = NULL; + IDA_mem->ida_lperf = NULL; + IDA_mem->ida_lfree = NULL; + IDA_mem->ida_lmem = NULL; + + /* Initialize the phi array */ + + 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; + + IDA_mem->ida_nge = 0; + + IDA_mem->ida_irfnd = 0; + + /* Initialize root-finding variables */ + + IDA_mem->ida_glo = NULL; + IDA_mem->ida_ghi = NULL; + IDA_mem->ida_grout = NULL; + IDA_mem->ida_iroots = NULL; + IDA_mem->ida_rootdir = NULL; + IDA_mem->ida_gfun = NULL; + IDA_mem->ida_nrtfn = 0; + IDA_mem->ida_gactive = NULL; + IDA_mem->ida_mxgnull = 1; + + /* Initial setup not done yet */ + + IDA_mem->ida_SetupDone = SUNFALSE; + + /* Problem memory has been successfully allocated */ + + IDA_mem->ida_MallocDone = SUNTRUE; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +/* + * IDAReInit + * + * IDAReInit re-initializes IDA's memory for a problem, assuming + * it has already beeen allocated in a prior IDAInit call. + * All problem specification inputs are checked for errors. + * The problem size Neq is assumed to be unchanged since the call + * to IDAInit, and the maximum order maxord must not be larger. + * If any error occurs during reinitialization, it is reported to + * the error handler function. + * The return value is IDA_SUCCESS = 0 if no errors occurred, or + * a negative value otherwise. + */ + +int IDAReInit(void *ida_mem, + realtype t0, N_Vector yy0, N_Vector yp0) +{ + IDAMem IDA_mem; + + /* Check for legal input parameters */ + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAReInit", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Check if problem was malloc'ed */ + + if (IDA_mem->ida_MallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_MALLOC, "IDA", "IDAReInit", MSG_NO_MALLOC); + return(IDA_NO_MALLOC); + } + + /* Check for legal input parameters */ + + if (yy0 == NULL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAReInit", MSG_Y0_NULL); + return(IDA_ILL_INPUT); + } + + if (yp0 == NULL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAReInit", MSG_YP0_NULL); + return(IDA_ILL_INPUT); + } + + /* Copy the input parameters into IDA memory block */ + + IDA_mem->ida_tn = t0; + + /* Initialize the phi array */ + + 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; + + IDA_mem->ida_nge = 0; + + IDA_mem->ida_irfnd = 0; + + /* Initial setup not done yet */ + + IDA_mem->ida_SetupDone = SUNFALSE; + + /* Problem has been successfully re-initialized */ + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +/* + * IDASStolerances + * IDASVtolerances + * IDAWFtolerances + * + * These functions specify the integration tolerances. One of them + * MUST be called before the first call to IDA. + * + * 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). + * IDAWFtolerances specifies a user-provides function (of type IDAEwtFn) + * which will be called to set the error weight vector. + */ + +int IDASStolerances(void *ida_mem, realtype reltol, realtype abstol) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASStolerances", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_MallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_MALLOC, "IDA", "IDASStolerances", MSG_NO_MALLOC); + return(IDA_NO_MALLOC); + } + + /* Check inputs */ + + if (reltol < ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASStolerances", MSG_BAD_RTOL); + return(IDA_ILL_INPUT); + } + + if (abstol < ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASStolerances", MSG_BAD_ATOL); + return(IDA_ILL_INPUT); + } + + /* Copy tolerances into memory */ + + IDA_mem->ida_rtol = reltol; + IDA_mem->ida_Satol = abstol; + + 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; */ + + return(IDA_SUCCESS); +} + + +int IDASVtolerances(void *ida_mem, realtype reltol, N_Vector abstol) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASVtolerances", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_MallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_MALLOC, "IDA", "IDASVtolerances", MSG_NO_MALLOC); + return(IDA_NO_MALLOC); + } + + /* Check inputs */ + + if (reltol < ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASVtolerances", MSG_BAD_RTOL); + return(IDA_ILL_INPUT); + } + + if (N_VMin(abstol) < ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "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; + IDA_mem->ida_liw += IDA_mem->ida_liw1; + IDA_mem->ida_VatolMallocDone = SUNTRUE; + } + + IDA_mem->ida_rtol = reltol; + N_VScale(ONE, abstol, IDA_mem->ida_Vatol); + + 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; */ + + return(IDA_SUCCESS); +} + + +int IDAWFtolerances(void *ida_mem, IDAEwtFn efun) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAWFtolerances", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_MallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_MALLOC, "IDA", "IDAWFtolerances", MSG_NO_MALLOC); + return(IDA_NO_MALLOC); + } + + IDA_mem->ida_itol = IDA_WF; + + IDA_mem->ida_user_efun = SUNTRUE; + IDA_mem->ida_efun = efun; + IDA_mem->ida_edata = NULL; /* will be set to user_data in InitialSetup */ + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +/* + * IDARootInit + * + * IDARootInit initializes a rootfinding problem to be solved + * during the integration of the DAE system. It loads the root + * function pointer and the number of root functions, and allocates + * workspace memory. The return value is IDA_SUCCESS = 0 if no + * errors occurred, or a negative value otherwise. + */ + +int IDARootInit(void *ida_mem, int nrtfn, IDARootFn g) +{ + IDAMem IDA_mem; + int i, nrt; + + /* Check ida_mem pointer */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDARootInit", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + nrt = (nrtfn < 0) ? 0 : nrtfn; + + /* If rerunning IDARootInit() with a different number of root + functions (changing number of gfun components), then free + currently held memory resources */ + if ((nrt != IDA_mem->ida_nrtfn) && (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_rootdir); IDA_mem->ida_rootdir = NULL; + free(IDA_mem->ida_gactive); IDA_mem->ida_gactive = NULL; + + IDA_mem->ida_lrw -= 3 * (IDA_mem->ida_nrtfn); + IDA_mem->ida_liw -= 3 * (IDA_mem->ida_nrtfn); + + } + + /* If IDARootInit() was called with nrtfn == 0, then set ida_nrtfn to + zero and ida_gfun to NULL before returning */ + if (nrt == 0) { + IDA_mem->ida_nrtfn = nrt; + IDA_mem->ida_gfun = NULL; + return(IDA_SUCCESS); + } + + /* If rerunning IDARootInit() with the same number of root functions + (not changing number of gfun components), then check if the root + function argument has changed */ + /* If g != NULL then return as currently reserved memory resources + will suffice */ + if (nrt == IDA_mem->ida_nrtfn) { + if (g != IDA_mem->ida_gfun) { + if (g == 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; + + IDA_mem->ida_lrw -= 3*nrt; + IDA_mem->ida_liw -= 3*nrt; + + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDARootInit", MSG_ROOT_FUNC_NULL); + return(IDA_ILL_INPUT); + } + else { + IDA_mem->ida_gfun = g; + return(IDA_SUCCESS); + } + } + else return(IDA_SUCCESS); + } + + /* Set variable values in IDA memory block */ + IDA_mem->ida_nrtfn = nrt; + if (g == NULL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDARootInit", MSG_ROOT_FUNC_NULL); + return(IDA_ILL_INPUT); + } + else IDA_mem->ida_gfun = g; + + /* Allocate necessary memory and return */ + IDA_mem->ida_glo = NULL; + IDA_mem->ida_glo = (realtype *) malloc(nrt*sizeof(realtype)); + if (IDA_mem->ida_glo == NULL) { + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDA", "IDARootInit", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + IDA_mem->ida_ghi = NULL; + IDA_mem->ida_ghi = (realtype *) malloc(nrt*sizeof(realtype)); + if (IDA_mem->ida_ghi == NULL) { + free(IDA_mem->ida_glo); IDA_mem->ida_glo = NULL; + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDA", "IDARootInit", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + IDA_mem->ida_grout = NULL; + IDA_mem->ida_grout = (realtype *) malloc(nrt*sizeof(realtype)); + if (IDA_mem->ida_grout == NULL) { + free(IDA_mem->ida_glo); IDA_mem->ida_glo = NULL; + free(IDA_mem->ida_ghi); IDA_mem->ida_ghi = NULL; + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDA", "IDARootInit", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + IDA_mem->ida_iroots = NULL; + IDA_mem->ida_iroots = (int *) malloc(nrt*sizeof(int)); + if (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; + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDA", "IDARootInit", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + IDA_mem->ida_rootdir = NULL; + IDA_mem->ida_rootdir = (int *) malloc(nrt*sizeof(int)); + if (IDA_mem->ida_rootdir == 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; + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDA", "IDARootInit", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + 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_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; + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDA", "IDARootInit", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + /* Set default values for rootdir (both directions) */ + for(i=0; i<nrt; i++) IDA_mem->ida_rootdir[i] = 0; + + /* Set default values for gactive (all active) */ + for(i=0; i<nrt; i++) IDA_mem->ida_gactive[i] = SUNTRUE; + + IDA_mem->ida_lrw += 3*nrt; + IDA_mem->ida_liw += 3*nrt; + + return(IDA_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Main solver function + * ----------------------------------------------------------------- + */ + +/* + * IDASolve + * + * This routine is the main driver of the IDA package. + * + * 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 + * problem, it computes a tentative initial step size. + * + * IDASolve supports two modes, specified by itask: + * In the IDA_NORMAL mode, the solver steps until it passes tout and then + * interpolates to obtain y(tout) and yp(tout). + * In the IDA_ONE_STEP mode, it takes one internal step and returns. + * + * IDASolve returns integer values corresponding to success and failure as below: + * + * successful returns: + * + * IDA_SUCCESS + * IDA_TSTOP_RETURN + * + * failed returns: + * + * IDA_ILL_INPUT + * IDA_TOO_MUCH_WORK + * IDA_MEM_NULL + * IDA_TOO_MUCH_ACC + * IDA_CONV_FAIL + * IDA_LSETUP_FAIL + * IDA_LSOLVE_FAIL + * IDA_CONSTR_FAIL + * IDA_ERR_FAIL + * IDA_REP_RES_ERR + * IDA_RES_FAIL + */ + +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, ir; + 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, "IDA", "IDASolve", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Check if problem was malloc'ed */ + + if (IDA_mem->ida_MallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_MALLOC, "IDA", "IDASolve", MSG_NO_MALLOC); + return(IDA_NO_MALLOC); + } + + /* Check for legal arguments */ + + if (yret == NULL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", MSG_YRET_NULL); + return(IDA_ILL_INPUT); + } + IDA_mem->ida_yy = yret; + + if (ypret == NULL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", MSG_YPRET_NULL); + return(IDA_ILL_INPUT); + } + IDA_mem->ida_yp = ypret; + + if (tret == NULL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", MSG_TRET_NULL); + return(IDA_ILL_INPUT); + } + + if ((itask != IDA_NORMAL) && (itask != IDA_ONE_STEP)) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", MSG_BAD_ITASK); + return(IDA_ILL_INPUT); + } + + if (itask == IDA_NORMAL) IDA_mem->ida_toutc = tout; + IDA_mem->ida_taskc = itask; + + 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(IDA_ILL_INPUT); + IDA_mem->ida_SetupDone = SUNTRUE; + } + + /* On first call, check for tout - tn too small, set initial hh, + check for approach to tstop, and scale phi[1] by hh. + Also check for zeros of root function g at and near t0. */ + + tdist = SUNRabs(tout - IDA_mem->ida_tn); + if (tdist == ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", MSG_TOO_CLOSE); + return(IDA_ILL_INPUT); + } + troundoff = TWO * IDA_mem->ida_uround * (SUNRabs(IDA_mem->ida_tn) + SUNRabs(tout)); + if (tdist < troundoff) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", MSG_TOO_CLOSE); + return(IDA_ILL_INPUT); + } + + IDA_mem->ida_hh = IDA_mem->ida_hin; + if ( (IDA_mem->ida_hh != ZERO) && ((tout-IDA_mem->ida_tn)*IDA_mem->ida_hh < ZERO) ) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", MSG_BAD_HINIT); + return(IDA_ILL_INPUT); + } + + if (IDA_mem->ida_hh == ZERO) { + 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; + } + + 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); + 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_h0u = IDA_mem->ida_hh; + IDA_mem->ida_kk = 0; + IDA_mem->ida_kused = 0; /* set in case of an error return before a step */ + + /* Check for exact zeros of the root functions at or near t0. */ + 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); + 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 the convergence test constants epsNewt and toldel */ + IDA_mem->ida_epsNewt = IDA_mem->ida_epcon; + IDA_mem->ida_toldel = PT0001 * IDA_mem->ida_epsNewt; + + } /* end of first-call block. */ + + /* Call lperf function and set nstloc for later performance testing. */ + + if (IDA_mem->ida_lperf != NULL) + IDA_mem->ida_lperf(IDA_mem, 0); + nstloc = 0; + + /* If not the first call, perform all stopping tests. */ + + if (IDA_mem->ida_nst > 0) { + + /* First, check for a root in the last step taken, other than the + last root found, if any. If itask = IDA_ONE_STEP and y(tn) was not + returned because of an intervening root, return y(tn) now. */ + + if (IDA_mem->ida_nrtfn > 0) { + + irfndp = IDA_mem->ida_irfnd; + + ier = IDARcheck2(IDA_mem); + + if (ier == CLOSERT) { + 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); + return(IDA_RTFUNC_FAIL); + } else if (ier == RTFOUND) { + IDA_mem->ida_tretlast = *tret = IDA_mem->ida_tlo; + return(IDA_ROOT_RETURN); + } + + /* If tn is distinct from tretlast (within roundoff), + check remaining interval for roots */ + troundoff = HUNDRED * IDA_mem->ida_uround * (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)); + if ( SUNRabs(IDA_mem->ida_tn - IDA_mem->ida_tretlast) > troundoff ) { + ier = IDARcheck3(IDA_mem); + if (ier == IDA_SUCCESS) { /* no root found */ + IDA_mem->ida_irfnd = 0; + if ((irfndp == 1) && (itask == IDA_ONE_STEP)) { + IDA_mem->ida_tretlast = *tret = IDA_mem->ida_tn; + ier = IDAGetSolution(IDA_mem, IDA_mem->ida_tn, yret, ypret); + return(IDA_SUCCESS); + } + } else if (ier == RTFOUND) { /* a new root was found */ + IDA_mem->ida_irfnd = 1; + 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); + return(IDA_RTFUNC_FAIL); + } + } + + } /* end of root stop check */ + + + /* Now test for all other stop conditions. */ + + istate = IDAStopTest1(IDA_mem, tout, tret, yret, ypret, itask); + if (istate != CONTINUE_STEPS) return(istate); + } + + /* 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, "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. */ + } + + /* Call lperf to generate warnings of poor performance. */ + + if (IDA_mem->ida_lperf != NULL) + IDA_mem->ida_lperf(IDA_mem, 1); + + /* Reset and check ewt (if not first call). */ + + if (IDA_mem->ida_nst > 0) { + + 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", "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); + + istate = IDA_ILL_INPUT; + ier = IDAGetSolution(IDA_mem, IDA_mem->ida_tn, yret, ypret); + *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tn; + break; + + } + + } + + /* Check for too much accuracy requested. */ + + nrm = IDAWrmsNorm(IDA_mem, IDA_mem->ida_phi[0], IDA_mem->ida_ewt, + IDA_mem->ida_suppressalg); + 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); + 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); + break; + } + + /* Call IDAStep to take a step. */ + + sflag = IDAStep(IDA_mem); + + /* Process all failed-step cases, and exit loop. */ + + if (sflag != IDA_SUCCESS) { + istate = IDAHandleFailure(IDA_mem, sflag); + *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tn; + ier = IDAGetSolution(IDA_mem, IDA_mem->ida_tn, yret, ypret); + break; + } + + nstloc++; + + /* After successful step, check for stop conditions; continue or break. */ + + /* First check for root in the last step taken. */ + + if (IDA_mem->ida_nrtfn > 0) { + + ier = IDARcheck3(IDA_mem); + + if (ier == RTFOUND) { /* A new root was found */ + IDA_mem->ida_irfnd = 1; + istate = IDA_ROOT_RETURN; + 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); + istate = IDA_RTFUNC_FAIL; + break; + } + + /* If we are at the end of the first step and we still have + * some event functions that are inactive, issue a warning + * as this may indicate a user error in the implementation + * of the root function. */ + + if (IDA_mem->ida_nst==1) { + inactive_roots = SUNFALSE; + for (ir=0; ir<IDA_mem->ida_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, "IDA", "IDASolve", MSG_INACTIVE_ROOTS); + } + } + + } + + /* Now check all other stop conditions. */ + + istate = IDAStopTest2(IDA_mem, tout, tret, yret, ypret, itask); + if (istate != CONTINUE_STEPS) break; + + } /* End of step loop */ + + return(istate); +} + +/* + * ----------------------------------------------------------------- + * Interpolated output + * ----------------------------------------------------------------- + */ + +/* + * 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 + * 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 + * 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 + * + */ + +int IDAGetDky(void *ida_mem, realtype t, int k, N_Vector dky) +{ + IDAMem IDA_mem; + realtype tfuzz, tp, delt, psij_1; + int i, j, retval; + realtype cjk [MXORDP1]; + realtype cjk_1[MXORDP1]; + + /* Check ida_mem */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetDky", MSG_NO_MEM); + return (IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + if (dky == NULL) { + IDAProcessError(IDA_mem, IDA_BAD_DKY, "IDA", "IDAGetDky", MSG_NULL_DKY); + return(IDA_BAD_DKY); + } + + if ((k < 0) || (k > IDA_mem->ida_kused)) { + IDAProcessError(IDA_mem, IDA_BAD_K, "IDA", "IDAGetDky", 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; + if ((t - tp)*IDA_mem->ida_hh < ZERO) { + IDAProcessError(IDA_mem, IDA_BAD_T, "IDA", "IDAGetDky", MSG_BAD_T, t, + IDA_mem->ida_tn-IDA_mem->ida_hused, IDA_mem->ida_tn); + return(IDA_BAD_T); + } + + /* Initialize the c_j^(k) and c_k^(k-1) */ + for(i=0; i<MXORDP1; i++) { + cjk [i] = 0; + cjk_1[i] = 0; + } + + delt = t-IDA_mem->ida_tn; + + for(i=0; i<=k; i++) { + + /* 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] + + For k=0, j=1: c_1 = c_0^(-1) + (delt+psi[-1]) / psi[0] + + 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 + for psi[j-2] when j>1 + */ + if(i==0) { + + cjk[i] = 1; + psij_1 = 0; + }else { + /* i i-1 1 + c_i^(i) can be always updated since c_i^(i) = ----- -------- ... ----- + psi_j psi_{j-1} psi_1 + */ + cjk[i] = cjk[i-1]*i / IDA_mem->ida_psi[i-1]; + psij_1 = IDA_mem->ida_psi[i-1]; + } + + /* update c_j^(i) */ + + /*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]; + psij_1 = IDA_mem->ida_psi[j-1]; + } + + /* save existing c_j^(i)'s */ + for(j=i+1; j<=IDA_mem->ida_kused-k+i; j++) cjk_1[j] = cjk[j]; + } + + /* Compute sum (c_j(t) * phi(t)) */ + + /* 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); +} + +/* + * ----------------------------------------------------------------- + * Deallocation function + * ----------------------------------------------------------------- + */ + +/* + * IDAFree + * + * This routine frees the problem memory allocated by IDAInit + * Such memory includes all the vectors allocated by IDAAllocVectors, + * and the memory lmem for the linear solver (deallocated by a call + * to lfree). + */ + +void IDAFree(void **ida_mem) +{ + IDAMem IDA_mem; + + if (*ida_mem == NULL) return; + + IDA_mem = (IDAMem) (*ida_mem); + + IDAFreeVectors(IDA_mem); + + /* if IDA created the nonlinear solver object then free it */ + if (IDA_mem->ownNLS) { + SUNNonlinSolFree(IDA_mem->NLS); + IDA_mem->ownNLS = SUNFALSE; + } + + 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_rootdir); IDA_mem->ida_rootdir = NULL; + free(IDA_mem->ida_gactive); IDA_mem->ida_gactive = NULL; + } + + free(*ida_mem); + *ida_mem = NULL; +} + +/* + * ================================================================= + * PRIVATE FUNCTIONS + * ================================================================= + */ + +/* + * IDACheckNvector + * + * This routine checks if all required vector operations are present. + * If any of them is missing it returns SUNFALSE. + */ + +static booleantype IDACheckNvector(N_Vector tmpl) +{ + if ((tmpl->ops->nvclone == NULL) || + (tmpl->ops->nvdestroy == NULL) || + (tmpl->ops->nvlinearsum == NULL) || + (tmpl->ops->nvconst == NULL) || + (tmpl->ops->nvprod == NULL) || + (tmpl->ops->nvscale == NULL) || + (tmpl->ops->nvabs == NULL) || + (tmpl->ops->nvinv == NULL) || + (tmpl->ops->nvaddconst == NULL) || + (tmpl->ops->nvwrmsnorm == NULL) || + (tmpl->ops->nvmin == NULL)) + return(SUNFALSE); + else + return(SUNTRUE); +} + +/* + * ----------------------------------------------------------------- + * Memory allocation/deallocation + * ----------------------------------------------------------------- + */ + +/* + * IDAAllocVectors + * + * 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 + * returns SUNFALSE. + * This routine also sets the optional outputs lrw and liw, which are + * (respectively) the lengths of the real and integer work spaces + * allocated here. + */ + +static booleantype IDAAllocVectors(IDAMem IDA_mem, N_Vector tmpl) +{ + int i, j, maxcol; + + /* Allocate ewt, ee, delta, ypredict, yppredict, savres, tempv1, tempv2, tempv3 */ + + IDA_mem->ida_ewt = N_VClone(tmpl); + if (IDA_mem->ida_ewt == NULL) return(SUNFALSE); + + IDA_mem->ida_ee = N_VClone(tmpl); + if (IDA_mem->ida_ee == NULL) { + N_VDestroy(IDA_mem->ida_ewt); + return(SUNFALSE); + } + + IDA_mem->ida_delta = N_VClone(tmpl); + if (IDA_mem->ida_delta == NULL) { + N_VDestroy(IDA_mem->ida_ewt); + N_VDestroy(IDA_mem->ida_ee); + return(SUNFALSE); + } + + IDA_mem->ida_yypredict = N_VClone(tmpl); + if (IDA_mem->ida_yypredict == NULL) { + N_VDestroy(IDA_mem->ida_ewt); + N_VDestroy(IDA_mem->ida_ee); + N_VDestroy(IDA_mem->ida_delta); + return(SUNFALSE); + } + + IDA_mem->ida_yppredict = N_VClone(tmpl); + if (IDA_mem->ida_yppredict == NULL) { + N_VDestroy(IDA_mem->ida_ewt); + N_VDestroy(IDA_mem->ida_ee); + N_VDestroy(IDA_mem->ida_delta); + N_VDestroy(IDA_mem->ida_yypredict); + return(SUNFALSE); + } + + IDA_mem->ida_savres = N_VClone(tmpl); + if (IDA_mem->ida_savres == NULL) { + 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); + return(SUNFALSE); + } + + IDA_mem->ida_tempv1 = N_VClone(tmpl); + if (IDA_mem->ida_tempv1 == NULL) { + 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); + return(SUNFALSE); + } + + IDA_mem->ida_tempv2 = N_VClone(tmpl); + if (IDA_mem->ida_tempv2 == NULL) { + 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); + return(SUNFALSE); + } + + IDA_mem->ida_tempv3 = N_VClone(tmpl); + if (IDA_mem->ida_tempv3 == NULL) { + 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); + return(SUNFALSE); + } + + + /* Allocate phi[0] ... phi[maxord]. Make sure phi[2] and phi[3] are + allocated (for use as temporary vectors), regardless of maxord. */ + + maxcol = SUNMAX(IDA_mem->ida_maxord,3); + for (j=0; j <= maxcol; j++) { + IDA_mem->ida_phi[j] = N_VClone(tmpl); + if (IDA_mem->ida_phi[j] == NULL) { + 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); + for (i=0; i < j; i++) N_VDestroy(IDA_mem->ida_phi[i]); + return(SUNFALSE); + } + } + + /* Update solver workspace lengths */ + IDA_mem->ida_lrw += (maxcol + 10)*IDA_mem->ida_lrw1; + IDA_mem->ida_liw += (maxcol + 10)*IDA_mem->ida_liw1; + + /* Store the value of maxord used here */ + IDA_mem->ida_maxord_alloc = IDA_mem->ida_maxord; + + return(SUNTRUE); +} + +/* + * IDAfreeVectors + * + * This routine frees the IDA vectors allocated for IDA. + */ + +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); + maxcol = SUNMAX(IDA_mem->ida_maxord_alloc,3); + for(j=0; j <= maxcol; j++) N_VDestroy(IDA_mem->ida_phi[j]); + + 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); + 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_lrw -= IDA_mem->ida_lrw1; + IDA_mem->ida_liw -= IDA_mem->ida_liw1; + } + + if (IDA_mem->ida_idMallocDone) { + N_VDestroy(IDA_mem->ida_id); + IDA_mem->ida_lrw -= IDA_mem->ida_lrw1; + IDA_mem->ida_liw -= IDA_mem->ida_liw1; + } + +} + +/* + * ----------------------------------------------------------------- + * Initial setup + * ----------------------------------------------------------------- + */ + +/* + * IDAInitialSetup + * + * 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 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; + + /* 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); + 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); + 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); + return(IDA_ILL_INPUT); + } + + /* Set data for efun */ + 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 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, "IDA", "IDAInitialSetup", MSG_FAIL_EWT); + else + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAInitialSetup", MSG_BAD_EWT); + return(IDA_ILL_INPUT); + } + + /* Check to see if y0 satisfies constraints. */ + 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); + return(IDA_ILL_INPUT); + } + } + + /* Call linit function if it exists. */ + 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); + return(IDA_LINIT_FAIL); + } + } + + /* Initialize the nonlinear solver (must occur after linear solver is initialize) so + * that lsetup and lsolve pointer have been set */ + ier = idaNlsInit(IDA_mem); + if (ier != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAInitialSetup", MSG_NLS_INIT_FAIL); + return(IDA_NLS_INIT_FAIL); + } + + return(IDA_SUCCESS); +} + +/* + * IDAEwtSet + * + * This routine is responsible for loading the error weight vector + * ewt, according to itol, as follows: + * (1) ewt[i] = 1 / (rtol * SUNRabs(ycur[i]) + atol), i=0,...,Neq-1 + * if itol = IDA_SS + * (2) ewt[i] = 1 / (rtol * SUNRabs(ycur[i]) + atol[i]), i=0,...,Neq-1 + * if itol = IDA_SV + * + * IDAEwtSet 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 IDAEwtSetSS, IDAEwtSetSV. + */ + +int IDAEwtSet(N_Vector ycur, N_Vector weight, void *data) +{ + IDAMem IDA_mem; + int flag = 0; + + /* data points to IDA_mem here */ + + IDA_mem = (IDAMem) data; + + switch(IDA_mem->ida_itol) { + case IDA_SS: + flag = IDAEwtSetSS(IDA_mem, ycur, weight); + break; + case IDA_SV: + flag = IDAEwtSetSV(IDA_mem, ycur, weight); + break; + } + return(flag); +} + +/* + * 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 + * undefined. + */ + +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); + N_VInv(IDA_mem->ida_tempv1, weight); + return(0); +} + +/* + * 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 + * 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_VInv(IDA_mem->ida_tempv1, weight); + return(0); +} + +/* + * ----------------------------------------------------------------- + * Stopping tests + * ----------------------------------------------------------------- + */ + +/* + * IDAStopTest1 + * + * This routine tests for stop conditions before taking a step. + * The tests depend on the value of itask. + * The variable tretlast is the previously returned value of tret. + * + * The return values are: + * 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 + * + * 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, + N_Vector yret, N_Vector ypret, int itask) +{ + int ier; + realtype troundoff; + + switch (itask) { + + case IDA_NORMAL: + + 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); + return(IDA_ILL_INPUT); + } + } + + /* Test for tout = tretlast, and for tn past tout. */ + if (tout == IDA_mem->ida_tretlast) { + *tret = IDA_mem->ida_tretlast = tout; + return(IDA_SUCCESS); + } + if ((IDA_mem->ida_tn - tout)*IDA_mem->ida_hh >= ZERO) { + ier = IDAGetSolution(IDA_mem, tout, yret, ypret); + if (ier != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", MSG_BAD_TOUT, tout); + return(IDA_ILL_INPUT); + } + *tret = IDA_mem->ida_tretlast = tout; + return(IDA_SUCCESS); + } + + if (IDA_mem->ida_tstopset) { + troundoff = HUNDRED * IDA_mem->ida_uround * (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)); + 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); + return(IDA_ILL_INPUT); + } + *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tstop; + 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) + 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) { + /* 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); + return(IDA_ILL_INPUT); + } + } + + /* Test for tn past tretlast. */ + if ((IDA_mem->ida_tn - IDA_mem->ida_tretlast)*IDA_mem->ida_hh > ZERO) { + ier = IDAGetSolution(IDA_mem, IDA_mem->ida_tn, yret, ypret); + *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tn; + return(IDA_SUCCESS); + } + + if (IDA_mem->ida_tstopset) { + troundoff = HUNDRED * IDA_mem->ida_uround * (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)); + 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); + return(IDA_ILL_INPUT); + } + *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tstop; + 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) + 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. */ +} + +/* + * IDAStopTest2 + * + * This routine tests for stop conditions after taking a step. + * The tests depend on the value of itask. + * + * The return values are: + * 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 + * + * In the two cases with tstop, this routine may reset the stepsize hh + * to cause the next step to reach tstop exactly. + * + * In the two cases with ONE_STEP mode, no interpolation to tn is needed + * because yret and ypret already contain the current y and y' values. + * + * Note: No test is made for an error return from IDAGetSolution here, + * because the same test was made prior to the step. + */ + +static int IDAStopTest2(IDAMem IDA_mem, realtype tout, realtype *tret, + N_Vector yret, N_Vector ypret, int itask) +{ + /* int ier; */ + realtype troundoff; + + switch (itask) { + + case IDA_NORMAL: + + /* Test for tn past tout. */ + if ((IDA_mem->ida_tn - tout)*IDA_mem->ida_hh >= ZERO) { + /* ier = */ IDAGetSolution(IDA_mem, tout, yret, ypret); + *tret = IDA_mem->ida_tretlast = tout; + return(IDA_SUCCESS); + } + + if (IDA_mem->ida_tstopset) { + /* Test for tn at tstop and for tn near tstop */ + troundoff = HUNDRED * IDA_mem->ida_uround * (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)); + if (SUNRabs(IDA_mem->ida_tn - IDA_mem->ida_tstop) <= troundoff) { + /* ier = */ IDAGetSolution(IDA_mem, IDA_mem->ida_tstop, yret, ypret); + *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tstop; + 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) + 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) { + /* Test for tn at tstop and for tn near tstop */ + troundoff = HUNDRED * IDA_mem->ida_uround * (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)); + if (SUNRabs(IDA_mem->ida_tn - IDA_mem->ida_tstop) <= troundoff) { + /* ier = */ IDAGetSolution(IDA_mem, IDA_mem->ida_tstop, yret, ypret); + *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tstop; + 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) + IDA_mem->ida_hh = (IDA_mem->ida_tstop - IDA_mem->ida_tn)*(ONE - FOUR * IDA_mem->ida_uround); + } + + *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tn; + return(IDA_SUCCESS); + + } + return IDA_ILL_INPUT; /* This return should never happen. */ +} + +/* + * ----------------------------------------------------------------- + * Error handler + * ----------------------------------------------------------------- + */ + +/* + * IDAHandleFailure + * + * This routine prints error messages for all cases of failure by + * IDAStep. It returns to IDASolve the value that it is to return to + * the user. + */ + +static int IDAHandleFailure(IDAMem IDA_mem, int sflag) +{ + /* Depending on sflag, print error message and return error flag */ + 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); + 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); + return(IDA_CONV_FAIL); + + case IDA_LSETUP_FAIL: + 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); + 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); + return(IDA_REP_RES_ERR); + + case IDA_RES_FAIL: + 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); + return(IDA_CONSTR_FAIL); + + case IDA_MEM_NULL: + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASolve", MSG_NO_MEM); + return(IDA_MEM_NULL); + + case SUN_NLS_MEM_NULL: + IDAProcessError(IDA_mem, IDA_MEM_NULL, "IDA", "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", + MSG_NLS_SETUP_FAILED, IDA_mem->ida_tn); + return(IDA_NLS_SETUP_FAIL); + } + + /* This return should never happen */ + IDAProcessError(IDA_mem, IDA_UNRECOGNIZED_ERROR, "IDA", "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 + * ----------------------------------------------------------------- + */ + +/* + * IDAStep + * + * This routine performs one internal IDA step, from tn to tn + hh. + * It calls other routines to do all the work. + * + * It solves a system of differential/algebraic equations of the form + * F(t,y,y') = 0, for one step. In IDA, tt is used for t, + * 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 + * coefficient forms of backward differentiation formulas. + * The code adjusts the stepsize and order to control the local error per step. + * + * The main operations done here are as follows: + * * initialize various quantities; + * * setting of multistep method coefficients; + * * solution of the nonlinear system for yy at t = tn + hh; + * * deciding on order reduction and testing the local error; + * * attempting to recover from failure in nonlinear solver or error test; + * * resetting stepsize and order for the next step. + * * updating phi and other state data if successful; + * + * On a failure in the nonlinear system solution or error test, the + * step may be reattempted, depending on the nature of the failure. + * + * Variables or arrays (all in the IDAMem structure) used in IDAStep are: + * + * 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 + * 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. + * 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 + * 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 + */ + +static int IDAStep(IDAMem IDA_mem) +{ + realtype saved_t, ck; + realtype err_k, err_km1; + int ncf, nef; + int nflag, kflag; + + saved_t = IDA_mem->ida_tn; + ncf = nef = 0; + + if (IDA_mem->ida_nst == ZERO){ + IDA_mem->ida_kk = 1; + IDA_mem->ida_kused = 0; + IDA_mem->ida_hused = ZERO; + IDA_mem->ida_psi[0] = IDA_mem->ida_hh; + IDA_mem->ida_cj = ONE/IDA_mem->ida_hh; + IDA_mem->ida_phase = 0; + IDA_mem->ida_ns = 0; + } + + /* To prevent 'unintialized variable' warnings */ + err_k = ZERO; + err_km1 = ZERO; + + /* Looping point for attempts to take a step */ + + for(;;) { + + /*----------------------- + Set method coefficients + -----------------------*/ + + IDASetCoeffs(IDA_mem, &ck); + + kflag = IDA_SUCCESS; + + /*---------------------------------------------------- + If tn is past tstop (by roundoff), reset it to tstop. + -----------------------------------------------------*/ + + IDA_mem->ida_tn = IDA_mem->ida_tn + IDA_mem->ida_hh; + if (IDA_mem->ida_tstopset) { + if ((IDA_mem->ida_tn - IDA_mem->ida_tstop)*IDA_mem->ida_hh > ZERO) + IDA_mem->ida_tn = IDA_mem->ida_tstop; + } + + /*----------------------- + Advance state variables + -----------------------*/ + + /* Compute predicted values for yy and yp */ + IDAPredict(IDA_mem); + + /* Nonlinear system solution */ + nflag = IDANls(IDA_mem); + + /* If NLS was successful, perform error test */ + if (nflag == IDA_SUCCESS) + nflag = IDATestError(IDA_mem, ck, &err_k, &err_km1); + + /* Test for convergence or error test failures */ + if (nflag != IDA_SUCCESS) { + + /* restore and decide what to do */ + IDARestore(IDA_mem, saved_t); + kflag = IDAHandleNFlag(IDA_mem, nflag, err_k, err_km1, + &(IDA_mem->ida_ncfn), &ncf, + &(IDA_mem->ida_netf), &nef); + + /* exit on nonrecoverable failure */ + if (kflag != PREDICT_AGAIN) return(kflag); + + /* recoverable error; predict again */ + if(IDA_mem->ida_nst==0) IDAReset(IDA_mem); + continue; + + } + + /* kflag == IDA_SUCCESS */ + break; + + } + + /* Nonlinear system solve and error test were both successful; + update data, and consider change of step and/or order */ + + 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 + it will be overwritten by + IDASolve()->IDAStep()->IDANls() + 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); + + 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 + * with ns = k + 2, the coefficients alpha, etc. need not be reset here. + * Also, IDACompleteStep prohibits an order increase until ns = k + 2. + */ + +static void IDASetCoeffs(IDAMem IDA_mem, realtype *ck) +{ + int i; + realtype temp1, temp2, alpha0, alphas; + + /* Set coefficients for the current stepsize h */ + + 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) { + 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++){ + 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_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; + } + /* compute alphas, alpha0 */ + alphas = ZERO; + alpha0 = ZERO; + for(i=0; i<IDA_mem->ida_kk ;i++){ + alphas = alphas - ONE/(i+1); + alpha0 = alpha0 - IDA_mem->ida_alpha[i]; + } + + /* 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 */ + + /* 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, + IDA_mem->ida_beta+IDA_mem->ida_ns, + IDA_mem->ida_phi+IDA_mem->ida_ns, + IDA_mem->ida_phi+IDA_mem->ida_ns); + +} + +/* + * ----------------------------------------------------------------- + * Nonlinear solver functions + * ----------------------------------------------------------------- + */ + +/* + * IDANls + * + * This routine attempts to solve the nonlinear system using the linear + * solver specified. NOTE: this routine uses N_Vector ee as the scratch + * vector tempv3 passed to lsetup. + * + * Possible return values: + * + * IDA_SUCCESS + * + * IDA_RES_RECVR IDA_RES_FAIL + * IDA_LSETUP_RECVR IDA_LSETUP_FAIL + * IDA_LSOLVE_RECVR IDA_LSOLVE_FAIL + * + * IDA_CONSTR_RECVR + * SUN_NLS_CONV_RECVR + * IDA_MEM_NULL + */ + +static int IDANls(IDAMem IDA_mem) +{ + int retval; + booleantype constraintsPassed, callLSetup; + realtype temp1, temp2, vnorm; + + callLSetup = SUNFALSE; + + /* Initialize if the first time called */ + + if (IDA_mem->ida_nst == 0){ + IDA_mem->ida_cjold = IDA_mem->ida_cj; + IDA_mem->ida_ss = TWENTY; + if (IDA_mem->ida_lsetup) callLSetup = SUNTRUE; + } + + /* Decide if lsetup is to be called */ + + if (IDA_mem->ida_lsetup) { + IDA_mem->ida_cjratio = IDA_mem->ida_cj / IDA_mem->ida_cjold; + temp1 = (ONE - XRATE) / (ONE + XRATE); + temp2 = ONE/temp1; + if (IDA_mem->ida_cjratio < temp1 || IDA_mem->ida_cjratio > temp2) callLSetup = SUNTRUE; + if (IDA_mem->ida_cj != IDA_mem->ida_cjlast) IDA_mem->ida_ss = HUNDRED; + } + + /* initial guess for the correction to the predictor */ + N_VConst(ZERO, IDA_mem->ida_delta); + + /* call nonlinear solver setup if it exists */ + if ((IDA_mem->NLS)->ops->setup) { + retval = SUNNonlinSolSetup(IDA_mem->NLS, IDA_mem->ida_delta, 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_ewt, IDA_mem->ida_epsNewt, + callLSetup, IDA_mem); + + /* update yy and yp based on the final correction from the nonlinear solve */ + 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); + + /* return if nonlinear solver failed */ + if (retval != IDA_SUCCESS) return(retval); + + /* 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 (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); + } + } + } + return(IDA_SUCCESS); +} + + +/* + * IDAPredict + * + * This routine predicts the new values for vectors yy and yp. + */ + +static void IDAPredict(IDAMem IDA_mem) +{ + int j; + + for(j=0; j<=IDA_mem->ida_kk; j++) + IDA_mem->ida_cvals[j] = ONE; + + (void) N_VLinearCombination(IDA_mem->ida_kk+1, IDA_mem->ida_cvals, + IDA_mem->ida_phi, IDA_mem->ida_yypredict); + + (void) N_VLinearCombination(IDA_mem->ida_kk, IDA_mem->ida_gamma+1, + IDA_mem->ida_phi+1, IDA_mem->ida_yppredict); +} + +/* + * ----------------------------------------------------------------- + * Error test + * ----------------------------------------------------------------- + */ + +/* + * IDATestError + * + * 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, + realtype *err_k, realtype *err_km1) +{ + realtype err_km2; /* estimated error at k-2 */ + 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); + + 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; + 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; + + /* 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; + + } + + } + + /* Perform error test */ + if (ck * enorm_k > ONE) return(ERROR_TEST_FAIL); + else return(IDA_SUCCESS); +} + +/* + * IDARestore + * + * This routine restores tn, psi, and phi in the event of a failure. + * It changes back phi-star to phi (changed in IDASetCoeffs) + */ + +static void IDARestore(IDAMem IDA_mem, realtype saved_t) +{ + int j; + + IDA_mem->ida_tn = saved_t; + + for (j = 1; j <= IDA_mem->ida_kk; j++) + IDA_mem->ida_psi[j-1] = IDA_mem->ida_psi[j] - IDA_mem->ida_hh; + + if (IDA_mem->ida_ns <= IDA_mem->ida_kk) { + + 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, + IDA_mem->ida_cvals, + IDA_mem->ida_phi+IDA_mem->ida_ns, + IDA_mem->ida_phi+IDA_mem->ida_ns); + } + +} + +/* + * ----------------------------------------------------------------- + * Handler for convergence and/or error test failures + * ----------------------------------------------------------------- + */ + +/* + * IDAHandleNFlag + * + * 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. + * + * Possible nflag values (input): + * + * --convergence failures-- + * IDA_RES_RECVR > 0 + * IDA_LSOLVE_RECVR > 0 + * IDA_CONSTR_RECVR > 0 + * SUN_NLS_CONV_RECV > 0 + * IDA_RES_FAIL < 0 + * IDA_LSOLVE_FAIL < 0 + * IDA_LSETUP_FAIL < 0 + * + * --error test failure-- + * ERROR_TEST_FAIL > 0 + * + * Possible kflag values (output): + * + * --recoverable-- + * PREDICT_AGAIN + * + * --nonrecoverable-- + * IDA_CONSTR_FAIL + * IDA_REP_RES_ERR + * IDA_ERR_FAIL + * IDA_CONV_FAIL + * IDA_RES_FAIL + * IDA_LSETUP_FAIL + * IDA_LSOLVE_FAIL + */ + +static int IDAHandleNFlag(IDAMem IDA_mem, int nflag, realtype err_k, realtype err_km1, + long int *ncfnPtr, int *ncfPtr, long int *netfPtr, int *nefPtr) +{ + realtype err_knew; + + IDA_mem->ida_phase = 1; + + if (nflag != ERROR_TEST_FAIL) { + + /*----------------------- + Nonlinear solver failed + -----------------------*/ + + (*ncfPtr)++; /* local counter for convergence failures */ + (*ncfnPtr)++; /* global counter for convergence failures */ + + if (nflag < 0) { /* nonrecoverable failure */ + + return(nflag); + + } 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; + IDA_mem->ida_hh *= IDA_mem->ida_rr; + + /* 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_CONSTR_RECVR) return(IDA_CONSTR_FAIL); + else return(IDA_CONV_FAIL); + } + + } else { + + /*----------------- + 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. + 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) ); + 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. + 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; + IDA_mem->ida_rr = QUARTER; + IDA_mem->ida_hh *= IDA_mem->ida_rr; + return(PREDICT_AGAIN); + + } else { + + /* Too many error test failures */ + return(IDA_ERR_FAIL); + + } + + } + +} + +/* + * IDAReset + * + * 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]. + */ + +static void IDAReset(IDAMem IDA_mem) +{ + IDA_mem->ida_psi[0] = IDA_mem->ida_hh; + + N_VScale(IDA_mem->ida_rr, IDA_mem->ida_phi[1], IDA_mem->ida_phi[1]); +} + +/* + * ----------------------------------------------------------------- + * Function called after a successful step + * ----------------------------------------------------------------- + */ + +/* + * IDACompleteStep + * + * 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. + */ + +static void IDACompleteStep(IDAMem IDA_mem, realtype err_k, realtype err_km1) +{ + int j, kdiff, action; + realtype terr_k, terr_km1, terr_kp1; + realtype err_knew, err_kp1; + realtype enorm, tmp, hnew; + + IDA_mem->ida_nst++; + kdiff = IDA_mem->ida_kk - IDA_mem->ida_kused; + 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) || + (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 + 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 + of the neccessary information is available yet. */ + + if (IDA_mem->ida_phase == 0) { + + 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 ) + hnew /= tmp; + IDA_mem->ida_hh = hnew; + } + + } 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;} + + /* 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); + 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; + + if (IDA_mem->ida_kk == 1) { + if (terr_kp1 >= HALF * terr_k) {action = MAINTAIN; goto takeaction;} + else {action = RAISE; goto takeaction;} + } 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 {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; } + + /* 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) ); + + 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 ) { + 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 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]); + } + + /* Update phi arrays */ + + /* To update phi arrays compute X += Z where */ + /* X = [ phi[kused], phi[kused-1], phi[kused-2], ... phi[1] ] */ + /* Z = [ ee, phi[kused], phi[kused-1], ... phi[0] ] */ + + IDA_mem->ida_Zvecs[0] = IDA_mem->ida_ee; + IDA_mem->ida_Xvecs[0] = IDA_mem->ida_phi[IDA_mem->ida_kused]; + for (j=1; j<=IDA_mem->ida_kused; j++) { + IDA_mem->ida_Zvecs[j] = IDA_mem->ida_phi[IDA_mem->ida_kused-j+1]; + IDA_mem->ida_Xvecs[j] = IDA_mem->ida_phi[IDA_mem->ida_kused-j]; + } + + (void) N_VLinearSumVectorArray(IDA_mem->ida_kused+1, + ONE, IDA_mem->ida_Xvecs, + ONE, IDA_mem->ida_Zvecs, + IDA_mem->ida_Xvecs); +} + +/* + * ----------------------------------------------------------------- + * 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, "IDA", "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, "IDA", "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 function + * ----------------------------------------------------------------- + */ + +/* + * IDAWrmsNorm + * + * Returns the WRMS norm of vector x with weights w. + * If mask = SUNTRUE, the weight vector w is masked by id, i.e., + * 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, + booleantype mask) +{ + realtype nrm; + + if (mask) nrm = N_VWrmsNormMask(x, w, IDA_mem->ida_id); + else nrm = N_VWrmsNorm(x, w); + + return(nrm); +} + +/* + * ----------------------------------------------------------------- + * Functions for rootfinding + * ----------------------------------------------------------------- + */ + +/* + * IDARcheck1 + * + * This routine completes the initialization of rootfinding memory + * information, and checks whether g has a zero both at and very near + * the initial point of the IVP. + * + * This routine returns an int equal to: + * IDA_RTFUNC_FAIL < 0 if the g function failed, or + * IDA_SUCCESS = 0 otherwise. + */ + +static int IDARcheck1(IDAMem IDA_mem) +{ + int i, retval; + realtype smallh, hratio, tplus; + booleantype zroot; + + 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; + + /* 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], + IDA_mem->ida_glo, IDA_mem->ida_user_data); + IDA_mem->ida_nge = 1; + if (retval != 0) return(IDA_RTFUNC_FAIL); + + zroot = SUNFALSE; + for (i = 0; i < IDA_mem->ida_nrtfn; i++) { + if (SUNRabs(IDA_mem->ida_glo[i]) == ZERO) { + zroot = SUNTRUE; + IDA_mem->ida_gactive[i] = SUNFALSE; + } + } + 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); + 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_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) { + IDA_mem->ida_gactive[i] = SUNTRUE; + IDA_mem->ida_glo[i] = IDA_mem->ida_ghi[i]; + } + } + return(IDA_SUCCESS); +} + +/* + * IDARcheck2 + * + * This routine checks for exact zeros of g at the last root found, + * if the last return was a root. It then checks for a close pair of + * zeros (an error condition), and for a new root at a nearby point. + * The array glo = g(tlo) at the left endpoint of the search interval + * is adjusted if necessary to assure that all g_i are nonzero + * there, before returning to do a root search in the interval. + * + * On entry, tlo = tretlast is the last value of tret returned by + * IDASolve. This may be the previous tn, the previous tout value, + * or the last root location. + * + * This routine returns an int equal to: + * IDA_RTFUNC_FAIL < 0 if the g function failed, or + * CLOSERT = 3 if a close pair of zeros was found, or + * RTFOUND = 1 if a new zero of g was found near tlo, or + * IDA_SUCCESS = 0 otherwise. + */ + +static int IDARcheck2(IDAMem IDA_mem) +{ + int i, retval; + realtype smallh, hratio, tplus; + booleantype zroot; + + 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); + IDA_mem->ida_nge++; + if (retval != 0) return(IDA_RTFUNC_FAIL); + + zroot = SUNFALSE; + for (i = 0; i < IDA_mem->ida_nrtfn; i++) + IDA_mem->ida_iroots[i] = 0; + for (i = 0; i < IDA_mem->ida_nrtfn; i++) { + if (!IDA_mem->ida_gactive[i]) continue; + if (SUNRabs(IDA_mem->ida_glo[i]) == ZERO) { + zroot = SUNTRUE; + IDA_mem->ida_iroots[i] = 1; + } + } + 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; + 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); + } 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_nge++; + if (retval != 0) return(IDA_RTFUNC_FAIL); + + /* Check for close roots (error return), for a new zero at tlo+smallh, + and for a g_i that changed from zero to nonzero. */ + zroot = SUNFALSE; + 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_iroots[i] == 1) return(CLOSERT); + zroot = SUNTRUE; + IDA_mem->ida_iroots[i] = 1; + } else { + if (IDA_mem->ida_iroots[i] == 1) + IDA_mem->ida_glo[i] = IDA_mem->ida_ghi[i]; + } + } + if (zroot) return(RTFOUND); + return(IDA_SUCCESS); +} + +/* + * IDARcheck3 + * + * This routine interfaces to IDARootfind to look for a root of g + * between tlo and either tn or tout, whichever comes first. + * Only roots beyond tlo in the direction of integration are sought. + * + * This routine returns an int equal to: + * IDA_RTFUNC_FAIL < 0 if the g function failed, or + * RTFOUND = 1 if a root of g was found, or + * IDA_SUCCESS = 0 otherwise. + */ + +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_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; + } + + /* Get y and y' at thi. */ + (void) IDAGetSolution(IDA_mem, IDA_mem->ida_thi, IDA_mem->ida_yy, IDA_mem->ida_yp); + + + /* 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_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; + ier = IDARootfind(IDA_mem); + if (ier == IDA_RTFUNC_FAIL) return(IDA_RTFUNC_FAIL); + for(i=0; i<IDA_mem->ida_nrtfn; i++) { + 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 (ier == IDA_SUCCESS) return(IDA_SUCCESS); + + /* If a root was found, interpolate to get y(trout) and return. */ + (void) IDAGetSolution(IDA_mem, IDA_mem->ida_trout, IDA_mem->ida_yy, IDA_mem->ida_yp); + return(RTFOUND); +} + +/* + * IDARootfind + * + * This routine solves for a root of g(t) between tlo and thi, if + * one exists. Only roots of odd multiplicity (i.e. with a change + * of sign in one of the g_i), or exact zeros, are found. + * Here the sign of tlo - thi is arbitrary, but if multiple roots + * are found, the one closest to tlo is returned. + * + * The method used is the Illinois algorithm, a modified secant method. + * Reference: Kathie L. Hiebert and Lawrence F. Shampine, Implicitly + * Defined Output Points for Solutions of ODEs, Sandia National + * Laboratory Report SAND80-0180, February 1980. + * + * This routine uses the following parameters for communication: + * + * nrtfn = number of functions g_i, or number of components of + * the vector-valued function g(t). Input only. + * + * gfun = user-defined function for g(t). Its form is + * (void) gfun(t, y, yp, gt, user_data) + * + * rootdir = in array specifying the direction of zero-crossings. + * If rootdir[i] > 0, search for roots of g_i only if + * g_i is increasing; if rootdir[i] < 0, search for + * roots of g_i only if g_i is decreasing; otherwise + * always search for roots of g_i. + * + * gactive = array specifying whether a component of g should + * or should not be monitored. gactive[i] is initially + * 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 + * corresponding g function moves away from 0.0. + * + * nge = cumulative counter for gfun calls. + * + * ttol = a convergence tolerance for trout. Input only. + * When a root at trout is found, it is located only to + * within a tolerance of ttol. Typically, ttol should + * be set to a value on the order of + * 100 * UROUND * max (SUNRabs(tlo), SUNRabs(thi)) + * where UROUND is the unit roundoff of the machine. + * + * tlo, thi = endpoints of the interval in which roots are sought. + * On input, these must be distinct, but tlo - thi may + * be of either sign. The direction of integration is + * assumed to be from tlo to thi. On return, tlo and thi + * are the endpoints of the final relevant interval. + * + * glo, ghi = arrays of length nrtfn containing the vectors g(tlo) + * and g(thi) respectively. Input and output. On input, + * none of the glo[i] should be zero. + * + * trout = root location, if a root was found, or thi if not. + * Output only. If a root was found other than an exact + * zero of g, trout is the endpoint thi of the final + * interval bracketing the root, with size at most ttol. + * + * grout = array of length nrtfn containing g(trout) on return. + * + * iroots = int array of length nrtfn with root information. + * Output only. If a root was found, iroots indicates + * which components g_i have a root at trout. For + * i = 0, ..., nrtfn-1, iroots[i] = 1 if g_i has a root + * and g_i is increasing, iroots[i] = -1 if g_i has a + * root and g_i is decreasing, and iroots[i] = 0 if g_i + * has no roots or g_i varies in the direction opposite + * to that indicated by rootdir[i]. + * + * This routine returns an int equal to: + * IDA_RTFUNC_FAIL < 0 if the g function failed, or + * RTFOUND = 1 if a root of g was found, or + * IDA_SUCCESS = 0 otherwise. + * + */ + +static int IDARootfind(IDAMem IDA_mem) +{ + realtype alph, tmid, gfrac, maxfrac, fracint, fracsub; + int i, retval, imax, side, sideprev; + booleantype zroot, sgnchg; + + imax = 0; + + /* First check for change in sign in ghi or for a zero in ghi. */ + maxfrac = ZERO; + zroot = SUNFALSE; + sgnchg = SUNFALSE; + 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) { + 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 (gfrac > maxfrac) { + sgnchg = SUNTRUE; + maxfrac = gfrac; + imax = i; + } + } + } + } + + /* 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. */ + if (!sgnchg) { + IDA_mem->ida_trout = IDA_mem->ida_thi; + for (i = 0; i < IDA_mem->ida_nrtfn; i++) + IDA_mem->ida_grout[i] = IDA_mem->ida_ghi[i]; + if (!zroot) return(IDA_SUCCESS); + for (i = 0; i < IDA_mem->ida_nrtfn; i++) { + 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_iroots[i] = IDA_mem->ida_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(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 + 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 = 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; + fracsub = (fracint > FIVE) ? PT1 : HALF/fracint; + tmid = IDA_mem->ida_thi - fracsub*(IDA_mem->ida_thi - IDA_mem->ida_tlo); + } + + (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_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. */ + maxfrac = ZERO; + zroot = SUNFALSE; + sgnchg = SUNFALSE; + sideprev = side; + 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) + 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) ) { + gfrac = SUNRabs(IDA_mem->ida_grout[i] / (IDA_mem->ida_grout[i] - IDA_mem->ida_glo[i])); + if (gfrac > maxfrac) { + sgnchg = SUNTRUE; + maxfrac = gfrac; + imax = i; + } + } + } + } + if (sgnchg) { + /* Sign change found in (tlo,tmid); replace thi with tmid. */ + IDA_mem->ida_thi = tmid; + for (i = 0; i < IDA_mem->ida_nrtfn; i++) + 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; + continue; /* Return to looping point. */ + } + + if (zroot) { + /* No sign change in (tlo,tmid), but g = 0 at tmid; return root tmid. */ + IDA_mem->ida_thi = tmid; + for (i = 0; i < IDA_mem->ida_nrtfn; i++) + IDA_mem->ida_ghi[i] = IDA_mem->ida_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. */ + IDA_mem->ida_tlo = tmid; + for (i = 0; i < IDA_mem->ida_nrtfn; i++) + 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; + + } /* End of root-search loop */ + + /* Reset trout and grout, set iroots, and return RTFOUND. */ + IDA_mem->ida_trout = IDA_mem->ida_thi; + for (i = 0; i < IDA_mem->ida_nrtfn; i++) { + IDA_mem->ida_grout[i] = IDA_mem->ida_ghi[i]; + 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_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) ) + IDA_mem->ida_iroots[i] = IDA_mem->ida_glo[i] > 0 ? -1:1; + } + return(RTFOUND); +} + +/* + * ================================================================= + * 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 + * pointed to by ida_ehfun. + */ + +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 + (msgfmt is the last required argument to IDAProcessError) */ + + va_start(ap, msgfmt); + + /* Compose the message */ + + vsprintf(msg, msgfmt, ap); + + if (IDA_mem == NULL) { /* We write to stderr */ +#ifndef NO_FPRINTF_OUTPUT + fprintf(stderr, "\n[%s ERROR] %s\n ", module, fname); + fprintf(stderr, "%s\n\n", msg); +#endif + + } else { /* We can call ehfun */ + IDA_mem->ida_ehfun(error_code, module, fname, msg, IDA_mem->ida_eh_data); + } + + /* Finalize argument processing */ + va_end(ap); + + return; +} + +/* IDAErrHandler is the default error handling function. + It sends the error message to the stream pointed to by ida_errfp */ + +void IDAErrHandler(int error_code, const char *module, + const char *function, char *msg, void *data) +{ + IDAMem IDA_mem; + char err_type[10]; + + /* data points to IDA_mem here */ + + IDA_mem = (IDAMem) data; + + if (error_code == IDA_WARNING) + sprintf(err_type,"WARNING"); + else + sprintf(err_type,"ERROR"); + +#ifndef NO_FPRINTF_OUTPUT + 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); + } +#endif + + return; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_bbdpre.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_bbdpre.c new file mode 100644 index 0000000..1cb11ce --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_bbdpre.c @@ -0,0 +1,667 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 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 + * linear solver interface. + * + * NOTE: With only one processor in use, a banded matrix results + * rather than a block-diagonal matrix with banded blocks. + * Diagonal blocking occurs at the processor level. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "ida_impl.h" +#include "ida_ls_impl.h" +#include "ida_bbdpre_impl.h" +#include <sundials/sundials_math.h> +#include <nvector/nvector_serial.h> + + +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) +#define TWO RCONST(2.0) + +/* Prototypes of functions IDABBDPrecSetup and IDABBDPrecSolve */ +static int IDABBDPrecSetup(realtype tt, N_Vector yy, N_Vector yp, + N_Vector rr, realtype c_j, void *prec_data); +static int IDABBDPrecSolve(realtype tt, N_Vector yy, N_Vector yp, + N_Vector rr, N_Vector rvec, N_Vector zvec, + realtype c_j, realtype delta, void *prec_data); + +/* Prototype for IDABBDPrecFree */ +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 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, + IDABBDLocalFn Gres, IDABBDCommFn Gcomm) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + IBBDPrecData pdata; + sunindextype muk, mlk, storage_mu, lrw1, liw1; + long int lrw, liw; + int flag; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDALS_MEM_NULL, "IDABBDPRE", + "IDABBDPrecInit", MSGBBD_MEM_NULL); + return(IDALS_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Test if the LS linear solver interface has been created */ + if (IDA_mem->ida_lmem == NULL) { + IDAProcessError(IDA_mem, IDALS_LMEM_NULL, "IDABBDPRE", + "IDABBDPrecInit", MSGBBD_LMEM_NULL); + return(IDALS_LMEM_NULL); + } + idals_mem = (IDALsMem) IDA_mem->ida_lmem; + + /* Test compatibility of NVECTOR package with the BBD preconditioner */ + if(IDA_mem->ida_tempv1->ops->nvgetarraypointer == NULL) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDABBDPRE", + "IDABBDPrecInit", MSGBBD_BAD_NVECTOR); + return(IDALS_ILL_INPUT); + } + + /* Allocate data memory. */ + pdata = NULL; + pdata = (IBBDPrecData) malloc(sizeof *pdata); + if (pdata == NULL) { + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDABBDPRE", + "IDABBDPrecInit", MSGBBD_MEM_FAIL); + return(IDALS_MEM_FAIL); + } + + /* Set pointers to glocal and gcomm; load half-bandwidths. */ + pdata->ida_mem = IDA_mem; + pdata->glocal = Gres; + pdata->gcomm = Gcomm; + pdata->mudq = SUNMIN(Nlocal-1, SUNMAX(0, mudq)); + pdata->mldq = SUNMIN(Nlocal-1, SUNMAX(0, mldq)); + muk = SUNMIN(Nlocal-1, SUNMAX(0, mukeep)); + mlk = SUNMIN(Nlocal-1, SUNMAX(0, mlkeep)); + pdata->mukeep = muk; + pdata->mlkeep = mlk; + + /* Set extended upper half-bandwidth for PP (required for pivoting). */ + storage_mu = SUNMIN(Nlocal-1, muk+mlk); + + /* Allocate memory for preconditioner matrix. */ + pdata->PP = NULL; + pdata->PP = SUNBandMatrixStorage(Nlocal, muk, mlk, storage_mu); + if (pdata->PP == NULL) { + free(pdata); pdata = NULL; + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDABBDPRE", + "IDABBDPrecInit", MSGBBD_MEM_FAIL); + return(IDALS_MEM_FAIL); + } + + /* Allocate memory for temporary N_Vectors */ + pdata->zlocal = NULL; + pdata->zlocal = N_VNewEmpty_Serial(Nlocal); + if (pdata->zlocal == NULL) { + SUNMatDestroy(pdata->PP); + free(pdata); pdata = NULL; + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDABBDPRE", + "IDABBDPrecInit", MSGBBD_MEM_FAIL); + return(IDALS_MEM_FAIL); + } + pdata->rlocal = NULL; + pdata->rlocal = N_VNewEmpty_Serial(Nlocal); + if (pdata->rlocal == NULL) { + N_VDestroy(pdata->zlocal); + SUNMatDestroy(pdata->PP); + free(pdata); pdata = NULL; + 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); + if (pdata->tempv1 == NULL){ + N_VDestroy(pdata->rlocal); + N_VDestroy(pdata->zlocal); + SUNMatDestroy(pdata->PP); + free(pdata); pdata = NULL; + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDABBDPRE", + "IDABBDPrecInit", MSGBBD_MEM_FAIL); + return(IDALS_MEM_FAIL); + } + pdata->tempv2 = NULL; + pdata->tempv2 = N_VClone(IDA_mem->ida_tempv1); + if (pdata->tempv2 == NULL){ + N_VDestroy(pdata->rlocal); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->tempv1); + SUNMatDestroy(pdata->PP); + free(pdata); pdata = NULL; + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDABBDPRE", + "IDABBDPrecInit", MSGBBD_MEM_FAIL); + return(IDALS_MEM_FAIL); + } + pdata->tempv3 = NULL; + pdata->tempv3 = N_VClone(IDA_mem->ida_tempv1); + if (pdata->tempv3 == NULL){ + N_VDestroy(pdata->rlocal); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->tempv1); + N_VDestroy(pdata->tempv2); + SUNMatDestroy(pdata->PP); + free(pdata); pdata = NULL; + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDABBDPRE", + "IDABBDPrecInit", MSGBBD_MEM_FAIL); + return(IDALS_MEM_FAIL); + } + pdata->tempv4 = NULL; + pdata->tempv4 = N_VClone(IDA_mem->ida_tempv1); + if (pdata->tempv4 == NULL){ + N_VDestroy(pdata->rlocal); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->tempv1); + N_VDestroy(pdata->tempv2); + N_VDestroy(pdata->tempv3); + SUNMatDestroy(pdata->PP); + free(pdata); pdata = NULL; + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDABBDPRE", + "IDABBDPrecInit", MSGBBD_MEM_FAIL); + return(IDALS_MEM_FAIL); + } + + /* Allocate memory for banded linear solver */ + pdata->LS = NULL; + pdata->LS = SUNLinSol_Band(pdata->rlocal, pdata->PP); + if (pdata->LS == NULL) { + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + N_VDestroy(pdata->tempv1); + N_VDestroy(pdata->tempv2); + N_VDestroy(pdata->tempv3); + N_VDestroy(pdata->tempv4); + SUNMatDestroy(pdata->PP); + free(pdata); pdata = NULL; + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDABBDPRE", + "IDABBDPrecInit", MSGBBD_MEM_FAIL); + return(IDALS_MEM_FAIL); + } + + /* initialize band linear solver object */ + flag = SUNLinSolInitialize(pdata->LS); + if (flag != SUNLS_SUCCESS) { + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + N_VDestroy(pdata->tempv1); + N_VDestroy(pdata->tempv2); + N_VDestroy(pdata->tempv3); + N_VDestroy(pdata->tempv4); + SUNMatDestroy(pdata->PP); + SUNLinSolFree(pdata->LS); + free(pdata); pdata = NULL; + IDAProcessError(IDA_mem, IDALS_SUNLS_FAIL, "IDABBDPRE", + "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); + + /* Store Nlocal to be used in IDABBDPrecSetup */ + pdata->n_local = Nlocal; + + /* Set work space sizes and initialize nge. */ + pdata->rpwsize = 0; + pdata->ipwsize = 0; + if (IDA_mem->ida_tempv1->ops->nvspace) { + N_VSpace(IDA_mem->ida_tempv1, &lrw1, &liw1); + pdata->rpwsize += 4*lrw1; + pdata->ipwsize += 4*liw1; + } + if (pdata->rlocal->ops->nvspace) { + N_VSpace(pdata->rlocal, &lrw1, &liw1); + pdata->rpwsize += 2*lrw1; + pdata->ipwsize += 2*liw1; + } + if (pdata->PP->ops->space) { + flag = SUNMatSpace(pdata->PP, &lrw, &liw); + pdata->rpwsize += lrw; + pdata->ipwsize += liw; + } + if (pdata->LS->ops->space) { + flag = SUNLinSolSpace(pdata->LS, &lrw, &liw); + pdata->rpwsize += lrw; + pdata->ipwsize += liw; + } + pdata->nge = 0; + + /* make sure pdata is free from any previous allocations */ + if (idals_mem->pfree) + idals_mem->pfree(IDA_mem); + + /* Point to the new pdata field in the LS memory */ + idals_mem->pdata = pdata; + + /* Attach the pfree function */ + idals_mem->pfree = IDABBDPrecFree; + + /* Attach preconditioner solve and setup functions */ + flag = IDASetPreconditioner(ida_mem, + IDABBDPrecSetup, + IDABBDPrecSolve); + + return(flag); +} + + +/*-------------------------------------------------------------*/ +int IDABBDPrecReInit(void *ida_mem, sunindextype mudq, + sunindextype mldq, realtype dq_rel_yy) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + IBBDPrecData pdata; + sunindextype Nlocal; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDALS_MEM_NULL, "IDABBDPRE", + "IDABBDPrecReInit", MSGBBD_MEM_NULL); + return(IDALS_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Test if the LS linear solver interface has been created */ + if (IDA_mem->ida_lmem == NULL) { + IDAProcessError(IDA_mem, IDALS_LMEM_NULL, "IDABBDPRE", + "IDABBDPrecReInit", MSGBBD_LMEM_NULL); + return(IDALS_LMEM_NULL); + } + idals_mem = (IDALsMem) IDA_mem->ida_lmem; + + /* Test if the preconditioner data is non-NULL */ + if (idals_mem->pdata == NULL) { + IDAProcessError(IDA_mem, IDALS_PMEM_NULL, "IDABBDPRE", + "IDABBDPrecReInit", MSGBBD_PMEM_NULL); + return(IDALS_PMEM_NULL); + } + pdata = (IBBDPrecData) idals_mem->pdata; + + /* Load half-bandwidths. */ + Nlocal = pdata->n_local; + pdata->mudq = SUNMIN(Nlocal-1, SUNMAX(0, mudq)); + pdata->mldq = SUNMIN(Nlocal-1, SUNMAX(0, mldq)); + + /* 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); + + /* Re-initialize nge */ + pdata->nge = 0; + + return(IDALS_SUCCESS); +} + + +/*-------------------------------------------------------------*/ +int IDABBDPrecGetWorkSpace(void *ida_mem, + long int *lenrwBBDP, + long int *leniwBBDP) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + IBBDPrecData pdata; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDALS_MEM_NULL, "IDABBDPRE", + "IDABBDPrecGetWorkSpace", MSGBBD_MEM_NULL); + return(IDALS_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_lmem == NULL) { + IDAProcessError(IDA_mem, IDALS_LMEM_NULL, "IDABBDPRE", + "IDABBDPrecGetWorkSpace", MSGBBD_LMEM_NULL); + return(IDALS_LMEM_NULL); + } + idals_mem = (IDALsMem) IDA_mem->ida_lmem; + + if (idals_mem->pdata == NULL) { + IDAProcessError(IDA_mem, IDALS_PMEM_NULL, "IDABBDPRE", + "IDABBDPrecGetWorkSpace", MSGBBD_PMEM_NULL); + return(IDALS_PMEM_NULL); + } + pdata = (IBBDPrecData) idals_mem->pdata; + + *lenrwBBDP = pdata->rpwsize; + *leniwBBDP = pdata->ipwsize; + + return(IDALS_SUCCESS); +} + + +/*-------------------------------------------------------------*/ +int IDABBDPrecGetNumGfnEvals(void *ida_mem, + long int *ngevalsBBDP) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + IBBDPrecData pdata; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDALS_MEM_NULL, "IDABBDPRE", + "IDABBDPrecGetNumGfnEvals", MSGBBD_MEM_NULL); + return(IDALS_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_lmem == NULL) { + IDAProcessError(IDA_mem, IDALS_LMEM_NULL, "IDABBDPRE", + "IDABBDPrecGetNumGfnEvals", MSGBBD_LMEM_NULL); + return(IDALS_LMEM_NULL); + } + idals_mem = (IDALsMem) IDA_mem->ida_lmem; + + if (idals_mem->pdata == NULL) { + IDAProcessError(IDA_mem, IDALS_PMEM_NULL, "IDABBDPRE", + "IDABBDPrecGetNumGfnEvals", MSGBBD_PMEM_NULL); + return(IDALS_PMEM_NULL); + } + pdata = (IBBDPrecData) idals_mem->pdata; + + *ngevalsBBDP = pdata->nge; + + return(IDALS_SUCCESS); +} + + +/*--------------------------------------------------------------- + IDABBDPrecSetup: + + IDABBDPrecSetup generates a band-block-diagonal preconditioner + matrix, where the local block (on this processor) is a band + matrix. Each local block is computed by a difference quotient + 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 + 0 if successful, + > 0 for a recoverable error (step will be retried), or + < 0 for a nonrecoverable error (step fails). + ----------------------------------------------------------------*/ +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; + + pdata =(IBBDPrecData) bbd_data; + + IDA_mem = (IDAMem) pdata->ida_mem; + + /* Call IBBDDQJac for a new Jacobian calculation and store in PP. */ + retval = SUNMatZero(pdata->PP); + retval = IBBDDQJac(pdata, tt, c_j, yy, yp, pdata->tempv1, + pdata->tempv2, pdata->tempv3, pdata->tempv4); + if (retval < 0) { + IDAProcessError(IDA_mem, -1, "IDABBDPRE", "IDABBDPrecSetup", + MSGBBD_FUNC_FAILED); + return(-1); + } + if (retval > 0) { + return(1); + } + + /* Do LU factorization of matrix and return error flag */ + ier = SUNLinSolSetup_Band(pdata->LS, pdata->PP); + return(ier); +} + + +/*--------------------------------------------------------------- + IDABBDPrecSolve + + 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 + solver object. + ---------------------------------------------------------------*/ +static int IDABBDPrecSolve(realtype tt, N_Vector yy, N_Vector yp, + N_Vector rr, N_Vector rvec, N_Vector zvec, + realtype c_j, realtype delta, void *bbd_data) +{ + 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, + pdata->rlocal, ZERO); + + /* Detach local data arrays from rlocal and zlocal */ + N_VSetArrayPointer(NULL, pdata->rlocal); + N_VSetArrayPointer(NULL, pdata->zlocal); + + return(retval); +} + + +/*-------------------------------------------------------------*/ +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; + + SUNLinSolFree(pdata->LS); + N_VDestroy(pdata->rlocal); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->tempv1); + N_VDestroy(pdata->tempv2); + N_VDestroy(pdata->tempv3); + N_VDestroy(pdata->tempv4); + SUNMatDestroy(pdata->PP); + + free(pdata); + pdata = NULL; + + return(0); +} + + +/*--------------------------------------------------------------- + IBBDDQJac + + This routine generates a banded difference quotient approximation + 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 ytemp, N_Vector yptemp, N_Vector gtemp) +{ + IDAMem IDA_mem; + realtype inc, inc_inv; + int retval; + sunindextype group, i, j, width, ngroups, i1, i2; + realtype *ydata, *ypdata, *ytempdata, *yptempdata, *grefdata, *gtempdata; + realtype *cnsdata = NULL, *ewtdata; + realtype *col_j, conj, yj, ypj, ewtj; + + IDA_mem = (IDAMem) pdata->ida_mem; + + /* Initialize ytemp and yptemp. */ + N_VScale(ONE, yy, ytemp); + N_VScale(ONE, yp, yptemp); + + /* Obtain pointers as required to the data array of vectors. */ + ydata = N_VGetArrayPointer(yy); + ypdata = N_VGetArrayPointer(yp); + gtempdata = N_VGetArrayPointer(gtemp); + ewtdata = N_VGetArrayPointer(IDA_mem->ida_ewt); + if (IDA_mem->ida_constraints != NULL) + cnsdata = N_VGetArrayPointer(IDA_mem->ida_constraints); + ytempdata = N_VGetArrayPointer(ytemp); + yptempdata= N_VGetArrayPointer(yptemp); + grefdata = N_VGetArrayPointer(gref); + + /* Call gcomm and glocal to get base value of G(t,y,y'). */ + if (pdata->gcomm != NULL) { + retval = pdata->gcomm(pdata->n_local, tt, yy, yp, IDA_mem->ida_user_data); + if (retval != 0) return(retval); + } + + retval = pdata->glocal(pdata->n_local, tt, yy, yp, gref, IDA_mem->ida_user_data); + pdata->nge++; + if (retval != 0) return(retval); + + /* Set bandwidth and number of column groups for band differencing. */ + width = pdata->mldq + pdata->mudq + 1; + ngroups = SUNMIN(width, pdata->n_local); + + /* 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. */ + inc = pdata->rel_yy * + 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) { + 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;} + } + + /* 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); + pdata->nge++; + if (retval != 0) return(retval); + + /* Loop over components of the group again; restore ytemp and yptemp. */ + for(j = group-1; j < pdata->n_local; j += width) { + yj = ytempdata[j] = ydata[j]; + ypj = yptempdata[j] = ypdata[j]; + ewtj = ewtdata[j]; + + /* Set increment inc as before .*/ + inc = pdata->rel_yy * + 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) { + 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;} + } + + /* Form difference quotients and load into PP. */ + inc_inv = ONE/inc; + col_j = SUNBandMatrix_Column(pdata->PP,j); + i1 = SUNMAX(0, j - pdata->mukeep); + i2 = SUNMIN(j + pdata->mlkeep, pdata->n_local-1); + for(i=i1; i <= i2; i++) + SM_COLUMN_ELEMENT_B(col_j,i,j) = + inc_inv * (gtempdata[i] - grefdata[i]); + } + } + + return(0); +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_bbdpre_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_bbdpre_impl.h new file mode 100644 index 0000000..e904803 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_bbdpre_impl.h @@ -0,0 +1,88 @@ +/*----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 (private version) for the IDABBDPRE + * module, for a band-block-diagonal preconditioner, i.e. a + * block-diagonal matrix with banded blocks, for use with IDA + * and an IDASPILS linear solver. + *-----------------------------------------------------------------*/ + +#ifndef _IDABBDPRE_IMPL_H +#define _IDABBDPRE_IMPL_H + +#include <ida/ida_bbdpre.h> +#include <sunmatrix/sunmatrix_band.h> +#include <sunlinsol/sunlinsol_band.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* + * ----------------------------------------------------------------- + * Definition of IBBDPrecData + * ----------------------------------------------------------------- + */ + +typedef struct IBBDPrecDataRec { + + /* passed by user to IDABBDPrecAlloc and used by + IDABBDPrecSetup/IDABBDPrecSolve functions */ + sunindextype mudq, mldq, mukeep, mlkeep; + realtype rel_yy; + IDABBDLocalFn glocal; + IDABBDCommFn gcomm; + + /* set by IDABBDPrecSetup and used by IDABBDPrecSetup and + IDABBDPrecSolve functions */ + sunindextype n_local; + SUNMatrix PP; + SUNLinearSolver LS; + N_Vector zlocal; + N_Vector rlocal; + N_Vector tempv1; + N_Vector tempv2; + N_Vector tempv3; + N_Vector tempv4; + + /* available for optional output */ + long int rpwsize; + long int ipwsize; + long int nge; + + /* pointer to ida_mem */ + void *ida_mem; + +} *IBBDPrecData; + +/* + * ----------------------------------------------------------------- + * IDABBDPRE error messages + * ----------------------------------------------------------------- + */ + +#define MSGBBD_MEM_NULL "Integrator memory is NULL." +#define MSGBBD_LMEM_NULL "Linear solver memory is NULL. One of the SPILS linear solvers must be attached." +#define MSGBBD_MEM_FAIL "A memory request failed." +#define MSGBBD_BAD_NVECTOR "A required vector operation is not implemented." +#define MSGBBD_SUNMAT_FAIL "An error arose from a SUNBandMatrix routine." +#define MSGBBD_SUNLS_FAIL "An error arose from a SUNBandLinearSolver routine." +#define MSGBBD_PMEM_NULL "BBD peconditioner memory is NULL. IDABBDPrecInit must be called." +#define MSGBBD_FUNC_FAILED "The Glocal or Gcomm routine failed in an unrecoverable manner." + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_direct.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_direct.c new file mode 100644 index 0000000..5ba46dd --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_direct.c @@ -0,0 +1,56 @@ +/*----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 + *----------------------------------------------------------------- + * Implementation file for the deprecated direct linear solver interface in + * IDA; these routines now just wrap the updated IDA generic + * linear solver interface in ida_ls.h. + *-----------------------------------------------------------------*/ + +#include <ida/ida_ls.h> +#include <ida/ida_direct.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*================================================================= + Exported Functions (wrappers for equivalent routines in ida_ls.h) + =================================================================*/ + +int IDADlsSetLinearSolver(void *ida_mem, SUNLinearSolver LS, SUNMatrix A) +{ return(IDASetLinearSolver(ida_mem, LS, A)); } + +int IDADlsSetJacFn(void *ida_mem, IDADlsJacFn jac) +{ return(IDASetJacFn(ida_mem, jac)); } + +int IDADlsGetWorkSpace(void *ida_mem, long int *lenrwLS, long int *leniwLS) +{ return(IDAGetLinWorkSpace(ida_mem, lenrwLS, leniwLS)); } + +int IDADlsGetNumJacEvals(void *ida_mem, long int *njevals) +{ return(IDAGetNumJacEvals(ida_mem, njevals)); } + +int IDADlsGetNumResEvals(void *ida_mem, long int *nfevalsLS) +{ return(IDAGetNumLinResEvals(ida_mem, nfevalsLS)); } + +int IDADlsGetLastFlag(void *ida_mem, long int *flag) +{ return(IDAGetLastLinFlag(ida_mem, flag)); } + +char *IDADlsGetReturnFlagName(long int flag) +{ return(IDAGetLinReturnFlagName(flag)); } + + +#ifdef __cplusplus +} +#endif + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_ic.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_ic.c new file mode 100644 index 0000000..305639c --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_ic.c @@ -0,0 +1,704 @@ +/* + * ----------------------------------------------------------------- + * $Revision$ + * $Date$ + * ----------------------------------------------------------------- + * Programmers: 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 IC calculation for IDA. + * It is independent of the linear solver in use. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "ida_impl.h" +#include <sundials/sundials_math.h> + +/* + * ================================================================= + * IDA Constants + * ================================================================= + */ + +/* Private Constants */ + +#define ZERO RCONST(0.0) /* real 0.0 */ +#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 PT99 RCONST(0.99) /* real 0.99 */ +#define PT1 RCONST(0.1) /* real 0.1 */ +#define PT001 RCONST(0.001) /* real 0.001 */ + +/* IDACalcIC control constants */ + +#define ICRATEMAX RCONST(0.9) /* max. Newton conv. rate */ +#define ALPHALS RCONST(0.0001) /* alpha in linesearch conv. test */ + +/* Return values for lower level routines used by IDACalcIC */ + +#define IC_FAIL_RECOV 1 +#define IC_CONSTR_FAILED 2 +#define IC_LINESRCH_FAILED 3 +#define IC_CONV_FAIL 4 +#define IC_SLOW_CONVRG 5 + +/* + * ================================================================= + * Private Helper Functions Prototypes + * ================================================================= + */ + +extern int IDAInitialSetup(IDAMem IDA_mem); +extern realtype IDAWrmsNorm(IDAMem IDA_mem, N_Vector x, N_Vector w, + booleantype mask); + +static int IDAnlsIC(IDAMem IDA_mem); +static int IDANewtonIC(IDAMem IDA_mem); +static int IDALineSrch(IDAMem IDA_mem, realtype *delnorm, realtype *fnorm); +static int IDAfnorm(IDAMem IDA_mem, realtype *fnorm); +static int IDANewyyp(IDAMem IDA_mem, realtype lambda); +static int IDANewy(IDAMem IDA_mem); +static int IDAICFailFlag(IDAMem IDA_mem, int retval); + +/* + * ================================================================= + * EXPORTED FUNCTIONS IMPLEMENTATION + * ================================================================= + */ + +/* + * ----------------------------------------------------------------- + * IDACalcIC + * ----------------------------------------------------------------- + * IDACalcIC computes consistent initial conditions, given the + * user's initial guess for unknown components of yy0 and/or yp0. + * + * The return value is IDA_SUCCESS = 0 if no error occurred. + * + * The error return values (fully described in ida.h) are: + * IDA_MEM_NULL ida_mem is NULL + * IDA_NO_MALLOC ida_mem was not allocated + * IDA_ILL_INPUT bad value for icopt, tout1, or id + * IDA_LINIT_FAIL the linear solver linit routine failed + * IDA_BAD_EWT zero value of some component of ewt + * IDA_RES_FAIL res had a non-recoverable error + * IDA_FIRST_RES_FAIL res failed recoverably on the first call + * IDA_LSETUP_FAIL lsetup had a non-recoverable error + * IDA_LSOLVE_FAIL lsolve had a non-recoverable error + * IDA_NO_RECOVERY res, lsetup, or lsolve had a recoverable + * error, but IDACalcIC could not recover + * IDA_CONSTR_FAIL the inequality constraints could not be met + * IDA_LINESEARCH_FAIL the linesearch failed (either on steptol test + * or on the maxbacks test) + * IDA_CONV_FAIL the Newton iterations failed to converge + * ----------------------------------------------------------------- + */ + +int IDACalcIC(void *ida_mem, int icopt, realtype tout1) +{ + int ewtsetOK; + int ier, nwt, nh, mxnh, icret, retval=0; + realtype tdist, troundoff, minid, hic, ypnorm; + IDAMem IDA_mem; + + /* Check if IDA memory exists */ + + if(ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDACalcIC", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Check if problem was malloc'ed */ + + if(IDA_mem->ida_MallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_MALLOC, "IDA", "IDACalcIC", MSG_NO_MALLOC); + return(IDA_NO_MALLOC); + } + + /* Check inputs to IDA for correctness and consistency */ + + ier = IDAInitialSetup(IDA_mem); + if(ier != IDA_SUCCESS) return(IDA_ILL_INPUT); + IDA_mem->ida_SetupDone = SUNTRUE; + + /* Check legality of input arguments, and set IDA memory copies. */ + + if(icopt != IDA_YA_YDP_INIT && icopt != IDA_Y_INIT) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDACalcIC", MSG_IC_BAD_ICOPT); + return(IDA_ILL_INPUT); + } + IDA_mem->ida_icopt = icopt; + + if(icopt == IDA_YA_YDP_INIT && (IDA_mem->ida_id == NULL)) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDACalcIC", MSG_IC_MISSING_ID); + return(IDA_ILL_INPUT); + } + + tdist = SUNRabs(tout1 - IDA_mem->ida_tn); + troundoff = TWO * IDA_mem->ida_uround * (SUNRabs(IDA_mem->ida_tn) + SUNRabs(tout1)); + if(tdist < troundoff) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDACalcIC", MSG_IC_TOO_CLOSE); + return(IDA_ILL_INPUT); + } + + /* Allocate space and initialize temporary vectors */ + + IDA_mem->ida_yy0 = N_VClone(IDA_mem->ida_ee); + IDA_mem->ida_yp0 = N_VClone(IDA_mem->ida_ee); + IDA_mem->ida_t0 = IDA_mem->ida_tn; + N_VScale(ONE, IDA_mem->ida_phi[0], IDA_mem->ida_yy0); + N_VScale(ONE, IDA_mem->ida_phi[1], IDA_mem->ida_yp0); + + /* For use in the IDA_YA_YP_INIT case, set sysindex and tscale. */ + + IDA_mem->ida_sysindex = 1; + IDA_mem->ida_tscale = tdist; + if(icopt == IDA_YA_YDP_INIT) { + minid = N_VMin(IDA_mem->ida_id); + if(minid < ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDACalcIC", MSG_IC_BAD_ID); + return(IDA_ILL_INPUT); + } + if(minid > HALF) IDA_mem->ida_sysindex = 0; + } + + /* Set the test constant in the Newton convergence test */ + + IDA_mem->ida_epsNewt = IDA_mem->ida_epiccon; + + /* Initializations: + cjratio = 1 (for use in direct linear solvers); + set nbacktr = 0; */ + + IDA_mem->ida_cjratio = ONE; + IDA_mem->ida_nbacktr = 0; + + /* Set hic, hh, cj, and mxnh. */ + + hic = PT001*tdist; + ypnorm = IDAWrmsNorm(IDA_mem, IDA_mem->ida_yp0, + IDA_mem->ida_ewt, IDA_mem->ida_suppressalg); + if(ypnorm > HALF/hic) hic = HALF/ypnorm; + if(tout1 < IDA_mem->ida_tn) hic = -hic; + IDA_mem->ida_hh = hic; + if(icopt == IDA_YA_YDP_INIT) { + IDA_mem->ida_cj = ONE/hic; + mxnh = IDA_mem->ida_maxnh; + } + else { + IDA_mem->ida_cj = ZERO; + mxnh = 1; + } + + /* Loop over nwt = number of evaluations of ewt vector. */ + + for(nwt = 1; nwt <= 2; nwt++) { + + /* Loop over nh = number of h values. */ + for(nh = 1; nh <= mxnh; nh++) { + + /* Call the IC nonlinear solver function. */ + retval = IDAnlsIC(IDA_mem); + + /* Cut h and loop on recoverable IDA_YA_YDP_INIT failure; else break. */ + if(retval == IDA_SUCCESS) break; + IDA_mem->ida_ncfn++; + if(retval < 0) break; + if(nh == mxnh) break; + /* If looping to try again, reset yy0 and yp0 if not converging. */ + if(retval != IC_SLOW_CONVRG) { + N_VScale(ONE, IDA_mem->ida_phi[0], IDA_mem->ida_yy0); + N_VScale(ONE, IDA_mem->ida_phi[1], IDA_mem->ida_yp0); + } + hic *= PT1; + IDA_mem->ida_cj = ONE/hic; + IDA_mem->ida_hh = hic; + } /* End of nh loop */ + + /* Break on failure; else reset ewt, save yy0, yp0 in phi, and loop. */ + if(retval != IDA_SUCCESS) break; + ewtsetOK = IDA_mem->ida_efun(IDA_mem->ida_yy0, IDA_mem->ida_ewt, + IDA_mem->ida_edata); + if(ewtsetOK != 0) { + retval = IDA_BAD_EWT; + break; + } + N_VScale(ONE, IDA_mem->ida_yy0, IDA_mem->ida_phi[0]); + N_VScale(ONE, IDA_mem->ida_yp0, IDA_mem->ida_phi[1]); + + } /* End of nwt loop */ + + /* Free temporary space */ + + N_VDestroy(IDA_mem->ida_yy0); + N_VDestroy(IDA_mem->ida_yp0); + + /* Load the optional outputs. */ + + if(icopt == IDA_YA_YDP_INIT) IDA_mem->ida_hused = hic; + + /* On any failure, print message and return proper flag. */ + + if(retval != IDA_SUCCESS) { + icret = IDAICFailFlag(IDA_mem, retval); + return(icret); + } + + /* Otherwise return success flag. */ + + return(IDA_SUCCESS); + +} + +/* + * ================================================================= + * PRIVATE FUNCTIONS IMPLEMENTATION + * ================================================================= + */ + +/* + * ----------------------------------------------------------------- + * IDAnlsIC + * ----------------------------------------------------------------- + * IDAnlsIC solves a nonlinear system for consistent initial + * conditions. It calls IDANewtonIC to do most of the work. + * + * The return value is IDA_SUCCESS = 0 if no error occurred. + * The error return values (positive) considered recoverable are: + * IC_FAIL_RECOV if res, lsetup, or lsolve failed recoverably + * IC_CONSTR_FAILED if the constraints could not be met + * IC_LINESRCH_FAILED if the linesearch failed (either on steptol test + * or on maxbacks test) + * IC_CONV_FAIL if the Newton iterations failed to converge + * IC_SLOW_CONVRG if the iterations are converging slowly + * (failed the convergence test, but showed + * norm reduction or convergence rate < 1) + * The error return values (negative) considered non-recoverable are: + * IDA_RES_FAIL if res had a non-recoverable error + * IDA_FIRST_RES_FAIL if res failed recoverably on the first call + * IDA_LSETUP_FAIL if lsetup had a non-recoverable error + * IDA_LSOLVE_FAIL if lsolve had a non-recoverable error + * ----------------------------------------------------------------- + */ + +static int IDAnlsIC (IDAMem IDA_mem) +{ + int retval, nj; + N_Vector tv1, tv2, tv3; + + tv1 = IDA_mem->ida_ee; + tv2 = IDA_mem->ida_tempv2; + tv3 = IDA_mem->ida_phi[2]; + + retval = IDA_mem->ida_res(IDA_mem->ida_t0, IDA_mem->ida_yy0, + IDA_mem->ida_yp0, IDA_mem->ida_delta, + IDA_mem->ida_user_data); + IDA_mem->ida_nre++; + if(retval < 0) return(IDA_RES_FAIL); + if(retval > 0) return(IDA_FIRST_RES_FAIL); + + N_VScale(ONE, IDA_mem->ida_delta, IDA_mem->ida_savres); + + /* Loop over nj = number of linear solve Jacobian setups. */ + + for(nj = 1; nj <= IDA_mem->ida_maxnj; nj++) { + + /* If there is a setup routine, call it. */ + if(IDA_mem->ida_lsetup) { + IDA_mem->ida_nsetups++; + retval = IDA_mem->ida_lsetup(IDA_mem, IDA_mem->ida_yy0, + IDA_mem->ida_yp0, IDA_mem->ida_delta, + tv1, tv2, tv3); + if(retval < 0) return(IDA_LSETUP_FAIL); + if(retval > 0) return(IC_FAIL_RECOV); + } + + /* Call the Newton iteration routine, and return if successful. */ + retval = IDANewtonIC(IDA_mem); + if(retval == IDA_SUCCESS) return(IDA_SUCCESS); + + /* If converging slowly and lsetup is nontrivial, retry. */ + if(retval == IC_SLOW_CONVRG && IDA_mem->ida_lsetup) { + N_VScale(ONE, IDA_mem->ida_savres, IDA_mem->ida_delta); + continue; + } else { + return(retval); + } + + } /* End of nj loop */ + + /* No convergence after maxnj tries; return with retval=IC_SLOW_CONVRG */ + return(retval); + +} + +/* + * ----------------------------------------------------------------- + * IDANewtonIC + * ----------------------------------------------------------------- + * IDANewtonIC performs the Newton iteration to solve for consistent + * initial conditions. It calls IDALineSrch within each iteration. + * On return, savres contains the current residual vector. + * + * The return value is IDA_SUCCESS = 0 if no error occurred. + * The error return values (positive) considered recoverable are: + * IC_FAIL_RECOV if res or lsolve failed recoverably + * IC_CONSTR_FAILED if the constraints could not be met + * IC_LINESRCH_FAILED if the linesearch failed (either on steptol test + * or on maxbacks test) + * IC_CONV_FAIL if the Newton iterations failed to converge + * IC_SLOW_CONVRG if the iterations appear to be converging slowly. + * They failed the convergence test, but showed + * an overall norm reduction (by a factor of < 0.1) + * or a convergence rate <= ICRATEMAX). + * The error return values (negative) considered non-recoverable are: + * IDA_RES_FAIL if res had a non-recoverable error + * IDA_LSOLVE_FAIL if lsolve had a non-recoverable error + * ----------------------------------------------------------------- + */ + +static int IDANewtonIC(IDAMem IDA_mem) +{ + int retval, mnewt; + realtype delnorm, fnorm, fnorm0, oldfnrm, rate; + + /* Set pointer for vector delnew */ + IDA_mem->ida_delnew = IDA_mem->ida_phi[2]; + + /* Call the linear solve function to get the Newton step, delta. */ + retval = IDA_mem->ida_lsolve(IDA_mem, IDA_mem->ida_delta, + IDA_mem->ida_ewt, IDA_mem->ida_yy0, + IDA_mem->ida_yp0, IDA_mem->ida_savres); + if(retval < 0) return(IDA_LSOLVE_FAIL); + if(retval > 0) return(IC_FAIL_RECOV); + + /* Compute the norm of the step; return now if this is small. */ + fnorm = IDAWrmsNorm(IDA_mem, IDA_mem->ida_delta, IDA_mem->ida_ewt, SUNFALSE); + if(IDA_mem->ida_sysindex == 0) + fnorm *= IDA_mem->ida_tscale * SUNRabs(IDA_mem->ida_cj); + if(fnorm <= IDA_mem->ida_epsNewt) + return(IDA_SUCCESS); + fnorm0 = fnorm; + + /* Initialize rate to avoid compiler warning message */ + rate = ZERO; + + /* Newton iteration loop */ + + for(mnewt = 0; mnewt < IDA_mem->ida_maxnit; mnewt++) { + + IDA_mem->ida_nni++; + delnorm = fnorm; + oldfnrm = fnorm; + + /* Call the Linesearch function and return if it failed. */ + retval = IDALineSrch(IDA_mem, &delnorm, &fnorm); + if(retval != IDA_SUCCESS) return(retval); + + /* Set the observed convergence rate and test for convergence. */ + rate = fnorm/oldfnrm; + if(fnorm <= IDA_mem->ida_epsNewt) return(IDA_SUCCESS); + + /* If not converged, copy new step vector, and loop. */ + N_VScale(ONE, IDA_mem->ida_delnew, IDA_mem->ida_delta); + + } /* End of Newton iteration loop */ + + /* Return either IC_SLOW_CONVRG or recoverable fail flag. */ + if(rate <= ICRATEMAX || fnorm < PT1*fnorm0) return(IC_SLOW_CONVRG); + return(IC_CONV_FAIL); + +} + + +/* + * ----------------------------------------------------------------- + * IDALineSrch + * ----------------------------------------------------------------- + * IDALineSrch performs the Linesearch algorithm with the + * calculation of consistent initial conditions. + * + * On entry, yy0 and yp0 are the current values of y and y', the + * Newton step is delta, the current residual vector F is savres, + * delnorm is WRMS-norm(delta), and fnorm is the norm of the vector + * J-inverse F. + * + * On a successful return, yy0, yp0, and savres have been updated, + * delnew contains the current value of J-inverse F, and fnorm is + * WRMS-norm(delnew). + * + * The return value is IDA_SUCCESS = 0 if no error occurred. + * The error return values (positive) considered recoverable are: + * IC_FAIL_RECOV if res or lsolve failed recoverably + * IC_CONSTR_FAILED if the constraints could not be met + * IC_LINESRCH_FAILED if the linesearch failed (either on steptol test + * or on maxbacks test) + * The error return values (negative) considered non-recoverable are: + * IDA_RES_FAIL if res had a non-recoverable error + * IDA_LSOLVE_FAIL if lsolve had a non-recoverable error + * ----------------------------------------------------------------- + */ + +static int IDALineSrch(IDAMem IDA_mem, realtype *delnorm, realtype *fnorm) +{ + booleantype conOK; + int retval, nbacks; + realtype f1norm, fnormp, f1normp, ratio, lambda, minlam, slpi; + N_Vector mc; + + /* Initialize work space pointers, f1norm, ratio. + (Use of mc in constraint check does not conflict with ypnew.) */ + mc = IDA_mem->ida_ee; + IDA_mem->ida_dtemp = IDA_mem->ida_phi[3]; + IDA_mem->ida_ynew = IDA_mem->ida_tempv2; + IDA_mem->ida_ypnew = IDA_mem->ida_ee; + f1norm = (*fnorm)*(*fnorm)*HALF; + ratio = ONE; + + /* If there are constraints, check and reduce step if necessary. */ + if(IDA_mem->ida_constraintsSet) { + + /* Update y and check constraints. */ + IDANewy(IDA_mem); + conOK = N_VConstrMask(IDA_mem->ida_constraints, IDA_mem->ida_ynew, mc); + + if(!conOK) { + /* Not satisfied. Compute scaled step to satisfy constraints. */ + N_VProd(mc, IDA_mem->ida_delta, IDA_mem->ida_dtemp); + ratio = PT99*N_VMinQuotient(IDA_mem->ida_yy0, IDA_mem->ida_dtemp); + (*delnorm) *= ratio; + if((*delnorm) <= IDA_mem->ida_steptol) return(IC_CONSTR_FAILED); + N_VScale(ratio, IDA_mem->ida_delta, IDA_mem->ida_delta); + } + + } /* End of constraints check */ + + slpi = -TWO*f1norm*ratio; + minlam = IDA_mem->ida_steptol / (*delnorm); + lambda = ONE; + nbacks = 0; + + /* In IDA_Y_INIT case, set ypnew = yp0 (fixed) for linesearch. */ + if(IDA_mem->ida_icopt == IDA_Y_INIT) + N_VScale(ONE, IDA_mem->ida_yp0, IDA_mem->ida_ypnew); + + /* Loop on linesearch variable lambda. */ + + for(;;) { + + if (nbacks == IDA_mem->ida_maxbacks) return(IC_LINESRCH_FAILED); + /* Get new (y,y') = (ynew,ypnew) and norm of new function value. */ + IDANewyyp(IDA_mem, lambda); + retval = IDAfnorm(IDA_mem, &fnormp); + if(retval != IDA_SUCCESS) return(retval); + + /* If lsoff option is on, break out. */ + if(IDA_mem->ida_lsoff) break; + + /* Do alpha-condition test. */ + f1normp = fnormp*fnormp*HALF; + if(f1normp <= f1norm + ALPHALS*slpi*lambda) break; + if(lambda < minlam) return(IC_LINESRCH_FAILED); + lambda /= TWO; + IDA_mem->ida_nbacktr++; nbacks++; + + } /* End of breakout linesearch loop */ + + /* Update yy0, yp0, and fnorm, then return. */ + N_VScale(ONE, IDA_mem->ida_ynew, IDA_mem->ida_yy0); + if(IDA_mem->ida_icopt == IDA_YA_YDP_INIT) + N_VScale(ONE, IDA_mem->ida_ypnew, IDA_mem->ida_yp0); + *fnorm = fnormp; + return(IDA_SUCCESS); + +} + +/* + * ----------------------------------------------------------------- + * IDAfnorm + * ----------------------------------------------------------------- + * IDAfnorm computes the norm of the current function value, by + * evaluating the DAE residual function, calling the linear + * system solver, and computing a WRMS-norm. + * + * On return, savres contains the current residual vector F, and + * delnew contains J-inverse F. + * + * The return value is IDA_SUCCESS = 0 if no error occurred, or + * IC_FAIL_RECOV if res or lsolve failed recoverably, or + * IDA_RES_FAIL if res had a non-recoverable error, or + * IDA_LSOLVE_FAIL if lsolve had a non-recoverable error. + * ----------------------------------------------------------------- + */ + +static int IDAfnorm(IDAMem IDA_mem, realtype *fnorm) +{ + + int retval; + + /* Get residual vector F, return if failed, and save F in savres. */ + retval = IDA_mem->ida_res(IDA_mem->ida_t0, IDA_mem->ida_ynew, + IDA_mem->ida_ypnew, IDA_mem->ida_delnew, + IDA_mem->ida_user_data); + IDA_mem->ida_nre++; + if(retval < 0) return(IDA_RES_FAIL); + if(retval > 0) return(IC_FAIL_RECOV); + + N_VScale(ONE, IDA_mem->ida_delnew, IDA_mem->ida_savres); + + /* Call the linear solve function to get J-inverse F; return if failed. */ + retval = IDA_mem->ida_lsolve(IDA_mem, IDA_mem->ida_delnew, + IDA_mem->ida_ewt, IDA_mem->ida_ynew, + IDA_mem->ida_ypnew, IDA_mem->ida_savres); + if(retval < 0) return(IDA_LSOLVE_FAIL); + if(retval > 0) return(IC_FAIL_RECOV); + + /* Compute the WRMS-norm; rescale if index = 0. */ + *fnorm = IDAWrmsNorm(IDA_mem, IDA_mem->ida_delnew, IDA_mem->ida_ewt, SUNFALSE); + if(IDA_mem->ida_sysindex == 0) + (*fnorm) *= IDA_mem->ida_tscale * SUNRabs(IDA_mem->ida_cj); + + return(IDA_SUCCESS); + +} + +/* + * ----------------------------------------------------------------- + * IDANewyyp + * ----------------------------------------------------------------- + * IDANewyyp updates the vectors ynew and ypnew from yy0 and yp0, + * using the current step vector lambda*delta, in a manner + * depending on icopt and the input id vector. + * + * The return value is always IDA_SUCCESS = 0. + * ----------------------------------------------------------------- + */ + +static int IDANewyyp(IDAMem IDA_mem, realtype lambda) +{ + + /* IDA_YA_YDP_INIT case: ynew = yy0 - lambda*delta where id_i = 0 + ypnew = yp0 - cj*lambda*delta where id_i = 1. */ + if(IDA_mem->ida_icopt == IDA_YA_YDP_INIT) { + N_VProd(IDA_mem->ida_id, IDA_mem->ida_delta, IDA_mem->ida_dtemp); + N_VLinearSum(ONE, IDA_mem->ida_yp0, -IDA_mem->ida_cj*lambda, + IDA_mem->ida_dtemp, IDA_mem->ida_ypnew); + N_VLinearSum(ONE, IDA_mem->ida_delta, -ONE, + IDA_mem->ida_dtemp, IDA_mem->ida_dtemp); + N_VLinearSum(ONE, IDA_mem->ida_yy0, -lambda, + IDA_mem->ida_dtemp, IDA_mem->ida_ynew); + return(IDA_SUCCESS); + } + + /* IDA_Y_INIT case: ynew = yy0 - lambda*delta. (ypnew = yp0 preset.) */ + N_VLinearSum(ONE, IDA_mem->ida_yy0, -lambda, + IDA_mem->ida_delta, IDA_mem->ida_ynew); + return(IDA_SUCCESS); + +} + +/* + * ----------------------------------------------------------------- + * IDANewy + * ----------------------------------------------------------------- + * IDANewy updates the vector ynew from yy0, + * using the current step vector delta, in a manner + * depending on icopt and the input id vector. + * + * The return value is always IDA_SUCCESS = 0. + * ----------------------------------------------------------------- + */ + +static int IDANewy(IDAMem IDA_mem) +{ + + /* IDA_YA_YDP_INIT case: ynew = yy0 - delta where id_i = 0. */ + if(IDA_mem->ida_icopt == IDA_YA_YDP_INIT) { + N_VProd(IDA_mem->ida_id, IDA_mem->ida_delta, IDA_mem->ida_dtemp); + N_VLinearSum(ONE, IDA_mem->ida_delta, -ONE, + IDA_mem->ida_dtemp, IDA_mem->ida_dtemp); + N_VLinearSum(ONE, IDA_mem->ida_yy0, -ONE, + IDA_mem->ida_dtemp, IDA_mem->ida_ynew); + return(IDA_SUCCESS); + } + + /* IDA_Y_INIT case: ynew = yy0 - delta. */ + N_VLinearSum(ONE, IDA_mem->ida_yy0, -ONE, + IDA_mem->ida_delta, IDA_mem->ida_ynew); + return(IDA_SUCCESS); + +} + +/* + * ----------------------------------------------------------------- + * IDAICFailFlag + * ----------------------------------------------------------------- + * IDAICFailFlag prints a message and sets the IDACalcIC return + * value appropriate to the flag retval returned by IDAnlsIC. + * ----------------------------------------------------------------- + */ + +static int IDAICFailFlag(IDAMem IDA_mem, int retval) +{ + + /* Depending on retval, print error message and return error flag. */ + switch(retval) { + + case IDA_RES_FAIL: + IDAProcessError(IDA_mem, IDA_RES_FAIL, "IDA", "IDACalcIC", MSG_IC_RES_NONREC); + return(IDA_RES_FAIL); + + case IDA_FIRST_RES_FAIL: + IDAProcessError(IDA_mem, IDA_FIRST_RES_FAIL, "IDA", "IDACalcIC", MSG_IC_RES_FAIL); + return(IDA_FIRST_RES_FAIL); + + case IDA_LSETUP_FAIL: + IDAProcessError(IDA_mem, IDA_LSETUP_FAIL, "IDA", "IDACalcIC", MSG_IC_SETUP_FAIL); + return(IDA_LSETUP_FAIL); + + case IDA_LSOLVE_FAIL: + IDAProcessError(IDA_mem, IDA_LSOLVE_FAIL, "IDA", "IDACalcIC", MSG_IC_SOLVE_FAIL); + return(IDA_LSOLVE_FAIL); + + case IC_FAIL_RECOV: + IDAProcessError(IDA_mem, IDA_NO_RECOVERY, "IDA", "IDACalcIC", MSG_IC_NO_RECOVERY); + return(IDA_NO_RECOVERY); + + case IC_CONSTR_FAILED: + IDAProcessError(IDA_mem, IDA_CONSTR_FAIL, "IDA", "IDACalcIC", MSG_IC_FAIL_CONSTR); + return(IDA_CONSTR_FAIL); + + case IC_LINESRCH_FAILED: + IDAProcessError(IDA_mem, IDA_LINESEARCH_FAIL, "IDA", "IDACalcIC", MSG_IC_FAILED_LINS); + return(IDA_LINESEARCH_FAIL); + + case IC_CONV_FAIL: + IDAProcessError(IDA_mem, IDA_CONV_FAIL, "IDA", "IDACalcIC", MSG_IC_CONV_FAILED); + return(IDA_CONV_FAIL); + + case IC_SLOW_CONVRG: + IDAProcessError(IDA_mem, IDA_CONV_FAIL, "IDA", "IDACalcIC", MSG_IC_CONV_FAILED); + return(IDA_CONV_FAIL); + + case IDA_BAD_EWT: + IDAProcessError(IDA_mem, IDA_BAD_EWT, "IDA", "IDACalcIC", MSG_IC_BAD_EWT); + return(IDA_BAD_EWT); + + } + return -99; +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_impl.h new file mode 100644 index 0000000..93b1458 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_impl.h @@ -0,0 +1,526 @@ +/* + * ----------------------------------------------------------------- + * $Revision$ + * $Date$ + * ----------------------------------------------------------------- + * Programmer(s): Allan G. Taylor, Alan C. Hindmarsh, Radu Serban, + * 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 (private version) for the main IDA solver. + * ----------------------------------------------------------------- + */ + +#ifndef _IDA_IMPL_H +#define _IDA_IMPL_H + +#include <stdarg.h> + +#include <ida/ida.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +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 + * ================================================================= + */ + + +/* 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 */ +#define MXSTEP_DEFAULT 500 /* mxstep default value */ + +/* Return values for lower level routines used by IDASolve and functions + provided to the nonlinear solver */ + +#define IDA_RES_RECVR +1 +#define IDA_LSETUP_RECVR +2 +#define IDA_LSOLVE_RECVR +3 +#define IDA_CONSTR_RECVR +5 +#define IDA_NLS_SETUP_RECVR +6 + +/* + * ---------------------------------------------------------------- + * Types : struct IDAMemRec, IDAMem + * ---------------------------------------------------------------- + * The type IDAMem is type pointer to struct IDAMemRec. This + * structure contains fields to keep track of problem state. + * ---------------------------------------------------------------- + */ + +typedef struct IDAMemRec { + + realtype ida_uround; /* machine unit roundoff */ + + /* Problem Specification Data */ + + IDAResFn ida_res; /* F(t,y(t),y'(t))=0; the function F */ + void *ida_user_data; /* user pointer passed to res */ + + 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 */ + booleantype ida_user_efun; /* SUNTRUE if user provides efun */ + IDAEwtFn ida_efun; /* function to set ewt */ + void *ida_edata; /* user pointer passed to efun */ + + + booleantype ida_constraintsSet; /* constraints vector present: + do constraints calc */ + booleantype ida_suppressalg; /* SUNTRUE means suppress algebraic vars + in local error tests */ + + /* Divided differences array and associated minor arrays */ + + N_Vector ida_phi[MXORDP1]; /* phi = (maxord+1) arrays of divided differences */ + + realtype ida_psi[MXORDP1]; /* differences in t (sums of recent step sizes) */ + realtype ida_alpha[MXORDP1]; /* ratios of current stepsize to psi values */ + realtype ida_beta[MXORDP1]; /* ratios of current to previous product of psi's */ + realtype ida_sigma[MXORDP1]; /* product successive alpha values and factorial */ + realtype ida_gamma[MXORDP1]; /* sum of reciprocals of psi values */ + + /* N_Vectors */ + + N_Vector ida_ewt; /* error weight vector */ + N_Vector ida_yy; /* work space for y vector (= user's yret) */ + N_Vector ida_yp; /* work space for y' vector (= user's ypret) */ + N_Vector ida_yypredict; /* predicted y vector */ + N_Vector ida_yppredict; /* predicted y' vector */ + N_Vector ida_delta; /* residual vector */ + N_Vector ida_id; /* bit vector for diff./algebraic components */ + N_Vector ida_constraints; /* vector of inequality constraint options */ + N_Vector ida_savres; /* saved residual vector */ + 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 */ + N_Vector ida_ynew; /* work vector for y in IDACalcIC (= tempv2) */ + N_Vector ida_ypnew; /* work vector for yp in IDACalcIC (= ee) */ + N_Vector ida_delnew; /* work vector for delta in IDACalcIC (= phi[2]) */ + N_Vector ida_dtemp; /* work vector in IDACalcIC (= phi[3]) */ + + /* Variables for use by IDACalcIC*/ + + realtype ida_t0; /* initial t */ + N_Vector ida_yy0; /* initial y vector (user-supplied). */ + N_Vector ida_yp0; /* initial y' vector (user-supplied). */ + + int ida_icopt; /* IC calculation user option */ + booleantype ida_lsoff; /* IC calculation linesearch turnoff option */ + int ida_maxnh; /* max. number of h tries in IC calculation */ + int ida_maxnj; /* max. number of J tries in IC calculation */ + int ida_maxnit; /* max. number of Netwon iterations in IC calc. */ + int ida_nbacktr; /* number of IC linesearch backtrack operations */ + int ida_sysindex; /* computed system index (0 or 1) */ + int ida_maxbacks; /* max backtracks per Newton step */ + realtype ida_epiccon; /* IC nonlinear convergence test constant */ + realtype ida_steptol; /* minimum Newton step size in IC calculation */ + realtype ida_tscale; /* time scale factor = abs(tout1 - t0) */ + + /* Tstop information */ + + booleantype ida_tstopset; + realtype ida_tstop; + + /* Step Data */ + + int ida_kk; /* current BDF method order */ + int ida_kused; /* method order used on last successful step */ + int ida_knew; /* order for next step from order decrease decision */ + int ida_phase; /* flag to trigger step doubling in first few steps */ + int ida_ns; /* counts steps at fixed stepsize and order */ + + realtype ida_hin; /* initial step */ + realtype ida_h0u; /* actual initial stepsize */ + realtype ida_hh; /* current step size h */ + realtype ida_hused; /* step size used on last successful step */ + realtype ida_rr; /* rr = hnext / hused */ + realtype ida_tn; /* current internal value of t */ + realtype ida_tretlast; /* value of tret previously returned by IDASolve */ + realtype ida_cj; /* current value of scalar (-alphas/hh) in Jacobian */ + realtype ida_cjlast; /* cj value saved from last successful step */ + realtype ida_cjold; /* cj value saved from last call to lsetup */ + realtype ida_cjratio; /* ratio of cj values: cj/cjold */ + realtype ida_ss; /* scalar used in Newton iteration convergence test */ + realtype ida_oldnrm; /* norm of previous nonlinear solver update */ + realtype ida_epsNewt; /* test constant in Newton convergence test */ + realtype ida_epcon; /* coeficient of the Newton covergence test */ + realtype ida_toldel; /* tolerance in direct test on Newton corrections */ + + /* Limits */ + + int ida_maxncf; /* max numer of convergence failures */ + int ida_maxnef; /* max number of error test failures */ + + int ida_maxord; /* max value of method order k: */ + int ida_maxord_alloc; /* value of maxord used when allocating memory */ + 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) */ + + /* Counters */ + + long int ida_nst; /* number of internal steps taken */ + long int ida_nre; /* number of function (res) calls */ + long int ida_ncfn; /* number of corrector convergence failures */ + long int ida_netf; /* number of error test failures */ + long int ida_nni; /* number of Newton iterations performed */ + long int ida_nsetups; /* number of lsetup calls */ + + /* Space requirements for IDA */ + + sunindextype ida_lrw1; /* no. of realtype words in 1 N_Vector */ + sunindextype ida_liw1; /* no. of integer words in 1 N_Vector */ + long int ida_lrw; /* number of realtype words in IDA work vectors */ + long int ida_liw; /* no. of integer words in IDA work vectors */ + + realtype ida_tolsf; /* tolerance scale factor (saved value) */ + + /* Error handler function and error ouput file */ + + IDAErrHandlerFn ida_ehfun; /* Error messages are handled by ehfun */ + void *ida_eh_data; /* dats pointer passed to ehfun */ + FILE *ida_errfp; /* IDA error messages are sent to errfp */ + + /* Flags to verify correct calling sequence */ + + booleantype ida_SetupDone; /* set to SUNFALSE by IDAMalloc and IDAReInit + 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 IDAMAlloc + tested by IDAReInit and IDASolve */ + + /* Nonlinear Solver */ + + SUNNonlinearSolver NLS; /* Sundials generic nonlinear solver object */ + booleantype ownNLS; /* flag indicating if IDA created the nonlinear + solver object */ + + /* Linear Solver Data */ + + /* Linear Solver functions to be called */ + + 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_lsolve)(struct IDAMemRec *idamem, N_Vector b, N_Vector weight, + N_Vector ycur, N_Vector ypcur, N_Vector rescur); + + int (*ida_lperf)(struct IDAMemRec *idamem, int perftask); + + int (*ida_lfree)(struct IDAMemRec *idamem); + + /* Linear Solver specific memory */ + + void *ida_lmem; + + /* Flag to indicate successful ida_linit call */ + + booleantype ida_linitOK; + + /* Rootfinding Data */ + + IDARootFn ida_gfun; /* Function g for roots sought */ + int ida_nrtfn; /* number of components of g */ + int *ida_iroots; /* array for root information */ + int *ida_rootdir; /* array specifying direction of zero-crossing */ + realtype ida_tlo; /* nearest endpoint of interval in root search */ + realtype ida_thi; /* farthest endpoint of interval in root search */ + realtype ida_trout; /* t return value from rootfinder routine */ + realtype *ida_glo; /* saved array of g values at t = tlo */ + realtype *ida_ghi; /* saved array of g values at t = thi */ + realtype *ida_grout; /* array of g values at t = trout */ + realtype ida_toutc; /* copy of tout (if NORMAL mode) */ + realtype ida_ttol; /* tolerance on root location */ + int ida_taskc; /* copy of parameter itask */ + int ida_irfnd; /* flag showing whether last step had a root */ + long int ida_nge; /* counter for g evaluations */ + booleantype *ida_gactive; /* array with active/inactive event functions */ + int ida_mxgnull; /* number of warning messages about possible g==0 */ + + /* Arrays for Fused Vector Operations */ + + realtype ida_cvals[MXORDP1]; + realtype ida_dvals[MAXORD_DEFAULT]; + + N_Vector ida_Xvecs[MXORDP1]; + N_Vector ida_Zvecs[MXORDP1]; + +} *IDAMem; + +/* + * ================================================================= + * 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); + * ----------------------------------------------------------------- + * 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 sent to the error handler function. + * ---------------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------- + * 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 ida_lsetup routine should return 0 if successful, + * 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); + * ----------------------------------------------------------------- + * 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 + * for an unrecoverable error. + * ----------------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------- + * int (*ida_lperf)(IDAMem IDA_mem, int perftask); + * ----------------------------------------------------------------- + * ida_lperf is called two places in IDA where linear solver + * performance data is required by IDA. For perftask = 0, an + * initialization of performance variables is performed, while for + * perftask = 1, the performance is evaluated. + * ----------------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------- + * 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 + * return 0 upon success, nonzero on failure. + * ----------------------------------------------------------------- + */ + +/* + * ================================================================= + * I D A I N T E R N A L F U N C T I O N S + * ================================================================= + */ + +/* Prototype of internal ewtSet function */ + +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, ...); + +/* Prototype of internal errHandler function */ + +void IDAErrHandler(int error_code, const char *module, const char *function, + char *msg, void *data); + +/* Norm functions */ + +realtype IDAWrmsNorm(IDAMem IDA_mem, N_Vector x, N_Vector w, booleantype mask); + +/* Nonlinear solver initialization function */ + +int idaNlsInit(IDAMem IDA_mem); + +/* + * ================================================================= + * I D A E R R O R M E S S A G E S + * ================================================================= + */ + +#if defined(SUNDIALS_EXTENDED_PRECISION) + +#define MSG_TIME "t = %Lg, " +#define MSG_TIME_H "t = %Lg and h = %Lg, " +#define MSG_TIME_INT "t = %Lg is not between tcur - hu = %Lg and tcur = %Lg." +#define MSG_TIME_TOUT "tout = %Lg" +#define MSG_TIME_TSTOP "tstop = %Lg" + +#elif defined(SUNDIALS_DOUBLE_PRECISION) + +#define MSG_TIME "t = %lg, " +#define MSG_TIME_H "t = %lg and h = %lg, " +#define MSG_TIME_INT "t = %lg is not between tcur - hu = %lg and tcur = %lg." +#define MSG_TIME_TOUT "tout = %lg" +#define MSG_TIME_TSTOP "tstop = %lg" + +#else + +#define MSG_TIME "t = %g, " +#define MSG_TIME_H "t = %g and h = %g, " +#define MSG_TIME_INT "t = %g is not between tcur - hu = %g and tcur = %g." +#define MSG_TIME_TOUT "tout = %g" +#define MSG_TIME_TSTOP "tstop = %g" + +#endif + +/* General errors */ + +#define MSG_MEM_FAIL "A memory request failed." +#define MSG_NO_MEM "ida_mem = NULL illegal." +#define MSG_NO_MALLOC "Attempt to call before IDAMalloc." +#define MSG_BAD_NVECTOR "A required vector operation is not implemented." + +/* Initialization errors */ + +#define MSG_Y0_NULL "y0 = NULL illegal." +#define MSG_YP0_NULL "yp0 = NULL illegal." +#define MSG_BAD_ITOL "Illegal value for itol. The legal values are IDA_SS, IDA_SV, and IDA_WF." +#define MSG_RES_NULL "res = NULL illegal." +#define MSG_BAD_RTOL "reltol < 0 illegal." +#define MSG_ATOL_NULL "abstol = NULL illegal." +#define MSG_BAD_ATOL "Some abstol component < 0.0 illegal." +#define MSG_ROOT_FUNC_NULL "g = NULL illegal." + +#define MSG_MISSING_ID "id = NULL but suppressalg option on." +#define MSG_NO_TOLS "No integration tolerances have been specified." +#define MSG_FAIL_EWT "The user-provide EwtSet function failed." +#define MSG_BAD_EWT "Some initial ewt component = 0.0 illegal." +#define MSG_Y0_FAIL_CONSTR "y0 fails to satisfy constraints." +#define MSG_LSOLVE_NULL "The linear solver's solve routine is NULL." +#define MSG_LINIT_FAIL "The linear solver's init routine failed." +#define MSG_NLS_INIT_FAIL "The nonlinear solver's init routine failed." + +/* IDACalcIC error messages */ + +#define MSG_IC_BAD_ICOPT "icopt has an illegal value." +#define MSG_IC_BAD_MAXBACKS "maxbacks <= 0 illegal." +#define MSG_IC_MISSING_ID "id = NULL conflicts with icopt." +#define MSG_IC_TOO_CLOSE "tout1 too close to t0 to attempt initial condition calculation." +#define MSG_IC_BAD_ID "id has illegal values." +#define MSG_IC_BAD_EWT "Some initial ewt component = 0.0 illegal." +#define MSG_IC_RES_NONREC "The residual function failed unrecoverably. " +#define MSG_IC_RES_FAIL "The residual function failed at the first call. " +#define MSG_IC_SETUP_FAIL "The linear solver setup failed unrecoverably." +#define MSG_IC_SOLVE_FAIL "The linear solver solve failed unrecoverably." +#define MSG_IC_NO_RECOVERY "The residual routine or the linear setup or solve routine had a recoverable error, but IDACalcIC was unable to recover." +#define MSG_IC_FAIL_CONSTR "Unable to satisfy the inequality constraints." +#define MSG_IC_FAILED_LINS "The linesearch algorithm failed: step too small or too many backtracks." +#define MSG_IC_CONV_FAILED "Newton/Linesearch algorithm failed to converge." + +/* IDASolve error messages */ + +#define MSG_YRET_NULL "yret = NULL illegal." +#define MSG_YPRET_NULL "ypret = NULL illegal." +#define MSG_TRET_NULL "tret = NULL illegal." +#define MSG_BAD_ITASK "itask has an illegal value." +#define MSG_TOO_CLOSE "tout too close to t0 to start integration." +#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_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." + +#define MSG_BAD_K "Illegal value for k." +#define MSG_NULL_DKY "dky = NULL illegal." +#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." + +/* IDASet* / IDAGet* error messages */ + +#define MSG_NEG_MAXORD "maxord <= 0 illegal." +#define MSG_BAD_MAXORD "Illegal attempt to increase maximum order." +#define MSG_NEG_HMAX "hmax < 0 illegal." +#define MSG_NEG_EPCON "epcon <= 0.0 illegal." +#define MSG_BAD_CONSTR "Illegal values in constraints vector." +#define MSG_BAD_EPICCON "epiccon <= 0.0 illegal." +#define MSG_BAD_MAXNH "maxnh <= 0 illegal." +#define MSG_BAD_MAXNJ "maxnj <= 0 illegal." +#define MSG_BAD_MAXNIT "maxnit <= 0 illegal." +#define MSG_BAD_STEPTOL "steptol <= 0.0 illegal." + +#define MSG_TOO_LATE "IDAGetConsistentIC can only be called before IDASolve." + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_io.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_io.c new file mode 100644 index 0000000..5c1868f --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_io.c @@ -0,0 +1,1183 @@ +/* + * ----------------------------------------------------------------- + * $Revision$ + * $Date$ + * ----------------------------------------------------------------- + * Programmer(s): Alan Hindmarsh, Radu Serban 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 implementation file for the optional inputs and + * outputs for the IDA solver. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "ida_impl.h" + +#include <sundials/sundials_math.h> + +#define ZERO RCONST(0.0) +#define HALF RCONST(0.5) +#define ONE RCONST(1.0) +#define TWOPT5 RCONST(2.5) + +/* + * ================================================================= + * IDA optional input functions + * ================================================================= + */ + +int IDASetErrHandlerFn(void *ida_mem, IDAErrHandlerFn ehfun, void *eh_data) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetErrHandlerFn", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + IDA_mem->ida_ehfun = ehfun; + IDA_mem->ida_eh_data = eh_data; + + return(IDA_SUCCESS); +} + + +int IDASetErrFile(void *ida_mem, FILE *errfp) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetErrFile", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + IDA_mem->ida_errfp = errfp; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetUserData(void *ida_mem, void *user_data) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetUserData", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + IDA_mem->ida_user_data = user_data; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetMaxOrd(void *ida_mem, int maxord) +{ + IDAMem IDA_mem; + int maxord_alloc; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetMaxOrd", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (maxord <= 0) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASetMaxOrd", MSG_NEG_MAXORD); + return(IDA_ILL_INPUT); + } + + /* Cannot increase maximum order beyond the value that + was used when allocating memory */ + maxord_alloc = IDA_mem->ida_maxord_alloc; + + 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); + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetMaxNumSteps(void *ida_mem, long int mxsteps) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetMaxNumSteps", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + /* Passing mxsteps=0 sets the default. Passing mxsteps<0 disables the test. */ + + if (mxsteps == 0) + IDA_mem->ida_mxstep = MXSTEP_DEFAULT; + else + IDA_mem->ida_mxstep = mxsteps; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetInitStep(void *ida_mem, realtype hin) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetInitStep", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + IDA_mem->ida_hin = hin; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetMaxStep(void *ida_mem, realtype hmax) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetMaxStep", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (hmax < 0) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASetMaxStep", MSG_NEG_HMAX); + return(IDA_ILL_INPUT); + } + + /* Passing 0 sets hmax = infinity */ + if (hmax == ZERO) { + IDA_mem->ida_hmax_inv = HMAX_INV_DEFAULT; + return(IDA_SUCCESS); + } + + IDA_mem->ida_hmax_inv = ONE/hmax; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetStopTime(void *ida_mem, realtype tstop) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetStopTime", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + /* If IDASolve was called at least once, test if tstop is legal + * (i.e. if it was not already passed). + * If IDASetStopTime is called before the first call to IDASolve, + * tstop will be checked in IDASolve. */ + if (IDA_mem->ida_nst > 0) { + + if ( (tstop - IDA_mem->ida_tn) * IDA_mem->ida_hh < ZERO ) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASetStopTime", MSG_BAD_TSTOP, tstop, IDA_mem->ida_tn); + return(IDA_ILL_INPUT); + } + + } + + IDA_mem->ida_tstop = tstop; + IDA_mem->ida_tstopset = SUNTRUE; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetNonlinConvCoef(void *ida_mem, realtype epcon) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetNonlinConvCoef", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (epcon <= ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASetNonlinConvCoef", MSG_NEG_EPCON); + return(IDA_ILL_INPUT); + } + + IDA_mem->ida_epcon = epcon; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetMaxErrTestFails(void *ida_mem, int maxnef) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetMaxErrTestFails", MSG_NO_MEM); + return (IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + IDA_mem->ida_maxnef = maxnef; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetMaxConvFails(void *ida_mem, int maxncf) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetMaxConvFails", MSG_NO_MEM); + return (IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + IDA_mem->ida_maxncf = maxncf; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetMaxNonlinIters(void *ida_mem, int maxcor) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", + "IDASetMaxNonlinIters", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + /* check that the NLS is non-NULL */ + if (IDA_mem->NLS == NULL) { + IDAProcessError(NULL, IDA_MEM_FAIL, "IDA", + "IDASetMaxNonlinIters", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + return(SUNNonlinSolSetMaxIters(IDA_mem->NLS, maxcor)); +} + +/*-----------------------------------------------------------------*/ + +int IDASetSuppressAlg(void *ida_mem, booleantype suppressalg) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetSuppressAlg", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + IDA_mem->ida_suppressalg = suppressalg; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetId(void *ida_mem, N_Vector id) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetId", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (id == NULL) { + if (IDA_mem->ida_idMallocDone) { + N_VDestroy(IDA_mem->ida_id); + IDA_mem->ida_lrw -= IDA_mem->ida_lrw1; + IDA_mem->ida_liw -= IDA_mem->ida_liw1; + } + IDA_mem->ida_idMallocDone = SUNFALSE; + return(IDA_SUCCESS); + } + + if ( !(IDA_mem->ida_idMallocDone) ) { + IDA_mem->ida_id = N_VClone(id); + IDA_mem->ida_lrw += IDA_mem->ida_lrw1; + IDA_mem->ida_liw += IDA_mem->ida_liw1; + IDA_mem->ida_idMallocDone = SUNTRUE; + } + + /* Load the id vector */ + + N_VScale(ONE, id, IDA_mem->ida_id); + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetConstraints(void *ida_mem, N_Vector constraints) +{ + IDAMem IDA_mem; + realtype temptest; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetConstraints", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (constraints == NULL) { + if (IDA_mem->ida_constraintsMallocDone) { + N_VDestroy(IDA_mem->ida_constraints); + IDA_mem->ida_lrw -= IDA_mem->ida_lrw1; + IDA_mem->ida_liw -= IDA_mem->ida_liw1; + } + IDA_mem->ida_constraintsMallocDone = SUNFALSE; + IDA_mem->ida_constraintsSet = SUNFALSE; + return(IDA_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) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASetConstraints", MSG_BAD_NVECTOR); + return(IDA_ILL_INPUT); + } + + /* Check the constraints vector */ + + temptest = N_VMaxNorm(constraints); + if((temptest > TWOPT5) || (temptest < HALF)){ + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASetConstraints", MSG_BAD_CONSTR); + return(IDA_ILL_INPUT); + } + + if ( !(IDA_mem->ida_constraintsMallocDone) ) { + IDA_mem->ida_constraints = N_VClone(constraints); + IDA_mem->ida_lrw += IDA_mem->ida_lrw1; + IDA_mem->ida_liw += IDA_mem->ida_liw1; + IDA_mem->ida_constraintsMallocDone = SUNTRUE; + } + + /* Load the constraints vector */ + + N_VScale(ONE, constraints, IDA_mem->ida_constraints); + + IDA_mem->ida_constraintsSet = SUNTRUE; + + return(IDA_SUCCESS); +} + +/* + * IDASetRootDirection + * + * Specifies the direction of zero-crossings to be monitored. + * The default is to monitor both crossings. + */ + +int IDASetRootDirection(void *ida_mem, int *rootdir) +{ + IDAMem IDA_mem; + int i, nrt; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetRootDirection", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + nrt = IDA_mem->ida_nrtfn; + if (nrt==0) { + IDAProcessError(NULL, IDA_ILL_INPUT, "IDA", "IDASetRootDirection", MSG_NO_ROOT); + return(IDA_ILL_INPUT); + } + + for(i=0; i<nrt; i++) IDA_mem->ida_rootdir[i] = rootdir[i]; + + return(IDA_SUCCESS); +} + +/* + * IDASetNoInactiveRootWarn + * + * Disables issuing a warning if some root function appears + * to be identically zero at the beginning of the integration + */ + +int IDASetNoInactiveRootWarn(void *ida_mem) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetNoInactiveRootWarn", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + IDA_mem->ida_mxgnull = 0; + + return(IDA_SUCCESS); +} + + +/* + * ================================================================= + * IDA IC optional input functions + * ================================================================= + */ + +int IDASetNonlinConvCoefIC(void *ida_mem, realtype epiccon) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetNonlinConvCoefIC", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (epiccon <= ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASetNonlinConvCoefIC", MSG_BAD_EPICCON); + return(IDA_ILL_INPUT); + } + + IDA_mem->ida_epiccon = epiccon; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetMaxNumStepsIC(void *ida_mem, int maxnh) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetMaxNumStepsIC", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (maxnh <= 0) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASetMaxNumStepsIC", MSG_BAD_MAXNH); + return(IDA_ILL_INPUT); + } + + IDA_mem->ida_maxnh = maxnh; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetMaxNumJacsIC(void *ida_mem, int maxnj) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetMaxNumJacsIC", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (maxnj <= 0) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASetMaxNumJacsIC", MSG_BAD_MAXNJ); + return(IDA_ILL_INPUT); + } + + IDA_mem->ida_maxnj = maxnj; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetMaxNumItersIC(void *ida_mem, int maxnit) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetMaxNumItersIC", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (maxnit <= 0) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASetMaxNumItersIC", MSG_BAD_MAXNIT); + return(IDA_ILL_INPUT); + } + + IDA_mem->ida_maxnit = maxnit; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetMaxBacksIC(void *ida_mem, int maxbacks) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetMaxBacksIC", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (maxbacks <= 0) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASetMaxBacksIC", MSG_IC_BAD_MAXBACKS); + return(IDA_ILL_INPUT); + } + + IDA_mem->ida_maxbacks = maxbacks; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetLineSearchOffIC(void *ida_mem, booleantype lsoff) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetLineSearchOffIC", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + IDA_mem->ida_lsoff = lsoff; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetStepToleranceIC(void *ida_mem, realtype steptol) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetStepToleranceIC", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (steptol <= ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASetStepToleranceIC", MSG_BAD_STEPTOL); + return(IDA_ILL_INPUT); + } + + IDA_mem->ida_steptol = steptol; + + return(IDA_SUCCESS); +} + +/* + * ================================================================= + * IDA optional input functions + * ================================================================= + */ + +int IDAGetNumSteps(void *ida_mem, long int *nsteps) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetNumSteps", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *nsteps = IDA_mem->ida_nst; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetNumResEvals(void *ida_mem, long int *nrevals) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetNumResEvals", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *nrevals = IDA_mem->ida_nre; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetNumLinSolvSetups(void *ida_mem, long int *nlinsetups) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetNumLinSolvSetups", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *nlinsetups = IDA_mem->ida_nsetups; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetNumErrTestFails(void *ida_mem, long int *netfails) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetNumErrTestFails", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *netfails = IDA_mem->ida_netf; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetNumBacktrackOps(void *ida_mem, long int *nbacktracks) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetNumBacktrackOps", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *nbacktracks = IDA_mem->ida_nbacktr; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +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; + + if (IDA_mem->ida_kused != 0) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDAGetConsistentIC", MSG_TOO_LATE); + return(IDA_ILL_INPUT); + } + + if(yy0 != NULL) N_VScale(ONE, IDA_mem->ida_phi[0], yy0); + if(yp0 != NULL) N_VScale(ONE, IDA_mem->ida_phi[1], yp0); + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetLastOrder(void *ida_mem, int *klast) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetLastOrder", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *klast = IDA_mem->ida_kused; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetCurrentOrder(void *ida_mem, int *kcur) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetCurrentOrder", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *kcur = IDA_mem->ida_kk; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetActualInitStep(void *ida_mem, realtype *hinused) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetActualInitStep", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *hinused = IDA_mem->ida_h0u; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetLastStep(void *ida_mem, realtype *hlast) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetLastStep", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *hlast = IDA_mem->ida_hused; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetCurrentStep(void *ida_mem, realtype *hcur) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetCurrentStep", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *hcur = IDA_mem->ida_hh; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetCurrentTime(void *ida_mem, realtype *tcur) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetCurrentTime", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *tcur = IDA_mem->ida_tn; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetTolScaleFactor(void *ida_mem, realtype *tolsfact) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetTolScaleFactor", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *tolsfact = IDA_mem->ida_tolsf; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +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; + + N_VScale(ONE, IDA_mem->ida_ewt, eweight); + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetEstLocalErrors(void *ida_mem, N_Vector ele) +{ + IDAMem IDA_mem; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetEstLocalErrors", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + N_VScale(ONE, IDA_mem->ida_ee, ele); + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetWorkSpace(void *ida_mem, long int *lenrw, long int *leniw) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetWorkSpace", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *leniw = IDA_mem->ida_liw; + *lenrw = IDA_mem->ida_lrw; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +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, + realtype *hcur, realtype *tcur) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetIntegratorStats", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *nsteps = IDA_mem->ida_nst; + *nrevals = IDA_mem->ida_nre; + *nlinsetups = IDA_mem->ida_nsetups; + *netfails = IDA_mem->ida_netf; + *klast = IDA_mem->ida_kused; + *kcur = IDA_mem->ida_kk; + *hinused = IDA_mem->ida_h0u; + *hlast = IDA_mem->ida_hused; + *hcur = IDA_mem->ida_hh; + *tcur = IDA_mem->ida_tn; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetNumGEvals(void *ida_mem, long int *ngevals) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetNumGEvals", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *ngevals = IDA_mem->ida_nge; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetRootInfo(void *ida_mem, int *rootsfound) +{ + IDAMem IDA_mem; + int i, nrt; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetRootInfo", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + nrt = IDA_mem->ida_nrtfn; + + for (i=0; i<nrt; i++) rootsfound[i] = IDA_mem->ida_iroots[i]; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetNumNonlinSolvIters(void *ida_mem, long int *nniters) +{ + IDAMem IDA_mem; + long int nls_iters; + int retval; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", + "IDAGetNumNonlinSolvIters", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + /* get number of iterations for IC calc */ + *nniters = IDA_mem->ida_nni; + + /* check that the NLS is non-NULL */ + if (IDA_mem->NLS == NULL) { + IDAProcessError(NULL, IDA_MEM_FAIL, "IDA", + "IDAGetNumNonlinSolvIters", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + /* 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; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetNumNonlinSolvConvFails(void *ida_mem, long int *nncfails) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDAGetNumNonlinSolvConvFails", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *nncfails = IDA_mem->ida_ncfn; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetNonlinSolvStats(void *ida_mem, long int *nniters, long int *nncfails) +{ + IDAMem IDA_mem; + long int nls_iters; + int retval; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", + "IDAGetNonlinSolvStats", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *nniters = IDA_mem->ida_nni; + *nncfails = IDA_mem->ida_ncfn; + + /* check that the NLS is non-NULL */ + if (IDA_mem->NLS == NULL) { + IDAProcessError(NULL, IDA_MEM_FAIL, "IDA", + "IDAGetNonlinSolvStats", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + /* 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; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +char *IDAGetReturnFlagName(long int flag) +{ + char *name; + + name = (char *)malloc(24*sizeof(char)); + + switch(flag) { + case IDA_SUCCESS: + sprintf(name,"IDA_SUCCESS"); + break; + case IDA_TSTOP_RETURN: + sprintf(name,"IDA_TSTOP_RETURN"); + break; + case IDA_ROOT_RETURN: + sprintf(name,"IDA_ROOT_RETURN"); + break; + case IDA_TOO_MUCH_WORK: + sprintf(name,"IDA_TOO_MUCH_WORK"); + break; + case IDA_TOO_MUCH_ACC: + sprintf(name,"IDA_TOO_MUCH_ACC"); + break; + case IDA_ERR_FAIL: + sprintf(name,"IDA_ERR_FAIL"); + break; + case IDA_CONV_FAIL: + sprintf(name,"IDA_CONV_FAIL"); + break; + case IDA_LINIT_FAIL: + sprintf(name,"IDA_LINIT_FAIL"); + break; + case IDA_LSETUP_FAIL: + sprintf(name,"IDA_LSETUP_FAIL"); + break; + case IDA_LSOLVE_FAIL: + sprintf(name,"IDA_LSOLVE_FAIL"); + break; + case IDA_CONSTR_FAIL: + sprintf(name,"IDA_CONSTR_FAIL"); + break; + case IDA_RES_FAIL: + sprintf(name,"IDA_RES_FAIL"); + break; + case IDA_FIRST_RES_FAIL: + sprintf(name,"IDA_FIRST_RES_FAIL"); + break; + case IDA_REP_RES_ERR: + sprintf(name,"IDA_REP_RES_ERR"); + break; + case IDA_RTFUNC_FAIL: + sprintf(name,"IDA_RTFUNC_FAIL"); + break; + case IDA_MEM_FAIL: + sprintf(name,"IDA_MEM_FAIL"); + break; + case IDA_MEM_NULL: + sprintf(name,"IDA_MEM_NULL"); + break; + case IDA_ILL_INPUT: + sprintf(name,"IDA_ILL_INPUT"); + break; + case IDA_NO_MALLOC: + sprintf(name,"IDA_NO_MALLOC"); + break; + case IDA_BAD_T: + sprintf(name,"IDA_BAD_T"); + break; + case IDA_BAD_EWT: + sprintf(name,"IDA_BAD_EWT"); + break; + case IDA_NO_RECOVERY: + sprintf(name,"IDA_NO_RECOVERY"); + break; + case IDA_LINESEARCH_FAIL: + sprintf(name,"IDA_LINESEARCH_FAIL"); + break; + + default: + sprintf(name,"NONE"); + } + + return(name); +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_ls.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_ls.c new file mode 100644 index 0000000..566605e --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_ls.c @@ -0,0 +1,1548 @@ +/*----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 + *----------------------------------------------------------------- + * Implementation file for IDA's linear solver interface. + *-----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "ida_impl.h" +#include "ida_ls_impl.h" +#include <sundials/sundials_math.h> +#include <sunmatrix/sunmatrix_band.h> +#include <sunmatrix/sunmatrix_dense.h> +#include <sunmatrix/sunmatrix_sparse.h> + +/* constants */ +#define MAX_ITERS 3 /* max. number of attempts to recover in DQ J*v */ +#define ZERO RCONST(0.0) +#define PT25 RCONST(0.25) +#define PT05 RCONST(0.05) +#define PT9 RCONST(0.9) +#define ONE RCONST(1.0) +#define TWO RCONST(2.0) + + +/*=============================================================== + IDALS Exported functions -- Required + ===============================================================*/ + +/*--------------------------------------------------------------- + IDASetLinearSolver specifies the linear solver + ---------------------------------------------------------------*/ +int IDASetLinearSolver(void *ida_mem, SUNLinearSolver LS, SUNMatrix A) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval, LSType; + + /* Return immediately if any input is NULL */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDALS_MEM_NULL, "IDALS", + "IDASetLinearSolver", MSG_LS_IDAMEM_NULL); + return(IDALS_MEM_NULL); + } + if (LS == NULL) { + IDAProcessError(NULL, IDALS_ILL_INPUT, "IDALS", + "IDASetLinearSolver", + "LS must be non-NULL"); + return(IDALS_ILL_INPUT); + } + 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) ) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDALS", + "IDASetLinearSolver", + "LS object is missing a required operation"); + return(IDALS_ILL_INPUT); + } + + /* Test if vector is compatible with LS interface */ + if ( (IDA_mem->ida_tempv1->ops->nvdotprod == NULL) || + (IDA_mem->ida_tempv1->ops->nvconst == 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)) { + 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 */ + if (IDA_mem->ida_lfree) IDA_mem->ida_lfree(IDA_mem); + + /* Set four main system linear solver function fields in IDA_mem */ + IDA_mem->ida_linit = idaLsInitialize; + IDA_mem->ida_lsetup = idaLsSetup; + IDA_mem->ida_lsolve = idaLsSolve; + 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; + + /* Allocate memory for IDALsMemRec */ + idals_mem = NULL; + idals_mem = (IDALsMem) malloc(sizeof(struct IDALsMemRec)); + if (idals_mem == NULL) { + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDALS", + "IDASetLinearSolver", MSG_LS_MEM_FAIL); + return(IDALS_MEM_FAIL); + } + memset(idals_mem, 0, sizeof(struct IDALsMemRec)); + + /* set SUNLinearSolver pointer */ + idals_mem->LS = LS; + + /* Set defaults for Jacobian-related fields */ + idals_mem->J = A; + if (A != NULL) { + idals_mem->jacDQ = SUNTRUE; + idals_mem->jac = idaLsDQJac; + idals_mem->J_data = IDA_mem; + } else { + idals_mem->jacDQ = SUNFALSE; + idals_mem->jac = NULL; + idals_mem->J_data = NULL; + } + idals_mem->jtimesDQ = SUNTRUE; + idals_mem->jtsetup = NULL; + idals_mem->jtimes = idaLsDQJtimes; + idals_mem->jt_data = IDA_mem; + + /* Set defaults for preconditioner-related fields */ + idals_mem->pset = NULL; + idals_mem->psolve = NULL; + idals_mem->pfree = NULL; + idals_mem->pdata = IDA_mem->ida_user_data; + + /* Initialize counters */ + idaLsInitializeCounters(idals_mem); + + /* Set default values for the rest of the Ls parameters */ + idals_mem->eplifac = PT05; + idals_mem->dqincfac = ONE; + idals_mem->last_flag = IDALS_SUCCESS; + + /* If LS supports ATimes, attach IDALs routine */ + if (LS->ops->setatimes) { + retval = SUNLinSolSetATimes(LS, IDA_mem, idaLsATimes); + if (retval != SUNLS_SUCCESS) { + IDAProcessError(IDA_mem, IDALS_SUNLS_FAIL, "IDALS", + "IDASetLinearSolver", + "Error in calling SUNLinSolSetATimes"); + free(idals_mem); idals_mem = NULL; + 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) { + IDAProcessError(IDA_mem, IDALS_SUNLS_FAIL, "IDALS", + "IDASetLinearSolver", + "Error in calling SUNLinSolSetPreconditioner"); + free(idals_mem); idals_mem = NULL; + return(IDALS_SUNLS_FAIL); + } + } + + /* Allocate memory for ytemp, yptemp and x */ + idals_mem->ytemp = N_VClone(IDA_mem->ida_tempv1); + if (idals_mem->ytemp == NULL) { + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDALS", + "IDASetLinearSolver", MSG_LS_MEM_FAIL); + free(idals_mem); idals_mem = NULL; + return(IDALS_MEM_FAIL); + } + + idals_mem->yptemp = N_VClone(IDA_mem->ida_tempv1); + if (idals_mem->yptemp == NULL) { + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDALS", + "IDASetLinearSolver", MSG_LS_MEM_FAIL); + N_VDestroy(idals_mem->ytemp); + free(idals_mem); idals_mem = NULL; + return(IDALS_MEM_FAIL); + } + + idals_mem->x = N_VClone(IDA_mem->ida_tempv1); + if (idals_mem->x == NULL) { + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDALS", + "IDASetLinearSolver", MSG_LS_MEM_FAIL); + N_VDestroy(idals_mem->ytemp); + N_VDestroy(idals_mem->yptemp); + free(idals_mem); idals_mem = NULL; + 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) ); + + /* Attach linear solver memory to integrator memory */ + IDA_mem->ida_lmem = idals_mem; + + return(IDALS_SUCCESS); +} + + +/*=============================================================== + Optional input/output routines + ===============================================================*/ + + +/* IDASetJacFn specifies the Jacobian function */ +int IDASetJacFn(void *ida_mem, IDALsJacFn jac) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure */ + retval = idaLs_AccessLMem(ida_mem, "IDALsSetJacFn", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* return with failure if jac cannot be used */ + if ((jac != NULL) && (idals_mem->J == NULL)) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDALS", "IDASetJacFn", + "Jacobian routine cannot be supplied for NULL SUNMatrix"); + return(IDALS_ILL_INPUT); + } + + /* set Jacobian routine pointer, and update relevant flags */ + if (jac != NULL) { + idals_mem->jacDQ = SUNFALSE; + idals_mem->jac = jac; + idals_mem->J_data = IDA_mem->ida_user_data; + } else { + idals_mem->jacDQ = SUNTRUE; + idals_mem->jac = idaLsDQJac; + idals_mem->J_data = IDA_mem; + } + + return(IDALS_SUCCESS); +} + + +/* IDASetEpsLin specifies the nonlinear -> linear tolerance scale factor */ +int IDASetEpsLin(void *ida_mem, realtype eplifac) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure */ + retval = idaLs_AccessLMem(ida_mem, "IDASetEpsLin", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* Check for legal eplifac */ + if (eplifac < ZERO) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDALS", + "IDASetEpsLin", MSG_LS_NEG_EPLIFAC); + return(IDALS_ILL_INPUT); + } + + idals_mem->eplifac = (eplifac == ZERO) ? PT05 : eplifac; + + return(IDALS_SUCCESS); +} + + +/* IDASetIncrementFactor specifies increment factor for DQ approximations to Jv */ +int IDASetIncrementFactor(void *ida_mem, realtype dqincfac) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure */ + retval = idaLs_AccessLMem(ida_mem, "IDASetIncrementFactor", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* Check for legal dqincfac */ + if (dqincfac <= ZERO) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDALS", + "IDASetIncrementFactor", MSG_LS_NEG_DQINCFAC); + return(IDALS_ILL_INPUT); + } + + idals_mem->dqincfac = dqincfac; + + return(IDALS_SUCCESS); +} + + +/* IDASetPreconditioner specifies the user-supplied psetup and psolve routines */ +int IDASetPreconditioner(void *ida_mem, + IDALsPrecSetupFn psetup, + IDALsPrecSolveFn psolve) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + PSetupFn idals_psetup; + PSolveFn idals_psolve; + int retval; + + /* access IDALsMem structure */ + retval = idaLs_AccessLMem(ida_mem, "IDASetPreconditioner", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* store function pointers for user-supplied routines in IDALs interface */ + idals_mem->pset = psetup; + idals_mem->psolve = psolve; + + /* issue error if LS object does not allow user-supplied preconditioning */ + if (idals_mem->LS->ops->setpreconditioner == NULL) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDALS", + "IDASetPreconditioner", + "SUNLinearSolver object does not support user-supplied preconditioning"); + return(IDALS_ILL_INPUT); + } + + /* notify iterative linear solver to call IDALs interface routines */ + idals_psetup = (psetup == NULL) ? NULL : idaLsPSetup; + idals_psolve = (psolve == NULL) ? NULL : idaLsPSolve; + retval = SUNLinSolSetPreconditioner(idals_mem->LS, IDA_mem, + idals_psetup, idals_psolve); + if (retval != SUNLS_SUCCESS) { + IDAProcessError(IDA_mem, IDALS_SUNLS_FAIL, "IDALS", + "IDASetPreconditioner", + "Error in calling SUNLinSolSetPreconditioner"); + return(IDALS_SUNLS_FAIL); + } + + return(IDALS_SUCCESS); +} + + +/* IDASetJacTimes specifies the user-supplied Jacobian-vector product + setup and multiply routines */ +int IDASetJacTimes(void *ida_mem, IDALsJacTimesSetupFn jtsetup, + IDALsJacTimesVecFn jtimes) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure */ + retval = idaLs_AccessLMem(ida_mem, "IDASetJacTimes", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* issue error if LS object does not allow user-supplied ATimes */ + if (idals_mem->LS->ops->setatimes == NULL) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDALS", + "IDASetJacTimes", + "SUNLinearSolver object does not support user-supplied ATimes routine"); + return(IDALS_ILL_INPUT); + } + + /* store function pointers for user-supplied routines in IDALs + interface (NULL jtimes implies use of DQ default) */ + if (jtimes != NULL) { + idals_mem->jtimesDQ = SUNFALSE; + idals_mem->jtsetup = jtsetup; + idals_mem->jtimes = jtimes; + idals_mem->jt_data = IDA_mem->ida_user_data; + } else { + idals_mem->jtimesDQ = SUNTRUE; + idals_mem->jtsetup = NULL; + idals_mem->jtimes = idaLsDQJtimes; + idals_mem->jt_data = IDA_mem; + } + + return(IDALS_SUCCESS); +} + + +/* IDAGetLinWorkSpace returns the length of workspace allocated + for the IDALS linear solver interface */ +int IDAGetLinWorkSpace(void *ida_mem, long int *lenrwLS, + long int *leniwLS) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + sunindextype lrw1, liw1; + long int lrw, liw; + int retval; + + /* access IDALsMem structure */ + retval = idaLs_AccessLMem(ida_mem, "IDAGetLinWorkSpace", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* start with fixed sizes plus vector/matrix pointers */ + *lenrwLS = 3; + *leniwLS = 33; + + /* add N_Vector sizes */ + if (IDA_mem->ida_tempv1->ops->nvspace) { + N_VSpace(IDA_mem->ida_tempv1, &lrw1, &liw1); + *lenrwLS += 3*lrw1; + *leniwLS += 3*liw1; + } + + /* add LS sizes */ + if (idals_mem->LS->ops->space) { + retval = SUNLinSolSpace(idals_mem->LS, &lrw, &liw); + if (retval == 0) { + *lenrwLS += lrw; + *leniwLS += liw; + } + } + + return(IDALS_SUCCESS); +} + + +/* IDAGetNumJacEvals returns the number of Jacobian evaluations */ +int IDAGetNumJacEvals(void *ida_mem, long int *njevals) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure; store output and return */ + retval = idaLs_AccessLMem(ida_mem, "IDAGetNumJacEvals", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + *njevals = idals_mem->nje; + return(IDALS_SUCCESS); +} + + +/* IDAGetNumPrecEvals returns the number of preconditioner evaluations */ +int IDAGetNumPrecEvals(void *ida_mem, long int *npevals) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure; store output and return */ + retval = idaLs_AccessLMem(ida_mem, "IDAGetNumPrecEvals", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + *npevals = idals_mem->npe; + return(IDALS_SUCCESS); +} + + +/* IDAGetNumPrecSolves returns the number of preconditioner solves */ +int IDAGetNumPrecSolves(void *ida_mem, long int *npsolves) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure; store output and return */ + retval = idaLs_AccessLMem(ida_mem, "IDAGetNumPrecSolves", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + *npsolves = idals_mem->nps; + return(IDALS_SUCCESS); +} + + +/* IDAGetNumLinIters returns the number of linear iterations */ +int IDAGetNumLinIters(void *ida_mem, long int *nliters) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure; store output and return */ + retval = idaLs_AccessLMem(ida_mem, "IDAGetNumLinIters", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + *nliters = idals_mem->nli; + return(IDALS_SUCCESS); +} + + +/* IDAGetNumLinConvFails returns the number of linear convergence failures */ +int IDAGetNumLinConvFails(void *ida_mem, long int *nlcfails) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure; store output and return */ + retval = idaLs_AccessLMem(ida_mem, "IDAGetNumLinConvFails", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + *nlcfails = idals_mem->ncfl; + return(IDALS_SUCCESS); +} + + +/* IDAGetNumJTSetupEvals returns the number of calls to the + user-supplied Jacobian-vector product setup routine */ +int IDAGetNumJTSetupEvals(void *ida_mem, long int *njtsetups) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure; store output and return */ + retval = idaLs_AccessLMem(ida_mem, "IDAGetNumJTSetupEvals", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + *njtsetups = idals_mem->njtsetup; + return(IDALS_SUCCESS); +} + + +/* IDAGetNumJtimesEvals returns the number of calls to the + Jacobian-vector product multiply routine */ +int IDAGetNumJtimesEvals(void *ida_mem, long int *njvevals) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure; store output and return */ + retval = idaLs_AccessLMem(ida_mem, "IDAGetNumJtimesEvals", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + *njvevals = idals_mem->njtimes; + return(IDALS_SUCCESS); +} + + +/* IDAGetNumLinResEvals returns the number of calls to the DAE + residual needed for the DQ Jacobian approximation or J*v + product approximation */ +int IDAGetNumLinResEvals(void *ida_mem, long int *nrevalsLS) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure; store output and return */ + retval = idaLs_AccessLMem(ida_mem, "IDAGetNumLinResEvals", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + *nrevalsLS = idals_mem->nreDQ; + return(IDALS_SUCCESS); +} + + +/* IDAGetLastLinFlag returns the last flag set in a IDALS function */ +int IDAGetLastLinFlag(void *ida_mem, long int *flag) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure; store output and return */ + retval = idaLs_AccessLMem(ida_mem, "IDAGetLastLinFlag", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + *flag = idals_mem->last_flag; + return(IDALS_SUCCESS); +} + + +/* IDAGetLinReturnFlagName translates from the integer error code + returned by an IDALs routine to the corresponding string + equivalent for that flag */ +char *IDAGetLinReturnFlagName(long int flag) +{ + char *name = (char *)malloc(30*sizeof(char)); + + switch(flag) { + case IDALS_SUCCESS: + sprintf(name,"IDALS_SUCCESS"); + break; + case IDALS_MEM_NULL: + sprintf(name,"IDALS_MEM_NULL"); + break; + case IDALS_LMEM_NULL: + sprintf(name,"IDALS_LMEM_NULL"); + break; + case IDALS_ILL_INPUT: + sprintf(name,"IDALS_ILL_INPUT"); + break; + case IDALS_MEM_FAIL: + sprintf(name,"IDALS_MEM_FAIL"); + break; + case IDALS_PMEM_NULL: + sprintf(name,"IDALS_PMEM_NULL"); + break; + case IDALS_JACFUNC_UNRECVR: + sprintf(name,"IDALS_JACFUNC_UNRECVR"); + break; + case IDALS_JACFUNC_RECVR: + sprintf(name,"IDALS_JACFUNC_RECVR"); + break; + case IDALS_SUNMAT_FAIL: + sprintf(name,"IDALS_SUNMAT_FAIL"); + break; + case IDALS_SUNLS_FAIL: + sprintf(name,"IDALS_SUNLS_FAIL"); + break; + default: + sprintf(name,"NONE"); + } + + return(name); +} + + +/*=============================================================== + IDALS Private functions + ===============================================================*/ + +/*--------------------------------------------------------------- + idaLsATimes: + + This routine generates the matrix-vector product z = Jv, where + J is the system Jacobian, by calling either the user provided + routine or the internal DQ routine. The return value is + the same as the value returned by jtimes -- + 0 if successful, nonzero otherwise. + ---------------------------------------------------------------*/ +int idaLsATimes(void *ida_mem, N_Vector v, N_Vector z) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure */ + retval = idaLs_AccessLMem(ida_mem, "idaLsATimes", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* call Jacobian-times-vector product routine + (either user-supplied or internal DQ) */ + retval = idals_mem->jtimes(IDA_mem->ida_tn, idals_mem->ycur, + idals_mem->ypcur, idals_mem->rcur, + v, z, IDA_mem->ida_cj, + idals_mem->jt_data, idals_mem->ytemp, + idals_mem->yptemp); + idals_mem->njtimes++; + return(retval); +} + + +/*--------------------------------------------------------------- + idaLsPSetup: + + This routine interfaces between the generic iterative linear + solvers and the user's psetup routine. It passes to psetup all + required state information from ida_mem. Its return value + is the same as that returned by psetup. Note that the generic + iterative linear solvers guarantee that idaLsPSetup will only + be called in the case that the user's psetup routine is non-NULL. + ---------------------------------------------------------------*/ +int idaLsPSetup(void *ida_mem) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure */ + retval = idaLs_AccessLMem(ida_mem, "idaLsPSetup", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* Call user pset routine to update preconditioner and possibly + reset jcur (pass !jbad as update suggestion) */ + retval = idals_mem->pset(IDA_mem->ida_tn, idals_mem->ycur, + idals_mem->ypcur, idals_mem->rcur, + IDA_mem->ida_cj, idals_mem->pdata); + idals_mem->npe++; + return(retval); +} + + +/*--------------------------------------------------------------- + idaLsPSolve: + + This routine interfaces between the generic SUNLinSolSolve + routine and the user's psolve routine. It passes to psolve all + required state information from ida_mem. Its return value is + the same as that returned by psolve. Note that the generic + SUNLinSol solver guarantees that IDASilsPSolve will not be + called in the case in which preconditioning is not done. This + is the only case in which the user's psolve routine is allowed + to be NULL. + ---------------------------------------------------------------*/ +int idaLsPSolve(void *ida_mem, N_Vector r, N_Vector z, realtype tol, int lr) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure */ + retval = idaLs_AccessLMem(ida_mem, "idaLsPSolve", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* call the user-supplied psolve routine, and accumulate count */ + retval = idals_mem->psolve(IDA_mem->ida_tn, idals_mem->ycur, + idals_mem->ypcur, idals_mem->rcur, + r, z, IDA_mem->ida_cj, tol, + idals_mem->pdata); + idals_mem->nps++; + return(retval); +} + + +/*--------------------------------------------------------------- + idaLsDQJac: + + This routine is a wrapper for the Dense and Band + implementations of the difference quotient Jacobian + approximation routines. +---------------------------------------------------------------*/ +int idaLsDQJac(realtype t, realtype c_j, N_Vector y, N_Vector yp, + N_Vector r, SUNMatrix Jac, void *ida_mem, + N_Vector tmp1, N_Vector tmp2, N_Vector tmp3) +{ + int retval; + IDAMem IDA_mem; + IDA_mem = (IDAMem) ida_mem; + + /* access IDAMem structure */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDALS_MEM_NULL, "IDALS", + "idaLsDQJac", MSG_LS_IDAMEM_NULL); + return(IDALS_MEM_NULL); + } + + /* verify that Jac is non-NULL */ + if (Jac == NULL) { + IDAProcessError(IDA_mem, IDALS_LMEM_NULL, "IDALS", + "idaLsDQJac", MSG_LS_LMEM_NULL); + return(IDALS_LMEM_NULL); + } + + /* 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 || + IDA_mem->ida_tempv1->ops->nvgetarraypointer == NULL || + IDA_mem->ida_tempv1->ops->nvsetarraypointer == NULL) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDALS", + "idaLsDQJac", MSG_LS_BAD_NVECTOR); + return(IDALS_ILL_INPUT); + } + + /* Call the matrix-structure-specific DQ approximation routine */ + if (SUNMatGetID(Jac) == SUNMATRIX_DENSE) { + retval = idaLsDenseDQJac(t, c_j, y, yp, r, Jac, IDA_mem, tmp1); + } else if (SUNMatGetID(Jac) == SUNMATRIX_BAND) { + retval = idaLsBandDQJac(t, c_j, y, yp, r, Jac, IDA_mem, tmp1, tmp2, tmp3); + } else { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDALS", + "idaLsDQJac", + "unrecognized matrix type for idaLsDQJac"); + retval = IDA_ILL_INPUT; + } + return(retval); +} + + +/*--------------------------------------------------------------- + idaLsDenseDQJac + + This routine generates a dense difference quotient approximation + to the Jacobian F_y + c_j*F_y'. It assumes a dense SUNmatrix + input (stored column-wise, and that elements within each column + are contiguous). The address of the jth column of J is obtained + via the function SUNDenseMatrix_Column() and this pointer is + associated with an N_Vector using the + N_VGetArrayPointer/N_VSetArrayPointer functions. Finally, the + actual computation of the jth column of the Jacobian is + done with a call to N_VLinearSum. +---------------------------------------------------------------*/ +int idaLsDenseDQJac(realtype tt, realtype c_j, N_Vector yy, + N_Vector yp, N_Vector rr, SUNMatrix Jac, + IDAMem IDA_mem, N_Vector tmp1) +{ + realtype inc, inc_inv, yj, ypj, srur, conj; + realtype *y_data, *yp_data, *ewt_data, *cns_data = NULL; + N_Vector rtemp, jthCol; + sunindextype j, N; + IDALsMem idals_mem; + int retval = 0; + + /* access LsMem interface structure */ + idals_mem = (IDALsMem) IDA_mem->ida_lmem; + + /* access matrix dimension */ + N = SUNDenseMatrix_Rows(Jac); + + /* Rename work vectors for readibility */ + rtemp = tmp1; + + /* Create an empty vector for matrix column calculations */ + jthCol = N_VCloneEmpty(tmp1); + + /* Obtain pointers to the data for ewt, yy, yp. */ + ewt_data = N_VGetArrayPointer(IDA_mem->ida_ewt); + y_data = N_VGetArrayPointer(yy); + yp_data = N_VGetArrayPointer(yp); + if(IDA_mem->ida_constraints!=NULL) + cns_data = N_VGetArrayPointer(IDA_mem->ida_constraints); + + srur = SUNRsqrt(IDA_mem->ida_uround); + + for (j=0; j < N; j++) { + + /* Generate the jth col of J(tt,yy,yp) as delta(F)/delta(y_j). */ + + /* Set data address of jthCol, and save y_j and yp_j values. */ + N_VSetArrayPointer(SUNDenseMatrix_Column(Jac,j), jthCol); + yj = y_data[j]; + ypj = yp_data[j]; + + /* Set increment inc to y_j based on sqrt(uround)*abs(y_j), with + adjustments using yp_j and ewt_j if this is small, and a further + adjustment to give it the same sign as hh*yp_j. */ + + inc = SUNMAX( srur * SUNMAX( SUNRabs(yj), SUNRabs(IDA_mem->ida_hh*ypj) ), + ONE/ewt_data[j] ); + + if (IDA_mem->ida_hh*ypj < ZERO) inc = -inc; + inc = (yj + inc) - yj; + + /* Adjust sign(inc) again if y_j has an inequality constraint. */ + if (IDA_mem->ida_constraints != NULL) { + 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;} + } + + /* Increment y_j and yp_j, call res, and break on error return. */ + y_data[j] += inc; + yp_data[j] += c_j*inc; + + retval = IDA_mem->ida_res(tt, yy, yp, rtemp, IDA_mem->ida_user_data); + idals_mem->nreDQ++; + if (retval != 0) break; + + /* Construct difference quotient in jthCol */ + inc_inv = ONE/inc; + N_VLinearSum(inc_inv, rtemp, -inc_inv, rr, jthCol); + + /* reset y_j, yp_j */ + y_data[j] = yj; + yp_data[j] = ypj; + } + + /* Destroy jthCol vector */ + N_VSetArrayPointer(NULL, jthCol); /* SHOULDN'T BE NEEDED */ + N_VDestroy(jthCol); + + return(retval); +} + + +/*--------------------------------------------------------------- + idaLsBandDQJac + + This routine generates a banded difference quotient approximation + JJ to the DAE system Jacobian J. It assumes a band SUNMatrix + input (stored column-wise, and that elements within each column + are contiguous). This makes it possible to get the address + of a column of JJ via the function SUNBandMatrix_Column(). The + columns of the Jacobian are constructed using mupper + mlower + 1 + calls to the res routine, and appropriate differencing. + The return value is either IDABAND_SUCCESS = 0, or the nonzero + value returned by the res routine, if any. + ---------------------------------------------------------------*/ +int idaLsBandDQJac(realtype tt, realtype c_j, N_Vector yy, + N_Vector yp, N_Vector rr, SUNMatrix Jac, + IDAMem IDA_mem, N_Vector tmp1, N_Vector tmp2, + N_Vector tmp3) +{ + realtype inc, inc_inv, yj, ypj, srur, conj, ewtj; + realtype *y_data, *yp_data, *ewt_data, *cns_data = NULL; + realtype *ytemp_data, *yptemp_data, *rtemp_data, *r_data, *col_j; + N_Vector rtemp, ytemp, yptemp; + sunindextype i, j, i1, i2, width, ngroups, group; + sunindextype N, mupper, mlower; + IDALsMem idals_mem; + int retval = 0; + + /* access LsMem interface structure */ + idals_mem = (IDALsMem) IDA_mem->ida_lmem; + + /* access matrix dimensions */ + N = SUNBandMatrix_Columns(Jac); + mupper = SUNBandMatrix_UpperBandwidth(Jac); + mlower = SUNBandMatrix_LowerBandwidth(Jac); + + /* Rename work vectors for use as temporary values of r, y and yp */ + rtemp = tmp1; + ytemp = tmp2; + yptemp= tmp3; + + /* Obtain pointers to the data for all eight vectors used. */ + ewt_data = N_VGetArrayPointer(IDA_mem->ida_ewt); + r_data = N_VGetArrayPointer(rr); + y_data = N_VGetArrayPointer(yy); + yp_data = N_VGetArrayPointer(yp); + rtemp_data = N_VGetArrayPointer(rtemp); + ytemp_data = N_VGetArrayPointer(ytemp); + yptemp_data = N_VGetArrayPointer(yptemp); + if (IDA_mem->ida_constraints != NULL) + cns_data = N_VGetArrayPointer(IDA_mem->ida_constraints); + + /* Initialize ytemp and yptemp. */ + N_VScale(ONE, yy, ytemp); + N_VScale(ONE, yp, yptemp); + + /* Compute miscellaneous values for the Jacobian computation. */ + srur = SUNRsqrt(IDA_mem->ida_uround); + width = mlower + mupper + 1; + ngroups = SUNMIN(width, N); + + /* Loop over column groups. */ + for (group=1; group <= ngroups; group++) { + + /* Increment all yy[j] and yp[j] for j in this group. */ + for (j=group-1; j<N; j+=width) { + yj = y_data[j]; + ypj = yp_data[j]; + ewtj = ewt_data[j]; + + /* Set increment inc to yj based on sqrt(uround)*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. */ + inc = SUNMAX( srur * SUNMAX( SUNRabs(yj), 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) { + 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;} + } + + /* Increment yj and ypj. */ + ytemp_data[j] += inc; + yptemp_data[j] += IDA_mem->ida_cj*inc; + } + + /* Call res routine with incremented arguments. */ + retval = IDA_mem->ida_res(tt, ytemp, yptemp, rtemp, IDA_mem->ida_user_data); + idals_mem->nreDQ++; + if (retval != 0) break; + + /* Loop over the indices j in this group again. */ + for (j=group-1; j<N; j+=width) { + + /* Reset ytemp and yptemp components that were perturbed. */ + yj = ytemp_data[j] = y_data[j]; + ypj = yptemp_data[j] = yp_data[j]; + col_j = SUNBandMatrix_Column(Jac, j); + ewtj = ewt_data[j]; + + /* Set increment inc exactly as above. */ + inc = SUNMAX( srur * SUNMAX( SUNRabs(yj), 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) { + 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;} + } + + /* Load the difference quotient Jacobian elements for column j */ + inc_inv = ONE/inc; + i1 = SUNMAX(0, j-mupper); + i2 = SUNMIN(j+mlower,N-1); + for (i=i1; i<=i2; i++) + SM_COLUMN_ELEMENT_B(col_j,i,j) = inc_inv * (rtemp_data[i]-r_data[i]); + } + } + + return(retval); +} + + +/*--------------------------------------------------------------- + idaLsDQJtimes + + This routine generates a difference quotient approximation to + the matrix-vector product z = Jv, where J is the system + Jacobian. The approximation is + Jv = [F(t,y1,yp1) - F(t,y,yp)]/sigma, + where + y1 = y + sigma*v, yp1 = yp + cj*sigma*v, + sigma = sqrt(Neq)*dqincfac. + The return value from the call to res is saved in order to set + the return flag from idaLsSolve. + ---------------------------------------------------------------*/ +int idaLsDQJtimes(realtype tt, N_Vector yy, N_Vector yp, N_Vector rr, + N_Vector v, N_Vector Jv, realtype c_j, + void *ida_mem, N_Vector work1, N_Vector work2) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + N_Vector y_tmp, yp_tmp; + realtype sig, siginv; + int iter, retval; + + /* 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 */ + + /* Rename work1 and work2 for readibility */ + y_tmp = work1; + yp_tmp = work2; + + for (iter=0; iter<MAX_ITERS; iter++) { + + /* Set y_tmp = yy + sig*v, yp_tmp = yp + cj*sig*v. */ + N_VLinearSum(sig, v, ONE, yy, y_tmp); + N_VLinearSum(c_j*sig, v, ONE, yp, yp_tmp); + + /* Call res for Jv = F(t, y_tmp, yp_tmp), and return if it failed. */ + retval = IDA_mem->ida_res(tt, y_tmp, yp_tmp, Jv, IDA_mem->ida_user_data); + idals_mem->nreDQ++; + if (retval == 0) break; + if (retval < 0) return(-1); + + sig *= PT25; + } + + if (retval > 0) return(+1); + + /* Set Jv to [Jv - rr]/sig and return. */ + siginv = ONE/sig; + N_VLinearSum(siginv, Jv, -siginv, rr, Jv); + + return(0); +} + + +/*--------------------------------------------------------------- + idaLsInitialize + + This routine performs remaining initializations specific + to the iterative linear solver interface (and solver itself) +---------------------------------------------------------------*/ +int idaLsInitialize(IDAMem IDA_mem) +{ + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure */ + if (IDA_mem->ida_lmem == NULL) { + IDAProcessError(IDA_mem, IDALS_LMEM_NULL, "IDALS", + "idaLsInitialize", MSG_LS_LMEM_NULL); + return(IDALS_LMEM_NULL); + } + idals_mem = (IDALsMem) IDA_mem->ida_lmem; + + + /* Test for valid combinations of matrix & Jacobian routines: */ + if (idals_mem->J == NULL) { + + /* If SUNMatrix A is NULL: ensure 'jac' function pointer is NULL */ + idals_mem->jacDQ = SUNFALSE; + idals_mem->jac = NULL; + idals_mem->J_data = NULL; + + } else if (idals_mem->jacDQ) { + + /* If J is non-NULL, and 'jac' is not user-supplied: + - if J is dense or band, ensure that our DQ approx. is used + - otherwise => error */ + retval = 0; + if (idals_mem->J->ops->getid) { + + if ( (SUNMatGetID(idals_mem->J) == SUNMATRIX_DENSE) || + (SUNMatGetID(idals_mem->J) == SUNMATRIX_BAND) ) { + idals_mem->jac = idaLsDQJac; + idals_mem->J_data = IDA_mem; + } else { + retval++; + } + + } else { + retval++; + } + if (retval) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDALS", "idaLsInitialize", + "No Jacobian constructor available for SUNMatrix type"); + idals_mem->last_flag = IDALS_ILL_INPUT; + return(IDALS_ILL_INPUT); + } + + } else { + + /* If J is non-NULL, and 'jac' is user-supplied, + reset J_data pointer (just in case) */ + idals_mem->J_data = IDA_mem->ida_user_data; + } + + /* reset counters */ + idaLsInitializeCounters(idals_mem); + + /* Set Jacobian-related fields, based on jtimesDQ */ + if (idals_mem->jtimesDQ) { + idals_mem->jtsetup = NULL; + idals_mem->jtimes = idaLsDQJtimes; + idals_mem->jt_data = IDA_mem; + } else { + idals_mem->jt_data = IDA_mem->ida_user_data; + } + + /* if J is NULL and psetup is not present, then idaLsSetup does + not need to be called, so set the lsetup function to NULL */ + if ( (idals_mem->J == NULL) && (idals_mem->pset == NULL) ) + IDA_mem->ida_lsetup = NULL; + + /* Call LS initialize routine */ + idals_mem->last_flag = SUNLinSolInitialize(idals_mem->LS); + return(idals_mem->last_flag); +} + + +/*--------------------------------------------------------------- + idaLsSetup + + This calls the Jacobian evaluation routine (if using a SUNMatrix + object), updates counters, and calls the LS 'setup' routine to + prepare for subsequent calls to the LS 'solve' routine. +---------------------------------------------------------------*/ +int idaLsSetup(IDAMem IDA_mem, N_Vector y, N_Vector yp, N_Vector r, + N_Vector vt1, N_Vector vt2, N_Vector vt3) +{ + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure */ + if (IDA_mem->ida_lmem == NULL) { + IDAProcessError(IDA_mem, IDALS_LMEM_NULL, "IDALS", + "idaLsSetup", MSG_LS_LMEM_NULL); + return(IDALS_LMEM_NULL); + } + idals_mem = (IDALsMem) IDA_mem->ida_lmem; + + /* Set IDALs N_Vector pointers to inputs */ + idals_mem->ycur = y; + idals_mem->ypcur = yp; + idals_mem->rcur = r; + + /* recompute if J if it is non-NULL */ + if (idals_mem->J) { + + /* 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); + } + + /* Call Jacobian routine */ + retval = idals_mem->jac(IDA_mem->ida_tn, IDA_mem->ida_cj, y, + yp, r, idals_mem->J, + idals_mem->J_data, vt1, vt2, vt3); + if (retval < 0) { + IDAProcessError(IDA_mem, IDALS_JACFUNC_UNRECVR, "IDALS", + "idaLsSetup", MSG_LS_JACFUNC_FAILED); + idals_mem->last_flag = IDALS_JACFUNC_UNRECVR; + return(-1); + } + if (retval > 0) { + idals_mem->last_flag = IDALS_JACFUNC_RECVR; + return(1); + } + + } + + /* Call LS setup routine -- the LS will call idaLsPSetup if applicable */ + idals_mem->last_flag = SUNLinSolSetup(idals_mem->LS, idals_mem->J); + return(idals_mem->last_flag); +} + + +/*--------------------------------------------------------------- + idaLsSolve + + This routine interfaces between IDA and the generic + SUNLinearSolver object LS, by setting the appropriate tolerance + and scaling vectors, calling the solver, accumulating + statistics from the solve for use/reporting by IDA, and scaling + the result if using a non-NULL SUNMatrix and cjratio does not + equal one. +---------------------------------------------------------------*/ +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; + realtype tol, w_mean, LSType; + + /* access IDALsMem structure */ + if (IDA_mem->ida_lmem == NULL) { + IDAProcessError(IDA_mem, IDALS_LMEM_NULL, "IDALS", + "idaLsSolve", MSG_LS_LMEM_NULL); + return(IDALS_LMEM_NULL); + } + 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) ) { + tol = idals_mem->sqrtN * idals_mem->eplifac * IDA_mem->ida_epsNewt; + } else { + tol = ZERO; + } + + /* Set vectors ycur, ypcur and rcur for use by the Atimes and + Psolve interface routines */ + idals_mem->ycur = ycur; + 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); + if (retval != SUNLS_SUCCESS) { + IDAProcessError(IDA_mem, IDALS_SUNLS_FAIL, "IDALS", "idaLsSolve", + "Error in calling SUNLinSolSetScalingVectors"); + idals_mem->last_flag = IDALS_SUNLS_FAIL; + return(idals_mem->last_flag); + } + + /* If solver is iterative and does not support scaling vectors, update the + tolerance in an attempt to account for weight vector. We make the + following assumptions: + 1. w_i = w_mean, for i=0,...,n-1 (i.e. the weights are homogeneous) + 2. the linear solver uses a basic 2-norm to measure convergence + Hence (using the notation from sunlinsol_spgmr.h, with S = diag(w)), + || bbar - Abar xbar ||_2 < tol + <=> || S b - S A x ||_2 < tol + <=> || S (b - A x) ||_2 < tol + <=> \sum_{i=0}^{n-1} (w_i (b - A x)_i)^2 < tol^2 + <=> 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) ) { + + w_mean = SUNRsqrt( N_VDotProd(weight, weight) ) / idals_mem->sqrtN; + tol /= w_mean; + + } + + /* 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, + IDA_mem->ida_cj, idals_mem->jt_data); + idals_mem->njtsetup++; + if (idals_mem->last_flag != 0) { + IDAProcessError(IDA_mem, retval, "IDALS", + "idaLsSolve", MSG_LS_JTSETUP_FAILED); + return(idals_mem->last_flag); + } + } + + /* Call solver */ + retval = SUNLinSolSolve(idals_mem->LS, idals_mem->J, + idals_mem->x, b, tol); + + /* Copy appropriate result to b (depending on solver type) */ + if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || + (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { + + /* Retrieve solver statistics */ + nli_inc = SUNLinSolNumIters(idals_mem->LS); + + /* Copy x (or preconditioned residual vector if no iterations required) to b */ + if (nli_inc == 0) N_VScale(ONE, SUNLinSolResid(idals_mem->LS), b); + else N_VScale(ONE, idals_mem->x, b); + + /* Increment nli counter */ + idals_mem->nli += nli_inc; + + } else { + + /* Copy x to b */ + N_VScale(ONE, idals_mem->x, b); + + } + + /* 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) ) + N_VScale(TWO/(ONE + IDA_mem->ida_cjratio), b, b); + + /* Increment ncfl counter */ + if (retval != SUNLS_SUCCESS) idals_mem->ncfl++; + + /* Interpret solver return value */ + idals_mem->last_flag = retval; + + switch(retval) { + + case SUNLS_SUCCESS: + return(0); + break; + case SUNLS_RES_REDUCED: + case SUNLS_CONV_FAIL: + case SUNLS_PSOLVE_FAIL_REC: + case SUNLS_PACKAGE_FAIL_REC: + case SUNLS_QRFACT_FAIL: + case SUNLS_LUFACT_FAIL: + return(1); + break; + case SUNLS_MEM_NULL: + case SUNLS_ILL_INPUT: + case SUNLS_MEM_FAIL: + case SUNLS_GS_FAIL: + case SUNLS_QRSOL_FAIL: + return(-1); + break; + case SUNLS_PACKAGE_FAIL_UNREC: + IDAProcessError(IDA_mem, SUNLS_PACKAGE_FAIL_UNREC, "IDALS", + "idaLsSolve", + "Failure in SUNLinSol external package"); + return(-1); + break; + case SUNLS_PSOLVE_FAIL_UNREC: + IDAProcessError(IDA_mem, SUNLS_PSOLVE_FAIL_UNREC, "IDALS", + "idaLsSolve", MSG_LS_PSOLVE_FAILED); + return(-1); + break; + } + + return(0); +} + + +/*--------------------------------------------------------------- + idaLsPerf: accumulates performance statistics information + for IDA +---------------------------------------------------------------*/ +int idaLsPerf(IDAMem IDA_mem, int perftask) +{ + IDALsMem idals_mem; + realtype rcfn, rcfl; + long int nstd, nnid; + booleantype lcfn, lcfl; + + /* access IDALsMem structure */ + if (IDA_mem->ida_lmem == NULL) { + IDAProcessError(IDA_mem, IDALS_LMEM_NULL, "IDALS", + "idaLsPerf", MSG_LS_LMEM_NULL); + return(IDALS_LMEM_NULL); + } + idals_mem = (IDALsMem) IDA_mem->ida_lmem; + + /* when perftask == 0, store current performance statistics */ + if (perftask == 0) { + idals_mem->nst0 = IDA_mem->ida_nst; + idals_mem->nni0 = IDA_mem->ida_nni; + idals_mem->ncfn0 = IDA_mem->ida_ncfn; + idals_mem->ncfl0 = idals_mem->ncfl; + idals_mem->nwarn = 0; + return(0); + } + + /* Compute statistics since last call + + Note: the performance monitor that checked whether the average + number of linear iterations was too close to maxl has been + removed, since the 'maxl' value is no longer owned by the + IDALs interface. + */ + nstd = IDA_mem->ida_nst - idals_mem->nst0; + 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) ); + lcfn = (rcfn > PT9); + lcfl = (rcfl > PT9); + if (!(lcfn || lcfl)) return(0); + idals_mem->nwarn++; + if (idals_mem->nwarn > 10) return(1); + if (lcfn) + IDAProcessError(IDA_mem, IDA_WARNING, "IDALS", "idaLsPerf", + MSG_LS_CFN_WARN, IDA_mem->ida_tn, rcfn); + if (lcfl) + IDAProcessError(IDA_mem, IDA_WARNING, "IDALS", "idaLsPerf", + MSG_LS_CFL_WARN, IDA_mem->ida_tn, rcfl); + return(0); +} + + +/*--------------------------------------------------------------- + idaLsFree frees memory associates with the IDALs system + solver interface. +---------------------------------------------------------------*/ +int idaLsFree(IDAMem IDA_mem) +{ + IDALsMem idals_mem; + + /* Return immediately if IDA_mem or IDA_mem->ida_lmem are NULL */ + if (IDA_mem == NULL) return (IDALS_SUCCESS); + if (IDA_mem->ida_lmem == NULL) return(IDALS_SUCCESS); + idals_mem = (IDALsMem) IDA_mem->ida_lmem; + + /* Free N_Vector memory */ + if (idals_mem->ytemp) { + N_VDestroy(idals_mem->ytemp); + idals_mem->ytemp = NULL; + } + if (idals_mem->yptemp) { + N_VDestroy(idals_mem->yptemp); + idals_mem->yptemp = NULL; + } + if (idals_mem->x) { + N_VDestroy(idals_mem->x); + idals_mem->x = NULL; + } + + /* Nullify other N_Vector pointers */ + idals_mem->ycur = NULL; + idals_mem->ypcur = NULL; + idals_mem->rcur = NULL; + + /* Nullify SUNMatrix pointer */ + idals_mem->J = NULL; + + /* Free preconditioner memory (if applicable) */ + if (idals_mem->pfree) idals_mem->pfree(IDA_mem); + + /* free IDALs interface structure */ + free(IDA_mem->ida_lmem); + + return(IDALS_SUCCESS); +} + + +/*--------------------------------------------------------------- + idaLsInitializeCounters resets all counters from an + IDALsMem structure. +---------------------------------------------------------------*/ +int idaLsInitializeCounters(IDALsMem idals_mem) +{ + idals_mem->nje = 0; + idals_mem->nreDQ = 0; + idals_mem->npe = 0; + idals_mem->nli = 0; + idals_mem->nps = 0; + idals_mem->ncfl = 0; + idals_mem->njtsetup = 0; + idals_mem->njtimes = 0; + return(0); +} + + +/*--------------------------------------------------------------- + idaLs_AccessLMem + + This routine unpacks the IDA_mem and idals_mem structures from + the void* ida_mem pointer. If either is missing it returns + IDALS_MEM_NULL or IDALS_LMEM_NULL. + ---------------------------------------------------------------*/ +int idaLs_AccessLMem(void* ida_mem, const char* fname, + IDAMem* IDA_mem, IDALsMem* idals_mem) +{ + if (ida_mem==NULL) { + IDAProcessError(NULL, IDALS_MEM_NULL, "IDALS", + fname, MSG_LS_IDAMEM_NULL); + return(IDALS_MEM_NULL); + } + *IDA_mem = (IDAMem) ida_mem; + if ((*IDA_mem)->ida_lmem==NULL) { + IDAProcessError(*IDA_mem, IDALS_LMEM_NULL, "IDALS", + fname, MSG_LS_LMEM_NULL); + return(IDALS_LMEM_NULL); + } + *idals_mem = (IDALsMem) (*IDA_mem)->ida_lmem; + return(IDALS_SUCCESS); +} + + +/*--------------------------------------------------------------- + EOF + ---------------------------------------------------------------*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_ls_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_ls_impl.h new file mode 100644 index 0000000..c4ee8d4 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_ls_impl.h @@ -0,0 +1,188 @@ +/*----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 + *----------------------------------------------------------------- + * Implementation header file for IDA's linear solver interface. + *-----------------------------------------------------------------*/ + +#ifndef _IDALS_IMPL_H +#define _IDALS_IMPL_H + +#include <ida/ida_ls.h> +#include "ida_impl.h" + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*----------------------------------------------------------------- + Types : struct IDALsMemRec, struct *IDALsMem + + The type IDALsMem is a pointer to a IDALsMemRec, which is a + structure containing fields that must be accessible by LS module + routines. + -----------------------------------------------------------------*/ +typedef struct IDALsMemRec { + + /* Jacobian construction & storage */ + booleantype jacDQ; /* SUNTRUE if using internal DQ Jacobian approx. */ + IDALsJacFn jac; /* Jacobian routine to be called */ + void *J_data; /* J_data is passed to jac */ + + /* Linear solver, matrix and vector objects/pointers */ + SUNLinearSolver LS; /* generic linear solver object */ + SUNMatrix J; /* J = dF/dy + cj*dF/dy' */ + N_Vector ytemp; /* temp vector used by IDAAtimesDQ */ + N_Vector yptemp; /* temp vector used by IDAAtimesDQ */ + N_Vector x; /* temp vector used by the solve function */ + N_Vector ycur; /* current y vector in Newton iteration */ + N_Vector ypcur; /* current yp vector in Newton iteration */ + N_Vector rcur; /* rcur = F(tn, ycur, ypcur) */ + + /* Iterative solver tolerance */ + realtype sqrtN; /* sqrt(N) */ + realtype eplifac; /* eplifac = linear convergence factor */ + + /* Statistics and associated parameters */ + realtype dqincfac; /* dqincfac = optional increment factor in Jv */ + long int nje; /* nje = no. of calls to jac */ + long int npe; /* npe = total number of precond calls */ + long int nli; /* nli = total number of linear iterations */ + long int nps; /* nps = total number of psolve calls */ + long int ncfl; /* ncfl = total number of convergence failures */ + long int nreDQ; /* nreDQ = total number of calls to res */ + long int njtsetup; /* njtsetup = total number of calls to jtsetup */ + long int njtimes; /* njtimes = total number of calls to jtimes */ + long int nst0; /* nst0 = saved nst (for performance monitor) */ + long int nni0; /* nni0 = saved nni (for performance monitor) */ + long int ncfn0; /* ncfn0 = saved ncfn (for performance monitor) */ + 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 */ + + /* Preconditioner computation + (a) user-provided: + - pdata == user_data + - pfree == NULL (the user dealocates memory) + (b) internal preconditioner module + - pdata == ida_mem + - pfree == set by the prec. module and called in idaLsFree */ + IDALsPrecSetupFn pset; + IDALsPrecSolveFn psolve; + int (*pfree)(IDAMem IDA_mem); + void *pdata; + + /* Jacobian times vector compuation + (a) jtimes function provided by the user: + - jt_data == user_data + - jtimesDQ == SUNFALSE + (b) internal jtimes + - jt_data == ida_mem + - jtimesDQ == SUNTRUE */ + booleantype jtimesDQ; + IDALsJacTimesSetupFn jtsetup; + IDALsJacTimesVecFn jtimes; + void *jt_data; + +} *IDALsMem; + + +/*----------------------------------------------------------------- + Prototypes of internal functions + -----------------------------------------------------------------*/ + +/* Interface routines called by system SUNLinearSolver */ +int idaLsATimes(void *ida_mem, N_Vector v, N_Vector z); +int idaLsPSetup(void *ida_mem); +int idaLsPSolve(void *ida_mem, N_Vector r, N_Vector z, + realtype tol, int lr); + +/* Difference quotient approximation for Jac times vector */ +int idaLsDQJtimes(realtype tt, N_Vector yy, N_Vector yp, + N_Vector rr, N_Vector v, N_Vector Jv, + realtype c_j, void *data, + N_Vector work1, N_Vector work2); + +/* Difference-quotient Jacobian approximation routines */ +int idaLsDQJac(realtype tt, realtype c_j, N_Vector yy, N_Vector yp, + N_Vector rr, SUNMatrix Jac, void *data, + N_Vector tmp1, N_Vector tmp2, N_Vector tmp3); +int idaLsDenseDQJac(realtype tt, realtype c_j, N_Vector yy, + N_Vector yp, N_Vector rr, SUNMatrix Jac, + IDAMem IDA_mem, N_Vector tmp1); +int idaLsBandDQJac(realtype tt, realtype c_j, N_Vector yy, + N_Vector yp, N_Vector rr, SUNMatrix Jac, + IDAMem IDA_mem, N_Vector tmp1, + N_Vector tmp2, N_Vector tmp3); + +/* Generic linit/lsetup/lsolve/lperf/lfree interface routines for IDA to call */ +int idaLsInitialize(IDAMem IDA_mem); +int idaLsSetup(IDAMem IDA_mem, N_Vector y, N_Vector yp, N_Vector r, + N_Vector vt1, N_Vector vt2, N_Vector vt3); +int idaLsSolve(IDAMem IDA_mem, N_Vector b, N_Vector weight, + N_Vector ycur, N_Vector ypcur, N_Vector rescur); +int idaLsPerf(IDAMem IDA_mem, int perftask); +int idaLsFree(IDAMem IDA_mem); + + +/* Auxilliary functions */ +int idaLsInitializeCounters(IDALsMem idals_mem); +int idaLs_AccessLMem(void* ida_mem, const char* fname, + IDAMem* IDA_mem, IDALsMem* idals_mem); + + +/*--------------------------------------------------------------- + Error and Warning Messages + ---------------------------------------------------------------*/ + +#if defined(SUNDIALS_EXTENDED_PRECISION) +#define MSG_LS_TIME "at t = %Lg, " +#define MSG_LS_FRMT "%Le." +#elif defined(SUNDIALS_DOUBLE_PRECISION) +#define MSG_LS_TIME "at t = %lg, " +#define MSG_LS_FRMT "%le." +#else +#define MSG_LS_TIME "at t = %g, " +#define MSG_LS_FRMT "%e." +#endif + +/* Error Messages */ +#define MSG_LS_IDAMEM_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_GSTYPE "gstype has an illegal value." +#define MSG_LS_NEG_MAXRS "maxrs < 0 illegal." +#define MSG_LS_NEG_EPLIFAC "eplifac < 0.0 illegal." +#define MSG_LS_NEG_DQINCFAC "dqincfac < 0.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." +#define MSG_LS_JTSETUP_FAILED "The Jacobian x vector setup routine failed in an unrecoverable manner." +#define MSG_LS_JTIMES_FAILED "The Jacobian x vector routine failed in an unrecoverable manner." +#define MSG_LS_JACFUNC_FAILED "The Jacobian routine failed in an unrecoverable manner." +#define MSG_LS_MATZERO_FAILED "The SUNMatZero routine failed in an unrecoverable manner." + +/* Warning Messages */ +#define MSG_LS_WARN "Warning: " MSG_LS_TIME "poor iterative algorithm performance. " +#define MSG_LS_CFN_WARN MSG_LS_WARN "Nonlinear convergence failure rate is " MSG_LS_FRMT +#define MSG_LS_CFL_WARN MSG_LS_WARN "Linear convergence failure rate is " MSG_LS_FRMT + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_nls.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_nls.c new file mode 100644 index 0000000..f64464b --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_nls.c @@ -0,0 +1,288 @@ +/* ----------------------------------------------------------------------------- + * 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 the implementation file for the IDA nonlinear solver interface. + * ---------------------------------------------------------------------------*/ + +#include "ida_impl.h" +#include "sundials/sundials_math.h" + +/* constant macros */ +#define PT0001 RCONST(0.0001) /* real 0.0001 */ +#define ONE RCONST(1.0) /* real 1.0 */ +#define TWENTY RCONST(20.0) /* real 20.0 */ + +/* nonlinear solver parameters */ +#define MAXIT 4 /* default max number of nonlinear iterations */ +#define RATEMAX RCONST(0.9) /* max convergence rate used in divergence check */ + +/* 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 idaNlsConvTest(SUNNonlinearSolver NLS, N_Vector ycor, N_Vector del, + realtype tol, N_Vector ewt, void* ida_mem); + +/* ----------------------------------------------------------------------------- + * Exported functions + * ---------------------------------------------------------------------------*/ + +int IDASetNonlinearSolver(void *ida_mem, SUNNonlinearSolver NLS) +{ + IDAMem IDA_mem; + int retval; + + /* return immediately if IDA memory is NULL */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", + "IDASetNonlinearSolver", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* return immediately if NLS memory is NULL */ + if (NLS == NULL) { + IDAProcessError(NULL, IDA_ILL_INPUT, "IDA", + "IDASetNonlinearSolver", + "NLS must be non-NULL"); + return(IDA_ILL_INPUT); + } + + /* 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, "IDA", + "IDASetNonlinearSolver", + "NLS does not support required operations"); + return(IDA_ILL_INPUT); + } + + /* check for allowed nonlinear solver types */ + if (SUNNonlinSolGetType(NLS) != SUNNONLINEARSOLVER_ROOTFIND) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", + "IDASetNonlinearSolver", + "NLS type must be SUNNONLINEARSOLVER_ROOTFIND"); + return(IDA_ILL_INPUT); + } + + /* free any existing nonlinear solver */ + if ((IDA_mem->NLS != NULL) && (IDA_mem->ownNLS)) + retval = SUNNonlinSolFree(IDA_mem->NLS); + + /* set SUNNonlinearSolver pointer */ + IDA_mem->NLS = NLS; + + /* Set NLS ownership flag. If this function was called to attach the default + NLS, IDA will set the flag to SUNTRUE after this function returns. */ + IDA_mem->ownNLS = SUNFALSE; + + /* set the nonlinear residual function */ + retval = SUNNonlinSolSetSysFn(IDA_mem->NLS, idaNlsResidual); + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", + "IDASetNonlinearSolver", + "Setting nonlinear system function failed"); + return(IDA_ILL_INPUT); + } + + /* set convergence test function */ + retval = SUNNonlinSolSetConvTestFn(IDA_mem->NLS, idaNlsConvTest); + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", + "IDASetNonlinearSolver", + "Setting convergence test function failed"); + return(IDA_ILL_INPUT); + } + + /* set max allowed nonlinear iterations */ + retval = SUNNonlinSolSetMaxIters(IDA_mem->NLS, MAXIT); + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", + "IDASetNonlinearSolver", + "Setting maximum number of nonlinear iterations failed"); + return(IDA_ILL_INPUT); + } + + return(IDA_SUCCESS); +} + + +/* ----------------------------------------------------------------------------- + * Private functions + * ---------------------------------------------------------------------------*/ + +int idaNlsInit(IDAMem IDA_mem) +{ + int retval; + + /* set the linear solver setup wrapper function */ + if (IDA_mem->ida_lsetup) + retval = SUNNonlinSolSetLSetupFn(IDA_mem->NLS, idaNlsLSetup); + else + retval = SUNNonlinSolSetLSetupFn(IDA_mem->NLS, NULL); + + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "idaNlsInit", + "Setting the linear solver setup function failed"); + return(IDA_NLS_INIT_FAIL); + } + + /* set the linear solver solve wrapper function */ + if (IDA_mem->ida_lsolve) + retval = SUNNonlinSolSetLSolveFn(IDA_mem->NLS, idaNlsLSolve); + else + retval = SUNNonlinSolSetLSolveFn(IDA_mem->NLS, NULL); + + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "idaNlsInit", + "Setting linear solver solve function failed"); + return(IDA_NLS_INIT_FAIL); + } + + /* initialize nonlinear solver */ + retval = SUNNonlinSolInitialize(IDA_mem->NLS); + + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "idaNlsInit", + MSG_NLS_INIT_FAIL); + return(IDA_NLS_INIT_FAIL); + } + + return(IDA_SUCCESS); +} + + +static int idaNlsLSetup(N_Vector ycor, N_Vector res, booleantype jbad, + booleantype* jcur, void* ida_mem) +{ + IDAMem IDA_mem; + int retval; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "idaNlsLSetup", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + 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); + + /* update Jacobian status */ + *jcur = SUNTRUE; + + /* update convergence test constants */ + IDA_mem->ida_cjold = IDA_mem->ida_cj; + IDA_mem->ida_cjratio = ONE; + IDA_mem->ida_ss = TWENTY; + + if (retval < 0) return(IDA_LSETUP_FAIL); + if (retval > 0) return(IDA_LSETUP_RECVR); + + return(IDA_SUCCESS); +} + + +static int idaNlsLSolve(N_Vector ycor, N_Vector delta, void* ida_mem) +{ + IDAMem IDA_mem; + int retval; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "idaNlsLSolve", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + 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, + IDA_mem->ida_savres); + + if (retval < 0) return(IDA_LSOLVE_FAIL); + if (retval > 0) return(IDA_LSOLVE_RECVR); + + return(IDA_SUCCESS); +} + + +static int idaNlsResidual(N_Vector ycor, N_Vector res, void* ida_mem) +{ + IDAMem IDA_mem; + int retval; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "idaNlsResidual", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* update yy and yp based on the current correction */ + N_VLinearSum(ONE, IDA_mem->ida_yypredict, ONE, ycor, IDA_mem->ida_yy); + N_VLinearSum(ONE, IDA_mem->ida_yppredict, IDA_mem->ida_cj, ycor, IDA_mem->ida_yp); + + /* evaluate residual */ + retval = IDA_mem->ida_res(IDA_mem->ida_tn, IDA_mem->ida_yy, IDA_mem->ida_yp, + res, IDA_mem->ida_user_data); + + /* increment the number of residual evaluations */ + IDA_mem->ida_nre++; + + /* save a copy of the residual vector in savres */ + N_VScale(ONE, res, IDA_mem->ida_savres); + + if (retval < 0) return(IDA_RES_FAIL); + if (retval > 0) return(IDA_RES_RECVR); + + return(IDA_SUCCESS); +} + + +static int idaNlsConvTest(SUNNonlinearSolver NLS, N_Vector ycor, N_Vector del, + realtype tol, N_Vector ewt, void* ida_mem) +{ + IDAMem IDA_mem; + int m, retval; + realtype delnrm; + realtype rate; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "idaNlsConvTest", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* compute the norm of the correction */ + delnrm = N_VWrmsNorm(del, ewt); + + /* get the current nonlinear solver iteration count */ + retval = SUNNonlinSolGetCurIter(NLS, &m); + if (retval != IDA_SUCCESS) return(IDA_MEM_NULL); + + /* test for convergence, first directly, then with rate estimate. */ + if (m == 0){ + IDA_mem->ida_oldnrm = delnrm; + if (delnrm <= PT0001 * IDA_mem->ida_toldel) return(SUN_NLS_SUCCESS); + } else { + rate = SUNRpowerR( delnrm/IDA_mem->ida_oldnrm, ONE/m ); + if (rate > RATEMAX) return(SUN_NLS_CONV_RECVR); + IDA_mem->ida_ss = rate/(ONE - rate); + } + + if (IDA_mem->ida_ss*delnrm <= tol) return(SUN_NLS_SUCCESS); + + /* not yet converged */ + return(SUN_NLS_CONTINUE); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_spils.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_spils.c new file mode 100644 index 0000000..5513214 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/ida/ida_spils.c @@ -0,0 +1,81 @@ +/*----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * Alan Hindmarsh, Radu Serban 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 + *----------------------------------------------------------------- + * Implementation file for the deprecated Scaled and Preconditioned + * Iterative Linear Solver interface in IDA; these routines now just + * wrap the updated IDA generic linear solver interface in ida_ls.h. + *-----------------------------------------------------------------*/ + +#include <ida/ida_ls.h> +#include <ida/ida_spils.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*================================================================= + Exported Functions (wrappers for equivalent routines in ida_ls.h) + =================================================================*/ + +int IDASpilsSetLinearSolver(void *ida_mem, SUNLinearSolver LS) +{ return(IDASetLinearSolver(ida_mem, LS, NULL)); } + +int IDASpilsSetPreconditioner(void *ida_mem, IDASpilsPrecSetupFn pset, + IDASpilsPrecSolveFn psolve) +{ return(IDASetPreconditioner(ida_mem, pset, psolve)); } + +int IDASpilsSetJacTimes(void *ida_mem, IDASpilsJacTimesSetupFn jtsetup, + IDASpilsJacTimesVecFn jtimes) +{ return(IDASetJacTimes(ida_mem, jtsetup, jtimes)); } + +int IDASpilsSetEpsLin(void *ida_mem, realtype eplifac) +{ return(IDASetEpsLin(ida_mem, eplifac)); } + +int IDASpilsSetIncrementFactor(void *ida_mem, realtype dqincfac) +{ return(IDASetIncrementFactor(ida_mem, dqincfac)); } + +int IDASpilsGetWorkSpace(void *ida_mem, long int *lenrwLS, long int *leniwLS) +{ return(IDAGetLinWorkSpace(ida_mem, lenrwLS, leniwLS)); } + +int IDASpilsGetNumPrecEvals(void *ida_mem, long int *npevals) +{ return(IDAGetNumPrecEvals(ida_mem, npevals)); } + +int IDASpilsGetNumPrecSolves(void *ida_mem, long int *npsolves) +{ return(IDAGetNumPrecSolves(ida_mem, npsolves)); } + +int IDASpilsGetNumLinIters(void *ida_mem, long int *nliters) +{ return(IDAGetNumLinIters(ida_mem, nliters)); } + +int IDASpilsGetNumConvFails(void *ida_mem, long int *nlcfails) +{ return(IDAGetNumLinConvFails(ida_mem, nlcfails)); } + +int IDASpilsGetNumJTSetupEvals(void *ida_mem, long int *njtsetups) +{ return(IDAGetNumJTSetupEvals(ida_mem, njtsetups)); } + +int IDASpilsGetNumJtimesEvals(void *ida_mem, long int *njvevals) +{ return(IDAGetNumJtimesEvals(ida_mem, njvevals)); } + +int IDASpilsGetNumResEvals(void *ida_mem, long int *nrevalsLS) +{ return(IDAGetNumLinResEvals(ida_mem, nrevalsLS)); } + +int IDASpilsGetLastFlag(void *ida_mem, long int *flag) +{ return(IDAGetLastLinFlag(ida_mem, flag)); } + +char *IDASpilsGetReturnFlagName(long int flag) +{ return(IDAGetLinReturnFlagName(flag)); } + +#ifdef __cplusplus +} +#endif + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idaa.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idaa.c new file mode 100644 index 0000000..32bc0cb --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idaa.c @@ -0,0 +1,3343 @@ +/* + * ----------------------------------------------------------------- + * $Revision$ + * $Date$ + * ----------------------------------------------------------------- + * Programmer(s): 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 IDAA adjoint integrator. + * ----------------------------------------------------------------- + */ + +/*=================================================================*/ +/* Import Header Files */ +/*=================================================================*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "idas_impl.h" +#include <sundials/sundials_math.h> + +/*=================================================================*/ +/* IDAA Private Constants */ +/*=================================================================*/ + +#define ZERO RCONST(0.0) /* real 0.0 */ +#define ONE RCONST(1.0) /* real 1.0 */ +#define TWO RCONST(2.0) /* real 2.0 */ +#define HUNDRED RCONST(100.0) /* real 100.0 */ +#define FUZZ_FACTOR RCONST(1000000.0) /* fuzz factor for IDAAgetY */ + + +/*=================================================================*/ +/* Private Functions Prototypes */ +/*=================================================================*/ + +static CkpntMem IDAAckpntInit(IDAMem IDA_mem); +static CkpntMem IDAAckpntNew(IDAMem IDA_mem); +static void IDAAckpntCopyVectors(IDAMem IDA_mem, CkpntMem ck_mem); +static booleantype IDAAckpntAllocVectors(IDAMem IDA_mem, CkpntMem ck_mem); +static void IDAAckpntDelete(CkpntMem *ck_memPtr); + +static void IDAAbckpbDelete(IDABMem *IDAB_memPtr); + +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 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, + 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, + 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 IDAAres(realtype tt, + N_Vector yyB, N_Vector ypB, + N_Vector resvalB, void *ida_mem); + +static int IDAArhsQ(realtype tt, + N_Vector yyB, N_Vector ypB, + N_Vector rrQB, void *ida_mem); + +static int IDAAGettnSolutionYp(IDAMem IDA_mem, N_Vector yp); +static int IDAAGettnSolutionYpS(IDAMem IDA_mem, N_Vector *ypS); + +extern int IDAGetSolution(void *ida_mem, realtype t, N_Vector yret, N_Vector ypret); + + +/*=================================================================*/ +/* Exported Functions */ +/*=================================================================*/ + +/* + * IDAAdjInit + * + * This routine allocates space for the global IDAA memory + * structure. + */ + + +int IDAAdjInit(void *ida_mem, long int steps, int interp) +{ + IDAadjMem IDAADJ_mem; + IDAMem IDA_mem; + + /* Check arguments */ + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDAAdjInit", MSGAM_NULL_IDAMEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem)ida_mem; + + if (steps <= 0) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDAAdjInit", MSGAM_BAD_STEPS); + return(IDA_ILL_INPUT); + } + + 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)); + if (IDAADJ_mem == NULL) { + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAA", "IDAAdjInit", MSGAM_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + /* Attach IDAS memory for forward runs */ + IDA_mem->ida_adj_mem = IDAADJ_mem; + + /* Initialization of check points. */ + IDAADJ_mem->ck_mem = NULL; + IDAADJ_mem->ia_nckpnts = 0; + IDAADJ_mem->ia_ckpntData = NULL; + + + /* Initialization of interpolation data. */ + IDAADJ_mem->ia_interpType = interp; + IDAADJ_mem->ia_nsteps = steps; + + /* Last index used in IDAAfindIndex, initailize to invalid value */ + IDAADJ_mem->ia_ilast = -1; + + /* Allocate space for the array of Data Point structures. */ + if (IDAAdataMalloc(IDA_mem) == SUNFALSE) { + free(IDAADJ_mem); IDAADJ_mem = NULL; + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAA", "IDAAdjInit", MSGAM_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + /* Attach functions for the appropriate interpolation module */ + switch(interp) { + + case IDA_HERMITE: + IDAADJ_mem->ia_malloc = IDAAhermiteMalloc; + IDAADJ_mem->ia_free = IDAAhermiteFree; + 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; + IDAADJ_mem->ia_storePnt = IDAApolynomialStorePnt; + break; + } + + /* The interpolation module has not been initialized yet */ + IDAADJ_mem->ia_mallocDone = SUNFALSE; + + /* 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 + * - noInterp will be set in IDACalcICB to SUNTRUE before the call to + * IDACalcIC and SUNFALSE after.*/ + + IDAADJ_mem->ia_storeSensi = SUNTRUE; + IDAADJ_mem->ia_interpSensi = SUNFALSE; + IDAADJ_mem->ia_noInterp = SUNFALSE; + + /* Initialize backward problems. */ + IDAADJ_mem->IDAB_mem = NULL; + IDAADJ_mem->ia_bckpbCrt = NULL; + IDAADJ_mem->ia_nbckpbs = 0; + + /* Flags for tracking the first calls to IDASolveF and IDASolveF. */ + IDAADJ_mem->ia_firstIDAFcall = SUNTRUE; + IDAADJ_mem->ia_tstopIDAFcall = SUNFALSE; + IDAADJ_mem->ia_firstIDABcall = SUNTRUE; + + /* Adjoint module initialized and allocated. */ + IDA_mem->ida_adj = SUNTRUE; + IDA_mem->ida_adjMallocDone = SUNTRUE; + + return(IDA_SUCCESS); +} + +/* + * IDAAdjReInit + * + * IDAAdjReInit reinitializes the IDAS memory structure for ASA + */ + +int IDAAdjReInit(void *ida_mem) +{ + IDAadjMem IDAADJ_mem; + IDAMem IDA_mem; + + /* Check arguments */ + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDAAdjReInit", MSGAM_NULL_IDAMEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem)ida_mem; + + /* Was ASA previously initialized? */ + if(IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDAAdjReInit", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Free all stored checkpoints. */ + while (IDAADJ_mem->ck_mem != NULL) + IDAAckpntDelete(&(IDAADJ_mem->ck_mem)); + + IDAADJ_mem->ck_mem = NULL; + IDAADJ_mem->ia_nckpnts = 0; + IDAADJ_mem->ia_ckpntData = NULL; + + /* Flags for tracking the first calls to IDASolveF and IDASolveF. */ + IDAADJ_mem->ia_firstIDAFcall = SUNTRUE; + IDAADJ_mem->ia_tstopIDAFcall = SUNFALSE; + IDAADJ_mem->ia_firstIDABcall = SUNTRUE; + + return(IDA_SUCCESS); +} + +/* + * IDAAdjFree + * + * IDAAdjFree routine frees the memory allocated by IDAAdjInit. +*/ + + +void IDAAdjFree(void *ida_mem) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + + if (ida_mem == NULL) return; + IDA_mem = (IDAMem) ida_mem; + + if(IDA_mem->ida_adjMallocDone) { + + /* 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)); + } + + IDAAdataFree(IDA_mem); + + /* Free all backward problems. */ + while (IDAADJ_mem->IDAB_mem != NULL) + IDAAbckpbDelete( &(IDAADJ_mem->IDAB_mem) ); + + /* Free IDAA memory. */ + free(IDAADJ_mem); + + IDA_mem->ida_adj_mem = NULL; + } +} + +/* + * ================================================================= + * PRIVATE FUNCTIONS FOR BACKWARD PROBLEMS + * ================================================================= + */ + +static void IDAAbckpbDelete(IDABMem *IDAB_memPtr) +{ + IDABMem IDAB_mem = (*IDAB_memPtr); + void * ida_mem; + + if (IDAB_mem == NULL) return; + + /* Move head to the next element in list. */ + *IDAB_memPtr = IDAB_mem->ida_next; + + /* IDAB_mem is going to be deallocated. */ + + /* Free IDAS memory for this backward problem. */ + ida_mem = (void *)IDAB_mem->IDA_mem; + IDAFree(&ida_mem); + + /* Free linear solver memory. */ + if (IDAB_mem->ida_lfree != NULL) IDAB_mem->ida_lfree(IDAB_mem); + + /* Free preconditioner memory. */ + if (IDAB_mem->ida_pfree != NULL) IDAB_mem->ida_pfree(IDAB_mem); + + /* Free any workspace vectors. */ + N_VDestroy(IDAB_mem->ida_yy); + N_VDestroy(IDAB_mem->ida_yp); + + /* Free the node itself. */ + free(IDAB_mem); + IDAB_mem = NULL; +} + +/*=================================================================*/ +/* Wrappers for IDAA */ +/*=================================================================*/ + +/* + * IDASolveF + * + * This routine integrates to tout and returns solution into yout. + * 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. +*/ + +int IDASolveF(void *ida_mem, realtype tout, realtype *tret, + N_Vector yret, N_Vector ypret, int itask, int *ncheckPtr) +{ + IDAadjMem IDAADJ_mem; + IDAMem IDA_mem; + CkpntMem tmp; + DtpntMem *dt_mem; + int flag, i; + booleantype /* iret, */ allocOK; + + /* Is the mem OK? */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDASolveF", MSGAM_NULL_IDAMEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized ? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDASolveF", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check for yret != NULL */ + if (yret == NULL) { + 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); + return(IDA_ILL_INPUT); + } + /* Check for tret != NULL */ + if (tret == NULL) { + 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 */ + if (IDA_mem->ida_tstopset) { + 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. + */ + 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) { + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAA", "IDASolveF", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + if (!IDAADJ_mem->ia_mallocDone) { + /* Do we need to store sensitivities? */ + if (!IDA_mem->ida_sensi) IDAADJ_mem->ia_storeSensi = SUNFALSE; + + /* Allocate space for interpolation data */ + allocOK = IDAADJ_mem->ia_malloc(IDA_mem); + if (!allocOK) { + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAA", "IDASolveF", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + /* Rename phi and, if needed, phiS for use in interpolation */ + for (i=0;i<MXORDP1;i++) IDAADJ_mem->ia_Y[i] = IDA_mem->ida_phi[i]; + if (IDAADJ_mem->ia_storeSensi) { + for (i=0;i<MXORDP1;i++) + IDAADJ_mem->ia_YS[i] = IDA_mem->ida_phiS[i]; + } + + IDAADJ_mem->ia_mallocDone = SUNTRUE; + } + + dt_mem[0]->t = IDAADJ_mem->ck_mem->ck_t0; + IDAADJ_mem->ia_storePnt(IDA_mem, dt_mem[0]); + + IDAADJ_mem->ia_firstIDAFcall = SUNFALSE; + + } else if ( (IDA_mem->ida_tn-tout)*IDA_mem->ida_hh >= ZERO ) { + + /* 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; + + return(flag); + } + /* Integrate to tout 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; + + /* Create a new check point, load it, and append it to the list */ + tmp = IDAAckpntNew(IDA_mem); + if (tmp == NULL) { + flag = IDA_MEM_FAIL; + break; + } + + 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; + 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; + + /* tfinal is now set to *t */ + IDAADJ_mem->ia_tfinal = *tret; + + /* In IDA_ONE_STEP mode break from loop */ + if (itask == IDA_ONE_STEP) break; + + /* Return if root reached */ + if ( flag == IDA_ROOT_RETURN ) { + IDAGetSolution(IDA_mem, *tret, yret, ypret); + break; + } + /* Return if tout reached */ + if ( (*tret - tout)*IDA_mem->ida_hh >= ZERO ) { + *tret = tout; + 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; + } + } + + /* Get ncheck from IDAADJ_mem */ + *ncheckPtr = IDAADJ_mem->ia_nckpnts; + + /* Data is available for the last interval */ + 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); +} + + + + +/* + * ================================================================= + * FUNCTIONS FOR BACKWARD PROBLEMS + * ================================================================= + */ + +int IDACreateB(void *ida_mem, int *which) +{ + IDAMem IDA_mem; + 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); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized ? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDACreateB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Allocate a new IDABMem struct. */ + new_IDAB_mem = (IDABMem) malloc( sizeof( struct IDABMemRec ) ); + if (new_IDAB_mem == NULL) { + 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) { + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAA", "IDACreateB", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + /* 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); + + /* Initialize fields in the IDABMem struct. */ + new_IDAB_mem->ida_index = IDAADJ_mem->ia_nbckpbs; + new_IDAB_mem->IDA_mem = (IDAMem) ida_memB; + + new_IDAB_mem->ida_res = NULL; + new_IDAB_mem->ida_resS = NULL; + new_IDAB_mem->ida_rhsQ = NULL; + new_IDAB_mem->ida_rhsQS = NULL; + + + new_IDAB_mem->ida_user_data = NULL; + + new_IDAB_mem->ida_lmem = NULL; + new_IDAB_mem->ida_lfree = NULL; + new_IDAB_mem->ida_pmem = NULL; + new_IDAB_mem->ida_pfree = NULL; + + new_IDAB_mem->ida_yy = NULL; + new_IDAB_mem->ida_yp = NULL; + + 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 + backward problem. */ + *which = IDAADJ_mem->ia_nbckpbs; + + /*Increase the counter of the backward problems stored. */ + IDAADJ_mem->ia_nbckpbs++; + + return(IDA_SUCCESS); + +} + +int IDAInitB(void *ida_mem, int which, IDAResFnB resB, + realtype tB0, N_Vector yyB0, N_Vector ypB0) +{ + IDAadjMem IDAADJ_mem; + IDAMem IDA_mem; + IDABMem IDAB_mem; + void * ida_memB; + int flag; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDAInitB", MSGAM_NULL_IDAMEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized ? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDAInitB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the initial time for this backward problem against the adjoint data. */ + if ( (tB0 < IDAADJ_mem->ia_tinitial) || (tB0 > IDAADJ_mem->ia_tfinal) ) { + IDAProcessError(IDA_mem, IDA_BAD_TB0, "IDAA", "IDAInitB", MSGAM_BAD_TB0); + return(IDA_BAD_TB0); + } + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + + /* Get the IDAMem corresponding to this backward problem. */ + ida_memB = (void*) IDAB_mem->IDA_mem; + + /* Call the IDAInit for this backward problem. */ + flag = IDAInit(ida_memB, IDAAres, tB0, yyB0, ypB0); + if (IDA_SUCCESS != flag) return(flag); + + /* Copy residual function in IDAB_mem. */ + IDAB_mem->ida_res = resB; + IDAB_mem->ida_res_withSensi = SUNFALSE; + + /* Initialized the initial time field. */ + IDAB_mem->ida_t0 = tB0; + + /* Allocate and initialize space workspace vectors. */ + IDAB_mem->ida_yy = N_VClone(yyB0); + IDAB_mem->ida_yp = N_VClone(yyB0); + N_VScale(ONE, yyB0, IDAB_mem->ida_yy); + N_VScale(ONE, ypB0, IDAB_mem->ida_yp); + + return(flag); + +} + +int IDAInitBS(void *ida_mem, int which, IDAResFnBS resS, + realtype tB0, N_Vector yyB0, N_Vector ypB0) +{ + IDAadjMem IDAADJ_mem; + IDAMem IDA_mem; + IDABMem IDAB_mem; + void * ida_memB; + int flag; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDAInitBS", MSGAM_NULL_IDAMEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized ? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDAInitBS", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the initial time for this backward problem against the adjoint data. */ + if ( (tB0 < IDAADJ_mem->ia_tinitial) || (tB0 > IDAADJ_mem->ia_tfinal) ) { + IDAProcessError(IDA_mem, IDA_BAD_TB0, "IDAA", "IDAInitBS", MSGAM_BAD_TB0); + return(IDA_BAD_TB0); + } + + /* Were sensitivities active during the forward integration? */ + if (!IDAADJ_mem->ia_storeSensi) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDAInitBS", MSGAM_BAD_SENSI); + return(IDA_ILL_INPUT); + } + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + + /* 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); + + if (flag != IDA_SUCCESS) return(flag); + + /* Copy residual function pointer in IDAB_mem. */ + IDAB_mem->ida_res_withSensi = SUNTRUE; + IDAB_mem->ida_resS = resS; + + /* Allocate space and initialize the yy and yp vectors. */ + IDAB_mem->ida_t0 = tB0; + IDAB_mem->ida_yy = N_VClone(yyB0); + IDAB_mem->ida_yp = N_VClone(ypB0); + N_VScale(ONE, yyB0, IDAB_mem->ida_yy); + N_VScale(ONE, ypB0, IDAB_mem->ida_yp); + + return(IDA_SUCCESS); +} + + +int IDAReInitB(void *ida_mem, int which, + realtype tB0, N_Vector yyB0, N_Vector ypB0) +{ + + IDAadjMem IDAADJ_mem; + IDAMem IDA_mem; + IDABMem IDAB_mem; + void * ida_memB; + int flag; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDAReInitB", MSGAM_NULL_IDAMEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized ? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDAReInitB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the initial time for this backward problem against the adjoint data. */ + if ( (tB0 < IDAADJ_mem->ia_tinitial) || (tB0 > IDAADJ_mem->ia_tfinal) ) { + IDAProcessError(IDA_mem, IDA_BAD_TB0, "IDAA", "IDAReInitB", MSGAM_BAD_TB0); + return(IDA_BAD_TB0); + } + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + + /* Get the IDAMem corresponding to this backward problem. */ + ida_memB = (void*) IDAB_mem->IDA_mem; + + + /* Call the IDAReInit for this backward problem. */ + flag = IDAReInit(ida_memB, tB0, yyB0, ypB0); + return(flag); +} + +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); + return IDA_MEM_NULL; + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDASStolerancesB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + + /* Get the IDAMem corresponding to this backward problem. */ + ida_memB = (void*) IDAB_mem->IDA_mem; + + /* Set tolerances and return. */ + return IDASStolerances(ida_memB, relTolB, absTolB); + +} +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); + return IDA_MEM_NULL; + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDASVtolerancesB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + + /* Get the IDAMem corresponding to this backward problem. */ + ida_memB = (void*) IDAB_mem->IDA_mem; + + /* Set tolerances and return. */ + return IDASVtolerances(ida_memB, relTolB, absTolB); +} + +int IDAQuadSStolerancesB(void *ida_mem, int which, + realtype reltolQB, realtype abstolQB) +{ + 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", "IDAQuadSStolerancesB", MSGAM_NULL_IDAMEM); + return IDA_MEM_NULL; + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDAQuadSStolerancesB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + ida_memB = (void *) IDAB_mem->IDA_mem; + + return IDAQuadSStolerances(ida_memB, reltolQB, abstolQB); +} + + +int IDAQuadSVtolerancesB(void *ida_mem, int which, + realtype reltolQB, N_Vector abstolQB) +{ + 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", "IDAQuadSVtolerancesB", MSGAM_NULL_IDAMEM); + return IDA_MEM_NULL; + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDAQuadSVtolerancesB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + ida_memB = (void *) IDAB_mem->IDA_mem; + + return IDAQuadSVtolerances(ida_memB, reltolQB, abstolQB); +} + + +int IDAQuadInitB(void *ida_mem, int which, IDAQuadRhsFnB rhsQB, N_Vector yQB0) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + 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); + return IDA_MEM_NULL; + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDAQuadInitB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + ida_memB = (void *) IDAB_mem->IDA_mem; + + flag = IDAQuadInit(ida_memB, IDAArhsQ, yQB0); + if (IDA_SUCCESS != flag) return flag; + + IDAB_mem->ida_rhsQ_withSensi = SUNFALSE; + IDAB_mem->ida_rhsQ = rhsQB; + + return(flag); +} + + +int IDAQuadInitBS(void *ida_mem, int which, + IDAQuadRhsFnBS rhsQS, N_Vector yQB0) +{ + IDAadjMem IDAADJ_mem; + IDAMem IDA_mem; + IDABMem IDAB_mem; + void * ida_memB; + int flag; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDAQuadInitBS", MSGAM_NULL_IDAMEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized ? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDAQuadInitBS", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + + /* 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); + + if (flag != IDA_SUCCESS) return(flag); + + /* Copy RHS function pointer in IDAB_mem and enable quad sensitivities. */ + IDAB_mem->ida_rhsQ_withSensi = SUNTRUE; + IDAB_mem->ida_rhsQS = rhsQS; + + return(IDA_SUCCESS); +} + + +int IDAQuadReInitB(void *ida_mem, int which, N_Vector yQB0) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + IDABMem IDAB_mem; + + /* Is ida_mem valid? */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDAQuadInitB", MSGAM_NULL_IDAMEM); + return IDA_MEM_NULL; + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDAQuadInitB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + + return IDAQuadReInit(ida_mem, yQB0); +} + + +/* + * ---------------------------------------------------------------- + * Function : IDACalcICB + * ---------------------------------------------------------------- + * 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). +*/ + +int IDACalcICB(void *ida_mem, int which, realtype tout1, + N_Vector yy0, N_Vector yp0) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + 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); + return IDA_MEM_NULL; + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDACalcICB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + ida_memB = (void *) IDAB_mem->IDA_mem; + + /* 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') in yyTmp and ypTmp for use in the res wrapper.*/ + /* 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. */ + IDAADJ_mem->ia_noInterp = SUNFALSE; + + return(flag); +} + +/* + * ---------------------------------------------------------------- + * Function : IDACalcICBS + * ---------------------------------------------------------------- + * 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, + N_Vector *yyS0, N_Vector *ypS0) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + 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); + return IDA_MEM_NULL; + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDACalcICBS", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Were sensitivities active during the forward integration? */ + if (!IDAADJ_mem->ia_storeSensi) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDACalcICBS", MSGAM_BAD_SENSI); + return(IDA_ILL_INPUT); + } + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + ida_memB = (void *) IDAB_mem->IDA_mem; + + /* 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); + } + + /* 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 + for residual will use these values instead of calling interpolation routine.*/ + + /* The four workspaces variables 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); + + for (is=0; is<IDA_mem->ida_Ns; is++) + IDA_mem->ida_cvals[is] = ONE; + + retval = N_VScaleVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_cvals, + yyS0, IDAADJ_mem->ia_yySTmp); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + 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. */ + IDAADJ_mem->ia_noInterp = SUNFALSE; + + return(flag); +} + + +/* + * IDASolveB + * + * 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 + * at tinitial. + * + * 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 + * for any given backward problem. + * + * If there are multiple backward problems and multiple check points, + * IDASolveB may not succeed in getting all problems to take one step + * when called in ONE_STEP mode. + */ + +int IDASolveB(void *ida_mem, realtype tBout, int itaskB) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + CkpntMem ck_mem; + IDABMem IDAB_mem, tmp_IDAB_mem; + int flag=0, sign; + realtype tfuzz, tBret, tBn; + booleantype gotCkpnt, reachedTBout, isActive; + + /* Is the mem OK? */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDASolveB", MSGAM_NULL_IDAMEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized ? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDASolveB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + if ( IDAADJ_mem->ia_nbckpbs == 0 ) { + IDAProcessError(IDA_mem, IDA_NO_BCK, "IDAA", "IDASolveB", MSGAM_NO_BCK); + return(IDA_NO_BCK); + } + IDAB_mem = IDAADJ_mem->IDAB_mem; + + /* Check whether IDASolveF has been called */ + if ( IDAADJ_mem->ia_firstIDAFcall ) { + IDAProcessError(IDA_mem, IDA_NO_FWD, "IDAA", "IDASolveB", MSGAM_NO_FWD); + return(IDA_NO_FWD); + } + sign = (IDAADJ_mem->ia_tfinal - IDAADJ_mem->ia_tinitial > ZERO) ? 1 : -1; + + /* If this is the first call, loop over all backward problems and + * - check that tB0 is valid + * - check that tBout is ahead of tB0 in the backward direction + * - check whether we need to interpolate forward sensitivities + */ + if (IDAADJ_mem->ia_firstIDABcall) { + + /* 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", + MSGAM_BAD_TB0, tmp_IDAB_mem->ida_index); + return(IDA_BAD_TB0); + } + + if (sign*(tBn-tBout) <= ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDASolveB", MSGAM_BAD_TBOUT, + tmp_IDAB_mem->ida_index); + return(IDA_ILL_INPUT); + } + + 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; + } + + if ( IDAADJ_mem->ia_interpSensi && !IDAADJ_mem->ia_storeSensi) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDASolveB", MSGAM_BAD_SENSI); + return(IDA_ILL_INPUT); + } + + IDAADJ_mem->ia_firstIDABcall = SUNFALSE; + } + + /* Check for valid itask */ + if ( (itaskB != IDA_NORMAL) && (itaskB != IDA_ONE_STEP) ) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDASolveB", MSG_BAD_ITASK); + return(IDA_ILL_INPUT); + } + + /* Check if tBout is legal */ + if ( (sign*(tBout-IDAADJ_mem->ia_tinitial) < ZERO) || (sign*(IDAADJ_mem->ia_tfinal-tBout) < ZERO) ) { + tfuzz = HUNDRED * IDA_mem->ida_uround * + (SUNRabs(IDAADJ_mem->ia_tinitial) + SUNRabs(IDAADJ_mem->ia_tfinal)); + if ( (sign*(tBout-IDAADJ_mem->ia_tinitial) < ZERO) && (SUNRabs(tBout-IDAADJ_mem->ia_tinitial) < tfuzz) ) { + tBout = IDAADJ_mem->ia_tinitial; + } else { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDASolveB", MSGAM_BAD_TBOUT); + return(IDA_ILL_INPUT); + } + } + + /* Loop through the check points and stop as soon as a backward + * problem has its tn value behind the current check point's t0_ + * value (in the backward direction) */ + + ck_mem = IDAADJ_mem->ck_mem; + + gotCkpnt = SUNFALSE; + + for(;;) { + tmp_IDAB_mem = IDAB_mem; + while(tmp_IDAB_mem != NULL) { + tBn = tmp_IDAB_mem->IDA_mem->ida_tn; + + if ( sign*(tBn-ck_mem->ck_t0) > ZERO ) { + gotCkpnt = SUNTRUE; + break; + } + + if ( (itaskB == IDA_NORMAL) && (tBn == ck_mem->ck_t0) && (sign*(tBout-ck_mem->ck_t0) >= ZERO) ) { + gotCkpnt = SUNTRUE; + break; + } + + tmp_IDAB_mem = tmp_IDAB_mem->ida_next; + } + + if (gotCkpnt) break; + + if (ck_mem->ck_next == NULL) break; + + ck_mem = ck_mem->ck_next; + } + + /* Loop while propagating backward problems */ + for(;;) { + + /* Store interpolation data if not available. + This is the 2nd forward integration pass */ + if (ck_mem != IDAADJ_mem->ia_ckpntData) { + + flag = IDAAdataStore(IDA_mem, ck_mem); + if (flag != IDA_SUCCESS) break; + } + + /* Starting with the current check point from above, loop over check points + while propagating backward problems */ + + tmp_IDAB_mem = IDAB_mem; + while (tmp_IDAB_mem != NULL) { + + /* Decide if current backward problem is "active" in this check point */ + isActive = SUNTRUE; + + tBn = tmp_IDAB_mem->IDA_mem->ida_tn; + + if ( (tBn == ck_mem->ck_t0) && (sign*(tBout-ck_mem->ck_t0) < ZERO ) ) isActive = SUNFALSE; + if ( (tBn == ck_mem->ck_t0) && (itaskB == IDA_ONE_STEP) ) isActive = SUNFALSE; + if ( sign*(tBn - ck_mem->ck_t0) < ZERO ) isActive = SUNFALSE; + + if ( isActive ) { + /* 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, + itaskB); + + /* Set the time at which we will report solution and/or quadratures */ + tmp_IDAB_mem->ida_tout = tBret; + + /* If an error occurred, exit while loop */ + if (flag < 0) break; + + } else { + + flag = IDA_SUCCESS; + tmp_IDAB_mem->ida_tout = tBn; + } + + /* 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", + MSGAM_BACK_ERROR, tmp_IDAB_mem->ida_index); + return(flag); + } + + /* If in IDA_ONE_STEP mode, return now (flag = IDA_SUCCESS) */ + if (itaskB == IDA_ONE_STEP) break; + + /* If all backward problems have succesfully reached tBout, return now */ + reachedTBout = SUNTRUE; + + tmp_IDAB_mem = IDAB_mem; + while(tmp_IDAB_mem != NULL) { + if ( sign*(tmp_IDAB_mem->ida_tout - tBout) > ZERO ) { + reachedTBout = SUNFALSE; + break; + } + tmp_IDAB_mem = tmp_IDAB_mem->ida_next; + } + + if ( reachedTBout ) break; + + /* Move check point in linked list to next one */ + ck_mem = ck_mem->ck_next; + + } /* End of loop. */ + + return(flag); +} + + +/* + * IDAGetB + * + * IDAGetB returns the state variables at the same time (also returned + * in tret) as that at which IDASolveBreturned the solution. + */ + +SUNDIALS_EXPORT int IDAGetB(void* ida_mem, int which, realtype *tret, + N_Vector yy, N_Vector yp) +{ + 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); + return IDA_MEM_NULL; + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDAGetB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + + N_VScale(ONE, IDAB_mem->ida_yy, yy); + N_VScale(ONE, IDAB_mem->ida_yp, yp); + *tret = IDAB_mem->ida_tout; + + return(IDA_SUCCESS); +} + + + +/* + * IDAGetQuadB + * + * IDAGetQuadB returns the quadrature variables at the same + * time (also returned in tret) as that at which IDASolveB + * returned the solution. + */ + +int IDAGetQuadB(void *ida_mem, int which, realtype *tret, N_Vector qB) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + IDABMem IDAB_mem; + 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); + return IDA_MEM_NULL; + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDAGetQuadB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + ida_memB = (void *) IDAB_mem->IDA_mem; + + /* If the integration for this backward problem has not started yet, + * simply return the current value of qB (i.e. the final conditions) */ + + flag = IDAGetNumSteps(ida_memB, &nstB); + if (IDA_SUCCESS != flag) return(flag); + + if (nstB == 0) { + N_VScale(ONE, IDAB_mem->IDA_mem->ida_phiQ[0], qB); + *tret = IDAB_mem->ida_tout; + } else { + flag = IDAGetQuad(ida_memB, tret, qB); + } + return(flag); +} + +/*=================================================================*/ +/* Private Functions Implementation */ +/*=================================================================*/ + +/* + * IDAAckpntInit + * + * This routine initializes the check point linked list with + * information from the initial time. +*/ + +static CkpntMem IDAAckpntInit(IDAMem IDA_mem) +{ + CkpntMem ck_mem; + + /* Allocate space for ckdata */ + ck_mem = (CkpntMem) malloc(sizeof(struct CkpntMemRec)); + if (NULL==ck_mem) return(NULL); + + ck_mem->ck_t0 = IDA_mem->ida_tn; + ck_mem->ck_nst = 0; + ck_mem->ck_kk = 1; + ck_mem->ck_hh = ZERO; + + /* Test if we need to carry quadratures */ + ck_mem->ck_quadr = IDA_mem->ida_quadr && IDA_mem->ida_errconQ; + + /* Test if we need to carry sensitivities */ + ck_mem->ck_sensi = IDA_mem->ida_sensi; + if(ck_mem->ck_sensi) ck_mem->ck_Ns = IDA_mem->ida_Ns; + + /* Test if we need to carry quadrature sensitivities */ + ck_mem->ck_quadr_sensi = IDA_mem->ida_quadr_sensi && IDA_mem->ida_errconQS; + + /* 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); + } + /* Save phi* vectors from IDA_mem to ck_mem. */ + IDAAckpntCopyVectors(IDA_mem, ck_mem); + + /* Next in list */ + ck_mem->ck_next = NULL; + + return(ck_mem); +} + +/* + * IDAAckpntNew + * + * This routine allocates space for a new check point and sets + * its data from current values in IDA_mem. +*/ + +static CkpntMem IDAAckpntNew(IDAMem IDA_mem) +{ + CkpntMem ck_mem; + int j; + + /* Allocate space for ckdata */ + ck_mem = (CkpntMem) malloc(sizeof(struct CkpntMemRec)); + if (ck_mem == NULL) return(NULL); + + ck_mem->ck_nst = IDA_mem->ida_nst; + ck_mem->ck_tretlast = IDA_mem->ida_tretlast; + ck_mem->ck_kk = IDA_mem->ida_kk; + ck_mem->ck_kused = IDA_mem->ida_kused; + ck_mem->ck_knew = IDA_mem->ida_knew; + ck_mem->ck_phase = IDA_mem->ida_phase; + ck_mem->ck_ns = IDA_mem->ida_ns; + ck_mem->ck_hh = IDA_mem->ida_hh; + ck_mem->ck_hused = IDA_mem->ida_hused; + ck_mem->ck_rr = IDA_mem->ida_rr; + ck_mem->ck_cj = IDA_mem->ida_cj; + ck_mem->ck_cjlast = IDA_mem->ida_cjlast; + ck_mem->ck_cjold = IDA_mem->ida_cjold; + ck_mem->ck_cjratio = IDA_mem->ida_cjratio; + ck_mem->ck_ss = IDA_mem->ida_ss; + ck_mem->ck_ssS = IDA_mem->ida_ssS; + ck_mem->ck_t0 = IDA_mem->ida_tn; + + for (j=0; j<MXORDP1; j++) { + ck_mem->ck_psi[j] = IDA_mem->ida_psi[j]; + ck_mem->ck_alpha[j] = IDA_mem->ida_alpha[j]; + ck_mem->ck_beta[j] = IDA_mem->ida_beta[j]; + ck_mem->ck_sigma[j] = IDA_mem->ida_sigma[j]; + ck_mem->ck_gamma[j] = IDA_mem->ida_gamma[j]; + } + + /* Test if we need to carry quadratures */ + ck_mem->ck_quadr = IDA_mem->ida_quadr && IDA_mem->ida_errconQ; + + /* Test if we need to carry sensitivities */ + ck_mem->ck_sensi = IDA_mem->ida_sensi; + if(ck_mem->ck_sensi) ck_mem->ck_Ns = IDA_mem->ida_Ns; + + /* Test if we need to carry quadrature sensitivities */ + ck_mem->ck_quadr_sensi = IDA_mem->ida_quadr_sensi && IDA_mem->ida_errconQS; + + ck_mem->ck_phi_alloc = (IDA_mem->ida_kk+2 < MXORDP1) ? + IDA_mem->ida_kk+2 : MXORDP1; + + if (!IDAAckpntAllocVectors(IDA_mem, ck_mem)) { + free(ck_mem); ck_mem = NULL; + return(NULL); + } + + /* Save phi* vectors from IDA_mem to ck_mem. */ + IDAAckpntCopyVectors(IDA_mem, ck_mem); + + return(ck_mem); +} + +/* IDAAckpntDelete + * + * This routine deletes the first check point in list. +*/ + +static void IDAAckpntDelete(CkpntMem *ck_memPtr) +{ + CkpntMem tmp; + int j; + + if (*ck_memPtr != NULL) { + /* store head of list */ + tmp = *ck_memPtr; + /* move head of list */ + *ck_memPtr = (*ck_memPtr)->ck_next; + + /* free N_Vectors in tmp */ + for (j=0; j<tmp->ck_phi_alloc; j++) + N_VDestroy(tmp->ck_phi[j]); + + /* free N_Vectors for quadratures in tmp */ + if (tmp->ck_quadr) { + for (j=0; j<tmp->ck_phi_alloc; j++) + N_VDestroy(tmp->ck_phiQ[j]); + } + + /* Free sensitivity related data. */ + if (tmp->ck_sensi) { + for (j=0; j<tmp->ck_phi_alloc; j++) + N_VDestroyVectorArray(tmp->ck_phiS[j], tmp->ck_Ns); + } + + if (tmp->ck_quadr_sensi) { + for (j=0; j<tmp->ck_phi_alloc; j++) + N_VDestroyVectorArray(tmp->ck_phiQS[j], tmp->ck_Ns); + } + + free(tmp); tmp=NULL; + } +} + +/* + * IDAAckpntAllocVectors + * + * Allocate checkpoint's phi, phiQ, phiS, phiQS vectors needed to save + * current state of IDAMem. + * + */ +static booleantype IDAAckpntAllocVectors(IDAMem IDA_mem, CkpntMem ck_mem) +{ + int j, jj; + + for (j=0; j<ck_mem->ck_phi_alloc; j++) { + ck_mem->ck_phi[j] = N_VClone(IDA_mem->ida_tempv1); + if(ck_mem->ck_phi[j] == NULL) { + for(jj=0; jj<j; jj++) N_VDestroy(ck_mem->ck_phi[jj]); + return(SUNFALSE); + } + } + + /* Do we need to carry quadratures? */ + if(ck_mem->ck_quadr) { + for (j=0; j<ck_mem->ck_phi_alloc; j++) { + ck_mem->ck_phiQ[j] = N_VClone(IDA_mem->ida_eeQ); + if(ck_mem->ck_phiQ[j] == NULL) { + for (jj=0; jj<j; jj++) N_VDestroy(ck_mem->ck_phiQ[jj]); + + for(jj=0; jj<ck_mem->ck_phi_alloc; jj++) + N_VDestroy(ck_mem->ck_phi[jj]); + + return(SUNFALSE); + } + } + } + + /* Do we need to carry sensitivities? */ + if(ck_mem->ck_sensi) { + + for (j=0; j<ck_mem->ck_phi_alloc; j++) { + ck_mem->ck_phiS[j] = N_VCloneVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_tempv1); + if (ck_mem->ck_phiS[j] == NULL) { + for (jj=0; jj<j; jj++) + N_VDestroyVectorArray(ck_mem->ck_phiS[jj], IDA_mem->ida_Ns); + + if (ck_mem->ck_quadr) + for (jj=0; jj<ck_mem->ck_phi_alloc; jj++) + N_VDestroy(ck_mem->ck_phiQ[jj]); + + for (jj=0; jj<ck_mem->ck_phi_alloc; jj++) + N_VDestroy(ck_mem->ck_phi[jj]); + + return(SUNFALSE); + } + } + } + + /* Do we need to carry quadrature sensitivities? */ + if (ck_mem->ck_quadr_sensi) { + + for (j=0; j<ck_mem->ck_phi_alloc; j++) { + ck_mem->ck_phiQS[j] = N_VCloneVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_eeQ); + if (ck_mem->ck_phiQS[j] == NULL) { + + for (jj=0; jj<j; jj++) + N_VDestroyVectorArray(ck_mem->ck_phiQS[jj], IDA_mem->ida_Ns); + + for (jj=0; jj<ck_mem->ck_phi_alloc; jj++) + N_VDestroyVectorArray(ck_mem->ck_phiS[jj], IDA_mem->ida_Ns); + + if (ck_mem->ck_quadr) + for (jj=0; jj<ck_mem->ck_phi_alloc; jj++) + N_VDestroy(ck_mem->ck_phiQ[jj]); + + for (jj=0; jj<ck_mem->ck_phi_alloc; jj++) + N_VDestroy(ck_mem->ck_phi[jj]); + + return(SUNFALSE); + } + } + } + return(SUNTRUE); +} + +/* + * IDAAckpntCopyVectors + * + * Copy phi* vectors from IDAMem in the corresponding vectors from checkpoint + * + */ +static void IDAAckpntCopyVectors(IDAMem IDA_mem, CkpntMem ck_mem) +{ + int j, is; + + /* Save phi* arrays from IDA_mem */ + + for (j=0; j<ck_mem->ck_phi_alloc; j++) + IDA_mem->ida_cvals[j] = ONE; + + (void) N_VScaleVectorArray(ck_mem->ck_phi_alloc, IDA_mem->ida_cvals, + IDA_mem->ida_phi, ck_mem->ck_phi); + + if (ck_mem->ck_quadr) + (void) N_VScaleVectorArray(ck_mem->ck_phi_alloc, IDA_mem->ida_cvals, + IDA_mem->ida_phiQ, ck_mem->ck_phiQ); + + if (ck_mem->ck_sensi || ck_mem->ck_quadr_sensi) { + for (j=0; j<ck_mem->ck_phi_alloc; j++) { + for (is=0; is<IDA_mem->ida_Ns; is++) { + IDA_mem->ida_cvals[j*IDA_mem->ida_Ns + is] = ONE; + } + } + } + + if (ck_mem->ck_sensi) { + for (j=0; j<ck_mem->ck_phi_alloc; j++) { + for (is=0; is<IDA_mem->ida_Ns; is++) { + IDA_mem->ida_Xvecs[j*IDA_mem->ida_Ns + is] = IDA_mem->ida_phiS[j][is]; + IDA_mem->ida_Zvecs[j*IDA_mem->ida_Ns + is] = ck_mem->ck_phiS[j][is]; + } + } + + (void) N_VScaleVectorArray(ck_mem->ck_phi_alloc * IDA_mem->ida_Ns, + IDA_mem->ida_cvals, + IDA_mem->ida_Xvecs, IDA_mem->ida_Zvecs); + } + + if(ck_mem->ck_quadr_sensi) { + for (j=0; j<ck_mem->ck_phi_alloc; j++) { + for (is=0; is<IDA_mem->ida_Ns; is++) { + IDA_mem->ida_Xvecs[j*IDA_mem->ida_Ns + is] = IDA_mem->ida_phiQS[j][is]; + IDA_mem->ida_Zvecs[j*IDA_mem->ida_Ns + is] = ck_mem->ck_phiQS[j][is]; + } + } + + (void) N_VScaleVectorArray(ck_mem->ck_phi_alloc * IDA_mem->ida_Ns, + IDA_mem->ida_cvals, + IDA_mem->ida_Xvecs, IDA_mem->ida_Zvecs); + } + +} + +/* + * 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 + * at any other time. +*/ + +static booleantype IDAAdataMalloc(IDAMem IDA_mem) +{ + IDAadjMem IDAADJ_mem; + DtpntMem *dt_mem; + long int i, j; + + IDAADJ_mem = IDA_mem->ida_adj_mem; + IDAADJ_mem->dt_mem = NULL; + + dt_mem = (DtpntMem *)malloc((IDAADJ_mem->ia_nsteps+1)*sizeof(struct DtpntMemRec *)); + 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; j<i; j++) + free(dt_mem[j]); + + free(dt_mem); + return(SUNFALSE); + } + dt_mem[i]->content = NULL; + } + /* Attach the allocated dt_mem to IDAADJ_mem. */ + IDAADJ_mem->dt_mem = dt_mem; + return(SUNTRUE); +} + +/* + * IDAAdataFree + * + * This routine frees the memory allocated for data storage. + */ + +static void IDAAdataFree(IDAMem IDA_mem) +{ + IDAadjMem IDAADJ_mem; + long int i; + + IDAADJ_mem = IDA_mem->ida_adj_mem; + + if (IDAADJ_mem == NULL) return; + + /* Destroy data points by calling the interpolation's 'free' routine. */ + IDAADJ_mem->ia_free(IDA_mem); + + for (i=0; i<=IDAADJ_mem->ia_nsteps; i++) { + free(IDAADJ_mem->dt_mem[i]); + IDAADJ_mem->dt_mem[i] = NULL; + } + + free(IDAADJ_mem->dt_mem); + IDAADJ_mem->dt_mem = NULL; +} + + +/* + * IDAAdataStore + * + * This routine integrates the forward model starting at the check + * point ck_mem and stores y and yprime at all intermediate + * steps. + * + * Return values: + * - the flag that IDASolve may return on error + * - IDA_REIFWD_FAIL if no check point is available for this hot start + * - IDA_SUCCESS + */ + +static int IDAAdataStore(IDAMem IDA_mem, CkpntMem ck_mem) +{ + IDAadjMem IDAADJ_mem; + DtpntMem *dt_mem; + realtype t; + long int i; + int flag, sign; + + IDAADJ_mem = IDA_mem->ida_adj_mem; + dt_mem = IDAADJ_mem->dt_mem; + + /* Initialize IDA_mem with data from ck_mem. */ + flag = IDAAckpntGet(IDA_mem, ck_mem); + if (flag != IDA_SUCCESS) + return(IDA_REIFWD_FAIL); + + /* Set first structure in dt_mem[0] */ + dt_mem[0]->t = ck_mem->ck_t0; + IDAADJ_mem->ia_storePnt(IDA_mem, dt_mem[0]); + + /* Decide whether TSTOP must be activated */ + if (IDAADJ_mem->ia_tstopIDAFcall) { + IDASetStopTime(IDA_mem, IDAADJ_mem->ia_tstopIDAF); + } + + sign = (IDAADJ_mem->ia_tfinal - IDAADJ_mem->ia_tinitial > ZERO) ? 1 : -1; + + /* Run IDASolve in IDA_ONE_STEP mode to set following structures in dt_mem[i]. */ + i = 1; + do { + + flag = IDASolve(IDA_mem, ck_mem->ck_t1, &t, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, IDA_ONE_STEP); + if (flag < 0) return(IDA_FWD_FAIL); + + dt_mem[i]->t = t; + IDAADJ_mem->ia_storePnt(IDA_mem, dt_mem[i]); + + i++; + } while ( sign*(ck_mem->ck_t1 - t) > ZERO ); + + /* New data is now available. */ + IDAADJ_mem->ia_ckpntData = ck_mem; + IDAADJ_mem->ia_newData = SUNTRUE; + IDAADJ_mem->ia_np = i; + + return(IDA_SUCCESS); +} + +/* + * CVAckpntGet + * + * This routine prepares IDAS for a hot restart from + * the check point ck_mem + */ + +static int IDAAckpntGet(IDAMem IDA_mem, CkpntMem ck_mem) +{ + int flag, j, is; + + 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 + * the first run. */ + + IDASetInitStep(IDA_mem, IDA_mem->ida_h0u); + + flag = IDAReInit(IDA_mem, ck_mem->ck_t0, ck_mem->ck_phi[0], ck_mem->ck_phi[1]); + if (flag != IDA_SUCCESS) return(flag); + + if (ck_mem->ck_quadr) { + flag = IDAQuadReInit(IDA_mem, ck_mem->ck_phiQ[0]); + if (flag != IDA_SUCCESS) return(flag); + } + + if (ck_mem->ck_sensi) { + flag = IDASensReInit(IDA_mem, IDA_mem->ida_ism, ck_mem->ck_phiS[0], ck_mem->ck_phiS[1]); + if (flag != IDA_SUCCESS) return(flag); + } + + if (ck_mem->ck_quadr_sensi) { + flag = IDAQuadSensReInit(IDA_mem, ck_mem->ck_phiQS[0]); + if (flag != IDA_SUCCESS) return(flag); + } + + } else { + + /* Copy parameters from check point data structure */ + IDA_mem->ida_nst = ck_mem->ck_nst; + IDA_mem->ida_tretlast = ck_mem->ck_tretlast; + IDA_mem->ida_kk = ck_mem->ck_kk; + IDA_mem->ida_kused = ck_mem->ck_kused; + IDA_mem->ida_knew = ck_mem->ck_knew; + IDA_mem->ida_phase = ck_mem->ck_phase; + IDA_mem->ida_ns = ck_mem->ck_ns; + IDA_mem->ida_hh = ck_mem->ck_hh; + IDA_mem->ida_hused = ck_mem->ck_hused; + IDA_mem->ida_rr = ck_mem->ck_rr; + IDA_mem->ida_cj = ck_mem->ck_cj; + IDA_mem->ida_cjlast = ck_mem->ck_cjlast; + IDA_mem->ida_cjold = ck_mem->ck_cjold; + IDA_mem->ida_cjratio = ck_mem->ck_cjratio; + IDA_mem->ida_tn = ck_mem->ck_t0; + 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; j<ck_mem->ck_phi_alloc; j++) + N_VScale(ONE, ck_mem->ck_phi[j], IDA_mem->ida_phi[j]); + + if(ck_mem->ck_quadr) { + for (j=0; j<ck_mem->ck_phi_alloc; j++) + N_VScale(ONE, ck_mem->ck_phiQ[j], IDA_mem->ida_phiQ[j]); + } + + if (ck_mem->ck_sensi) { + for (is=0; is<IDA_mem->ida_Ns; is++) { + for (j=0; j<ck_mem->ck_phi_alloc; j++) + N_VScale(ONE, ck_mem->ck_phiS[j][is], IDA_mem->ida_phiS[j][is]); + } + } + + if (ck_mem->ck_quadr_sensi) { + for (is=0; is<IDA_mem->ida_Ns; is++) { + for (j=0; j<ck_mem->ck_phi_alloc; j++) + N_VScale(ONE, ck_mem->ck_phiQS[j][is], IDA_mem->ida_phiQS[j][is]); + } + } + + for (j=0; j<MXORDP1; j++) { + IDA_mem->ida_psi[j] = ck_mem->ck_psi[j]; + IDA_mem->ida_alpha[j] = ck_mem->ck_alpha[j]; + IDA_mem->ida_beta[j] = ck_mem->ck_beta[j]; + IDA_mem->ida_sigma[j] = ck_mem->ck_sigma[j]; + IDA_mem->ida_gamma[j] = ck_mem->ck_gamma[j]; + } + + /* Force a call to setup */ + IDA_mem->ida_forceSetup = SUNTRUE; + } + + return(IDA_SUCCESS); +} + + +/* + * ----------------------------------------------------------------- + * Functions specific to cubic Hermite interpolation + * ----------------------------------------------------------------- + */ + +/* + * 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 + * at any other time. + */ + +static booleantype IDAAhermiteMalloc(IDAMem IDA_mem) +{ + IDAadjMem IDAADJ_mem; + DtpntMem *dt_mem; + HermiteDataMem content; + long int i, ii=0; + booleantype allocOK; + + allocOK = SUNTRUE; + + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Allocate space for the vectors yyTmp and ypTmp. */ + IDAADJ_mem->ia_yyTmp = N_VClone(IDA_mem->ida_tempv1); + if (IDAADJ_mem->ia_yyTmp == NULL) { + return(SUNFALSE); + } + IDAADJ_mem->ia_ypTmp = N_VClone(IDA_mem->ida_tempv1); + if (IDAADJ_mem->ia_ypTmp == NULL) { + return(SUNFALSE); + } + + /* 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); + N_VDestroy(IDAADJ_mem->ia_ypTmp); + return(SUNFALSE); + } + + IDAADJ_mem->ia_ypSTmp = N_VCloneVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_tempv1); + if (IDAADJ_mem->ia_ypSTmp == NULL) { + N_VDestroy(IDAADJ_mem->ia_yyTmp); + N_VDestroy(IDAADJ_mem->ia_ypTmp); + N_VDestroyVectorArray(IDAADJ_mem->ia_yySTmp, IDA_mem->ida_Ns); + return(SUNFALSE); + + } + } + + /* Allocate space for the content field of the dt structures */ + + dt_mem = IDAADJ_mem->dt_mem; + + for (i=0; i<=IDAADJ_mem->ia_nsteps; i++) { + + content = NULL; + content = (HermiteDataMem) malloc(sizeof(struct HermiteDataMemRec)); + if (content == NULL) { + ii = i; + allocOK = SUNFALSE; + break; + } + + content->y = N_VClone(IDA_mem->ida_tempv1); + if (content->y == NULL) { + free(content); content = NULL; + ii = i; + allocOK = SUNFALSE; + break; + } + + content->yd = N_VClone(IDA_mem->ida_tempv1); + if (content->yd == NULL) { + N_VDestroy(content->y); + free(content); content = NULL; + ii = i; + allocOK = SUNFALSE; + break; + } + + 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); + N_VDestroy(content->yd); + free(content); content = NULL; + ii = i; + allocOK = SUNFALSE; + break; + } + + content->ySd = N_VCloneVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_tempv1); + if (content->ySd == NULL) { + N_VDestroy(content->y); + N_VDestroy(content->yd); + N_VDestroyVectorArray(content->yS, IDA_mem->ida_Ns); + free(content); content = NULL; + ii = i; + allocOK = SUNFALSE; + 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); + + 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); + } + + for (i=0; i<ii; i++) { + content = (HermiteDataMem) (dt_mem[i]->content); + N_VDestroy(content->y); + N_VDestroy(content->yd); + + if (IDAADJ_mem->ia_storeSensi) { + N_VDestroyVectorArray(content->yS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(content->ySd, IDA_mem->ida_Ns); + } + + free(dt_mem[i]->content); dt_mem[i]->content = NULL; + } + + } + + return(allocOK); +} + +/* + * IDAAhermiteFree + * + * This routine frees the memory allocated for data storage. + */ + +static void IDAAhermiteFree(IDAMem IDA_mem) +{ + IDAadjMem IDAADJ_mem; + DtpntMem *dt_mem; + HermiteDataMem content; + long int i; + + IDAADJ_mem = IDA_mem->ida_adj_mem; + + N_VDestroy(IDAADJ_mem->ia_yyTmp); + N_VDestroy(IDAADJ_mem->ia_ypTmp); + + 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); + } + + dt_mem = IDAADJ_mem->dt_mem; + + for (i=0; i<=IDAADJ_mem->ia_nsteps; i++) { + + content = (HermiteDataMem) (dt_mem[i]->content); + /* content might be NULL, if IDAAdjInit was called but IDASolveF was not. */ + if(content) { + + N_VDestroy(content->y); + N_VDestroy(content->yd); + + if (IDAADJ_mem->ia_storeSensi) { + N_VDestroyVectorArray(content->yS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(content->ySd, IDA_mem->ida_Ns); + } + free(dt_mem[i]->content); + dt_mem[i]->content = NULL; + } + } +} + +/* + * IDAAhermiteStorePnt + * + * This routine stores a new point (y,yd) in the structure d for use + * in the cubic Hermite interpolation. + * Note that the time is already stored. + */ + +static int IDAAhermiteStorePnt(IDAMem IDA_mem, DtpntMem d) +{ + IDAadjMem IDAADJ_mem; + HermiteDataMem content; + int is, retval; + + IDAADJ_mem = IDA_mem->ida_adj_mem; + + content = (HermiteDataMem) d->content; + + /* Load solution(s) */ + N_VScale(ONE, IDA_mem->ida_phi[0], content->y); + + if (IDAADJ_mem->ia_storeSensi) { + for (is=0; is<IDA_mem->ida_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); + } + + /* Load derivative(s). */ + IDAAGettnSolutionYp(IDA_mem, content->yd); + + if (IDAADJ_mem->ia_storeSensi) { + IDAAGettnSolutionYpS(IDA_mem, content->ySd); + } + + return(0); +} + + +/* + * IDAAhermiteGetY + * + * 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 + */ + +static int IDAAhermiteGetY(IDAMem IDA_mem, realtype t, + N_Vector yy, N_Vector yp, + N_Vector *yyS, N_Vector *ypS) +{ + IDAadjMem IDAADJ_mem; + DtpntMem *dt_mem; + HermiteDataMem content0, content1; + + realtype t0, t1, delta; + realtype factor1, factor2, factor3; + + N_Vector y0, yd0, y1, yd1; + N_Vector *yS0=NULL, *ySd0=NULL, *yS1, *ySd1; + + int flag, is, NS; + long int indx; + booleantype newpoint; + + /* local variables for fused vector oerations */ + int retval; + 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; + + /* Get the index in dt_mem */ + flag = IDAAfindIndex(IDA_mem, t, &indx, &newpoint); + if (flag != IDA_SUCCESS) return(flag); + + /* If we are beyond the left limit but close enough, + then return y at the left limit. */ + + if (indx == 0) { + content0 = (HermiteDataMem) (dt_mem[0]->content); + N_VScale(ONE, content0->y, yy); + N_VScale(ONE, content0->yd, yp); + + if (NS > 0) { + for (is=0; is<NS; is++) + IDA_mem->ida_cvals[is] = ONE; + + retval = N_VScaleVectorArray(NS, IDA_mem->ida_cvals, content0->yS, yyS); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + retval = N_VScaleVectorArray(NS, IDA_mem->ida_cvals, content0->ySd, ypS); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + } + + return(IDA_SUCCESS); + } + + /* Extract stuff from the appropriate data points */ + t0 = dt_mem[indx-1]->t; + t1 = dt_mem[indx]->t; + delta = t1 - t0; + + content0 = (HermiteDataMem) (dt_mem[indx-1]->content); + y0 = content0->y; + yd0 = content0->yd; + if (IDAADJ_mem->ia_interpSensi) { + yS0 = content0->yS; + ySd0 = content0->ySd; + } + + if (newpoint) { + + /* Recompute Y0 and Y1 */ + content1 = (HermiteDataMem) (dt_mem[indx]->content); + + y1 = content1->y; + yd1 = content1->yd; + + /* Y1 = delta (yd1 + yd0) - 2 (y1 - y0) */ + cvals[0] = -TWO; Xvecs[0] = y1; + cvals[1] = TWO; Xvecs[1] = y0; + cvals[2] = delta; Xvecs[2] = yd1; + cvals[3] = delta; Xvecs[3] = yd0; + + retval = N_VLinearCombination(4, cvals, Xvecs, IDAADJ_mem->ia_Y[1]); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + /* Y0 = y1 - y0 - delta * yd0 */ + cvals[0] = ONE; Xvecs[0] = y1; + cvals[1] = -ONE; Xvecs[1] = y0; + cvals[2] = -delta; Xvecs[2] = yd0; + + retval = N_VLinearCombination(3, cvals, Xvecs, IDAADJ_mem->ia_Y[0]); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + /* Recompute YS0 and YS1, if needed */ + + if (NS > 0) { + + yS1 = content1->yS; + ySd1 = content1->ySd; + + /* YS1 = delta (ySd1 + ySd0) - 2 (yS1 - yS0) */ + cvals[0] = -TWO; XXvecs[0] = yS1; + cvals[1] = TWO; XXvecs[1] = yS0; + cvals[2] = delta; XXvecs[2] = ySd1; + cvals[3] = delta; XXvecs[3] = ySd0; + + retval = N_VLinearCombinationVectorArray(NS, 4, cvals, XXvecs, IDAADJ_mem->ia_YS[1]); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + /* YS0 = yS1 - yS0 - delta * ySd0 */ + cvals[0] = ONE; XXvecs[0] = yS1; + cvals[1] = -ONE; XXvecs[1] = yS0; + cvals[2] = -delta; XXvecs[2] = ySd0; + + retval = N_VLinearCombinationVectorArray(NS, 3, cvals, XXvecs, IDAADJ_mem->ia_YS[0]); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + } + + } + + /* Perform the actual interpolation. */ + + /* For y. */ + factor1 = t - t0; + + factor2 = factor1/delta; + factor2 = factor2*factor2; + + factor3 = factor2*(t-t1)/delta; + + cvals[0] = ONE; + cvals[1] = factor1; + cvals[2] = factor2; + cvals[3] = factor3; + + /* y = y0 + factor1 yd0 + factor2 * Y[0] + factor3 Y[1] */ + Xvecs[0] = y0; + Xvecs[1] = yd0; + Xvecs[2] = IDAADJ_mem->ia_Y[0]; + Xvecs[3] = IDAADJ_mem->ia_Y[1]; + + retval = N_VLinearCombination(4, cvals, Xvecs, yy); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + /* Sensi Interpolation. */ + + /* yS = yS0 + factor1 ySd0 + factor2 * YS[0] + factor3 YS[1], if needed */ + if (NS > 0) { + + XXvecs[0] = yS0; + XXvecs[1] = ySd0; + XXvecs[2] = IDAADJ_mem->ia_YS[0]; + XXvecs[3] = IDAADJ_mem->ia_YS[1]; + + retval = N_VLinearCombinationVectorArray(NS, 4, cvals, XXvecs, yyS); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + } + + /* For y'. */ + factor1 = factor1/delta/delta; /* factor1 = 2(t-t0)/(t1-t0)^2 */ + factor2 = factor1*((3*t-2*t1-t0)/delta); /* factor2 = (t-t0)(3*t-2*t1-t0)/(t1-t0)^3 */ + factor1 *= 2; + + cvals[0] = ONE; + cvals[1] = factor1; + cvals[2] = factor2; + + /* yp = yd0 + factor1 Y[0] + factor 2 Y[1] */ + Xvecs[0] = yd0; + Xvecs[1] = IDAADJ_mem->ia_Y[0]; + Xvecs[2] = IDAADJ_mem->ia_Y[1]; + + 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 */ + if (NS > 0) { + + XXvecs[0] = ySd0; + XXvecs[1] = IDAADJ_mem->ia_YS[0]; + XXvecs[2] = IDAADJ_mem->ia_YS[1]; + + retval = N_VLinearCombinationVectorArray(NS, 3, cvals, XXvecs, ypS); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + } + + return(IDA_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Functions specific to Polynomial interpolation + * ----------------------------------------------------------------- + */ + +/* + * 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 + * at any other time. + * + * Information about the first derivative is stored only for the first + * data point. + */ + +static booleantype IDAApolynomialMalloc(IDAMem IDA_mem) +{ + IDAadjMem IDAADJ_mem; + DtpntMem *dt_mem; + PolynomialDataMem content; + long int i, ii=0; + booleantype allocOK; + + allocOK = SUNTRUE; + + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Allocate space for the vectors yyTmp and ypTmp */ + IDAADJ_mem->ia_yyTmp = N_VClone(IDA_mem->ida_tempv1); + if (IDAADJ_mem->ia_yyTmp == NULL) { + return(SUNFALSE); + } + IDAADJ_mem->ia_ypTmp = N_VClone(IDA_mem->ida_tempv1); + if (IDAADJ_mem->ia_ypTmp == NULL) { + return(SUNFALSE); + } + + 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); + N_VDestroy(IDAADJ_mem->ia_ypTmp); + return(SUNFALSE); + } + + IDAADJ_mem->ia_ypSTmp = N_VCloneVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_tempv1); + if (IDAADJ_mem->ia_ypSTmp == NULL) { + N_VDestroy(IDAADJ_mem->ia_yyTmp); + N_VDestroy(IDAADJ_mem->ia_ypTmp); + N_VDestroyVectorArray(IDAADJ_mem->ia_yySTmp, IDA_mem->ida_Ns); + return(SUNFALSE); + + } + } + + /* Allocate space for the content field of the dt structures */ + dt_mem = IDAADJ_mem->dt_mem; + + for (i=0; i<=IDAADJ_mem->ia_nsteps; i++) { + + content = NULL; + content = (PolynomialDataMem) malloc(sizeof(struct PolynomialDataMemRec)); + if (content == NULL) { + ii = i; + allocOK = SUNFALSE; + break; + } + + content->y = N_VClone(IDA_mem->ida_tempv1); + if (content->y == NULL) { + free(content); content = NULL; + ii = i; + allocOK = SUNFALSE; + break; + } + + /* 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); + free(content); content = NULL; + ii = i; + allocOK = SUNFALSE; + } + } else { + /* Not the first data point. */ + content->yd = NULL; + } + + 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); + if (content->yd) N_VDestroy(content->yd); + free(content); content = NULL; + ii = i; + allocOK = SUNFALSE; + break; + } + + if (i==0) { + content->ySd = N_VCloneVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_tempv1); + if (content->ySd == NULL) { + N_VDestroy(content->y); + if (content->yd) N_VDestroy(content->yd); + N_VDestroyVectorArray(content->yS, IDA_mem->ida_Ns); + free(content); content = NULL; + ii = i; + allocOK = SUNFALSE; + } + } else { + content->ySd = NULL; + } + } + + 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); + 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); + } + + for (i=0; i<ii; i++) { + content = (PolynomialDataMem) (dt_mem[i]->content); + N_VDestroy(content->y); + + 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); + } + free(dt_mem[i]->content); dt_mem[i]->content = NULL; + } + + } + return(allocOK); +} + +/* + * IDAApolynomialFree + * + * This routine frees the memory allocated for data storage. + */ + +static void IDAApolynomialFree(IDAMem IDA_mem) +{ + IDAadjMem IDAADJ_mem; + DtpntMem *dt_mem; + PolynomialDataMem content; + long int i; + + IDAADJ_mem = IDA_mem->ida_adj_mem; + + N_VDestroy(IDAADJ_mem->ia_yyTmp); + N_VDestroy(IDAADJ_mem->ia_ypTmp); + + 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); + } + + dt_mem = IDAADJ_mem->dt_mem; + + for (i=0; i<=IDAADJ_mem->ia_nsteps; i++) { + + content = (PolynomialDataMem) (dt_mem[i]->content); + + /* content might be NULL, if IDAAdjInit was called but IDASolveF was not. */ + if(content) { + N_VDestroy(content->y); + + 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); + } + free(dt_mem[i]->content); dt_mem[i]->content = NULL; + } + } +} + +/* + * IDAApolynomialStorePnt + * + * 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, + * in which case content->yp is non-null. + */ + +static int IDAApolynomialStorePnt(IDAMem IDA_mem, DtpntMem d) +{ + IDAadjMem IDAADJ_mem; + PolynomialDataMem content; + int is, retval; + + IDAADJ_mem = IDA_mem->ida_adj_mem; + content = (PolynomialDataMem) d->content; + + N_VScale(ONE, IDA_mem->ida_phi[0], content->y); + + /* copy also the derivative for the first data point (in this case + content->yp is non-null). */ + if (content->yd) + IDAAGettnSolutionYp(IDA_mem, content->yd); + + if (IDAADJ_mem->ia_storeSensi) { + + for (is=0; is<IDA_mem->ida_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); + } + + content->order = IDA_mem->ida_kused; + + return(0); +} + +/* + * IDAApolynomialGetY + * + * 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. + */ + +static int IDAApolynomialGetY(IDAMem IDA_mem, realtype t, + N_Vector yy, N_Vector yp, + N_Vector *yyS, N_Vector *ypS) +{ + IDAadjMem IDAADJ_mem; + DtpntMem *dt_mem; + PolynomialDataMem content; + + int flag, dir, order, i, j, is, NS, retval; + long int indx, base; + booleantype newpoint; + realtype delt, factor, Psi, Psiprime; + + 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; + + /* Get the index in dt_mem */ + flag = IDAAfindIndex(IDA_mem, t, &indx, &newpoint); + if (flag != IDA_SUCCESS) return(flag); + + /* If we are beyond the left limit but close enough, + then return y at the left limit. */ + + if (indx == 0) { + content = (PolynomialDataMem) (dt_mem[0]->content); + N_VScale(ONE, content->y, yy); + N_VScale(ONE, content->yd, yp); + + if (NS > 0) { + for (is=0; is<NS; is++) + IDA_mem->ida_cvals[is] = ONE; + + retval = N_VScaleVectorArray(NS, IDA_mem->ida_cvals, content->yS, yyS); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + retval = N_VScaleVectorArray(NS, IDA_mem->ida_cvals, content->ySd, ypS); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + } + + return(IDA_SUCCESS); + } + + /* Scaling factor */ + delt = SUNRabs(dt_mem[indx]->t - dt_mem[indx-1]->t); + + /* Find the direction of the forward integration */ + dir = (IDAADJ_mem->ia_tfinal - IDAADJ_mem->ia_tinitial > ZERO) ? 1 : -1; + + /* Establish the base point depending on the integration direction. + Modify the base if there are not enough points for the current order */ + + if (dir == 1) { + base = indx; + content = (PolynomialDataMem) (dt_mem[base]->content); + order = content->order; + if(indx < order) base += order-indx; + } else { + base = indx-1; + content = (PolynomialDataMem) (dt_mem[base]->content); + order = content->order; + if (IDAADJ_mem->ia_np-indx > order) base -= indx+order-IDAADJ_mem->ia_np; + } + + /* Recompute Y (divided differences for Newton polynomial) if needed */ + + if (newpoint) { + + /* Store 0-th order DD */ + if (dir == 1) { + for(j=0;j<=order;j++) { + IDAADJ_mem->ia_T[j] = dt_mem[base-j]->t; + content = (PolynomialDataMem) (dt_mem[base-j]->content); + N_VScale(ONE, content->y, IDAADJ_mem->ia_Y[j]); + + if (NS > 0) { + for (is=0; is<NS; is++) + IDA_mem->ida_cvals[is] = ONE; + retval = N_VScaleVectorArray(NS, IDA_mem->ida_cvals, + content->yS, IDAADJ_mem->ia_YS[j]); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + } + } + } else { + for(j=0;j<=order;j++) { + IDAADJ_mem->ia_T[j] = dt_mem[base-1+j]->t; + content = (PolynomialDataMem) (dt_mem[base-1+j]->content); + N_VScale(ONE, content->y, IDAADJ_mem->ia_Y[j]); + + if (NS > 0) { + for (is=0; is<NS; is++) + IDA_mem->ida_cvals[is] = ONE; + retval = N_VScaleVectorArray(NS, IDA_mem->ida_cvals, + content->yS, IDAADJ_mem->ia_YS[j]); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + } + } + } + + /* Compute higher-order DD */ + for(i=1;i<=order;i++) { + for(j=order;j>=i;j--) { + 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; is<NS; is++) + N_VLinearSum(factor, IDAADJ_mem->ia_YS[j][is], -factor, IDAADJ_mem->ia_YS[j-1][is], IDAADJ_mem->ia_YS[j][is]); + + } + } + } + + /* Perform the actual interpolation for yy using nested multiplications */ + + IDA_mem->ida_cvals[0] = ONE; + for (i=0; i<order; i++) + IDA_mem->ida_cvals[i+1] = IDA_mem->ida_cvals[i] * (t-IDAADJ_mem->ia_T[i]) / delt; + + retval = N_VLinearCombination(order+1, IDA_mem->ida_cvals, IDAADJ_mem->ia_Y, yy); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + if (NS > 0) { + 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: + - 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} + + psi_k is rescaled with 1/delt each time is computed, because the Newton DDs from Y were + scaled with delt. + */ + + Psi = ONE; + Psiprime = ZERO; + + for(i=1; i<=order; i++) { + factor = (t-IDAADJ_mem->ia_T[i-1])/delt; + + Psiprime = Psi/delt + factor * Psiprime; + Psi = Psi * factor; + + IDA_mem->ida_cvals[i-1] = Psiprime; + } + + retval = N_VLinearCombination(order, IDA_mem->ida_cvals, IDAADJ_mem->ia_Y+1, yp); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + if (NS > 0) { + retval = N_VLinearCombinationVectorArray(NS, order, IDA_mem->ida_cvals, IDAADJ_mem->ia_YS+1, ypS); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + } + + 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 + * particular case when t=tn (i.e. delta=0). + * + * This function was implemented to avoid calls to IDAGetSolution which computes + * y by doing a loop that is not necessary for this particular situation. + */ + +static int IDAAGettnSolutionYp(IDAMem IDA_mem, N_Vector yp) +{ + int j, kord, retval; + realtype C, D, gam; + + if (IDA_mem->ida_nst==0) { + + /* If no integration was done, return the yp supplied by user.*/ + N_VScale(ONE, IDA_mem->ida_phi[1], yp); + + return(0); + } + + /* 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++) { + 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; + } + + retval = N_VLinearCombination(kord, IDA_mem->ida_dvals, + IDA_mem->ida_phi+1, yp); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + return(0); +} + + +/* + * IDAAGettnSolutionYpS + * + * Same as IDAAGettnSolutionYp, but for first derivative of the sensitivities. + * + */ + +static int IDAAGettnSolutionYpS(IDAMem IDA_mem, N_Vector *ypS) +{ + int j, kord, is, retval; + realtype C, D, gam; + + if (IDA_mem->ida_nst==0) { + + /* If no integration was done, return the ypS supplied by user.*/ + for (is=0; is<IDA_mem->ida_Ns; is++) + IDA_mem->ida_cvals[is] = ONE; + + retval = N_VScaleVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_cvals, + IDA_mem->ida_phiS[1], ypS); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + 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; + } + + retval = N_VLinearCombinationVectorArray(IDA_mem->ida_Ns, kord, + IDA_mem->ida_dvals, + IDA_mem->ida_phiS+1, ypS); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + return(0); +} + + + +/* + * IDAAfindIndex + * + * Finds the index in the array of data point strctures such that + * dt_mem[indx-1].t <= t < dt_mem[indx].t + * If indx is changed from the previous invocation, then newpoint = SUNTRUE + * + * If t is beyond the leftmost limit, but close enough, indx=0. + * + * Returns IDA_SUCCESS if successful and IDA_GETY_BADT if unable to + * find indx (t is too far beyond limits). + */ + +static int IDAAfindIndex(IDAMem ida_mem, realtype t, + long int *indx, booleantype *newpoint) +{ + IDAadjMem IDAADJ_mem; + IDAMem IDA_mem; + DtpntMem *dt_mem; + int sign; + booleantype to_left, to_right; + + IDA_mem = (IDAMem) ida_mem; + IDAADJ_mem = IDA_mem->ida_adj_mem; + dt_mem = IDAADJ_mem->dt_mem; + + *newpoint = SUNFALSE; + + /* Find the direction of integration */ + sign = (IDAADJ_mem->ia_tfinal - IDAADJ_mem->ia_tinitial > ZERO) ? 1 : -1; + + /* If this is the first time we use new data */ + if (IDAADJ_mem->ia_newData) { + IDAADJ_mem->ia_ilast = IDAADJ_mem->ia_np-1; + *newpoint = SUNTRUE; + IDAADJ_mem->ia_newData = SUNFALSE; + } + + /* Search for indx starting from ilast */ + to_left = ( sign*(t - dt_mem[IDAADJ_mem->ia_ilast-1]->t) < ZERO); + to_right = ( sign*(t - dt_mem[IDAADJ_mem->ia_ilast]->t) > ZERO); + + if ( to_left ) { + /* look for a new indx to the left */ + + *newpoint = SUNTRUE; + + *indx = IDAADJ_mem->ia_ilast; + for(;;) { + if ( *indx == 0 ) break; + if ( sign*(t - dt_mem[*indx-1]->t) <= ZERO ) (*indx)--; + else break; + } + + if ( *indx == 0 ) + IDAADJ_mem->ia_ilast = 1; + else + IDAADJ_mem->ia_ilast = *indx; + + if ( *indx == 0 ) { + /* 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); + } + } + + } else if ( to_right ) { + /* look for a new indx to the right */ + + *newpoint = SUNTRUE; + + *indx = IDAADJ_mem->ia_ilast; + for(;;) { + if ( sign*(t - dt_mem[*indx]->t) > ZERO) (*indx)++; + else break; + } + + IDAADJ_mem->ia_ilast = *indx; + + } else { + /* ilast is still OK */ + + *indx = IDAADJ_mem->ia_ilast; + + } + return(IDA_SUCCESS); +} + + +/* + * IDAGetAdjY + * + * This routine returns the interpolated forward solution at time t. + * The user must allocate space for y. + */ + +int IDAGetAdjY(void *ida_mem, realtype t, N_Vector yy, N_Vector yp) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + int flag; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDAGetAdjY", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + IDAADJ_mem = IDA_mem->ida_adj_mem; + + flag = IDAADJ_mem->ia_getY(IDA_mem, t, yy, yp, NULL, NULL); + + return(flag); +} + +/*=================================================================*/ +/* Wrappers for adjoint system */ +/*=================================================================*/ + +/* + * IDAAres + * + * This routine interfaces to the RhsFnB routine provided by + * the user. +*/ + +static int IDAAres(realtype tt, + N_Vector yyB, N_Vector ypB, N_Vector rrB, + void *ida_mem) +{ + IDAadjMem IDAADJ_mem; + IDABMem IDAB_mem; + IDAMem IDA_mem; + int flag, retval; + + IDA_mem = (IDAMem) ida_mem; + + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Get the current backward problem. */ + IDAB_mem = IDAADJ_mem->ia_bckpbCrt; + + /* Get forward solution from interpolation. */ + if( IDAADJ_mem->ia_noInterp == SUNFALSE) { + if (IDAADJ_mem->ia_interpSensi) + 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); + } + } + + /* 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, + IDAADJ_mem->ia_yySTmp, IDAADJ_mem->ia_ypSTmp, + 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); + } + return(retval); +} + +/* + *IDAArhsQ + * + * This routine interfaces to the IDAQuadRhsFnB routine provided by + * the user. + * + * It is passed to IDAQuadInit calls for backward problem, so it must + * be of IDAQuadRhsFn type. +*/ + +static int IDAArhsQ(realtype tt, + N_Vector yyB, N_Vector ypB, + N_Vector resvalQB, void *ida_mem) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + IDABMem IDAB_mem; + int retval, flag; + + IDA_mem = (IDAMem) ida_mem; + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Get current backward problem. */ + IDAB_mem = IDAADJ_mem->ia_bckpbCrt; + + retval = IDA_SUCCESS; + + /* Get forward solution from interpolation. */ + if (IDAADJ_mem->ia_noInterp == SUNFALSE) { + if (IDAADJ_mem->ia_interpSensi) { + 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", "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, + resvalQB, IDAB_mem->ida_user_data); + } else { + retval = IDAB_mem->ida_rhsQ(tt, + IDAADJ_mem->ia_yyTmp, IDAADJ_mem->ia_ypTmp, + yyB, ypB, + resvalQB, IDAB_mem->ida_user_data); + } + return(retval); +} + + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idaa_io.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idaa_io.c new file mode 100644 index 0000000..b328cd9 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idaa_io.c @@ -0,0 +1,782 @@ +/* + * ----------------------------------------------------------------- + * $Revision$ + * $Date$ + * ----------------------------------------------------------------- + * Programmer(s): Radu Serban and Cosmin Petra @ 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 optional input and output + * functions for the adjoint module in the IDAS solver. + * ----------------------------------------------------------------- + */ + + +/* + * ================================================================= + * IMPORTED HEADER FILES + * ================================================================= + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "idas_impl.h" +#include <sundials/sundials_types.h> + +/* + * ================================================================= + * IDAA PRIVATE CONSTANTS + * ================================================================= + */ + +#define ONE RCONST(1.0) + +/* + * ----------------------------------------------------------------- + * Optional input functions for ASA + * ----------------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------- + * IDAAdjSetNoSensi + * ----------------------------------------------------------------- + * Disables the forward sensitivity analysis in IDASolveF. + * ----------------------------------------------------------------- + */ + +SUNDIALS_EXPORT int IDAAdjSetNoSensi(void *ida_mem) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + + /* Is ida_mem valid? */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDAAdjSetNoSensi", MSGAM_NULL_IDAMEM); + return IDA_MEM_NULL; + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDAAdjSetNoSensi", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + IDAADJ_mem->ia_storeSensi = SUNFALSE; + + return(IDA_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Optional input functions for backward integration + * ----------------------------------------------------------------- + */ + +int IDASetNonlinearSolverB(void *ida_mem, int which, SUNNonlinearSolver NLS) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + IDABMem IDAB_mem; + void *ida_memB; + + /* Check if ida_mem exists */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", + "IDASetNonlinearSolverB", MSGAM_NULL_IDAMEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Was ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", + "IDASetNonlinearSolverB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", + "IDASetNonlinearSolverB", 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) { + if ( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + + ida_memB = (void *) (IDAB_mem->IDA_mem); + + return(IDASetNonlinearSolver(ida_memB, NLS)); +} + +int IDASetUserDataB(void *ida_mem, int which, void *user_dataB) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + IDABMem IDAB_mem; + + /* Is ida_mem valid? */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDASetUserDataB", MSGAM_NULL_IDAMEM); + return IDA_MEM_NULL; + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDASetUserDataB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDASetUserDataB", 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + + /* Set user data for this backward problem. */ + IDAB_mem->ida_user_data = user_dataB; + + return(IDA_SUCCESS); +} + +int IDASetMaxOrdB(void *ida_mem, int which, int maxordB) +{ + 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", "IDASetMaxOrdB", MSGAM_NULL_IDAMEM); + return IDA_MEM_NULL; + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDASetMaxOrdB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDASetMaxOrdB", 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + ida_memB = (void *) IDAB_mem->IDA_mem; + + return IDASetMaxOrd(ida_memB, maxordB); +} + +int IDASetMaxNumStepsB(void *ida_mem, int which, long int mxstepsB) +{ + 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", "IDASetMaxNumStepsB", MSGAM_NULL_IDAMEM); + return IDA_MEM_NULL; + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDASetMaxNumStepsB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDASetMaxNumStepsB", 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + ida_memB = (void *) IDAB_mem->IDA_mem; + + return IDASetMaxNumSteps(ida_memB, mxstepsB); +} + +int IDASetInitStepB(void *ida_mem, int which, realtype hinB) +{ + 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", "IDASetInitStepB", MSGAM_NULL_IDAMEM); + return IDA_MEM_NULL; + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDASetInitStepB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDASetInitStepB", 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + ida_memB = (void *) IDAB_mem->IDA_mem; + + return IDASetInitStep(ida_memB, hinB); +} + +int IDASetMaxStepB(void *ida_mem, int which, realtype hmaxB) +{ + 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", "IDASetMaxStepB", MSGAM_NULL_IDAMEM); + return IDA_MEM_NULL; + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDASetMaxStepB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDASetMaxStepB", 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + ida_memB = (void *) IDAB_mem->IDA_mem; + + return IDASetMaxStep(ida_memB, hmaxB); +} + +int IDASetSuppressAlgB(void *ida_mem, int which, booleantype suppressalgB) +{ + 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", "IDASetSuppressAlgB", MSGAM_NULL_IDAMEM); + return IDA_MEM_NULL; + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDASetSuppressAlgB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDASetSuppressAlgB", 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + ida_memB = (void *) IDAB_mem->IDA_mem; + + return IDASetSuppressAlg(ida_memB, suppressalgB); +} + +int IDASetIdB(void *ida_mem, int which, N_Vector idB) +{ + 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", "IDASetIdB", MSGAM_NULL_IDAMEM); + return IDA_MEM_NULL; + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDASetIdB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDASetIdB", 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + ida_memB = (void *) IDAB_mem->IDA_mem; + + return IDASetId(ida_memB, idB); +} + +int IDASetConstraintsB(void *ida_mem, int which, N_Vector constraintsB) +{ + 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", "IDASetConstraintsB", MSGAM_NULL_IDAMEM); + return IDA_MEM_NULL; + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDASetConstraintsB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDASetConstraintsB", 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + ida_memB = (void *) IDAB_mem->IDA_mem; + + return IDASetConstraints(ida_memB, constraintsB); +} +/* + * ---------------------------------------------------------------- + * Input quadrature functions for ASA + * ---------------------------------------------------------------- + */ + +int IDASetQuadErrConB(void *ida_mem, int which, int errconQB) +{ + 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", "IDASetQuadErrConB", MSGAM_NULL_IDAMEM); + return IDA_MEM_NULL; + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDASetQuadErrConB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDASetQuadErrConB", 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + ida_memB = (void *) IDAB_mem->IDA_mem; + + return IDASetQuadErrCon(ida_memB, errconQB); + +} + +/* + * ----------------------------------------------------------------- + * Optional output functions for backward integration + * ----------------------------------------------------------------- + */ + +/* + * IDAGetAdjIDABmem + * + * This function returns a (void *) pointer to the IDAS + * memory allocated for the backward problem. This pointer can + * then be used to call any of the IDAGet* IDAS routines to + * extract optional output for the backward integration phase. + */ + +SUNDIALS_EXPORT void *IDAGetAdjIDABmem(void *ida_mem, int which) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + IDABMem IDAB_mem; + void *ida_memB; + + /* Is ida_mem valid? */ + if (ida_mem == NULL) { + IDAProcessError(NULL, 0, "IDAA", "IDAGetAdjIDABmem", MSGAM_NULL_IDAMEM); + return(NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, 0, "IDAA", "IDAGetAdjIDABmem", MSGAM_NO_ADJ); + return(NULL); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + IDAProcessError(IDA_mem, 0, "IDAA", "IDAGetAdjIDABmem", MSGAM_BAD_WHICH); + return(NULL); + } + + /* Find the IDABMem entry in the linked list corresponding to 'which'. */ + IDAB_mem = IDAADJ_mem->IDAB_mem; + while (IDAB_mem != NULL) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + ida_memB = (void *) IDAB_mem->IDA_mem; + + return(ida_memB); +} + +/* + * IDAGetAdjCheckPointsInfo + * + * Loads an array of nckpnts structures of type IDAadjCheckPointRec + * defined below. + * + * The user must allocate space for ckpnt (ncheck+1). + */ + +int IDAGetAdjCheckPointsInfo(void *ida_mem, IDAadjCheckPointRec *ckpnt) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + CkpntMem ck_mem; + int i; + + /* Is ida_mem valid? */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDAGetAdjCheckPointsInfo", MSGAM_NULL_IDAMEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDAGetAdjCheckPointsInfo", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + i=0; + ck_mem = IDAADJ_mem->ck_mem; + while (ck_mem != NULL) { + + ckpnt[i].my_addr = (void *) ck_mem; + ckpnt[i].next_addr = (void *) ck_mem->ck_next; + ckpnt[i].t0 = ck_mem->ck_t0; + ckpnt[i].t1 = ck_mem->ck_t1; + ckpnt[i].nstep = ck_mem->ck_nst; + ckpnt[i].order = ck_mem->ck_kk; + ckpnt[i].step = ck_mem->ck_hh; + + ck_mem = ck_mem->ck_next; + i++; + } + + return(IDA_SUCCESS); +} + +/* IDAGetConsistentICB + * + * Returns the consistent initial conditions computed by IDACalcICB or + * IDACalcICBS + * + * It must be preceded by a successful call to IDACalcICB or IDACalcICBS + * for 'which' backward problem. + */ + +int IDAGetConsistentICB(void *ida_mem, int which, N_Vector yyB0_mod, N_Vector ypB0_mod) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + IDABMem IDAB_mem; + void *ida_memB; + int flag; + + /* Is ida_mem valid? */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDAGetConsistentICB", MSGAM_NULL_IDAMEM); + return IDA_MEM_NULL; + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDAGetConsistentICB", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDAGetConsistentICB", 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) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + ida_memB = (void *) IDAB_mem->IDA_mem; + + flag = IDAGetConsistentIC(ida_memB, yyB0_mod, ypB0_mod); + + return(flag); +} + + +/* + * ----------------------------------------------------------------- + * Undocumented development user-callable functions + * ----------------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------- + * IDAGetAdjDataPointHermite + * ----------------------------------------------------------------- + * Returns the 2 vectors stored for cubic Hermite interpolation at + * the data point 'which'. The user must allocate space for yy and + * yd. + * + * Returns IDA_MEM_NULL if ida_mem is NULL, IDA_ILL_INPUT if the + * interpolation type previously specified is not IDA_HERMITE or + * IDA_SUCCESS otherwise. + * + */ +int IDAGetAdjDataPointHermite(void *ida_mem, int which, + realtype *t, N_Vector yy, N_Vector yd) + +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + DtpntMem *dt_mem; + HermiteDataMem content; + + /* Is ida_mem valid? */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDAGetAdjDataPointHermite", MSGAM_NULL_IDAMEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDAGetAdjDataPointHermite", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + dt_mem = IDAADJ_mem->dt_mem; + + if (IDAADJ_mem->ia_interpType != IDA_HERMITE) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDAGetAdjDataPointHermite", MSGAM_WRONG_INTERP); + return(IDA_ILL_INPUT); + } + + *t = dt_mem[which]->t; + content = (HermiteDataMem) dt_mem[which]->content; + + if (yy != NULL) N_VScale(ONE, content->y, yy); + if (yd != NULL) N_VScale(ONE, content->yd, yd); + + return(IDA_SUCCESS); +} + +/* + * IDAGetAdjDataPointPolynomial + * + * Returns the vector stored for polynomial interpolation at the + * data point 'which'. The user must allocate space for y. + * + * Returns IDA_MEM_NULL if ida_mem is NULL, IDA_ILL_INPUT if the + * interpolation type previously specified is not IDA_POLYNOMIAL or + * IDA_SUCCESS otherwise. + */ + + +int IDAGetAdjDataPointPolynomial(void *ida_mem, int which, + realtype *t, int *order, N_Vector y) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + DtpntMem *dt_mem; + PolynomialDataMem content; + /* Is ida_mem valid? */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDAGetAdjDataPointPolynomial", MSGAM_NULL_IDAMEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDAGetAdjDataPointPolynomial", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + dt_mem = IDAADJ_mem->dt_mem; + + if (IDAADJ_mem->ia_interpType != IDA_POLYNOMIAL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAA", "IDAGetAdjDataPointPolynomial", MSGAM_WRONG_INTERP); + return(IDA_ILL_INPUT); + } + + *t = dt_mem[which]->t; + content = (PolynomialDataMem) dt_mem[which]->content; + + if (y != NULL) N_VScale(ONE, content->y, y); + + *order = content->order; + + return(IDA_SUCCESS); +} + +/* + * IDAGetAdjCurrentCheckPoint + * + * Returns the address of the 'active' check point. + */ + +SUNDIALS_EXPORT int IDAGetAdjCurrentCheckPoint(void *ida_mem, void **addr) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAA", "IDAGetAdjCurrentCheckPoint", MSGAM_NULL_IDAMEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_ADJ, "IDAA", "IDAGetAdjCurrentCheckPoint", MSGAM_NO_ADJ); + return(IDA_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + *addr = (void *) IDAADJ_mem->ia_ckpntData; + + return(IDA_SUCCESS); +} + + + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas.c new file mode 100644 index 0000000..7770b40 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas.c @@ -0,0 +1,7416 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): 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 main IDAS solver. + * It is independent of the linear solver in use. + * ----------------------------------------------------------------- + * + * EXPORTED FUNCTIONS + * ------------------ + * Creation, allocation and re-initialization functions + * IDACreate + * IDAInit + * IDAReInit + * IDAQuadInit + * IDAQuadReInit + * IDAQuadSStolerances + * IDAQuadSVtolerances + * IDASensInit + * IDASensReInit + * IDASensToggleOff + * IDASensSStolerances + * IDASensSVtolerances + * IDASensEEtolerances + * IDAQuadSensInit + * IDAQuadSensReInit + * IDARootInit + * + * Main solver function + * IDASolve + * + * Interpolated output and extraction functions + * IDAGetDky + * IDAGetQuad + * IDAGetQuadDky + * IDAGetSens + * IDAGetSens1 + * IDAGetSensDky + * IDAGetSensDky1 + * + * Deallocation functions + * IDAFree + * IDAQuadFree + * IDASensFree + * IDAQuadSensFree + * + * PRIVATE FUNCTIONS + * ----------------- + * IDACheckNvector + * Memory allocation/deallocation + * IDAAllocVectors + * IDAFreeVectors + * IDAQuadAllocVectors + * IDAQuadFreeVectors + * IDASensAllocVectors + * IDASensFreeVectors + * IDAQuadSensAllocVectors + * IDAQuadSensFreeVectors + * Initial setup + * IDAInitialSetup + * IDAEwtSet + * IDAEwtSetSS + * IDAEwtSetSV + * IDAQuadEwtSet + * IDAQuadEwtSetSS + * IDAQuadEwtSetSV + * IDASensEwtSet + * IDASensEwtSetEE + * IDASensEwtSetSS + * IDASensEwtSetSV + * IDAQuadSensEwtSet + * IDAQuadSensEwtSetEE + * IDAQuadSensEwtSetSS + * IDAQuadSensEwtSetSV + * Stopping tests + * IDAStopTest1 + * IDAStopTest2 + * Error handler + * IDAHandleFailure + * Main IDAStep function + * IDAStep + * IDASetCoeffs + * Nonlinear solver functions + * IDANls + * IDAPredict + * IDAQuadNls + * IDAQuadSensNls + * IDAQuadPredict + * IDAQuadSensPredict + * IDASensNls + * IDASensPredict + * Error test + * IDATestError + * IDAQuadTestError + * IDASensTestError + * IDAQuadSensTestError + * IDARestore + * Handler for convergence and/or error test failures + * IDAHandleNFlag + * IDAReset + * Function called after a successful step + * IDACompleteStep + * Get solution + * IDAGetSolution + * Norm functions + * IDAWrmsNorm + * IDASensWrmsNorm + * IDAQuadSensWrmsNorm + * IDAQuadWrmsNormUpdate + * IDASensWrmsNormUpdate + * IDAQuadSensWrmsNormUpdate + * Functions for rootfinding + * IDARcheck1 + * IDARcheck2 + * IDARcheck3 + * IDARootfind + * IDA Error message handling functions + * IDAProcessError + * IDAErrHandler + * Internal DQ approximations for sensitivity RHS + * IDASensResDQ + * IDASensRes1DQ + * IDAQuadSensResDQ + * IDAQuadSensRes1DQ + * ----------------------------------------------------------------- + */ + +/* + * ================================================================= + * IMPORTED HEADER FILES + * ================================================================= + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> + +#include "idas_impl.h" +#include <sundials/sundials_math.h> +#include <sundials/sundials_types.h> +#include <sundials/sundials_nvector_senswrapper.h> +#include <sunnonlinsol/sunnonlinsol_newton.h> + +/* + * ================================================================= + * IDAS PRIVATE CONSTANTS + * ================================================================= + */ + +#define ZERO RCONST(0.0) /* real 0.0 */ +#define HALF RCONST(0.5) /* real 0.5 */ +#define QUARTER RCONST(0.25) /* real 0.25 */ +#define TWOTHIRDS RCONST(0.667) /* real 2/3 */ +#define ONE RCONST(1.0) /* real 1.0 */ +#define ONEPT5 RCONST(1.5) /* real 1.5 */ +#define TWO RCONST(2.0) /* real 2.0 */ +#define FOUR RCONST(4.0) /* real 4.0 */ +#define FIVE RCONST(5.0) /* real 5.0 */ +#define TEN RCONST(10.0) /* real 10.0 */ +#define TWELVE RCONST(12.0) /* real 12.0 */ +#define TWENTY RCONST(20.0) /* real 20.0 */ +#define HUNDRED RCONST(100.0) /* real 100.0 */ +#define PT9 RCONST(0.9) /* real 0.9 */ +#define PT99 RCONST(0.99) /* real 0.99 */ +#define PT1 RCONST(0.1) /* real 0.1 */ +#define PT01 RCONST(0.01) /* real 0.01 */ +#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 + * ------------------------------------------------------------ + */ + +/* IDAStep control constants */ + +#define PREDICT_AGAIN 20 + +/* Return values for lower level routines used by IDASolve */ + +#define CONTINUE_STEPS +99 + +/* IDACompleteStep constants */ + +#define UNSET -1 +#define LOWER 1 +#define RAISE 2 +#define MAINTAIN 3 + +/* IDATestError constants */ + +#define ERROR_TEST_FAIL +7 + +/* + * Control constants for lower-level rootfinding functions + * ------------------------------------------------------- + */ + +#define RTFOUND 1 +#define CLOSERT 3 + +/* + * Control constants for sensitivity DQ + * ------------------------------------ + */ + +#define CENTERED1 +1 +#define CENTERED2 +2 +#define FORWARD1 +3 +#define FORWARD2 +4 + +/* + * Algorithmic constants + * --------------------- + */ + +#define MXNCF 10 /* max number of convergence failures allowed */ +#define MXNEF 10 /* max number of error test failures allowed */ +#define MAXNH 5 /* max. number of h tries in IC calc. */ +#define MAXNJ 4 /* max. number of J tries in IC calc. */ +#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 */ + + +/* IDANewtonIter constants */ + +#define MAXIT 4 +#define XRATE RCONST(0.25) /* constant for updating Jacobian/preconditioner */ + +/* + * ================================================================= + * PRIVATE FUNCTION PROTOTYPES + * ================================================================= + */ + +static booleantype IDACheckNvector(N_Vector tmpl); + +/* Memory allocation/deallocation */ + +static booleantype IDAAllocVectors(IDAMem IDA_mem, N_Vector tmpl); +static void IDAFreeVectors(IDAMem IDA_mem); + +static booleantype IDAQuadAllocVectors(IDAMem IDA_mem, N_Vector tmpl); +static void IDAQuadFreeVectors(IDAMem IDA_mem); + +static booleantype IDASensAllocVectors(IDAMem IDA_mem, N_Vector tmpl); +static void IDASensFreeVectors(IDAMem IDA_mem); + +static booleantype IDAQuadSensAllocVectors(IDAMem ida_mem, N_Vector tmpl); +static void IDAQuadSensFreeVectors(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); + +static int IDAQuadEwtSet(IDAMem IDA_mem, N_Vector qcur, N_Vector weightQ); +static int IDAQuadEwtSetSS(IDAMem IDA_mem, N_Vector qcur, N_Vector weightQ); +static int IDAQuadEwtSetSV(IDAMem IDA_mem, N_Vector qcur, N_Vector weightQ); + +/* Used in IC for sensitivities. */ +int IDASensEwtSet(IDAMem IDA_mem, N_Vector *yScur, N_Vector *weightS); +static int IDASensEwtSetEE(IDAMem IDA_mem, N_Vector *yScur, N_Vector *weightS); +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 IDAQuadSensEwtSet(IDAMem IDA_mem, N_Vector *yQScur, N_Vector *weightQS); +static int IDAQuadSensEwtSetEE(IDAMem IDA_mem, N_Vector *yScur, N_Vector *weightS); +static int IDAQuadSensEwtSetSS(IDAMem IDA_mem, N_Vector *yScur, N_Vector *weightS); +static int IDAQuadSensEwtSetSV(IDAMem IDA_mem, N_Vector *yScur, N_Vector *weightS); + +/* Main IDAStep function */ + +static int IDAStep(IDAMem IDA_mem); + +/* Function called at beginning of step */ + +static void IDASetCoeffs(IDAMem IDA_mem, realtype *ck); + +/* Nonlinear solver functions */ + +static void IDAPredict(IDAMem IDA_mem); +static void IDAQuadPredict(IDAMem IDA_mem); +static void IDASensPredict(IDAMem IDA_mem, N_Vector *yySens, N_Vector *ypSens); +static void IDAQuadSensPredict(IDAMem IDA_mem, N_Vector *yQS, N_Vector *ypQS); + +static int IDANls(IDAMem IDA_mem); +static int IDASensNls(IDAMem IDA_mem); + +static int IDAQuadNls(IDAMem IDA_mem); +static int IDAQuadSensNls(IDAMem IDA_mem); + +/* Error tests */ + +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, + realtype *err_k, realtype *err_km1, realtype *err_km2); +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, + realtype *err_k, realtype *err_km1, realtype *err_km2); + +/* Handling of convergence and/or error test failures */ + +static void IDARestore(IDAMem IDA_mem, realtype saved_t); +static int IDAHandleNFlag(IDAMem IDA_mem, int nflag, realtype err_k, realtype err_km1, + long int *ncfnPtr, int *ncfPtr, long int *netfPtr, int *nefPtr); +static void IDAReset(IDAMem IDA_mem); + +/* Function called after a successful step */ + +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, + N_Vector yret, N_Vector ypret, int itask); +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); + +/* Norm functions */ + +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, + N_Vector *xQS, N_Vector *wQS); + +/* Functions for rootfinding */ + +static int IDARcheck1(IDAMem IDA_mem); +static int IDARcheck2(IDAMem IDA_mem); +static int IDARcheck3(IDAMem IDA_mem); +static int IDARootfind(IDAMem IDA_mem); + +/* Sensitivity residual DQ function */ + +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, + N_Vector yy, N_Vector yp, + N_Vector *yyS, N_Vector *ypS, + N_Vector rrQ, N_Vector *resvalQS, + 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, + N_Vector yyS, N_Vector ypS, + 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 + * 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. + */ + +void *IDACreate(void) +{ + IDAMem IDA_mem; + + IDA_mem = NULL; + IDA_mem = (IDAMem) malloc(sizeof(struct IDAMemRec)); + if (IDA_mem == NULL) { + IDAProcessError(NULL, 0, "IDAS", "IDACreate", MSG_MEM_FAIL); + return (NULL); + } + + /* Zero out ida_mem */ + memset(IDA_mem, 0, sizeof(struct IDAMemRec)); + + /* Set unit roundoff in IDA_mem */ + IDA_mem->ida_uround = UNIT_ROUNDOFF; + + /* Set default values for integrator optional inputs */ + IDA_mem->ida_res = NULL; + IDA_mem->ida_user_data = NULL; + IDA_mem->ida_itol = IDA_NN; + IDA_mem->ida_user_efun = SUNFALSE; + IDA_mem->ida_efun = NULL; + IDA_mem->ida_edata = NULL; + IDA_mem->ida_ehfun = IDAErrHandler; + IDA_mem->ida_eh_data = IDA_mem; + IDA_mem->ida_errfp = stderr; + IDA_mem->ida_maxord = MAXORD_DEFAULT; + IDA_mem->ida_mxstep = MXSTEP_DEFAULT; + IDA_mem->ida_hmax_inv = HMAX_INV_DEFAULT; + IDA_mem->ida_hin = ZERO; + 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; + IDA_mem->ida_constraintsSet = SUNFALSE; + IDA_mem->ida_tstopset = SUNFALSE; + + /* set the saved value maxord_alloc */ + IDA_mem->ida_maxord_alloc = MAXORD_DEFAULT; + + /* Set default values for IC optional inputs */ + IDA_mem->ida_epiccon = PT01 * EPCON; + IDA_mem->ida_maxnh = MAXNH; + IDA_mem->ida_maxnj = MAXNJ; + IDA_mem->ida_maxnit = MAXNI; + IDA_mem->ida_maxbacks = MAXBACKS; + IDA_mem->ida_lsoff = SUNFALSE; + IDA_mem->ida_steptol = SUNRpowerR(IDA_mem->ida_uround, TWOTHIRDS); + + /* Set default values for quad. optional inputs */ + IDA_mem->ida_quadr = SUNFALSE; + IDA_mem->ida_rhsQ = NULL; + IDA_mem->ida_errconQ = SUNFALSE; + IDA_mem->ida_itolQ = IDA_NN; + + /* Set default values for sensi. optional inputs */ + IDA_mem->ida_sensi = SUNFALSE; + IDA_mem->ida_user_dataS = (void *)IDA_mem; + IDA_mem->ida_resS = IDASensResDQ; + IDA_mem->ida_resSDQ = SUNTRUE; + IDA_mem->ida_DQtype = IDA_CENTERED; + IDA_mem->ida_DQrhomax = ZERO; + IDA_mem->ida_p = NULL; + 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_ism = -1; /* initialize to invalid option */ + + /* Defaults for sensi. quadr. optional inputs. */ + IDA_mem->ida_quadr_sensi = SUNFALSE; + IDA_mem->ida_user_dataQS = (void *)IDA_mem; + IDA_mem->ida_rhsQS = IDAQuadSensRhsInternalDQ; + IDA_mem->ida_rhsQSDQ = SUNTRUE; + IDA_mem->ida_errconQS = SUNFALSE; + IDA_mem->ida_itolQS = IDA_EE; + + /* Set defaults for ASA. */ + IDA_mem->ida_adj = SUNFALSE; + IDA_mem->ida_adj_mem = NULL; + + /* Initialize lrw and liw */ + IDA_mem->ida_lrw = 25 + 5*MXORDP1; + 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; + IDA_mem->ida_MallocDone = SUNFALSE; + + IDA_mem->ida_VatolQMallocDone = SUNFALSE; + IDA_mem->ida_quadMallocDone = SUNFALSE; + + IDA_mem->ida_VatolSMallocDone = SUNFALSE; + IDA_mem->ida_SatolSMallocDone = SUNFALSE; + IDA_mem->ida_sensMallocDone = SUNFALSE; + + IDA_mem->ida_VatolQSMallocDone = SUNFALSE; + IDA_mem->ida_SatolQSMallocDone = SUNFALSE; + IDA_mem->ida_quadSensMallocDone = SUNFALSE; + + IDA_mem->ida_adjMallocDone = SUNFALSE; + + /* Initialize nonlinear solver variables */ + IDA_mem->NLS = NULL; + IDA_mem->ownNLS = SUNFALSE; + + IDA_mem->NLSsim = NULL; + IDA_mem->ownNLSsim = SUNFALSE; + IDA_mem->ycor0Sim = 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->ycorStg = NULL; + IDA_mem->ewtStg = NULL; + IDA_mem->stgMallocDone = SUNFALSE; + + /* Return pointer to IDA memory block */ + return((void *)IDA_mem); +} + +/*-----------------------------------------------------------------*/ + +/* + * IDAInit + * + * 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 handler function. + */ + +int IDAInit(void *ida_mem, IDAResFn res, + realtype t0, N_Vector yy0, N_Vector yp0) +{ + int retval; + IDAMem IDA_mem; + booleantype nvectorOK, allocOK; + sunindextype lrw1, liw1; + SUNNonlinearSolver NLS; + + /* Check ida_mem */ + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAInit", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Check for legal input parameters */ + + if (yy0 == NULL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInit", MSG_Y0_NULL); + return(IDA_ILL_INPUT); + } + + if (yp0 == NULL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInit", MSG_YP0_NULL); + return(IDA_ILL_INPUT); + } + + if (res == NULL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInit", MSG_RES_NULL); + return(IDA_ILL_INPUT); + } + + /* Test if all required vector operations are implemented */ + + nvectorOK = IDACheckNvector(yy0); + if (!nvectorOK) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInit", MSG_BAD_NVECTOR); + return(IDA_ILL_INPUT); + } + + /* Set space requirements for one N_Vector */ + + if (yy0->ops->nvspace != NULL) { + N_VSpace(yy0, &lrw1, &liw1); + } else { + lrw1 = 0; + liw1 = 0; + } + IDA_mem->ida_lrw1 = lrw1; + IDA_mem->ida_liw1 = liw1; + + /* Allocate the vectors (using yy0 as a template) */ + + allocOK = IDAAllocVectors(IDA_mem, yy0); + if (!allocOK) { + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", "IDAInit", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + /* Allocate temporary work arrays for fused vector ops */ + IDA_mem->ida_cvals = NULL; + IDA_mem->ida_cvals = (realtype *) malloc(MXORDP1*sizeof(realtype)); + + IDA_mem->ida_Xvecs = NULL; + IDA_mem->ida_Xvecs = (N_Vector *) malloc(MXORDP1*sizeof(N_Vector)); + + IDA_mem->ida_Zvecs = NULL; + IDA_mem->ida_Zvecs = (N_Vector *) malloc(MXORDP1*sizeof(N_Vector)); + + if ((IDA_mem->ida_cvals == NULL) || + (IDA_mem->ida_Xvecs == NULL) || + (IDA_mem->ida_Zvecs == NULL)) { + IDAFreeVectors(IDA_mem); + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", "IDAInit", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + /* create a Newton nonlinear solver object by default */ + NLS = SUNNonlinSol_Newton(yy0); + + /* check that nonlinear solver is non-NULL */ + if (NLS == NULL) { + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", "IDAInit", MSG_MEM_FAIL); + IDAFreeVectors(IDA_mem); + return(IDA_MEM_FAIL); + } + + /* attach the nonlinear solver to the IDA memory */ + retval = IDASetNonlinearSolver(IDA_mem, NLS); + + /* check that the nonlinear solver was successfully attached */ + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, retval, "IDAS", "IDAInit", + "Setting the nonlinear solver failed"); + IDAFreeVectors(IDA_mem); + SUNNonlinSolFree(NLS); + return(IDA_MEM_FAIL); + } + + /* set ownership flag */ + IDA_mem->ownNLS = SUNTRUE; + + /* All error checking is complete at this point */ + + /* Copy the input parameters into IDA memory block */ + + IDA_mem->ida_res = res; + IDA_mem->ida_tn = t0; + + /* Set the linear solver addresses to NULL */ + + IDA_mem->ida_linit = NULL; + IDA_mem->ida_lsetup = NULL; + IDA_mem->ida_lsolve = NULL; + IDA_mem->ida_lperf = NULL; + IDA_mem->ida_lfree = NULL; + IDA_mem->ida_lmem = NULL; + + /* Set forceSetup to SUNFALSE */ + + IDA_mem->ida_forceSetup = SUNFALSE; + + /* Initialize the phi array */ + + 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; + + IDA_mem->ida_nge = 0; + + IDA_mem->ida_irfnd = 0; + + /* Initialize counters specific to IC calculation. */ + IDA_mem->ida_nbacktr = 0; + + /* Initialize root-finding variables */ + + IDA_mem->ida_glo = NULL; + IDA_mem->ida_ghi = NULL; + IDA_mem->ida_grout = NULL; + IDA_mem->ida_iroots = NULL; + IDA_mem->ida_rootdir = NULL; + IDA_mem->ida_gfun = NULL; + IDA_mem->ida_nrtfn = 0; + IDA_mem->ida_gactive = NULL; + IDA_mem->ida_mxgnull = 1; + + /* Initial setup not done yet */ + + IDA_mem->ida_SetupDone = SUNFALSE; + + /* Problem memory has been successfully allocated */ + + IDA_mem->ida_MallocDone = SUNTRUE; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +/* + * IDAReInit + * + * IDAReInit re-initializes IDA's memory for a problem, assuming + * it has already beeen allocated in a prior IDAInit call. + * All problem specification inputs are checked for errors. + * The problem size Neq is assumed to be unchanged since the call + * to IDAInit, and the maximum order maxord must not be larger. + * If any error occurs during reinitialization, it is reported to + * the error handler function. + * The return value is IDA_SUCCESS = 0 if no errors occurred, or + * a negative value otherwise. + */ + +int IDAReInit(void *ida_mem, + realtype t0, N_Vector yy0, N_Vector yp0) +{ + 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); + } + 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) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAReInit", MSG_Y0_NULL); + return(IDA_ILL_INPUT); + } + + if (yp0 == NULL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAReInit", MSG_YP0_NULL); + return(IDA_ILL_INPUT); + } + + /* Copy the input parameters into IDA memory block */ + + IDA_mem->ida_tn = t0; + + /* Set forceSetup to SUNFALSE */ + + IDA_mem->ida_forceSetup = SUNFALSE; + + /* Initialize the phi array */ + + 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; + + IDA_mem->ida_nge = 0; + + IDA_mem->ida_irfnd = 0; + + /* Initial setup not done yet */ + + IDA_mem->ida_SetupDone = SUNFALSE; + + /* Problem has been successfully re-initialized */ + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +/* + * IDASStolerances + * IDASVtolerances + * IDAWFtolerances + * + * These functions specify the integration tolerances. One of them + * MUST be called before the first call to IDA. + * + * 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). + * IDAWFtolerances specifies a user-provides function (of type IDAEwtFn) + * which will be called to set the error weight vector. + */ + +int IDASStolerances(void *ida_mem, realtype reltol, realtype abstol) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASStolerances", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_MallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_MALLOC, "IDAS", "IDASStolerances", MSG_NO_MALLOC); + return(IDA_NO_MALLOC); + } + + /* Check inputs */ + if (reltol < ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASStolerances", MSG_BAD_RTOL); + return(IDA_ILL_INPUT); + } + + if (abstol < ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASStolerances", MSG_BAD_ATOL); + return(IDA_ILL_INPUT); + } + + /* Copy tolerances into memory */ + IDA_mem->ida_rtol = reltol; + IDA_mem->ida_Satol = abstol; + + 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 */ + + return(IDA_SUCCESS); +} + + +int IDASVtolerances(void *ida_mem, realtype reltol, N_Vector abstol) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASVtolerances", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_MallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_MALLOC, "IDAS", "IDASVtolerances", MSG_NO_MALLOC); + return(IDA_NO_MALLOC); + } + + /* Check inputs */ + + if (reltol < ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASVtolerances", MSG_BAD_RTOL); + return(IDA_ILL_INPUT); + } + + if (N_VMin(abstol) < 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; + IDA_mem->ida_liw += IDA_mem->ida_liw1; + IDA_mem->ida_VatolMallocDone = SUNTRUE; + } + + IDA_mem->ida_rtol = reltol; + N_VScale(ONE, abstol, IDA_mem->ida_Vatol); + + 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 */ + + return(IDA_SUCCESS); +} + + +int IDAWFtolerances(void *ida_mem, IDAEwtFn efun) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAWFtolerances", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_MallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_MALLOC, "IDAS", "IDAWFtolerances", MSG_NO_MALLOC); + return(IDA_NO_MALLOC); + } + + IDA_mem->ida_itol = IDA_WF; + + IDA_mem->ida_user_efun = SUNTRUE; + IDA_mem->ida_efun = efun; + IDA_mem->ida_edata = NULL; /* will be set to user_data in InitialSetup */ + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +/* + * 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. + * The return value is IDA_SUCCESS = 0 if no errors occurred, or + * a negative value otherwise. + */ + +int IDAQuadInit(void *ida_mem, IDAQuadRhsFn rhsQ, N_Vector yQ0) +{ + IDAMem IDA_mem; + booleantype allocOK; + sunindextype lrw1Q, liw1Q; + int retval; + + /* Check ida_mem */ + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAQuadInit", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Set space requirements for one N_Vector */ + N_VSpace(yQ0, &lrw1Q, &liw1Q); + IDA_mem->ida_lrw1Q = lrw1Q; + IDA_mem->ida_liw1Q = liw1Q; + + /* Allocate the vectors (using yQ0 as a template) */ + allocOK = IDAQuadAllocVectors(IDA_mem, yQ0); + if (!allocOK) { + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", "IDAQuadInit", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + /* Initialize phiQ in the history array */ + N_VScale(ONE, yQ0, IDA_mem->ida_phiQ[0]); + + retval = N_VConstVectorArray(IDA_mem->ida_maxord, ZERO, IDA_mem->ida_phiQ+1); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + /* Copy the input parameters into IDAS state */ + IDA_mem->ida_rhsQ = rhsQ; + + /* Initialize counters */ + IDA_mem->ida_nrQe = 0; + IDA_mem->ida_netfQ = 0; + + /* Quadrature integration turned ON */ + IDA_mem->ida_quadr = SUNTRUE; + IDA_mem->ida_quadMallocDone = SUNTRUE; + + /* Quadrature initialization was successfull */ + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +/* + * 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. + * 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 IDAQuadReInit(void *ida_mem, N_Vector yQ0) +{ + IDAMem IDA_mem; + int retval; + + /* Check ida_mem */ + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAQuadReInit", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Ckeck if quadrature was initialized */ + if (IDA_mem->ida_quadMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_QUAD, "IDAS", "IDAQuadReInit", MSG_NO_QUAD); + return(IDA_NO_QUAD); + } + + /* Initialize phiQ in the history array */ + N_VScale(ONE, yQ0, IDA_mem->ida_phiQ[0]); + + retval = N_VConstVectorArray(IDA_mem->ida_maxord, ZERO, IDA_mem->ida_phiQ+1); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + /* Initialize counters */ + IDA_mem->ida_nrQe = 0; + IDA_mem->ida_netfQ = 0; + + /* Quadrature integration turned ON */ + IDA_mem->ida_quadr = SUNTRUE; + + /* Quadrature re-initialization was successfull */ + return(IDA_SUCCESS); +} + + +/* + * IDAQuadSStolerances + * IDAQuadSVtolerances + * + * + * These functions specify the integration tolerances for quadrature + * variables. One of them MUST be called before the first call to + * IDA IF error control on the quadrature variables is enabled + * (see IDASetQuadErrCon). + * + * 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). + */ +int IDAQuadSStolerances(void *ida_mem, realtype reltolQ, realtype abstolQ) +{ + IDAMem IDA_mem; + + /*Check ida mem*/ + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAQuadSStolerances", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Ckeck if quadrature was initialized */ + if (IDA_mem->ida_quadMallocDone == SUNFALSE) { + 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); + return(IDA_ILL_INPUT); + } + + if (abstolQ < ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAQuadSStolerances", MSG_BAD_ATOLQ); + return(IDA_ILL_INPUT); + } + + /* Copy tolerances into memory */ + IDA_mem->ida_itolQ = IDA_SS; + + IDA_mem->ida_rtolQ = reltolQ; + IDA_mem->ida_SatolQ = abstolQ; + + + return (IDA_SUCCESS); +} + +int IDAQuadSVtolerances(void *ida_mem, realtype reltolQ, N_Vector abstolQ) +{ + IDAMem IDA_mem; + + /*Check ida mem*/ + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAQuadSVtolerances", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Ckeck if quadrature was initialized */ + if (IDA_mem->ida_quadMallocDone == SUNFALSE) { + 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)<ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAQuadSVtolerances", MSG_BAD_ATOLQ); + return(IDA_ILL_INPUT); + } + + /* Copy tolerances into memory */ + IDA_mem->ida_itolQ = IDA_SV; + IDA_mem->ida_rtolQ = reltolQ; + + /* clone the absolute tolerances vector (if necessary) */ + if (SUNFALSE == IDA_mem->ida_VatolQMallocDone) { + IDA_mem->ida_VatolQ = N_VClone(abstolQ); + IDA_mem->ida_lrw += IDA_mem->ida_lrw1Q; + IDA_mem->ida_liw += IDA_mem->ida_liw1Q; + IDA_mem->ida_VatolQMallocDone = SUNTRUE; + } + + N_VScale(ONE, abstolQ, IDA_mem->ida_VatolQ); + + return(IDA_SUCCESS); +} + +/* + * 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. + * 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, + 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); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Check if Ns is legal */ + if (Ns<=0) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASensInit", MSG_BAD_NS); + return(IDA_ILL_INPUT); + } + IDA_mem->ida_Ns = Ns; + + /* Check if ism is legal */ + if ((ism!=IDA_SIMULTANEOUS) && (ism!=IDA_STAGGERED)) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASensInit", MSG_BAD_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); + return(IDA_ILL_INPUT); + } + if (ypS0 == NULL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASensInit", MSG_NULL_YPS0); + return(IDA_ILL_INPUT); + } + + /* Store sensitivity RHS-related data */ + + if (fS != NULL) { + IDA_mem->ida_resS = fS; + IDA_mem->ida_user_dataS = IDA_mem->ida_user_data; + IDA_mem->ida_resSDQ = SUNFALSE; + } else { + IDA_mem->ida_resS = IDASensResDQ; + IDA_mem->ida_user_dataS = ida_mem; + IDA_mem->ida_resSDQ = SUNTRUE; + } + + /* Allocate the vectors (using yS0[0] as a template) */ + + allocOK = IDASensAllocVectors(IDA_mem, yS0[0]); + if (!allocOK) { + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", "IDASensInit", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + /* Allocate temporary work arrays for fused vector ops */ + if (Ns*MXORDP1 > MXORDP1) { + free(IDA_mem->ida_cvals); IDA_mem->ida_cvals = NULL; + free(IDA_mem->ida_Xvecs); IDA_mem->ida_Xvecs = NULL; + free(IDA_mem->ida_Zvecs); IDA_mem->ida_Zvecs = NULL; + + IDA_mem->ida_cvals = (realtype *) malloc((Ns*MXORDP1)*sizeof(realtype)); + IDA_mem->ida_Xvecs = (N_Vector *) malloc((Ns*MXORDP1)*sizeof(N_Vector)); + IDA_mem->ida_Zvecs = (N_Vector *) malloc((Ns*MXORDP1)*sizeof(N_Vector)); + + if ((IDA_mem->ida_cvals == NULL) || + (IDA_mem->ida_Xvecs == NULL) || + (IDA_mem->ida_Zvecs == NULL)) { + IDASensFreeVectors(IDA_mem); + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", "IDASensInit", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + } + + /*---------------------------------------------- + All error checking is complete at this point + -----------------------------------------------*/ + + /* Initialize the phiS array */ + for (is=0; is<Ns; is++) + IDA_mem->ida_cvals[is] = ONE; + + retval = N_VScaleVectorArray(Ns, IDA_mem->ida_cvals, yS0, IDA_mem->ida_phiS[0]); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + retval = N_VScaleVectorArray(Ns, IDA_mem->ida_cvals, ypS0, IDA_mem->ida_phiS[1]); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + /* Initialize all sensitivity related counters */ + IDA_mem->ida_nrSe = 0; + IDA_mem->ida_nreS = 0; + IDA_mem->ida_ncfnS = 0; + IDA_mem->ida_netfS = 0; + IDA_mem->ida_nniS = 0; + IDA_mem->ida_nsetupsS = 0; + + /* Set default values for plist and pbar */ + for (is=0; is<Ns; is++) { + IDA_mem->ida_plist[is] = is; + IDA_mem->ida_pbar[is] = ONE; + } + + /* Sensitivities will be computed */ + IDA_mem->ida_sensi = SUNTRUE; + IDA_mem->ida_sensMallocDone = SUNTRUE; + + /* create a Newton nonlinear solver object by default */ + if (ism == IDA_SIMULTANEOUS) + NLS = SUNNonlinSol_NewtonSens(Ns+1, IDA_mem->ida_delta); + else + NLS = SUNNonlinSol_NewtonSens(Ns, IDA_mem->ida_delta); + + /* check that the nonlinear solver is non-NULL */ + if (NLS == NULL) { + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", "IDASensInit", MSG_MEM_FAIL); + IDASensFreeVectors(IDA_mem); + return(IDA_MEM_FAIL); + } + + /* attach the nonlinear solver to the IDA memory */ + if (ism == IDA_SIMULTANEOUS) + retval = IDASetNonlinearSolverSensSim(IDA_mem, NLS); + else + retval = IDASetNonlinearSolverSensStg(IDA_mem, NLS); + + /* check that the nonlinear solver was successfully attached */ + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, retval, "IDAS", "IDASensInit", + "Setting the nonlinear solver failed"); + IDASensFreeVectors(IDA_mem); + SUNNonlinSolFree(NLS); + return(IDA_MEM_FAIL); + } + + /* set ownership flag */ + if (ism == IDA_SIMULTANEOUS) + IDA_mem->ownNLSsim = SUNTRUE; + else + IDA_mem->ownNLSstg = SUNTRUE; + + /* Sensitivity initialization was successfull */ + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +/* + * IDASensReInit + * + * IDASensReInit re-initializes IDAS's sensitivity related memory + * for a problem, assuming it has already been allocated in prior + * calls to IDAInit and IDASensInit. + * All problem specification inputs are checked for errors. + * The number of sensitivities Ns is assumed to be unchanged since + * the previous call to IDASensInit. + * 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 IDASensReInit(void *ida_mem, int ism, N_Vector *yS0, N_Vector *ypS0) +{ + IDAMem IDA_mem; + int is, retval; + SUNNonlinearSolver NLS; + + /* Check ida_mem */ + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", + "IDASensReInit", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Was sensitivity initialized? */ + if (IDA_mem->ida_sensMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", + "IDASensReInit", MSG_NO_SENSI); + return(IDA_NO_SENS); + } + + /* Check if ism is legal */ + if ((ism!=IDA_SIMULTANEOUS) && (ism!=IDA_STAGGERED)) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", + "IDASensReInit", MSG_BAD_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", + "IDASensReInit", MSG_NULL_YYS0); + return(IDA_ILL_INPUT); + } + if (ypS0 == NULL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", + "IDASensReInit", MSG_NULL_YPS0); + return(IDA_ILL_INPUT); + } + + /*----------------------------------------------- + All error checking is complete at this point + -----------------------------------------------*/ + + /* Initialize the phiS array */ + for (is=0; is<IDA_mem->ida_Ns; is++) + IDA_mem->ida_cvals[is] = ONE; + + retval = N_VScaleVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_cvals, + yS0, IDA_mem->ida_phiS[0]); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + retval = N_VScaleVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_cvals, + ypS0, IDA_mem->ida_phiS[1]); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + /* Initialize all sensitivity related counters */ + IDA_mem->ida_nrSe = 0; + IDA_mem->ida_nreS = 0; + IDA_mem->ida_ncfnS = 0; + IDA_mem->ida_netfS = 0; + IDA_mem->ida_nniS = 0; + IDA_mem->ida_nsetupsS = 0; + + /* Set default values for plist and pbar */ + for (is=0; is<IDA_mem->ida_Ns; is++) { + IDA_mem->ida_plist[is] = is; + IDA_mem->ida_pbar[is] = ONE; + } + + /* Sensitivities will be computed */ + IDA_mem->ida_sensi = SUNTRUE; + + /* Check if the NLS exists, create the default NLS if needed */ + if ((ism == IDA_SIMULTANEOUS && IDA_mem->NLSsim == NULL) || + (ism == IDA_STAGGERED && IDA_mem->NLSstg == NULL)) { + + /* create a Newton nonlinear solver object by default */ + if (ism == IDA_SIMULTANEOUS) + NLS = SUNNonlinSol_NewtonSens(IDA_mem->ida_Ns+1, IDA_mem->ida_delta); + else + NLS = SUNNonlinSol_NewtonSens(IDA_mem->ida_Ns, IDA_mem->ida_delta); + + /* check that the nonlinear solver is non-NULL */ + if (NLS == NULL) { + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", + "IDASensReInit", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + /* attach the nonlinear solver to the IDA memory */ + if (ism == IDA_SIMULTANEOUS) + retval = IDASetNonlinearSolverSensSim(IDA_mem, NLS); + else + retval = IDASetNonlinearSolverSensStg(IDA_mem, NLS); + + /* check that the nonlinear solver was successfully attached */ + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, retval, "IDAS", "IDASensReInit", + "Setting the nonlinear solver failed"); + SUNNonlinSolFree(NLS); + return(IDA_MEM_FAIL); + } + + /* set ownership flag */ + if (ism == IDA_SIMULTANEOUS) + IDA_mem->ownNLSsim = SUNTRUE; + else + IDA_mem->ownNLSstg = SUNTRUE; + + /* initialize the NLS object, this assumes that the linear solver has + already been initialized in IDAInit */ + if (ism == IDA_SIMULTANEOUS) + retval = idaNlsInitSensSim(IDA_mem); + else + retval = idaNlsInitSensStg(IDA_mem); + + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_NLS_INIT_FAIL, "IDAS", + "IDASensReInit", MSG_NLS_INIT_FAIL); + return(IDA_NLS_INIT_FAIL); + } + } + + /* Sensitivity re-initialization was successfull */ + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +/* + * IDASensSStolerances + * IDASensSVtolerances + * IDASensEEtolerances + * + * These functions specify the integration tolerances for sensitivity + * variables. One of them MUST be called before the first call to IDASolve. + * + * IDASensSStolerances specifies scalar relative and absolute tolerances. + * IDASensSVtolerances specifies scalar relative tolerance and a vector + * absolute tolerance for each sensitivity vector (a potentially different + * absolute tolerance for each vector component). + * IDASensEEtolerances specifies that tolerances for sensitivity variables + * should be estimated from those provided for the state variables. + */ + + +int IDASensSStolerances(void *ida_mem, realtype reltolS, realtype *abstolS) +{ + IDAMem IDA_mem; + int is; + + /* Check ida_mem pointer */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASensSStolerances", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Was sensitivity initialized? */ + + 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); + } + + if (abstolS == NULL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASensSStolerances", MSG_NULL_ATOLS); + return(IDA_ILL_INPUT); + } + + for (is=0; is<IDA_mem->ida_Ns; is++) + if (abstolS[is] < ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASensSStolerances", MSG_BAD_ATOLS); + return(IDA_ILL_INPUT); + } + + /* Copy tolerances into memory */ + + IDA_mem->ida_itolS = IDA_SS; + + IDA_mem->ida_rtolS = reltolS; + + 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_lrw += IDA_mem->ida_Ns; + IDA_mem->ida_SatolSMallocDone = SUNTRUE; + } + + for (is=0; is<IDA_mem->ida_Ns; is++) + IDA_mem->ida_SatolS[is] = abstolS[is]; + + return(IDA_SUCCESS); +} + + +int IDASensSVtolerances(void *ida_mem, realtype reltolS, N_Vector *abstolS) +{ + IDAMem IDA_mem; + int is, retval; + + /* Check ida_mem pointer */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASensSVtolerances", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Was sensitivity initialized? */ + + 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); + } + + if (abstolS == NULL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASensSVtolerances", MSG_NULL_ATOLS); + return(IDA_ILL_INPUT); + } + + for (is=0; is<IDA_mem->ida_Ns; is++) { + if (N_VMin(abstolS[is])<ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASensSStolerances", MSG_BAD_ATOLS); + return(IDA_ILL_INPUT); + } + } + + IDA_mem->ida_itolS = IDA_SV; + IDA_mem->ida_rtolS = reltolS ; + + if ( SUNFALSE == IDA_mem->ida_VatolSMallocDone ) { + IDA_mem->ida_VatolS = N_VCloneVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_tempv1); + 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; is<IDA_mem->ida_Ns; is++) + IDA_mem->ida_cvals[is] = ONE; + + 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); +} + +int IDASensEEtolerances(void *ida_mem) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASensEEtolerances", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Was sensitivity initialized? */ + + 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; + + return(IDA_SUCCESS); +} + + +int IDAQuadSensInit(void *ida_mem, IDAQuadSensRhsFn rhsQS, N_Vector *yQS0) +{ + IDAMem IDA_mem; + booleantype allocOK; + int is, retval; + + if (ida_mem==NULL) { + 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); + return(IDA_NO_SENS); + } + + /* Verifiy yQS0 parameter. */ + if (yQS0==NULL) { + 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); + return(IDA_MEM_FAIL); + } + + /* Error checking complete. */ + if (rhsQS == NULL) { + IDA_mem->ida_rhsQSDQ = SUNTRUE; + IDA_mem->ida_rhsQS = IDAQuadSensRhsInternalDQ; + + IDA_mem->ida_user_dataQS = ida_mem; + } else { + IDA_mem->ida_rhsQSDQ = SUNFALSE; + IDA_mem->ida_rhsQS = rhsQS; + + IDA_mem->ida_user_dataQS = IDA_mem->ida_user_data; + } + + /* Initialize phiQS[0] in the history array */ + for (is=0; is<IDA_mem->ida_Ns; is++) + IDA_mem->ida_cvals[is] = ONE; + + retval = N_VScaleVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_cvals, + yQS0, IDA_mem->ida_phiQS[0]); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + /* Initialize all sensitivities related counters. */ + IDA_mem->ida_nrQSe = 0; + IDA_mem->ida_nrQeS = 0; + IDA_mem->ida_netfQS = 0; + + /* Everything allright, set the flags and return with success. */ + IDA_mem->ida_quadr_sensi = SUNTRUE; + IDA_mem->ida_quadSensMallocDone = SUNTRUE; + + return(IDA_SUCCESS); +} + +int IDAQuadSensReInit(void *ida_mem, N_Vector *yQS0) +{ + IDAMem IDA_mem; + int is, retval; + + if (ida_mem==NULL) { + 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); + 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); + return(IDA_NO_QUADSENS); + } + + /* Verifiy yQS0 parameter. */ + if (yQS0==NULL) { + 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 */ + for (is=0; is<IDA_mem->ida_Ns; is++) + IDA_mem->ida_cvals[is] = ONE; + + retval = N_VScaleVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_cvals, + yQS0, IDA_mem->ida_phiQS[0]); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + /* Initialize all sensitivities related counters. */ + IDA_mem->ida_nrQSe = 0; + IDA_mem->ida_nrQeS = 0; + IDA_mem->ida_netfQS = 0; + + /* Everything allright, set the flags and return with success. */ + IDA_mem->ida_quadr_sensi = SUNTRUE; + + return(IDA_SUCCESS); +} + +/* + * IDAQuadSensSStolerances + * IDAQuadSensSVtolerances + * IDAQuadSensEEtolerances + * + * These functions specify the integration tolerances for quadrature + * sensitivity variables. One of them MUST be called before the first + * call to IDAS IF these variables are included in the error test. + * + * IDAQuadSensSStolerances specifies scalar relative and absolute tolerances. + * IDAQuadSensSVtolerances specifies scalar relative tolerance and a vector + * absolute tolerance for each quadrature sensitivity vector (a potentially + * different absolute tolerance for each vector component). + * IDAQuadSensEEtolerances specifies that tolerances for sensitivity variables + * should be estimated from those provided for the quadrature variables. + * In this case, tolerances for the quadrature variables must be + * specified through a call to one of IDAQuad**tolerances. + */ + +int IDAQuadSensSStolerances(void *ida_mem, realtype reltolQS, realtype *abstolQS) +{ + IDAMem IDA_mem; + int is; + + if (ida_mem==NULL) { + 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); + 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); + return(IDA_NO_QUADSENS); + } + + /* Test user-supplied tolerances */ + + if (reltolQS < ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAQuadSensSStolerances", MSG_BAD_RELTOLQS); + return(IDA_ILL_INPUT); + } + + if (abstolQS == NULL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAQuadSensSStolerances", MSG_NULL_ABSTOLQS); + return(IDA_ILL_INPUT); + } + + for (is=0; is<IDA_mem->ida_Ns; is++) + if (abstolQS[is] < ZERO) { + 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_lrw += IDA_mem->ida_Ns; + IDA_mem->ida_SatolQSMallocDone = SUNTRUE; + } + + for (is=0; is<IDA_mem->ida_Ns; is++) + IDA_mem->ida_SatolQS[is] = abstolQS[is]; + + return(IDA_SUCCESS); +} + +int IDAQuadSensSVtolerances(void *ida_mem, realtype reltolQS, N_Vector *abstolQS) +{ + IDAMem IDA_mem; + int is, retval; + + if (ida_mem==NULL) { + 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); + 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); + return(IDA_NO_QUADSENS); + } + + /* Test user-supplied tolerances */ + + if (reltolQS < ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAQuadSensSVtolerances", MSG_BAD_RELTOLQS); + return(IDA_ILL_INPUT); + } + + if (abstolQS == NULL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAQuadSensSVtolerances", MSG_NULL_ABSTOLQS); + return(IDA_ILL_INPUT); + } + + for (is=0; is<IDA_mem->ida_Ns; is++) + if (N_VMin(abstolQS[is]) < ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAQuadSensSVtolerances", MSG_BAD_ABSTOLQS); + 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_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; is<IDA_mem->ida_Ns; is++) + IDA_mem->ida_cvals[is] = ONE; + + retval = N_VScaleVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_cvals, + abstolQS, IDA_mem->ida_VatolQS); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + return(IDA_SUCCESS); +} + +int IDAQuadSensEEtolerances(void *ida_mem) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + 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); + 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); + return(IDA_NO_QUADSENS); + } + + IDA_mem->ida_itolQS = IDA_EE; + + return(IDA_SUCCESS); +} + +/* + * IDASensToggleOff + * + * IDASensToggleOff deactivates sensitivity calculations. + * It does NOT deallocate sensitivity-related memory. + */ +int IDASensToggleOff(void *ida_mem) +{ + IDAMem IDA_mem; + + /* Check ida_mem */ + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", + "IDASensToggleOff", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Disable sensitivities */ + IDA_mem->ida_sensi = SUNFALSE; + IDA_mem->ida_quadr_sensi = SUNFALSE; + + return(IDA_SUCCESS); +} + +/* + * IDARootInit + * + * IDARootInit initializes a rootfinding problem to be solved + * during the integration of the DAE system. It loads the root + * function pointer and the number of root functions, and allocates + * workspace memory. The return value is IDA_SUCCESS = 0 if no + * errors occurred, or a negative value otherwise. + */ + +int IDARootInit(void *ida_mem, int nrtfn, IDARootFn g) +{ + IDAMem IDA_mem; + int i, nrt; + + /* Check ida_mem pointer */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDARootInit", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + nrt = (nrtfn < 0) ? 0 : nrtfn; + + /* If rerunning IDARootInit() with a different number of root + functions (changing number of gfun components), then free + currently held memory resources */ + if ((nrt != IDA_mem->ida_nrtfn) && (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_rootdir); IDA_mem->ida_rootdir = NULL; + free(IDA_mem->ida_gactive); IDA_mem->ida_gactive = NULL; + + IDA_mem->ida_lrw -= 3 * (IDA_mem->ida_nrtfn); + IDA_mem->ida_liw -= 3 * (IDA_mem->ida_nrtfn); + + } + + /* If IDARootInit() was called with nrtfn == 0, then set ida_nrtfn to + zero and ida_gfun to NULL before returning */ + if (nrt == 0) { + IDA_mem->ida_nrtfn = nrt; + IDA_mem->ida_gfun = NULL; + return(IDA_SUCCESS); + } + + /* If rerunning IDARootInit() with the same number of root functions + (not changing number of gfun components), then check if the root + function argument has changed */ + /* If g != NULL then return as currently reserved memory resources + will suffice */ + if (nrt == IDA_mem->ida_nrtfn) { + if (g != IDA_mem->ida_gfun) { + if (g == 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; + + IDA_mem->ida_lrw -= 3*nrt; + IDA_mem->ida_liw -= 3*nrt; + + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDARootInit", MSG_ROOT_FUNC_NULL); + return(IDA_ILL_INPUT); + } + else { + IDA_mem->ida_gfun = g; + return(IDA_SUCCESS); + } + } + else return(IDA_SUCCESS); + } + + /* Set variable values in IDA memory block */ + IDA_mem->ida_nrtfn = nrt; + if (g == NULL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDARootInit", MSG_ROOT_FUNC_NULL); + return(IDA_ILL_INPUT); + } + else IDA_mem->ida_gfun = g; + + /* Allocate necessary memory and return */ + IDA_mem->ida_glo = NULL; + IDA_mem->ida_glo = (realtype *) malloc(nrt*sizeof(realtype)); + if (IDA_mem->ida_glo == NULL) { + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", "IDARootInit", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + IDA_mem->ida_ghi = NULL; + IDA_mem->ida_ghi = (realtype *) malloc(nrt*sizeof(realtype)); + if (IDA_mem->ida_ghi == NULL) { + free(IDA_mem->ida_glo); IDA_mem->ida_glo = NULL; + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", "IDARootInit", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + IDA_mem->ida_grout = NULL; + IDA_mem->ida_grout = (realtype *) malloc(nrt*sizeof(realtype)); + if (IDA_mem->ida_grout == NULL) { + free(IDA_mem->ida_glo); IDA_mem->ida_glo = NULL; + free(IDA_mem->ida_ghi); IDA_mem->ida_ghi = NULL; + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", "IDARootInit", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + IDA_mem->ida_iroots = NULL; + IDA_mem->ida_iroots = (int *) malloc(nrt*sizeof(int)); + if (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; + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", "IDARootInit", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + IDA_mem->ida_rootdir = NULL; + IDA_mem->ida_rootdir = (int *) malloc(nrt*sizeof(int)); + if (IDA_mem->ida_rootdir == 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; + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", "IDARootInit", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + 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_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; + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDA", "IDARootInit", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + /* Set default values for rootdir (both directions) */ + for(i=0; i<nrt; i++) IDA_mem->ida_rootdir[i] = 0; + + /* Set default values for gactive (all active) */ + for(i=0; i<nrt; i++) IDA_mem->ida_gactive[i] = SUNTRUE; + + IDA_mem->ida_lrw += 3*nrt; + IDA_mem->ida_liw += 3*nrt; + + return(IDA_SUCCESS); +} + + + +/* + * ----------------------------------------------------------------- + * Main solver function + * ----------------------------------------------------------------- + */ + +/* + * IDASolve + * + * This routine is the main driver of the IDA package. + * + * 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 + * problem, it computes a tentative initial step size. + * + * IDASolve supports two modes, specified by itask: + * In the IDA_NORMAL mode, the solver steps until it passes tout and then + * interpolates to obtain y(tout) and yp(tout). + * In the IDA_ONE_STEP mode, it takes one internal step and returns. + * + * IDASolve returns integer values corresponding to success and failure as below: + * + * successful returns: + * + * IDA_SUCCESS + * IDA_TSTOP_RETURN + * + * failed returns: + * + * IDA_ILL_INPUT + * IDA_TOO_MUCH_WORK + * IDA_MEM_NULL + * IDA_TOO_MUCH_ACC + * IDA_CONV_FAIL + * IDA_LSETUP_FAIL + * IDA_LSOLVE_FAIL + * IDA_CONSTR_FAIL + * IDA_ERR_FAIL + * IDA_REP_RES_ERR + * IDA_RES_FAIL + */ + +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; + 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); + } + 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; + + 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); + } + + if ((itask != IDA_NORMAL) && (itask != IDA_ONE_STEP)) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", MSG_BAD_ITASK); + return(IDA_ILL_INPUT); + } + + if (itask == IDA_NORMAL) IDA_mem->ida_toutc = tout; + IDA_mem->ida_taskc = itask; + + /* Sensitivity-specific tests (if using internal DQ functions) */ + if (IDA_mem->ida_sensi && IDA_mem->ida_resSDQ) { + /* Make sure we have the right 'user data' */ + IDA_mem->ida_user_dataS = ida_mem; + /* Test if we have the problem parameters */ + if(IDA_mem->ida_p == NULL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", MSG_NULL_P); + return(IDA_ILL_INPUT); + } + } + + if (IDA_mem->ida_quadr_sensi && IDA_mem->ida_rhsQSDQ) { + IDA_mem->ida_user_dataQS = ida_mem; + /* Test if we have the problem parameters */ + if(IDA_mem->ida_p == NULL) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", MSG_NULL_P); + return(IDA_ILL_INPUT); + } + } + + 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); + IDA_mem->ida_SetupDone = SUNTRUE; + } + + /* On first call, check for tout - tn too small, set initial hh, + check for approach to tstop, and scale phi[1], phiQ[1], and phiS[1] by hh. + Also check for zeros of root function g at and near t0. */ + + tdist = SUNRabs(tout - IDA_mem->ida_tn); + if (tdist == ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", MSG_TOO_CLOSE); + return(IDA_ILL_INPUT); + } + troundoff = TWO * IDA_mem->ida_uround * (SUNRabs(IDA_mem->ida_tn) + SUNRabs(tout)); + if (tdist < troundoff) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", MSG_TOO_CLOSE); + return(IDA_ILL_INPUT); + } + + IDA_mem->ida_hh = IDA_mem->ida_hin; + if ( (IDA_mem->ida_hh != ZERO) && ((tout-IDA_mem->ida_tn)*IDA_mem->ida_hh < ZERO) ) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASolve", MSG_BAD_HINIT); + return(IDA_ILL_INPUT); + } + + if (IDA_mem->ida_hh == ZERO) { + IDA_mem->ida_hh = PT001*tdist; + ypnorm = IDAWrmsNorm(IDA_mem, IDA_mem->ida_phi[1], + IDA_mem->ida_ewt, IDA_mem->ida_suppressalg); + if (IDA_mem->ida_errconQ) + ypnorm = IDAQuadWrmsNormUpdate(IDA_mem, ypnorm, + IDA_mem->ida_phiQ[1], IDA_mem->ida_ewtQ); + if (IDA_mem->ida_errconS) + ypnorm = IDASensWrmsNormUpdate(IDA_mem, ypnorm, IDA_mem->ida_phiS[1], + IDA_mem->ida_ewtS, IDA_mem->ida_suppressalg); + if (IDA_mem->ida_errconQS) + 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 (tout < IDA_mem->ida_tn) IDA_mem->ida_hh = -IDA_mem->ida_hh; + } + + 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, "IDAS", "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_h0u = IDA_mem->ida_hh; + IDA_mem->ida_kk = 0; + IDA_mem->ida_kused = 0; /* set in case of an error return before a step */ + + /* Check for exact zeros of the root functions at or near t0. */ + 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); + 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' */ + + 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' */ + + if (IDA_mem->ida_sensi || IDA_mem->ida_quadr_sensi) + for (is=0; is<IDA_mem->ida_Ns; is++) + IDA_mem->ida_cvals[is] = IDA_mem->ida_hh; + + if (IDA_mem->ida_sensi) { + /* set phiS[1][i] = hh*yS_i' */ + ier = N_VScaleVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_cvals, + IDA_mem->ida_phiS[1], IDA_mem->ida_phiS[1]); + if (ier != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + } + + if (IDA_mem->ida_quadr_sensi) { + ier = N_VScaleVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_cvals, + IDA_mem->ida_phiQS[1], IDA_mem->ida_phiQS[1]); + if (ier != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + } + + /* Set the convergence test constants epsNewt and toldel */ + IDA_mem->ida_epsNewt = IDA_mem->ida_epcon; + IDA_mem->ida_toldel = PT0001 * IDA_mem->ida_epsNewt; + + } /* end of first-call block. */ + + /* Call lperf function and set nstloc for later performance testing. */ + + if (IDA_mem->ida_lperf != NULL) + IDA_mem->ida_lperf(IDA_mem, 0); + nstloc = 0; + + /* If not the first call, perform all stopping tests. */ + + if (IDA_mem->ida_nst > 0) { + + /* First, check for a root in the last step taken, other than the + last root found, if any. If itask = IDA_ONE_STEP and y(tn) was not + returned because of an intervening root, return y(tn) now. */ + + 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); + 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); + return(IDA_RTFUNC_FAIL); + } else if (ier == RTFOUND) { + IDA_mem->ida_tretlast = *tret = IDA_mem->ida_tlo; + return(IDA_ROOT_RETURN); + } + + /* If tn is distinct from tretlast (within roundoff), + check remaining interval for roots */ + troundoff = HUNDRED * IDA_mem->ida_uround * (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)); + if ( SUNRabs(IDA_mem->ida_tn - IDA_mem->ida_tretlast) > troundoff ) { + ier = IDARcheck3(IDA_mem); + if (ier == IDA_SUCCESS) { /* no root found */ + IDA_mem->ida_irfnd = 0; + if ((irfndp == 1) && (itask == IDA_ONE_STEP)) { + IDA_mem->ida_tretlast = *tret = IDA_mem->ida_tn; + ier = IDAGetSolution(IDA_mem, IDA_mem->ida_tn, yret, ypret); + return(IDA_SUCCESS); + } + } else if (ier == RTFOUND) { /* a new root was found */ + IDA_mem->ida_irfnd = 1; + 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); + return(IDA_RTFUNC_FAIL); + } + } + + } /* end of root stop check */ + + + /* Now test for all other stop conditions. */ + + istate = IDAStopTest1(IDA_mem, tout, tret, yret, ypret, itask); + if (istate != CONTINUE_STEPS) return(istate); + } + + /* 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); + 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. */ + } + + /* Call lperf to generate warnings of poor performance. */ + + if (IDA_mem->ida_lperf != NULL) + IDA_mem->ida_lperf(IDA_mem, 1); + + /* Reset and check ewt, ewtQ, ewtS and ewtQS (if not first call). */ + + if (IDA_mem->ida_nst > 0) { + + 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); + else + 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); + 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_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); + 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_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); + istate = IDA_ILL_INPUT; + ier = IDAGetSolution(IDA_mem, IDA_mem->ida_tn, yret, ypret); + IDA_mem->ida_tretlast = *tret = IDA_mem->ida_tn; + break; + } + } + + } + + /* Check for too much accuracy requested. */ + + 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); + if (IDA_mem->ida_errconS) + nrm = IDASensWrmsNormUpdate(IDA_mem, nrm, IDA_mem->ida_phiS[0], + IDA_mem->ida_ewtS, IDA_mem->ida_suppressalg); + if (IDA_mem->ida_errconQS) + nrm = IDAQuadSensWrmsNormUpdate(IDA_mem, nrm, IDA_mem->ida_phiQS[0], + IDA_mem->ida_ewtQS); + + 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); + 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); + break; + } + + /* Call IDAStep to take a step. */ + + sflag = IDAStep(IDA_mem); + + /* Process all failed-step cases, and exit loop. */ + + if (sflag != IDA_SUCCESS) { + istate = IDAHandleFailure(IDA_mem, sflag); + *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tn; + 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 */ + if (IDA_mem->ida_tstopset) { + troundoff = HUNDRED * IDA_mem->ida_uround * (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)); + if (SUNRabs(IDA_mem->ida_tn - IDA_mem->ida_tstop) <= troundoff) + IDA_mem->ida_tn = IDA_mem->ida_tstop; + } + + /* After successful step, check for stop conditions; continue or break. */ + + /* First check for root in the last step taken. */ + + if (IDA_mem->ida_nrtfn > 0) { + + ier = IDARcheck3(IDA_mem); + + if (ier == RTFOUND) { /* A new root was found */ + IDA_mem->ida_irfnd = 1; + istate = IDA_ROOT_RETURN; + 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); + istate = IDA_RTFUNC_FAIL; + break; + } + + /* If we are at the end of the first step and we still have + * some event functions that are inactive, issue a warning + * as this may indicate a user error in the implementation + * of the root function. */ + + if (IDA_mem->ida_nst==1) { + inactive_roots = SUNFALSE; + for (ir=0; ir<IDA_mem->ida_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); + } + } + + } + + /* Now check all other stop conditions. */ + + istate = IDAStopTest2(IDA_mem, tout, tret, yret, ypret, itask); + if (istate != CONTINUE_STEPS) break; + + } /* End of step loop */ + + 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 + * 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 + * + */ + +int IDAGetDky(void *ida_mem, realtype t, int k, N_Vector dky) +{ + IDAMem IDA_mem; + realtype tfuzz, tp, delt, psij_1; + int i, j, retval; + realtype cjk [MXORDP1]; + realtype cjk_1[MXORDP1]; + + /* Check ida_mem */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetDky", MSG_NO_MEM); + return (IDA_MEM_NULL); + } + 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); + } + + /* 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", "IDAGetDky", MSG_BAD_T, + t, IDA_mem->ida_tn-IDA_mem->ida_hused, IDA_mem->ida_tn); + return(IDA_BAD_T); + } + + /* Initialize the c_j^(k) and c_k^(k-1) */ + for(i=0; i<MXORDP1; i++) { + cjk [i] = 0; + cjk_1[i] = 0; + } + + delt = t-IDA_mem->ida_tn; + + for(i=0; i<=k; i++) { + + /* 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] + + For k=0, j=1: c_1 = c_0^(-1) + (delt+psi[-1]) / psi[0] + + 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 + for psi[j-2] when j>1 + */ + if(i==0) { + + cjk[i] = 1; + psij_1 = 0; + }else { + /* i i-1 1 + c_i^(i) can be always updated since c_i^(i) = ----- -------- ... ----- + psi_j psi_{j-1} psi_1 + */ + cjk[i] = cjk[i-1]*i / IDA_mem->ida_psi[i-1]; + psij_1 = IDA_mem->ida_psi[i-1]; + } + + /* update c_j^(i) */ + + /*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]; + psij_1 = IDA_mem->ida_psi[j-1]; + } + + /* save existing c_j^(i)'s */ + for(j=i+1; j<=IDA_mem->ida_kused-k+i; j++) cjk_1[j] = cjk[j]; + } + + /* 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); + + return(IDA_SUCCESS); +} + +/* + * IDAGetQuad + * + * 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. + */ + +int IDAGetQuad(void *ida_mem, realtype *ptret, N_Vector yQout) +{ + IDAMem IDA_mem; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuad", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem)ida_mem; + + *ptret = IDA_mem->ida_tretlast; + + return IDAGetQuadDky(ida_mem, IDA_mem->ida_tretlast, 0, yQout); +} + +/* + * IDAGetQuadDky + * + * Returns the quadrature variables (or their + * derivatives up to the current method order) at any time within + * the last integration step (dense output). + */ +int IDAGetQuadDky(void *ida_mem, realtype t, int k, N_Vector dkyQ) +{ + IDAMem IDA_mem; + realtype tfuzz, tp, delt, psij_1; + int i, j, retval; + realtype cjk [MXORDP1]; + realtype cjk_1[MXORDP1]; + + /* Check ida_mem */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuadDky", MSG_NO_MEM); + return (IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Ckeck if quadrature was initialized */ + if (IDA_mem->ida_quadr != SUNTRUE) { + IDAProcessError(IDA_mem, IDA_NO_QUAD, "IDAS", "IDAGetQuadDky", MSG_NO_QUAD); + return(IDA_NO_QUAD); + } + + if (dkyQ == NULL) { + 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) { + IDAProcessError(IDA_mem, IDA_BAD_T, "IDAS", "IDAGetQuadDky", MSG_BAD_T, + t, IDA_mem->ida_tn-IDA_mem->ida_hused, IDA_mem->ida_tn); + return(IDA_BAD_T); + } + + /* Initialize the c_j^(k) and c_k^(k-1) */ + for(i=0; i<MXORDP1; i++) { + cjk [i] = 0; + cjk_1[i] = 0; + } + delt = t-IDA_mem->ida_tn; + + for(i=0; i<=k; i++) { + + if(i==0) { + cjk[i] = 1; + psij_1 = 0; + }else { + cjk[i] = cjk[i-1]*i / IDA_mem->ida_psi[i-1]; + psij_1 = IDA_mem->ida_psi[i-1]; + } + + /* update c_j^(i) */ + 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]; + psij_1 = IDA_mem->ida_psi[j-1]; + } + + /* save existing c_j^(i)'s */ + for(j=i+1; j<=IDA_mem->ida_kused-k+i; j++) cjk_1[j] = cjk[j]; + } + + /* Compute sum (c_j(t) * phi(t)) */ + + retval = N_VLinearCombination(IDA_mem->ida_kused-k+1, cjk+k, IDA_mem->ida_phiQ+k, dkyQ); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + return(IDA_SUCCESS); +} + + +/* + * 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 + * is=0, 1, ... ,NS-1. + */ + +int IDAGetSens(void *ida_mem, realtype *ptret, N_Vector *yySout) +{ + IDAMem IDA_mem; + int is, ierr=0; + + /* Check ida_mem */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetSens", MSG_NO_MEM); + return (IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /*Check the parameters */ + if (yySout == NULL) { + IDAProcessError(IDA_mem, IDA_BAD_DKY, "IDAS", "IDAGetSens", MSG_NULL_DKY); + return(IDA_BAD_DKY); + } + + /* are sensitivities enabled? */ + if (IDA_mem->ida_sensi==SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAGetSens", MSG_NO_SENSI); + return(IDA_NO_SENS); + } + + *ptret = IDA_mem->ida_tretlast; + + for(is=0; is<IDA_mem->ida_Ns; is++) + if( IDA_SUCCESS != (ierr = IDAGetSensDky1(ida_mem, *ptret, 0, is, yySout[is])) ) break; + + return(ierr); +} + +/* + * IDAGetSensDky + * + * 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 + * least Ns vectors. + */ +int IDAGetSensDky(void *ida_mem, realtype t, int k, N_Vector *dkySout) +{ + int is, ier=0; + IDAMem IDA_mem; + + /* Check all inputs for legality */ + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetSensDky", MSG_NO_MEM); + return (IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_sensi==SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAGetSensDky", MSG_NO_SENSI); + return(IDA_NO_SENS); + } + + if (dkySout == NULL) { + 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; is<IDA_mem->ida_Ns; is++) { + ier = IDAGetSensDky1(ida_mem, t, k, is, dkySout[is]); + if (ier!=IDA_SUCCESS) break; + } + + return(ier); +} + + +/* + * IDAGetSens1 + * + * This routine extracts the is-th sensitivity solution into ySout + * at the time at which IDASolve returned the solution. + * This is just a wrapper that calls IDASensDky1 with k=0. + */ + +int IDAGetSens1(void *ida_mem, realtype *ptret, int is, N_Vector yySret) +{ + IDAMem IDA_mem; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetSens1", MSG_NO_MEM); + return (IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + *ptret = IDA_mem->ida_tretlast; + + return IDAGetSensDky1(ida_mem, *ptret, 0, is, 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 + * 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 + * computation enabled. + */ +int IDAGetSensDky1(void *ida_mem, realtype t, int k, int is, N_Vector dkyS) +{ + IDAMem IDA_mem; + realtype tfuzz, tp, delt, psij_1; + int i, j, retval; + realtype cjk [MXORDP1]; + realtype cjk_1[MXORDP1]; + + /* Check all inputs for legality */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetSensDky1", MSG_NO_MEM); + return (IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_sensi==SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAGetSensDky1", MSG_NO_SENSI); + return(IDA_NO_SENS); + } + + if (dkyS == NULL) { + IDAProcessError(IDA_mem, IDA_BAD_DKY, "IDAS", "IDAGetSensDky1", MSG_NULL_DKY); + return(IDA_BAD_DKY); + } + + /* Is the requested sensitivity index valid? */ + 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; + if ((t - tp)*IDA_mem->ida_hh < ZERO) { + IDAProcessError(IDA_mem, IDA_BAD_T, "IDAS", "IDAGetSensDky1", MSG_BAD_T, + t, IDA_mem->ida_tn-IDA_mem->ida_hused, IDA_mem->ida_tn); + return(IDA_BAD_T); + } + + /* Initialize the c_j^(k) and c_k^(k-1) */ + for(i=0; i<MXORDP1; i++) { + cjk [i] = 0; + cjk_1[i] = 0; + } + + delt = t - IDA_mem->ida_tn; + + for(i=0; i<=k; i++) { + + if(i==0) { + cjk[i] = 1; + psij_1 = 0; + }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 */ + 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]; + 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++) + IDA_mem->ida_Xvecs[j-k] = IDA_mem->ida_phiS[j][is]; + + retval = N_VLinearCombination(IDA_mem->ida_kused-k+1, cjk+k, + IDA_mem->ida_Xvecs, dkyS); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + 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 + * is=0, 1, ... ,NS-1. + */ + +int IDAGetQuadSens(void *ida_mem, realtype *ptret, N_Vector *yyQSout) +{ + IDAMem IDA_mem; + int is, ierr=0; + + /* Check ida_mem */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuadSens", MSG_NO_MEM); + return (IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /*Check the parameters */ + if (yyQSout == NULL) { + IDAProcessError(IDA_mem, IDA_BAD_DKY, "IDAS", "IDAGetQuadSens", MSG_NULL_DKY); + return(IDA_BAD_DKY); + } + + /* are sensitivities enabled? */ + if (IDA_mem->ida_quadr_sensi==SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAGetQuadSens", MSG_NO_QUADSENSI); + return(IDA_NO_SENS); + } + + *ptret = IDA_mem->ida_tretlast; + + for(is=0; is<IDA_mem->ida_Ns; is++) + if( IDA_SUCCESS != (ierr = IDAGetQuadSensDky1(ida_mem, *ptret, 0, is, yyQSout[is])) ) break; + + return(ierr); +} + +/* + * 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 + * least Ns vectors. + */ +int IDAGetQuadSensDky(void *ida_mem, realtype t, int k, N_Vector *dkyQSout) +{ + int is, ier=0; + IDAMem IDA_mem; + + /* Check all inputs for legality */ + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuadSensDky", MSG_NO_MEM); + return (IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_sensi==SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAGetQuadSensDky", MSG_NO_SENSI); + return(IDA_NO_SENS); + } + + if (IDA_mem->ida_quadr_sensi==SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_QUADSENS, "IDAS", "IDAGetQuadSensDky", MSG_NO_QUADSENSI); + return(IDA_NO_QUADSENS); + } + + if (dkyQSout == NULL) { + 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; is<IDA_mem->ida_Ns; is++) { + ier = IDAGetQuadSensDky1(ida_mem, t, k, is, dkyQSout[is]); + if (ier!=IDA_SUCCESS) break; + } + + return(ier); +} + + +/* + * IDAGetQuadSens1 + * + * This routine extracts the is-th quadrature sensitivity solution into yQSout + * at the time at which IDASolve returned the solution. + * This is just a wrapper that calls IDASensDky1 with k=0. + */ + +int IDAGetQuadSens1(void *ida_mem, realtype *ptret, int is, N_Vector yyQSret) +{ + IDAMem IDA_mem; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuadSens1", MSG_NO_MEM); + return (IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_sensi==SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAGetQuadSens1", MSG_NO_SENSI); + return(IDA_NO_SENS); + } + + if (IDA_mem->ida_quadr_sensi==SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_QUADSENS, "IDAS", "IDAGetQuadSens1", MSG_NO_QUADSENSI); + return(IDA_NO_QUADSENS); + } + + if (yyQSret == NULL) { + IDAProcessError(IDA_mem, IDA_BAD_DKY, "IDAS", "IDAGetQuadSens1", MSG_NULL_DKY); + return(IDA_BAD_DKY); + } + + *ptret = IDA_mem->ida_tretlast; + + return IDAGetQuadSensDky1(ida_mem, *ptret, 0, is, 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 + * 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 + * computation enabled. + */ +int IDAGetQuadSensDky1(void *ida_mem, realtype t, int k, int is, N_Vector dkyQS) +{ + IDAMem IDA_mem; + realtype tfuzz, tp, delt, psij_1; + int i, j, retval; + realtype cjk [MXORDP1]; + realtype cjk_1[MXORDP1]; + + /* Check all inputs for legality */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetQuadSensDky1", MSG_NO_MEM); + return (IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_sensi==SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAGetQuadSensDky1", MSG_NO_SENSI); + return(IDA_NO_SENS); + } + + if (IDA_mem->ida_quadr_sensi==SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_QUADSENS, "IDAS", "IDAGetQuadSensDky1", MSG_NO_QUADSENSI); + return(IDA_NO_QUADSENS); + } + + + if (dkyQS == NULL) { + IDAProcessError(IDA_mem, IDA_BAD_DKY, "IDAS", "IDAGetQuadSensDky1", MSG_NULL_DKY); + return(IDA_BAD_DKY); + } + + /* Is the requested sensitivity index valid*/ + 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; + if ((t - tp)*IDA_mem->ida_hh < ZERO) { + IDAProcessError(IDA_mem, IDA_BAD_T, "IDAS", "IDAGetQuadSensDky1", MSG_BAD_T, + t, IDA_mem->ida_tn-IDA_mem->ida_hused, IDA_mem->ida_tn); + return(IDA_BAD_T); + } + + /* Initialize the c_j^(k) and c_k^(k-1) */ + for(i=0; i<MXORDP1; i++) { + cjk [i] = 0; + cjk_1[i] = 0; + } + + delt = t - IDA_mem->ida_tn; + + for(i=0; i<=k; i++) { + + if(i==0) { + cjk[i] = 1; + psij_1 = 0; + }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 */ + 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]; + 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++) + IDA_mem->ida_Xvecs[j-k] = IDA_mem->ida_phiQS[j][is]; + + retval = N_VLinearCombination(IDA_mem->ida_kused-k+1, cjk+k, + IDA_mem->ida_Xvecs, dkyQS); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + return(IDA_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Deallocation functions + * ----------------------------------------------------------------- + */ + +/* + * IDAFree + * + * This routine frees the problem memory allocated by IDAInit + * Such memory includes all the vectors allocated by IDAAllocVectors, + * and the memory lmem for the linear solver (deallocated by a call + * to lfree). + */ + +void IDAFree(void **ida_mem) +{ + IDAMem IDA_mem; + + if (*ida_mem == NULL) return; + + IDA_mem = (IDAMem) (*ida_mem); + + IDAFreeVectors(IDA_mem); + + IDAQuadFree(IDA_mem); + + IDASensFree(IDA_mem); + + IDAQuadSensFree(IDA_mem); + + IDAAdjFree(IDA_mem); + + 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_rootdir); IDA_mem->ida_rootdir = NULL; + free(IDA_mem->ida_gactive); IDA_mem->ida_gactive = NULL; + } + + free(IDA_mem->ida_cvals); IDA_mem->ida_cvals = NULL; + 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; +} + +/* + * IDAQuadFree + * + * IDAQuadFree frees the problem memory in ida_mem allocated + * for quadrature integration. Its only argument is the pointer + * ida_mem returned by IDACreate. + */ + +void IDAQuadFree(void *ida_mem) +{ + IDAMem IDA_mem; + + if (ida_mem == NULL) return; + IDA_mem = (IDAMem) ida_mem; + + if(IDA_mem->ida_quadMallocDone) { + IDAQuadFreeVectors(IDA_mem); + IDA_mem->ida_quadMallocDone = SUNFALSE; + IDA_mem->ida_quadr = SUNFALSE; + } +} + +/* + * IDASensFree + * + * IDASensFree frees the problem memory in ida_mem allocated + * for sensitivity analysis. Its only argument is the pointer + * ida_mem returned by IDACreate. + */ + +void IDASensFree(void *ida_mem) +{ + IDAMem IDA_mem; + + /* return immediately if IDA memory is NULL */ + if (ida_mem == NULL) return; + IDA_mem = (IDAMem) ida_mem; + + if(IDA_mem->ida_sensMallocDone) { + IDASensFreeVectors(IDA_mem); + IDA_mem->ida_sensMallocDone = SUNFALSE; + IDA_mem->ida_sensi = SUNFALSE; + } + + /* 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; + 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; + IDA_mem->stgMallocDone = SUNFALSE; + } + + /* if IDA created the NLS object then free it */ + if (IDA_mem->ownNLSsim) { + SUNNonlinSolFree(IDA_mem->NLSsim); + IDA_mem->ownNLSsim = SUNFALSE; + IDA_mem->NLSsim = NULL; + } + if (IDA_mem->ownNLSstg) { + SUNNonlinSolFree(IDA_mem->NLSstg); + IDA_mem->ownNLSstg = SUNFALSE; + IDA_mem->NLSstg = 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. + */ +void IDAQuadSensFree(void* ida_mem) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) return; + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_quadSensMallocDone) { + IDAQuadSensFreeVectors(IDA_mem); + IDA_mem->ida_quadSensMallocDone=SUNFALSE; + IDA_mem->ida_quadr_sensi = SUNFALSE; + } +} + +/* + * ================================================================= + * PRIVATE FUNCTIONS + * ================================================================= + */ + +/* + * IDACheckNvector + * + * This routine checks if all required vector operations are present. + * If any of them is missing it returns SUNFALSE. + */ + +static booleantype IDACheckNvector(N_Vector tmpl) +{ + if ((tmpl->ops->nvclone == NULL) || + (tmpl->ops->nvdestroy == NULL) || + (tmpl->ops->nvlinearsum == NULL) || + (tmpl->ops->nvconst == NULL) || + (tmpl->ops->nvprod == NULL) || + (tmpl->ops->nvscale == NULL) || + (tmpl->ops->nvabs == NULL) || + (tmpl->ops->nvinv == NULL) || + (tmpl->ops->nvaddconst == NULL) || + (tmpl->ops->nvwrmsnorm == NULL) || + (tmpl->ops->nvmin == NULL)) + return(SUNFALSE); + else + return(SUNTRUE); +} + +/* + * ----------------------------------------------------------------- + * Memory allocation/deallocation + * ----------------------------------------------------------------- + */ + +/* + * IDAAllocVectors + * + * 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 + * returns SUNFALSE. + * This routine also sets the optional outputs lrw and liw, which are + * (respectively) the lengths of the real and integer work spaces + * allocated here. + */ + +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); + + IDA_mem->ida_ee = N_VClone(tmpl); + if (IDA_mem->ida_ee == NULL) { + N_VDestroy(IDA_mem->ida_ewt); + return(SUNFALSE); + } + + IDA_mem->ida_delta = N_VClone(tmpl); + if (IDA_mem->ida_delta == NULL) { + N_VDestroy(IDA_mem->ida_ewt); + N_VDestroy(IDA_mem->ida_ee); + return(SUNFALSE); + } + + IDA_mem->ida_yypredict = N_VClone(tmpl); + if (IDA_mem->ida_yypredict == NULL) { + N_VDestroy(IDA_mem->ida_ewt); + N_VDestroy(IDA_mem->ida_ee); + N_VDestroy(IDA_mem->ida_delta); + return(SUNFALSE); + } + + IDA_mem->ida_yppredict = N_VClone(tmpl); + if (IDA_mem->ida_yppredict == NULL) { + N_VDestroy(IDA_mem->ida_ewt); + N_VDestroy(IDA_mem->ida_ee); + N_VDestroy(IDA_mem->ida_delta); + N_VDestroy(IDA_mem->ida_yypredict); + return(SUNFALSE); + } + + IDA_mem->ida_savres = N_VClone(tmpl); + if (IDA_mem->ida_savres == NULL) { + 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); + return(SUNFALSE); + } + + IDA_mem->ida_tempv1 = N_VClone(tmpl); + if (IDA_mem->ida_tempv1 == NULL) { + 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); + return(SUNFALSE); + } + + IDA_mem->ida_tempv2 = N_VClone(tmpl); + if (IDA_mem->ida_tempv2 == NULL) { + 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); + return(SUNFALSE); + } + + IDA_mem->ida_tempv3 = N_VClone(tmpl); + if (IDA_mem->ida_tempv3 == NULL) { + 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); + return(SUNFALSE); + } + + /* Allocate phi[0] ... phi[maxord]. Make sure phi[2] and phi[3] are + allocated (for use as temporary vectors), regardless of maxord. */ + + maxcol = SUNMAX(IDA_mem->ida_maxord,3); + for (j=0; j <= maxcol; j++) { + IDA_mem->ida_phi[j] = N_VClone(tmpl); + if (IDA_mem->ida_phi[j] == NULL) { + 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); + for (i=0; i < j; i++) + N_VDestroy(IDA_mem->ida_phi[i]); + return(SUNFALSE); + } + } + + /* Update solver workspace lengths */ + IDA_mem->ida_lrw += (maxcol + 10)*IDA_mem->ida_lrw1; + IDA_mem->ida_liw += (maxcol + 10)*IDA_mem->ida_liw1; + + /* Store the value of maxord used here */ + IDA_mem->ida_maxord_alloc = IDA_mem->ida_maxord; + + return(SUNTRUE); +} + +/* + * IDAfreeVectors + * + * This routine frees the IDA vectors allocated for IDA. + */ + +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_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]); + 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); 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); IDA_mem->ida_id = NULL; + IDA_mem->ida_lrw -= IDA_mem->ida_lrw1; + IDA_mem->ida_liw -= IDA_mem->ida_liw1; + } + +} + +/* + * IDAQuadAllocVectors + * + * 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 + * IDAQuadReInit. + */ + +static booleantype IDAQuadAllocVectors(IDAMem IDA_mem, N_Vector tmpl) +{ + int i, j; + + /* Allocate yyQ */ + IDA_mem->ida_yyQ = N_VClone(tmpl); + if (IDA_mem->ida_yyQ == NULL) { + return (SUNFALSE); + } + + /* Allocate ypQ */ + IDA_mem->ida_ypQ = N_VClone(tmpl); + if (IDA_mem->ida_ypQ == NULL) { + N_VDestroy(IDA_mem->ida_yyQ); + return (SUNFALSE); + } + + /* Allocate ewtQ */ + IDA_mem->ida_ewtQ = N_VClone(tmpl); + if (IDA_mem->ida_ewtQ == NULL) { + N_VDestroy(IDA_mem->ida_yyQ); + N_VDestroy(IDA_mem->ida_ypQ); + return (SUNFALSE); + } + + /* Allocate eeQ */ + IDA_mem->ida_eeQ = N_VClone(tmpl); + if (IDA_mem->ida_eeQ == NULL) { + N_VDestroy(IDA_mem->ida_yyQ); + N_VDestroy(IDA_mem->ida_ypQ); + N_VDestroy(IDA_mem->ida_ewtQ); + return (SUNFALSE); + } + + for (j=0; j <= IDA_mem->ida_maxord; j++) { + IDA_mem->ida_phiQ[j] = N_VClone(tmpl); + if (IDA_mem->ida_phiQ[j] == NULL) { + N_VDestroy(IDA_mem->ida_yyQ); + N_VDestroy(IDA_mem->ida_ypQ); + N_VDestroy(IDA_mem->ida_ewtQ); + N_VDestroy(IDA_mem->ida_eeQ); + for (i=0; i < j; i++) N_VDestroy(IDA_mem->ida_phiQ[i]); + return(SUNFALSE); + } + } + + IDA_mem->ida_lrw += (IDA_mem->ida_maxord+4)*IDA_mem->ida_lrw1Q; + IDA_mem->ida_liw += (IDA_mem->ida_maxord+4)*IDA_mem->ida_liw1Q; + + return(SUNTRUE); +} + + + +/* + * IDAQuadFreeVectors + * + * This routine frees the IDAS vectors allocated in IDAQuadAllocVectors. + */ + +static void IDAQuadFreeVectors(IDAMem IDA_mem) +{ + int j; + + N_VDestroy(IDA_mem->ida_yyQ); IDA_mem->ida_yyQ = NULL; + N_VDestroy(IDA_mem->ida_ypQ); IDA_mem->ida_ypQ = NULL; + N_VDestroy(IDA_mem->ida_ewtQ); IDA_mem->ida_ewtQ = NULL; + N_VDestroy(IDA_mem->ida_eeQ); IDA_mem->ida_eeQ = NULL; + for(j=0; j <= IDA_mem->ida_maxord; j++) { + N_VDestroy(IDA_mem->ida_phiQ[j]); + IDA_mem->ida_phiQ[j] = NULL; + } + + IDA_mem->ida_lrw -= (IDA_mem->ida_maxord+5)*IDA_mem->ida_lrw1Q; + IDA_mem->ida_liw -= (IDA_mem->ida_maxord+5)*IDA_mem->ida_liw1Q; + + if (IDA_mem->ida_VatolQMallocDone) { + N_VDestroy(IDA_mem->ida_VatolQ); IDA_mem->ida_VatolQ = NULL; + IDA_mem->ida_lrw -= IDA_mem->ida_lrw1Q; + IDA_mem->ida_liw -= IDA_mem->ida_liw1Q; + } + + IDA_mem->ida_VatolQMallocDone = SUNFALSE; +} + +/* + * IDASensAllocVectors + * + * Allocates space for the N_Vectors, plist, and pbar required for FSA. + */ + +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; + + /* Allocate space for workspace vectors */ + + IDA_mem->ida_tmpS3 = N_VClone(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); + return(SUNFALSE); + } + + IDA_mem->ida_eeS = N_VCloneVectorArray(IDA_mem->ida_Ns, tmpl); + if (IDA_mem->ida_eeS==NULL) { + N_VDestroy(IDA_mem->ida_tmpS3); + N_VDestroyVectorArray(IDA_mem->ida_ewtS, IDA_mem->ida_Ns); + return(SUNFALSE); + } + + IDA_mem->ida_yyS = N_VCloneVectorArray(IDA_mem->ida_Ns, tmpl); + if (IDA_mem->ida_yyS==NULL) { + N_VDestroyVectorArray(IDA_mem->ida_eeS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ewtS, IDA_mem->ida_Ns); + 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); + N_VDestroyVectorArray(IDA_mem->ida_eeS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ewtS, IDA_mem->ida_Ns); + N_VDestroy(IDA_mem->ida_tmpS3); + return(SUNFALSE); + } + + IDA_mem->ida_yySpredict = N_VCloneVectorArray(IDA_mem->ida_Ns, tmpl); + if (IDA_mem->ida_yySpredict==NULL) { + N_VDestroyVectorArray(IDA_mem->ida_ypS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_yyS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_eeS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ewtS, IDA_mem->ida_Ns); + N_VDestroy(IDA_mem->ida_tmpS3); + return(SUNFALSE); + } + + IDA_mem->ida_ypSpredict = N_VCloneVectorArray(IDA_mem->ida_Ns, tmpl); + if (IDA_mem->ida_ypSpredict==NULL) { + N_VDestroyVectorArray(IDA_mem->ida_yySpredict, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ypS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_yyS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_eeS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ewtS, IDA_mem->ida_Ns); + N_VDestroy(IDA_mem->ida_tmpS3); + return(SUNFALSE); + } + + IDA_mem->ida_deltaS = N_VCloneVectorArray(IDA_mem->ida_Ns, tmpl); + if (IDA_mem->ida_deltaS==NULL) { + N_VDestroyVectorArray(IDA_mem->ida_ypSpredict, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_yySpredict, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ypS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_yyS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_eeS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ewtS, IDA_mem->ida_Ns); + N_VDestroy(IDA_mem->ida_tmpS3); + return(SUNFALSE); + } + + /* Update solver workspace lengths */ + IDA_mem->ida_lrw += (5*IDA_mem->ida_Ns+1)*IDA_mem->ida_lrw1; + IDA_mem->ida_liw += (5*IDA_mem->ida_Ns+1)*IDA_mem->ida_liw1; + + /* Allocate space for phiS */ + /* Make sure phiS[2], phiS[3] and phiS[4] are + allocated (for use as temporary vectors), regardless of maxord.*/ + + maxcol = SUNMAX(IDA_mem->ida_maxord,4); + for (j=0; j <= maxcol; j++) { + IDA_mem->ida_phiS[j] = N_VCloneVectorArray(IDA_mem->ida_Ns, tmpl); + if (IDA_mem->ida_phiS[j] == NULL) { + N_VDestroy(IDA_mem->ida_tmpS3); + N_VDestroyVectorArray(IDA_mem->ida_ewtS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_eeS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_yyS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ypS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_yySpredict, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ypSpredict, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_deltaS, IDA_mem->ida_Ns); + return(SUNFALSE); + } + } + + /* Update solver workspace lengths */ + IDA_mem->ida_lrw += maxcol*IDA_mem->ida_Ns*IDA_mem->ida_lrw1; + IDA_mem->ida_liw += maxcol*IDA_mem->ida_Ns*IDA_mem->ida_liw1; + + /* Allocate space for pbar and plist */ + + IDA_mem->ida_pbar = NULL; + IDA_mem->ida_pbar = (realtype *)malloc(IDA_mem->ida_Ns*sizeof(realtype)); + if (IDA_mem->ida_pbar == NULL) { + N_VDestroy(IDA_mem->ida_tmpS3); + N_VDestroyVectorArray(IDA_mem->ida_ewtS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_eeS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_yyS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ypS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_yySpredict, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ypSpredict, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_deltaS, IDA_mem->ida_Ns); + for (j=0; j<=maxcol; j++) N_VDestroyVectorArray(IDA_mem->ida_phiS[j], IDA_mem->ida_Ns); + return(SUNFALSE); + } + + IDA_mem->ida_plist = NULL; + IDA_mem->ida_plist = (int *)malloc(IDA_mem->ida_Ns*sizeof(int)); + if (IDA_mem->ida_plist == NULL) { + N_VDestroy(IDA_mem->ida_tmpS3); + N_VDestroyVectorArray(IDA_mem->ida_ewtS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_eeS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_yyS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ypS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_yySpredict, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ypSpredict, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_deltaS, IDA_mem->ida_Ns); + 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; + return(SUNFALSE); + } + + /* Update solver workspace lengths */ + IDA_mem->ida_lrw += IDA_mem->ida_Ns; + IDA_mem->ida_liw += IDA_mem->ida_Ns; + + return(SUNTRUE); +} + +/* + * IDASensFreeVectors + * + * Frees memory allocated by IDASensAllocVectors. + */ + +static void IDASensFreeVectors(IDAMem IDA_mem) +{ + int j, maxcol; + + N_VDestroyVectorArray(IDA_mem->ida_deltaS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ypSpredict, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_yySpredict, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ypS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_yyS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_eeS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ewtS, IDA_mem->ida_Ns); + N_VDestroy(IDA_mem->ida_tmpS3); + + maxcol = SUNMAX(IDA_mem->ida_maxord_alloc, 4); + 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; + free(IDA_mem->ida_plist); IDA_mem->ida_plist = NULL; + + IDA_mem->ida_lrw -= ( (maxcol+3)*IDA_mem->ida_Ns + 1 ) * IDA_mem->ida_lrw1 + IDA_mem->ida_Ns; + IDA_mem->ida_liw -= ( (maxcol+3)*IDA_mem->ida_Ns + 1 ) * IDA_mem->ida_liw1 + IDA_mem->ida_Ns; + + if (IDA_mem->ida_VatolSMallocDone) { + N_VDestroyVectorArray(IDA_mem->ida_VatolS, IDA_mem->ida_Ns); + 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; + IDA_mem->ida_SatolSMallocDone = SUNFALSE; + } +} + + +/* + * IDAQuadSensAllocVectors + * + * 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) +{ + int i, j, maxcol; + + /* Allocate yQS */ + IDA_mem->ida_yyQS = N_VCloneVectorArray(IDA_mem->ida_Ns, tmpl); + if (IDA_mem->ida_yyQS == NULL) { + return(SUNFALSE); + } + + /* Allocate ewtQS */ + IDA_mem->ida_ewtQS = N_VCloneVectorArray(IDA_mem->ida_Ns, tmpl); + if (IDA_mem->ida_ewtQS == NULL) { + N_VDestroyVectorArray(IDA_mem->ida_yyQS, IDA_mem->ida_Ns); + return(SUNFALSE); + } + + /* Allocate tempvQS */ + IDA_mem->ida_tempvQS = N_VCloneVectorArray(IDA_mem->ida_Ns, tmpl); + if (IDA_mem->ida_tempvQS == NULL) { + N_VDestroyVectorArray(IDA_mem->ida_yyQS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ewtQS, IDA_mem->ida_Ns); + return(SUNFALSE); + } + + IDA_mem->ida_eeQS = N_VCloneVectorArray(IDA_mem->ida_Ns, tmpl); + if (IDA_mem->ida_eeQS == NULL) { + N_VDestroyVectorArray(IDA_mem->ida_yyQS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ewtQS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_tempvQS, IDA_mem->ida_Ns); + return(SUNFALSE); + } + + IDA_mem->ida_savrhsQ = N_VClone(tmpl); + if (IDA_mem->ida_savrhsQ == NULL) { + N_VDestroyVectorArray(IDA_mem->ida_yyQS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ewtQS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_tempvQS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_eeQS, IDA_mem->ida_Ns); + } + + maxcol = SUNMAX(IDA_mem->ida_maxord,4); + /* Allocate phiQS */ + for (j=0; j<=maxcol; j++) { + IDA_mem->ida_phiQS[j] = N_VCloneVectorArray(IDA_mem->ida_Ns, tmpl); + if (IDA_mem->ida_phiQS[j] == NULL) { + N_VDestroyVectorArray(IDA_mem->ida_yyQS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ewtQS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_tempvQS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_eeQS, IDA_mem->ida_Ns); + N_VDestroy(IDA_mem->ida_savrhsQ); + for (i=0; i<j; i++) + N_VDestroyVectorArray(IDA_mem->ida_phiQS[i], IDA_mem->ida_Ns); + return(SUNFALSE); + } + } + + /* Update solver workspace lengths */ + 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; + + return(SUNTRUE); +} + + +/* + * IDAQuadSensFreeVectors + * + * This routine frees the IDAS vectors allocated in IDAQuadSensAllocVectors. + */ + +static void IDAQuadSensFreeVectors(IDAMem IDA_mem) +{ + int j, maxcol; + + maxcol = SUNMAX(IDA_mem->ida_maxord, 4); + + N_VDestroyVectorArray(IDA_mem->ida_yyQS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ewtQS, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_eeQS, IDA_mem->ida_Ns); + 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); + + 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; + + if (IDA_mem->ida_VatolQSMallocDone) { + N_VDestroyVectorArray(IDA_mem->ida_VatolQS, IDA_mem->ida_Ns); + IDA_mem->ida_lrw -= IDA_mem->ida_Ns*IDA_mem->ida_lrw1Q; + IDA_mem->ida_liw -= IDA_mem->ida_Ns*IDA_mem->ida_liw1Q; + } + if (IDA_mem->ida_SatolQSMallocDone) { + free(IDA_mem->ida_SatolQS); IDA_mem->ida_SatolQS = NULL; + IDA_mem->ida_lrw -= IDA_mem->ida_Ns; + } + IDA_mem->ida_VatolQSMallocDone = SUNFALSE; + IDA_mem->ida_SatolQSMallocDone = SUNFALSE; +} + + +/* + * ----------------------------------------------------------------- + * Initial setup + * ----------------------------------------------------------------- + */ + +/* + * IDAInitialSetup + * + * 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 + * handler function. + */ + +int IDAInitialSetup(IDAMem IDA_mem) +{ + booleantype conOK; + int ier, retval; + + /* 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); + 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); + } + + /* Did the user specify tolerances? */ + if (IDA_mem->ida_itol == IDA_NN) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAInitialSetup", MSG_NO_TOLS); + return(IDA_ILL_INPUT); + } + + /* Set data for efun */ + 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 */ + 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); + else + 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); + IDA_mem->ida_nrQe++; + if (retval < 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); + return(IDA_FIRST_QRHS_ERR); + } + + if (IDA_mem->ida_errconQ) { + + /* Did the user specify tolerances? */ + if (IDA_mem->ida_itolQ == IDA_NN) { + 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); + return(IDA_ILL_INPUT); + } + } + } else { + IDA_mem->ida_errconQ = SUNFALSE; + } + + if (IDA_mem->ida_sensi) { + + /* Did the user specify tolerances? */ + if (IDA_mem->ida_itolS == IDA_NN) { + 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); + return(IDA_ILL_INPUT); + } + } else { + IDA_mem->ida_errconS = SUNFALSE; + } + + 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); + IDA_mem->ida_nrQSe++; + if (retval < 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); + return(IDA_FIRST_QSRHS_ERR); + } + + /* 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 (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); + 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); + return(IDA_ILL_INPUT); + } + } + + 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); + 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); + 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); + return(IDA_ILL_INPUT); + } + } + } else { + IDA_mem->ida_errconQS = SUNFALSE; + } + + /* Check to see if y0 satisfies constraints. */ + 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); + 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); + } + } + + /* 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); + return(IDA_LINIT_FAIL); + } + } + + /* Initialize the nonlinear solver (must occur after linear solver is initialize) so + * that lsetup and lsolve pointers have been set */ + + /* 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); + 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); + 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); + return(IDA_NLS_INIT_FAIL); + } + } + + return(IDA_SUCCESS); +} + +/* + * IDAEwtSet + * + * This routine is responsible for loading the error weight vector + * ewt, according to itol, as follows: + * (1) ewt[i] = 1 / (rtol * SUNRabs(ycur[i]) + atol), i=0,...,Neq-1 + * if itol = IDA_SS + * (2) ewt[i] = 1 / (rtol * SUNRabs(ycur[i]) + atol[i]), i=0,...,Neq-1 + * if itol = IDA_SV + * + * IDAEwtSet 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 IDAEwtSetSS, IDAEwtSetSV. + */ + +int IDAEwtSet(N_Vector ycur, N_Vector weight, void *data) +{ + IDAMem IDA_mem; + int flag = 0; + + /* data points to IDA_mem here */ + + IDA_mem = (IDAMem) data; + + switch(IDA_mem->ida_itol) { + case IDA_SS: + flag = IDAEwtSetSS(IDA_mem, ycur, weight); + break; + case IDA_SV: + flag = IDAEwtSetSV(IDA_mem, ycur, weight); + break; + } + return(flag); +} + +/* + * 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 + * undefined. + */ + +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); + N_VInv(IDA_mem->ida_tempv1, weight); + return(0); +} + +/* + * 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 + * 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_VInv(IDA_mem->ida_tempv1, weight); + return(0); +} + +/* + * IDAQuadEwtSet + * + */ + +static int IDAQuadEwtSet(IDAMem IDA_mem, N_Vector qcur, N_Vector weightQ) +{ + int flag=0; + + switch (IDA_mem->ida_itolQ) { + case IDA_SS: + flag = IDAQuadEwtSetSS(IDA_mem, qcur, weightQ); + break; + case IDA_SV: + flag = IDAQuadEwtSetSV(IDA_mem, qcur, weightQ); + break; + } + + return(flag); + +} + +/* + * IDAQuadEwtSetSS + * + */ + +static int IDAQuadEwtSetSS(IDAMem IDA_mem, N_Vector qcur, N_Vector weightQ) +{ + N_Vector tempvQ; + + /* Use ypQ as temporary storage */ + tempvQ = IDA_mem->ida_ypQ; + + 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); + N_VInv(tempvQ, weightQ); + + return(0); +} + +/* + * IDAQuadEwtSetSV + * + */ + +static int IDAQuadEwtSetSV(IDAMem IDA_mem, N_Vector qcur, N_Vector weightQ) +{ + N_Vector tempvQ; + + /* Use ypQ as temporary storage */ + tempvQ = IDA_mem->ida_ypQ; + + N_VAbs(qcur, tempvQ); + N_VLinearSum(IDA_mem->ida_rtolQ, tempvQ, ONE, IDA_mem->ida_VatolQ, tempvQ); + if (N_VMin(tempvQ) <= ZERO) return(-1); + N_VInv(tempvQ, weightQ); + + return(0); +} + +/* + * IDASensEwtSet + * + */ + +int IDASensEwtSet(IDAMem IDA_mem, N_Vector *yScur, N_Vector *weightS) +{ + int flag=0; + + switch (IDA_mem->ida_itolS) { + case IDA_EE: + flag = IDASensEwtSetEE(IDA_mem, yScur, weightS); + break; + case IDA_SS: + flag = IDASensEwtSetSS(IDA_mem, yScur, weightS); + break; + case IDA_SV: + flag = IDASensEwtSetSV(IDA_mem, yScur, weightS); + break; + } + + return(flag); + +} + +/* + * IDASensEwtSetEE + * + * 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 IDASensEwtSetEE(IDAMem IDA_mem, N_Vector *yScur, N_Vector *weightS) +{ + int is; + N_Vector pyS; + int flag; + + /* Use tempv1 as temporary storage for the scaled sensitivity */ + pyS = IDA_mem->ida_tempv1; + + for (is=0; is<IDA_mem->ida_Ns; is++) { + N_VScale(IDA_mem->ida_pbar[is], yScur[is], pyS); + flag = IDA_mem->ida_efun(pyS, weightS[is], IDA_mem->ida_edata); + if (flag != 0) return(-1); + N_VScale(IDA_mem->ida_pbar[is], weightS[is], weightS[is]); + } + + return(0); +} + +/* + * IDASensEwtSetSS + * + */ + +static int IDASensEwtSetSS(IDAMem IDA_mem, N_Vector *yScur, N_Vector *weightS) +{ + int is; + + for (is=0; is<IDA_mem->ida_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); + N_VInv(IDA_mem->ida_tempv1, weightS[is]); + } + return(0); +} + +/* + * IDASensEwtSetSV + * + */ + +static int IDASensEwtSetSV(IDAMem IDA_mem, N_Vector *yScur, N_Vector *weightS) +{ + int is; + + for (is=0; is<IDA_mem->ida_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); + N_VInv(IDA_mem->ida_tempv1, weightS[is]); + } + + return(0); +} + +/* + * IDAQuadSensEwtSet + * + */ + +int IDAQuadSensEwtSet(IDAMem IDA_mem, N_Vector *yQScur, N_Vector *weightQS) +{ + int flag=0; + + switch (IDA_mem->ida_itolQS) { + case IDA_EE: + flag = IDAQuadSensEwtSetEE(IDA_mem, yQScur, weightQS); + break; + case IDA_SS: + flag = IDAQuadSensEwtSetSS(IDA_mem, yQScur, weightQS); + break; + case IDA_SV: + flag = IDAQuadSensEwtSetSV(IDA_mem, yQScur, weightQS); + break; + } + + return(flag); +} + +/* + * IDAQuadSensEwtSetEE + * + * In this case, the error weight vector for the i-th quadrature sensitivity + * is set to + * + * ewtQS_i = pbar_i * IDAQuadEwtSet(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 IDAQuadSensEwtSetEE(IDAMem IDA_mem, N_Vector *yQScur, N_Vector *weightQS) +{ + int is; + N_Vector pyS; + int flag; + + /* Use tempvQS[0] as temporary storage for the scaled sensitivity */ + pyS = IDA_mem->ida_tempvQS[0]; + + for (is=0; is<IDA_mem->ida_Ns; is++) { + N_VScale(IDA_mem->ida_pbar[is], yQScur[is], pyS); + flag = IDAQuadEwtSet(IDA_mem, pyS, weightQS[is]); + if (flag != 0) return(-1); + N_VScale(IDA_mem->ida_pbar[is], weightQS[is], weightQS[is]); + } + + return(0); +} + +static int IDAQuadSensEwtSetSS(IDAMem IDA_mem, N_Vector *yQScur, N_Vector *weightQS) +{ + int is; + N_Vector tempvQ; + + /* Use ypQ as temporary storage */ + tempvQ = IDA_mem->ida_ypQ; + + for (is=0; is<IDA_mem->ida_Ns; is++) { + 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); + N_VInv(tempvQ, weightQS[is]); + } + + return(0); +} + +static int IDAQuadSensEwtSetSV(IDAMem IDA_mem, N_Vector *yQScur, N_Vector *weightQS) +{ + int is; + N_Vector tempvQ; + + /* Use ypQ as temporary storage */ + tempvQ = IDA_mem->ida_ypQ; + + for (is=0; is<IDA_mem->ida_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); + N_VInv(tempvQ, weightQS[is]); + } + + return(0); +} + + +/* + * ----------------------------------------------------------------- + * Stopping tests + * ----------------------------------------------------------------- + */ + +/* + * IDAStopTest1 + * + * This routine tests for stop conditions before taking a step. + * The tests depend on the value of itask. + * The variable tretlast is the previously returned value of tret. + * + * The return values are: + * 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 + * + * 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, + N_Vector yret, N_Vector ypret, int itask) +{ + int ier; + realtype troundoff; + + switch (itask) { + + case IDA_NORMAL: + + 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); + return(IDA_ILL_INPUT); + } + } + + /* Test for tout = tretlast, and for tn past tout. */ + if (tout == IDA_mem->ida_tretlast) { + *tret = IDA_mem->ida_tretlast = tout; + return(IDA_SUCCESS); + } + if ((IDA_mem->ida_tn - tout)*IDA_mem->ida_hh >= ZERO) { + ier = IDAGetSolution(IDA_mem, tout, yret, ypret); + if (ier != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASolve", MSG_BAD_TOUT, tout); + return(IDA_ILL_INPUT); + } + *tret = IDA_mem->ida_tretlast = tout; + return(IDA_SUCCESS); + } + + if (IDA_mem->ida_tstopset) { + troundoff = HUNDRED * IDA_mem->ida_uround * (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)); + 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); + return(IDA_ILL_INPUT); + } + *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tstop; + 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) + 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) { + /* 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); + return(IDA_ILL_INPUT); + } + } + + /* Test for tn past tretlast. */ + if ((IDA_mem->ida_tn - IDA_mem->ida_tretlast)*IDA_mem->ida_hh > ZERO) { + ier = IDAGetSolution(IDA_mem, IDA_mem->ida_tn, yret, ypret); + *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tn; + return(IDA_SUCCESS); + } + + if (IDA_mem->ida_tstopset) { + troundoff = HUNDRED * IDA_mem->ida_uround * (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)); + 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); + return(IDA_ILL_INPUT); + } + *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tstop; + 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) + 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. */ +} + +/* + * IDAStopTest2 + * + * This routine tests for stop conditions after taking a step. + * The tests depend on the value of itask. + * + * The return values are: + * 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 + * + * In the two cases with tstop, this routine may reset the stepsize hh + * to cause the next step to reach tstop exactly. + * + * In the two cases with ONE_STEP mode, no interpolation to tn is needed + * because yret and ypret already contain the current y and y' values. + * + * Note: No test is made for an error return from IDAGetSolution here, + * because the same test was made prior to the step. + */ + +static int IDAStopTest2(IDAMem IDA_mem, realtype tout, realtype *tret, + N_Vector yret, N_Vector ypret, int itask) +{ + /* int ier; */ + realtype troundoff; + + switch (itask) { + + case IDA_NORMAL: + + /* Test for tn past tout. */ + if ((IDA_mem->ida_tn - tout)*IDA_mem->ida_hh >= ZERO) { + /* ier = */ IDAGetSolution(IDA_mem, tout, yret, ypret); + *tret = IDA_mem->ida_tretlast = tout; + return(IDA_SUCCESS); + } + + if (IDA_mem->ida_tstopset) { + /* Test for tn at tstop and for tn near tstop */ + troundoff = HUNDRED * IDA_mem->ida_uround * (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)); + if (SUNRabs(IDA_mem->ida_tn - IDA_mem->ida_tstop) <= troundoff) { + /* ier = */ IDAGetSolution(IDA_mem, IDA_mem->ida_tstop, yret, ypret); + *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tstop; + 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) + 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) { + /* Test for tn at tstop and for tn near tstop */ + troundoff = HUNDRED * IDA_mem->ida_uround * (SUNRabs(IDA_mem->ida_tn) + SUNRabs(IDA_mem->ida_hh)); + if (SUNRabs(IDA_mem->ida_tn - IDA_mem->ida_tstop) <= troundoff) { + /* ier = */ IDAGetSolution(IDA_mem, IDA_mem->ida_tstop, yret, ypret); + *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tstop; + 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) + IDA_mem->ida_hh = (IDA_mem->ida_tstop - IDA_mem->ida_tn)*(ONE - FOUR * IDA_mem->ida_uround); + } + + *tret = IDA_mem->ida_tretlast = IDA_mem->ida_tn; + return(IDA_SUCCESS); + + } + return IDA_ILL_INPUT; /* This return should never happen. */ +} + +/* + * ----------------------------------------------------------------- + * Error handler + * ----------------------------------------------------------------- + */ + +/* + * IDAHandleFailure + * + * This routine prints error messages for all cases of failure by + * IDAStep. It returns to IDASolve the value that it is to return to + * the user. + */ + +static int IDAHandleFailure(IDAMem IDA_mem, int sflag) +{ + /* Depending on sflag, print error message and return error flag */ + 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); + 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); + return(IDA_CONV_FAIL); + + 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); + 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); + return(IDA_REP_RES_ERR); + + 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); + return(IDA_CONSTR_FAIL); + + case IDA_MEM_NULL: + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASolve", MSG_NO_MEM); + return(IDA_MEM_NULL); + + case SUN_NLS_MEM_NULL: + IDAProcessError(IDA_mem, IDA_MEM_NULL, "IDA", "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", + MSG_NLS_SETUP_FAILED, IDA_mem->ida_tn); + return(IDA_NLS_SETUP_FAIL); + } + + /* This return should never happen */ + IDAProcessError(IDA_mem, IDA_UNRECOGNIZED_ERROR, "IDA", "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 + * ----------------------------------------------------------------- + */ + +/* + * IDAStep + * + * This routine performs one internal IDA step, from tn to tn + hh. + * It calls other routines to do all the work. + * + * It solves a system of differential/algebraic equations of the form + * F(t,y,y') = 0, for one step. In IDA, tt is used for t, + * 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 + * coefficient forms of backward differentiation formulas. + * The code adjusts the stepsize and order to control the local error per step. + * + * The main operations done here are as follows: + * * initialize various quantities; + * * setting of multistep method coefficients; + * * solution of the nonlinear system for yy at t = tn + hh; + * * deciding on order reduction and testing the local error; + * * attempting to recover from failure in nonlinear solver or error test; + * * resetting stepsize and order for the next step. + * * updating phi and other state data if successful; + * + * On a failure in the nonlinear system solution or error test, the + * step may be reattempted, depending on the nature of the failure. + * + * Variables or arrays (all in the IDAMem structure) used in IDAStep are: + * + * 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 + * 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. + * 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 + * 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 + */ + +static int IDAStep(IDAMem IDA_mem) +{ + realtype saved_t, ck; + realtype err_k, err_km1, err_km2; + int ncf, nef; + int nflag, kflag; + int retval; + booleantype sensi_stg, sensi_sim; + + /* Are we computing sensitivities with the staggered or simultaneous approach? */ + sensi_stg = (IDA_mem->ida_sensi && (IDA_mem->ida_ism==IDA_STAGGERED)); + sensi_sim = (IDA_mem->ida_sensi && (IDA_mem->ida_ism==IDA_SIMULTANEOUS)); + + saved_t = IDA_mem->ida_tn; + ncf = nef = 0; + + if (IDA_mem->ida_nst == ZERO){ + IDA_mem->ida_kk = 1; + IDA_mem->ida_kused = 0; + IDA_mem->ida_hused = ZERO; + IDA_mem->ida_psi[0] = IDA_mem->ida_hh; + IDA_mem->ida_cj = ONE/IDA_mem->ida_hh; + IDA_mem->ida_phase = 0; + IDA_mem->ida_ns = 0; + } + + /* To prevent 'unintialized variable' warnings */ + err_k = ZERO; + err_km1 = ZERO; + err_km2 = ZERO; + + /* Looping point for attempts to take a step */ + + for(;;) { + + /*----------------------- + Set method coefficients + -----------------------*/ + + IDASetCoeffs(IDA_mem, &ck); + + kflag = IDA_SUCCESS; + + /*---------------------------------------------------- + If tn is past tstop (by roundoff), reset it to tstop. + -----------------------------------------------------*/ + + IDA_mem->ida_tn = IDA_mem->ida_tn + IDA_mem->ida_hh; + if (IDA_mem->ida_tstopset) { + if ((IDA_mem->ida_tn - IDA_mem->ida_tstop)*IDA_mem->ida_hh > ZERO) + IDA_mem->ida_tn = IDA_mem->ida_tstop; + } + + /*----------------------- + Advance state variables + -----------------------*/ + + /* Compute predicted values for yy and yp */ + IDAPredict(IDA_mem); + + /* Compute predicted values for yyS and ypS (if simultaneous approach) */ + if (sensi_sim) + IDASensPredict(IDA_mem, IDA_mem->ida_yySpredict, IDA_mem->ida_ypSpredict); + + /* Nonlinear system solution */ + nflag = IDANls(IDA_mem); + + /* If NLS was successful, perform error test */ + if (nflag == IDA_SUCCESS) + nflag = IDATestError(IDA_mem, ck, &err_k, &err_km1, &err_km2); + + /* Test for convergence or error test failures */ + if (nflag != IDA_SUCCESS) { + + /* restore and decide what to do */ + IDARestore(IDA_mem, saved_t); + kflag = IDAHandleNFlag(IDA_mem, nflag, err_k, err_km1, + &(IDA_mem->ida_ncfn), &ncf, + &(IDA_mem->ida_netf), &nef); + + /* exit on nonrecoverable failure */ + if (kflag != PREDICT_AGAIN) return(kflag); + + /* recoverable error; predict again */ + if(IDA_mem->ida_nst==0) IDAReset(IDA_mem); + continue; + + } + + /*---------------------------- + Advance quadrature variables + ----------------------------*/ + if (IDA_mem->ida_quadr) { + + nflag = IDAQuadNls(IDA_mem); + + /* If NLS was successful, perform error test */ + if (IDA_mem->ida_errconQ && (nflag == IDA_SUCCESS)) + nflag = IDAQuadTestError(IDA_mem, ck, &err_k, &err_km1, &err_km2); + + /* Test for convergence or error test failures */ + if (nflag != IDA_SUCCESS) { + + /* restore and decide what to do */ + IDARestore(IDA_mem, saved_t); + kflag = IDAHandleNFlag(IDA_mem, nflag, err_k, err_km1, + &(IDA_mem->ida_ncfnQ), &ncf, + &(IDA_mem->ida_netfQ), &nef); + + /* exit on nonrecoverable failure */ + if (kflag != PREDICT_AGAIN) return(kflag); + + /* recoverable error; predict again */ + if(IDA_mem->ida_nst==0) IDAReset(IDA_mem); + continue; + } + } + + /*-------------------------------------------------- + Advance sensitivity variables (Staggered approach) + --------------------------------------------------*/ + 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 + attempt the step again */ + + retval = IDA_mem->ida_res(IDA_mem->ida_tn, + IDA_mem->ida_yy, IDA_mem->ida_yp, + IDA_mem->ida_delta, IDA_mem->ida_user_data); + + 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); + + /* Test for convergence or error test failures */ + if (nflag != IDA_SUCCESS) { + + /* restore and decide what to do */ + IDARestore(IDA_mem, saved_t); + kflag = IDAHandleNFlag(IDA_mem, nflag, err_k, err_km1, + &(IDA_mem->ida_ncfnQ), &ncf, + &(IDA_mem->ida_netfQ), &nef); + + /* exit on nonrecoverable failure */ + if (kflag != PREDICT_AGAIN) return(kflag); + + /* recoverable error; predict again */ + if(IDA_mem->ida_nst==0) IDAReset(IDA_mem); + continue; + } + } + + /*------------------------------------------- + Advance quadrature sensitivity variables + -------------------------------------------*/ + if (IDA_mem->ida_quadr_sensi) { + + nflag = IDAQuadSensNls(IDA_mem); + + /* If NLS was successful, perform error test */ + if (IDA_mem->ida_errconQS && (nflag == IDA_SUCCESS)) + nflag = IDAQuadSensTestError(IDA_mem, ck, &err_k, &err_km1, &err_km2); + + /* Test for convergence or error test failures */ + if (nflag != IDA_SUCCESS) { + + /* restore and decide what to do */ + IDARestore(IDA_mem, saved_t); + kflag = IDAHandleNFlag(IDA_mem, nflag, err_k, err_km1, + &(IDA_mem->ida_ncfnQ), &ncf, + &(IDA_mem->ida_netfQ), &nef); + + /* exit on nonrecoverable failure */ + if (kflag != PREDICT_AGAIN) return(kflag); + + /* recoverable error; predict again */ + if(IDA_mem->ida_nst==0) IDAReset(IDA_mem); + continue; + } + } + + /* 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 */ + + 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 + it will be overwritten by + IDASolve()->IDAStep()->IDANls() + 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); + + 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 + * with ns = k + 2, the coefficients alpha, etc. need not be reset here. + * Also, IDACompleteStep prohibits an order increase until ns = k + 2. + */ + +static void IDASetCoeffs(IDAMem IDA_mem, realtype *ck) +{ + int i, j, is; + realtype temp1, temp2, alpha0, alphas; + + /* Set coefficients for the current stepsize h */ + + 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) { + 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++){ + 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_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; + } + /* compute alphas, alpha0 */ + alphas = ZERO; + alpha0 = ZERO; + for(i=0;i<IDA_mem->ida_kk;i++){ + alphas = alphas - ONE/(i+1); + alpha0 = alpha0 - IDA_mem->ida_alpha[i]; + } + + /* 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) { + + 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]; + + (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); + + if (IDA_mem->ida_quadr) + (void) N_VScaleVectorArray(IDA_mem->ida_kk - IDA_mem->ida_ns + 1, + IDA_mem->ida_cvals, + IDA_mem->ida_phiQ+IDA_mem->ida_ns, + IDA_mem->ida_phiQ+IDA_mem->ida_ns); + + if (IDA_mem->ida_sensi || IDA_mem->ida_quadr_sensi) { + j = 0; + for(i=IDA_mem->ida_ns; i<=IDA_mem->ida_kk; i++) { + for(is=0; is<IDA_mem->ida_Ns; is++) { + IDA_mem->ida_cvals[j] = IDA_mem->ida_beta[i]; + j++; + } + } + } + + if (IDA_mem->ida_sensi) { + j = 0; + for(i=IDA_mem->ida_ns; i<=IDA_mem->ida_kk; i++) { + for(is=0; is<IDA_mem->ida_Ns; is++) { + IDA_mem->ida_Xvecs[j] = IDA_mem->ida_phiS[i][is]; + j++; + } + } + + (void) N_VScaleVectorArray(j, IDA_mem->ida_cvals, IDA_mem->ida_Xvecs, + IDA_mem->ida_Xvecs); + } + + if (IDA_mem->ida_quadr_sensi) { + j = 0; + for(i=IDA_mem->ida_ns; i<=IDA_mem->ida_kk; i++) { + for(is=0; is<IDA_mem->ida_Ns; is++) { + IDA_mem->ida_Xvecs[j] = IDA_mem->ida_phiQS[i][is]; + j++; + } + } + + (void) N_VScaleVectorArray(j, IDA_mem->ida_cvals, IDA_mem->ida_Xvecs, + IDA_mem->ida_Xvecs); + } + } + +} + +/* + * ----------------------------------------------------------------- + * Nonlinear solver functions + * ----------------------------------------------------------------- + */ + +/* + * IDANls + * + * This routine attempts to solve the nonlinear system using the linear + * solver specified. NOTE: this routine uses N_Vector ee as the scratch + * vector tempv3 passed to lsetup. + * + * Possible return values: + * + * IDA_SUCCESS + * + * IDA_RES_RECVR IDA_RES_FAIL + * IDA_SRES_RECVR IDA_SRES_FAIL + * IDA_LSETUP_RECVR IDA_LSETUP_FAIL + * IDA_LSOLVE_RECVR IDA_LSOLVE_FAIL + * + * IDA_CONSTR_RECVR + * SUN_NLS_CONV_RECVR + * IDA_MEM_NULL + */ + +static int IDANls(IDAMem IDA_mem) +{ + int retval; + booleantype constraintsPassed, callLSetup, sensi_sim; + realtype temp1, temp2, vnorm; + + /* Are we computing sensitivities with the IDA_SIMULTANEOUS approach? */ + sensi_sim = (IDA_mem->ida_sensi && (IDA_mem->ida_ism==IDA_SIMULTANEOUS)); + + callLSetup = SUNFALSE; + + /* Initialize if the first time called */ + + if (IDA_mem->ida_nst == 0){ + IDA_mem->ida_cjold = IDA_mem->ida_cj; + IDA_mem->ida_ss = TWENTY; + IDA_mem->ida_ssS = TWENTY; + if (IDA_mem->ida_lsetup) callLSetup = SUNTRUE; + } + + /* Decide if lsetup is to be called */ + + if (IDA_mem->ida_lsetup) { + IDA_mem->ida_cjratio = IDA_mem->ida_cj / IDA_mem->ida_cjold; + temp1 = (ONE - XRATE) / (ONE + XRATE); + 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;} + } + + /* initial guess for the correction to the predictor */ + if (sensi_sim) + N_VConst(ZERO, IDA_mem->ycor0Sim); + else + N_VConst(ZERO, IDA_mem->ida_delta); + + /* 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); + else + retval = SUNNonlinSolSetup(IDA_mem->NLS, IDA_mem->ida_delta, IDA_mem); + + if (retval < 0) return(IDA_NLS_SETUP_FAIL); + if (retval > 0) return(IDA_NLS_SETUP_RECVR); + } + + /* solve the nonlinear system */ + if (sensi_sim) + retval = SUNNonlinSolSolve(IDA_mem->NLSsim, + IDA_mem->ycor0Sim, 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_ewt, IDA_mem->ida_epsNewt, + callLSetup, IDA_mem); + + /* update the state using 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); + + /* update the sensitivities based on the final correction from the nonlinear solver */ + if (sensi_sim) { + N_VLinearSumVectorArray(IDA_mem->ida_Ns, + ONE, IDA_mem->ida_yySpredict, + ONE, IDA_mem->ida_eeS, IDA_mem->ida_yyS); + N_VLinearSumVectorArray(IDA_mem->ida_Ns, + ONE, IDA_mem->ida_ypSpredict, + IDA_mem->ida_cj, IDA_mem->ida_eeS, IDA_mem->ida_ypS); + } + + /* return if nonlinear solver failed */ + if (retval != IDA_SUCCESS) return(retval); + + /* 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 (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); + } + } + } + + return(IDA_SUCCESS); +} + + +/* + * IDAPredict + * + * This routine predicts the new values for vectors yy and yp. + */ + +static void IDAPredict(IDAMem IDA_mem) +{ + int j; + + for(j=0; j<=IDA_mem->ida_kk; j++) + IDA_mem->ida_cvals[j] = ONE; + + (void) N_VLinearCombination(IDA_mem->ida_kk+1, IDA_mem->ida_cvals, + IDA_mem->ida_phi, IDA_mem->ida_yypredict); + + (void) N_VLinearCombination(IDA_mem->ida_kk, IDA_mem->ida_gamma+1, + IDA_mem->ida_phi+1, IDA_mem->ida_yppredict); +} + +/* + * 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 + * uniformity purposes. + * + */ + +static int IDAQuadNls(IDAMem IDA_mem) +{ + int retval; + + /* 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, + IDA_mem->ida_user_data); + IDA_mem->ida_nrQe++; + if (retval < 0) return(IDA_QRHS_FAIL); + else if (retval > 0) return(IDA_QRHS_RECVR); + + if (IDA_mem->ida_quadr_sensi) + N_VScale(ONE, IDA_mem->ida_eeQ, IDA_mem->ida_savrhsQ); + + N_VLinearSum(ONE, IDA_mem->ida_eeQ, -ONE, IDA_mem->ida_ypQ, IDA_mem->ida_eeQ); + N_VScale(ONE/IDA_mem->ida_cj, IDA_mem->ida_eeQ, IDA_mem->ida_eeQ); + + /* Apply correction: yyQ = yyQ + eeQ */ + N_VLinearSum(ONE, IDA_mem->ida_yyQ, ONE, IDA_mem->ida_eeQ, IDA_mem->ida_yyQ); + + return(IDA_SUCCESS); +} + +/* + * IDAQuadPredict + * + * This routine predicts the new value for vectors yyQ and ypQ + */ + +static void IDAQuadPredict(IDAMem IDA_mem) +{ + int j; + + for(j=0; j<=IDA_mem->ida_kk; j++) + IDA_mem->ida_cvals[j] = ONE; + + (void) N_VLinearCombination(IDA_mem->ida_kk+1, IDA_mem->ida_cvals, + IDA_mem->ida_phiQ, IDA_mem->ida_yyQ); + + (void) N_VLinearCombination(IDA_mem->ida_kk, IDA_mem->ida_gamma+1, + IDA_mem->ida_phiQ+1, IDA_mem->ida_ypQ); + +} + +/* + * IDASensNls + * + * This routine attempts to solve, one by one, all the sensitivity + * linear systems using nonlinear iterations and the linear solver + * specified (Staggered approach). + */ + +static int IDASensNls(IDAMem IDA_mem) +{ + booleantype callLSetup; + int retval; + + callLSetup = SUNFALSE; + + /* initial guess for the correction to the predictor */ + N_VConst(ZERO, IDA_mem->ycor0Stg); + + /* solve the nonlinear system */ + retval = SUNNonlinSolSolve(IDA_mem->NLSstg, + IDA_mem->ycor0Stg, IDA_mem->ycorStg, + IDA_mem->ewtStg, IDA_mem->ida_epsNewt, + callLSetup, IDA_mem); + + /* update using the final correction from the nonlinear solver */ + N_VLinearSumVectorArray(IDA_mem->ida_Ns, + ONE, IDA_mem->ida_yySpredict, + ONE, IDA_mem->ida_eeS, IDA_mem->ida_yyS); + N_VLinearSumVectorArray(IDA_mem->ida_Ns, + ONE, IDA_mem->ida_ypSpredict, + IDA_mem->ida_cj, IDA_mem->ida_eeS, IDA_mem->ida_ypS); + + if (retval != IDA_SUCCESS) + IDA_mem->ida_ncfnS++; + + return(retval); + +} + +/* + * IDASensPredict + * + * 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] + */ + +static void IDASensPredict(IDAMem IDA_mem, N_Vector *yySens, N_Vector *ypSens) +{ + int j; + + for(j=0; j<=IDA_mem->ida_kk; j++) + IDA_mem->ida_cvals[j] = ONE; + + (void) N_VLinearCombinationVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_kk+1, + IDA_mem->ida_cvals, + IDA_mem->ida_phiS, yySens); + + (void) N_VLinearCombinationVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_kk, + IDA_mem->ida_gamma+1, + IDA_mem->ida_phiS+1, 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 + * uniformity purposes. + * + */ + +static int IDAQuadSensNls(IDAMem IDA_mem) +{ + int retval; + N_Vector *ypQS; + + /* 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); + + /* Compute correction eeQS */ + retval = IDA_mem->ida_rhsQS(IDA_mem->ida_Ns, IDA_mem->ida_tn, + IDA_mem->ida_yy, IDA_mem->ida_yp, + IDA_mem->ida_yyS, IDA_mem->ida_ypS, + IDA_mem->ida_savrhsQ, IDA_mem->ida_eeQS, + IDA_mem->ida_user_dataQS, IDA_mem->ida_tmpS1, + IDA_mem->ida_tmpS2, IDA_mem->ida_tmpS3); + IDA_mem->ida_nrQSe++; + + if (retval < 0) return(IDA_QSRHS_FAIL); + else if (retval > 0) return(IDA_QSRHS_RECVR); + + retval = N_VLinearSumVectorArray(IDA_mem->ida_Ns, + ONE/IDA_mem->ida_cj, IDA_mem->ida_eeQS, + -ONE/IDA_mem->ida_cj, ypQS, + IDA_mem->ida_eeQS); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + /* Apply correction: yyQS[is] = yyQ[is] + eeQ[is] */ + retval = N_VLinearSumVectorArray(IDA_mem->ida_Ns, + ONE, IDA_mem->ida_yyQS, + ONE, IDA_mem->ida_eeQS, + IDA_mem->ida_yyQS); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + return(IDA_SUCCESS); +} + +/* + * IDAQuadSensPredict + * + * This routine predicts the new value for vectors yyQS and ypQS + */ + +static void IDAQuadSensPredict(IDAMem IDA_mem, N_Vector *yQS, N_Vector *ypQS) +{ + int j; + + for(j=0; j<=IDA_mem->ida_kk; j++) + IDA_mem->ida_cvals[j] = ONE; + + (void) N_VLinearCombinationVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_kk+1, + IDA_mem->ida_cvals, + IDA_mem->ida_phiQS, yQS); + + (void) N_VLinearCombinationVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_kk, + IDA_mem->ida_gamma+1, + IDA_mem->ida_phiQS+1, ypQS); + +} + + +/* + * ----------------------------------------------------------------- + * Error test + * ----------------------------------------------------------------- + */ + +/* + * 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. + * + * IDATestError returns either IDA_SUCCESS or ERROR_TEST_FAIL. + */ + +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); + + 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; + 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 */ + + 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 */ + + if (terr_km1 <= (HALF * terr_k) ) + 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. + * + * 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, + realtype *err_k, realtype *err_km1, realtype *err_km2) +{ + realtype enormQ; + realtype errQ_k, errQ_km1, errQ_km2; + realtype terr_k, terr_km1, terr_km2; + N_Vector tempv; + booleantype check_for_reduction = SUNFALSE; + + /* Rename ypQ */ + tempv = IDA_mem->ida_ypQ; + + /* Update error for order k. */ + enormQ = N_VWrmsNorm(IDA_mem->ida_eeQ, IDA_mem->ida_ewtQ); + errQ_k = IDA_mem->ida_sigma[IDA_mem->ida_kk] * enormQ; + if (errQ_k > *err_k) { + *err_k = errQ_k; + 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); + if (errQ_km1 > *err_km1) { + *err_km1 = errQ_km1; + check_for_reduction = SUNTRUE; + } + terr_km1 = IDA_mem->ida_kk * (*err_km1); + + /* Has an order decrease already been decided in IDATestError? */ + if (IDA_mem->ida_knew != IDA_mem->ida_kk) + check_for_reduction = SUNFALSE; + + if (check_for_reduction) { + + if ( IDA_mem->ida_kk > 2 ) { + + /* Update error at order k-2 */ + N_VLinearSum(ONE, IDA_mem->ida_phiQ[IDA_mem->ida_kk-1], ONE, tempv, tempv); + errQ_km2 = IDA_mem->ida_sigma[IDA_mem->ida_kk-2] * N_VWrmsNorm(tempv, IDA_mem->ida_ewtQ); + if (errQ_km2 > *err_km2) { + *err_km2 = errQ_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 { + + /* 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; + + } + + } + + } + + /* Perform error test */ + if (ck * enormQ > ONE) return(ERROR_TEST_FAIL); + else return(IDA_SUCCESS); + +} + +/* + * 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, + * and performs the local error test. (Used only in staggered approach). + * + * 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, + realtype *err_k, realtype *err_km1, realtype *err_km2) +{ + realtype enormS; + realtype errS_k, errS_km1, errS_km2; + realtype terr_k, terr_km1, terr_km2; + N_Vector *tempv; + booleantype check_for_reduction = SUNFALSE; + int retval; + + /* Rename deltaS */ + tempv = IDA_mem->ida_deltaS; + + /* Update error for order k. */ + enormS = IDASensWrmsNorm(IDA_mem, IDA_mem->ida_eeS, IDA_mem->ida_ewtS, IDA_mem->ida_suppressalg); + errS_k = IDA_mem->ida_sigma[IDA_mem->ida_kk] * enormS; + if (errS_k > *err_k) { + *err_k = errS_k; + 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], + ONE, IDA_mem->ida_eeS, tempv); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + errS_km1 = IDA_mem->ida_sigma[IDA_mem->ida_kk-1] * + IDASensWrmsNorm(IDA_mem, tempv, IDA_mem->ida_ewtS, IDA_mem->ida_suppressalg); + + if (errS_km1 > *err_km1) { + *err_km1 = errS_km1; + check_for_reduction = SUNTRUE; + } + terr_km1 = IDA_mem->ida_kk * (*err_km1); + + /* Has an order decrease already been decided in IDATestError? */ + if (IDA_mem->ida_knew != IDA_mem->ida_kk) + check_for_reduction = SUNFALSE; + + if (check_for_reduction) { + + if ( IDA_mem->ida_kk > 2 ) { + + /* Update error at order k-2 */ + retval = N_VLinearSumVectorArray(IDA_mem->ida_Ns, + ONE, IDA_mem->ida_phiS[IDA_mem->ida_kk-1], + ONE, tempv, tempv); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + errS_km2 = IDA_mem->ida_sigma[IDA_mem->ida_kk-2] * + IDASensWrmsNorm(IDA_mem, tempv, IDA_mem->ida_ewtS, IDA_mem->ida_suppressalg); + + if (errS_km2 > *err_km2) { + *err_km2 = errS_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 { + + /* 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; + + } + + } + + } + + /* Perform error test */ + if (ck * enormS > ONE) return(ERROR_TEST_FAIL); + else return(IDA_SUCCESS); + +} + +/* + * 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 + * only in staggered approach). + * + * 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, + realtype *err_k, realtype *err_km1, realtype *err_km2) +{ + realtype enormQS; + realtype errQS_k, errQS_km1, errQS_km2; + realtype terr_k, terr_km1, terr_km2; + N_Vector *tempv; + booleantype check_for_reduction = SUNFALSE; + int retval; + + tempv = IDA_mem->ida_yyQS; + + enormQS = IDAQuadSensWrmsNorm(IDA_mem, IDA_mem->ida_eeQS, IDA_mem->ida_ewtQS); + errQS_k = IDA_mem->ida_sigma[IDA_mem->ida_kk] * enormQS; + + if (errQS_k > *err_k) { + *err_k = errQS_k; + 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], + ONE, IDA_mem->ida_eeQS, tempv); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + errQS_km1 = IDA_mem->ida_sigma[IDA_mem->ida_kk-1] * + IDAQuadSensWrmsNorm(IDA_mem, tempv, IDA_mem->ida_ewtQS); + + if (errQS_km1 > *err_km1) { + *err_km1 = errQS_km1; + check_for_reduction = SUNTRUE; + } + terr_km1 = IDA_mem->ida_kk * (*err_km1); + + /* Has an order decrease already been decided in IDATestError? */ + if (IDA_mem->ida_knew != IDA_mem->ida_kk) + check_for_reduction = SUNFALSE; + + if (check_for_reduction) { + if ( IDA_mem->ida_kk > 2 ) { + + /* Update error at order k-2 */ + retval = N_VLinearSumVectorArray(IDA_mem->ida_Ns, + ONE, IDA_mem->ida_phiQS[IDA_mem->ida_kk-1], + ONE, tempv, tempv); + if (retval != IDA_SUCCESS) return (IDA_VECTOROP_ERR); + + errQS_km2 = IDA_mem->ida_sigma[IDA_mem->ida_kk-2] * + IDAQuadSensWrmsNorm(IDA_mem, tempv, IDA_mem->ida_ewtQS); + + if (errQS_km2 > *err_km2) { + *err_km2 = errQS_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 { + /* 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; + } + } + } + + /* Perform error test */ + if (ck * enormQS > ONE) return(ERROR_TEST_FAIL); + else return(IDA_SUCCESS); +} +/* + * IDARestore + * + * This routine restores IDA_mem->ida_tn, psi, and phi in the event of a failure. + * It changes back phi-star to phi (changed in IDASetCoeffs) + */ + +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++) + 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, + IDA_mem->ida_cvals, + IDA_mem->ida_phi+IDA_mem->ida_ns, + IDA_mem->ida_phi+IDA_mem->ida_ns); + + if (IDA_mem->ida_quadr) + (void) N_VScaleVectorArray(IDA_mem->ida_kk - IDA_mem->ida_ns + 1, + IDA_mem->ida_cvals, + IDA_mem->ida_phiQ+IDA_mem->ida_ns, + IDA_mem->ida_phiQ+IDA_mem->ida_ns); + + if (IDA_mem->ida_sensi || IDA_mem->ida_quadr_sensi) { + j = 0; + for(i=IDA_mem->ida_ns; i<=IDA_mem->ida_kk; i++) { + for(is=0; is<IDA_mem->ida_Ns; is++) { + IDA_mem->ida_cvals[j] = ONE/IDA_mem->ida_beta[i]; + j++; + } + } + } + + if (IDA_mem->ida_sensi) { + j = 0; + for(i=IDA_mem->ida_ns; i<=IDA_mem->ida_kk; i++) { + for(is=0; is<IDA_mem->ida_Ns; is++) { + IDA_mem->ida_Xvecs[j] = IDA_mem->ida_phiS[i][is]; + j++; + } + } + + (void) N_VScaleVectorArray(j, IDA_mem->ida_cvals, IDA_mem->ida_Xvecs, + IDA_mem->ida_Xvecs); + } + + if (IDA_mem->ida_quadr_sensi) { + j = 0; + for(i=IDA_mem->ida_ns; i<=IDA_mem->ida_kk; i++) { + for(is=0; is<IDA_mem->ida_Ns; is++) { + IDA_mem->ida_Xvecs[j] = IDA_mem->ida_phiQS[i][is]; + j++; + } + } + + (void) N_VScaleVectorArray(j, IDA_mem->ida_cvals, IDA_mem->ida_Xvecs, + IDA_mem->ida_Xvecs); + } + } + +} + +/* + * ----------------------------------------------------------------- + * Handler for convergence and/or error test failures + * ----------------------------------------------------------------- + */ + +/* + * IDAHandleNFlag + * + * 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. + * + * Possible nflag values (input): + * + * --convergence failures-- + * IDA_RES_RECVR > 0 + * IDA_LSOLVE_RECVR > 0 + * IDA_CONSTR_RECVR > 0 + * SUN_NLS_CONV_RECVR > 0 + * IDA_QRHS_RECVR > 0 + * IDA_QSRHS_RECVR > 0 + * IDA_RES_FAIL < 0 + * IDA_LSOLVE_FAIL < 0 + * IDA_LSETUP_FAIL < 0 + * IDA_QRHS_FAIL < 0 + * + * --error test failure-- + * ERROR_TEST_FAIL > 0 + * + * Possible kflag values (output): + * + * --recoverable-- + * PREDICT_AGAIN + * + * --nonrecoverable-- + * IDA_CONSTR_FAIL + * IDA_REP_RES_ERR + * IDA_ERR_FAIL + * IDA_CONV_FAIL + * IDA_RES_FAIL + * IDA_LSETUP_FAIL + * IDA_LSOLVE_FAIL + * IDA_QRHS_FAIL + * IDA_REP_QRHS_ERR + */ + +static int IDAHandleNFlag(IDAMem IDA_mem, int nflag, realtype err_k, realtype err_km1, + long int *ncfnPtr, int *ncfPtr, long int *netfPtr, int *nefPtr) +{ + realtype err_knew; + + IDA_mem->ida_phase = 1; + + if (nflag != ERROR_TEST_FAIL) { + + /*----------------------- + Nonlinear solver failed + -----------------------*/ + + (*ncfPtr)++; /* local counter for convergence failures */ + (*ncfnPtr)++; /* global counter for convergence failures */ + + if (nflag < 0) { /* nonrecoverable failure */ + + return(nflag); + + } 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; + IDA_mem->ida_hh *= IDA_mem->ida_rr; + + /* 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_QSRHS_RECVR) return(IDA_REP_QSRHS_ERR); + else if (nflag == IDA_CONSTR_RECVR) return(IDA_CONSTR_FAIL); + else return(IDA_CONV_FAIL); + } + + } else { + + /*----------------- + 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. + 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)) ); + 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. + 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; + IDA_mem->ida_rr = QUARTER; + IDA_mem->ida_hh *= IDA_mem->ida_rr; + return(PREDICT_AGAIN); + + } else { + + /* Too many error test failures */ + return(IDA_ERR_FAIL); + + } + + } + +} + +/* + * IDAReset + * + * 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]. + */ + +static void IDAReset(IDAMem IDA_mem) +{ + int is; + + IDA_mem->ida_psi[0] = IDA_mem->ida_hh; + + N_VScale(IDA_mem->ida_rr, IDA_mem->ida_phi[1], IDA_mem->ida_phi[1]); + + if (IDA_mem->ida_quadr) + N_VScale(IDA_mem->ida_rr, IDA_mem->ida_phiQ[1], IDA_mem->ida_phiQ[1]); + + if (IDA_mem->ida_sensi || IDA_mem->ida_quadr_sensi) + for(is=0; is<IDA_mem->ida_Ns; is++) + IDA_mem->ida_cvals[is] = IDA_mem->ida_rr; + + if (IDA_mem->ida_sensi) + (void) N_VScaleVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_cvals, + IDA_mem->ida_phiS[1], IDA_mem->ida_phiS[1]); + + if (IDA_mem->ida_quadr_sensi) + (void) N_VScaleVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_cvals, + IDA_mem->ida_phiQS[1], IDA_mem->ida_phiQS[1]); +} + +/* + * ----------------------------------------------------------------- + * Function called after a successful step + * ----------------------------------------------------------------- + */ + +/* + * IDACompleteStep + * + * 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) +{ + int i, j, is, kdiff, action; + realtype terr_k, terr_km1, terr_kp1; + realtype err_knew, err_kp1; + realtype enorm, tmp, hnew; + N_Vector tempvQ, *tempvS; + + IDA_mem->ida_nst++; + kdiff = IDA_mem->ida_kk - IDA_mem->ida_kused; + 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) || + (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 + 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 + of the neccessary information is available yet. */ + + if (IDA_mem->ida_phase == 0) { + + 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 ) + hnew /= tmp; + IDA_mem->ida_hh = hnew; + } + + } 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;} + + /* 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); + + if (IDA_mem->ida_errconQ) { + tempvQ = IDA_mem->ida_ypQ; + N_VLinearSum (ONE, IDA_mem->ida_eeQ, -ONE, + IDA_mem->ida_phiQ[IDA_mem->ida_kk+1], tempvQ); + enorm = IDAQuadWrmsNormUpdate(IDA_mem, enorm, tempvQ, IDA_mem->ida_ewtQ); + } + + if (IDA_mem->ida_errconS) { + tempvS = IDA_mem->ida_ypS; + + (void) N_VLinearSumVectorArray(IDA_mem->ida_Ns, + ONE, IDA_mem->ida_eeS, + -ONE, IDA_mem->ida_phiS[IDA_mem->ida_kk+1], + tempvS); + + enorm = IDASensWrmsNormUpdate(IDA_mem, enorm, tempvS, + IDA_mem->ida_ewtS, IDA_mem->ida_suppressalg); + } + + if (IDA_mem->ida_errconQS) { + (void) N_VLinearSumVectorArray(IDA_mem->ida_Ns, + ONE, IDA_mem->ida_eeQS, + -ONE, IDA_mem->ida_phiQS[IDA_mem->ida_kk+1], + IDA_mem->ida_tempvQS); + + enorm = IDAQuadSensWrmsNormUpdate(IDA_mem, enorm, + IDA_mem->ida_tempvQS, IDA_mem->ida_ewtQS); + } + 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; + + if (IDA_mem->ida_kk == 1) { + if (terr_kp1 >= HALF * terr_k) {action = MAINTAIN; goto takeaction;} + else {action = RAISE; goto takeaction;} + } 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 {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; } + + /* Compute rr = tentative ratio hnew/hh from error norm. + 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) ) ); + + 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 ) { + 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]); + + if (IDA_mem->ida_quadr) + N_VScale(ONE, IDA_mem->ida_eeQ, IDA_mem->ida_phiQ[IDA_mem->ida_kused+1]); + + if (IDA_mem->ida_sensi || IDA_mem->ida_quadr_sensi) + for (is=0; is<IDA_mem->ida_Ns; is++) + IDA_mem->ida_cvals[is] = ONE; + + if (IDA_mem->ida_sensi) + (void) N_VScaleVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_cvals, + IDA_mem->ida_eeS, + IDA_mem->ida_phiS[IDA_mem->ida_kused+1]); + + if (IDA_mem->ida_quadr_sensi) + (void) N_VScaleVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_cvals, + IDA_mem->ida_eeQS, + IDA_mem->ida_phiQS[IDA_mem->ida_kused+1]); + } + + /* Update phi arrays */ + + /* To update phi arrays compute X += Z where */ + /* X = [ phi[kused], phi[kused-1], phi[kused-2], ... phi[1] ] */ + /* Z = [ ee, phi[kused], phi[kused-1], ... phi[0] ] */ + + IDA_mem->ida_Zvecs[0] = IDA_mem->ida_ee; + IDA_mem->ida_Xvecs[0] = IDA_mem->ida_phi[IDA_mem->ida_kused]; + for (j=1; j<=IDA_mem->ida_kused; j++) { + IDA_mem->ida_Zvecs[j] = IDA_mem->ida_phi[IDA_mem->ida_kused-j+1]; + IDA_mem->ida_Xvecs[j] = IDA_mem->ida_phi[IDA_mem->ida_kused-j]; + } + + (void) N_VLinearSumVectorArray(IDA_mem->ida_kused+1, + ONE, IDA_mem->ida_Xvecs, + ONE, IDA_mem->ida_Zvecs, + IDA_mem->ida_Xvecs); + + if (IDA_mem->ida_quadr) { + + IDA_mem->ida_Zvecs[0] = IDA_mem->ida_eeQ; + IDA_mem->ida_Xvecs[0] = IDA_mem->ida_phiQ[IDA_mem->ida_kused]; + for (j=1; j<=IDA_mem->ida_kused; j++) { + IDA_mem->ida_Zvecs[j] = IDA_mem->ida_phiQ[IDA_mem->ida_kused-j+1]; + IDA_mem->ida_Xvecs[j] = IDA_mem->ida_phiQ[IDA_mem->ida_kused-j]; + } + + (void) N_VLinearSumVectorArray(IDA_mem->ida_kused+1, + ONE, IDA_mem->ida_Xvecs, + ONE, IDA_mem->ida_Zvecs, + IDA_mem->ida_Xvecs); + } + + if (IDA_mem->ida_sensi) { + + i=0; + for (is=0; is<IDA_mem->ida_Ns; is++) { + IDA_mem->ida_Zvecs[i] = IDA_mem->ida_eeS[is]; + IDA_mem->ida_Xvecs[i] = IDA_mem->ida_phiS[IDA_mem->ida_kused][is]; + i++; + for (j=1; j<=IDA_mem->ida_kused; j++) { + IDA_mem->ida_Zvecs[i] = IDA_mem->ida_phiS[IDA_mem->ida_kused-j+1][is]; + IDA_mem->ida_Xvecs[i] = IDA_mem->ida_phiS[IDA_mem->ida_kused-j][is]; + i++; + } + } + + (void) N_VLinearSumVectorArray(IDA_mem->ida_Ns*(IDA_mem->ida_kused+1), + ONE, IDA_mem->ida_Xvecs, + ONE, IDA_mem->ida_Zvecs, + IDA_mem->ida_Xvecs); + } + + if (IDA_mem->ida_quadr_sensi) { + + i=0; + for (is=0; is<IDA_mem->ida_Ns; is++) { + IDA_mem->ida_Zvecs[i] = IDA_mem->ida_eeQS[is]; + IDA_mem->ida_Xvecs[i] = IDA_mem->ida_phiQS[IDA_mem->ida_kused][is]; + i++; + for (j=1; j<=IDA_mem->ida_kused; j++) { + IDA_mem->ida_Zvecs[i] = IDA_mem->ida_phiQS[IDA_mem->ida_kused-j+1][is]; + IDA_mem->ida_Xvecs[i] = IDA_mem->ida_phiQS[IDA_mem->ida_kused-j][is]; + i++; + } + } + + (void) N_VLinearSumVectorArray(IDA_mem->ida_Ns*(IDA_mem->ida_kused+1), + ONE, IDA_mem->ida_Xvecs, + ONE, IDA_mem->ida_Zvecs, + IDA_mem->ida_Xvecs); + } + +} + +/* + * ----------------------------------------------------------------- + * Norm functions + * ----------------------------------------------------------------- + */ + +/* + * IDAWrmsNorm + * + * Returns the WRMS norm of vector x with weights w. + * If mask = SUNTRUE, the weight vector w is masked by id, i.e., + * 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, + booleantype mask) +{ + realtype nrm; + + if (mask) nrm = N_VWrmsNormMask(x, w, IDA_mem->ida_id); + else nrm = N_VWrmsNorm(x, w); + + return(nrm); +} + +/* + * IDASensWrmsNorm + * + * 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]) } + * + * 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. + */ + +realtype IDASensWrmsNorm(IDAMem IDA_mem, N_Vector *xS, N_Vector *wS, + booleantype mask) +{ + int is; + realtype nrm; + + if (mask) + (void) N_VWrmsNormMaskVectorArray(IDA_mem->ida_Ns, xS, wS, + IDA_mem->ida_id, IDA_mem->ida_cvals); + else + (void) N_VWrmsNormVectorArray(IDA_mem->ida_Ns, xS, wS, + IDA_mem->ida_cvals); + + nrm = IDA_mem->ida_cvals[0]; + for (is=1; is<IDA_mem->ida_Ns; is++) + if ( IDA_mem->ida_cvals[is] > nrm ) nrm = IDA_mem->ida_cvals[is]; + + return (nrm); +} + +/* + * IDAQuadSensWrmsNorm + * + * 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]) } + */ + +static realtype IDAQuadSensWrmsNorm(IDAMem IDA_mem, N_Vector *xQS, N_Vector *wQS) +{ + int is; + realtype nrm; + + (void) N_VWrmsNormVectorArray(IDA_mem->ida_Ns, xQS, wQS, + IDA_mem->ida_cvals); + + nrm = IDA_mem->ida_cvals[0]; + for (is=1; is<IDA_mem->ida_Ns; is++) + if ( IDA_mem->ida_cvals[is] > nrm ) nrm = IDA_mem->ida_cvals[is]; + + return (nrm); +} + +/* + * IDAQuadWrmsNormUpdate + * + * Updates the norm old_nrm to account for all quadratures. + */ + +static realtype IDAQuadWrmsNormUpdate(IDAMem IDA_mem, realtype old_nrm, + N_Vector xQ, N_Vector wQ) +{ + realtype qnrm; + + qnrm = N_VWrmsNorm(xQ, wQ); + if (old_nrm > qnrm) return(old_nrm); + else return(qnrm); +} + +/* + * IDASensWrmsNormUpdate + * + * Updates the norm old_nrm to account for all sensitivities. + * + * This function is declared global since it is used for finding + * IC for sensitivities, + */ + +realtype IDASensWrmsNormUpdate(IDAMem IDA_mem, realtype old_nrm, + N_Vector *xS, N_Vector *wS, + 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, + N_Vector *xQS, N_Vector *wQS) +{ + realtype qsnrm; + + qsnrm = IDAQuadSensWrmsNorm(IDA_mem, xQS, wQS); + if (old_nrm > qsnrm) return(old_nrm); + else return(qsnrm); +} + +/* + * ----------------------------------------------------------------- + * Functions for rootfinding + * ----------------------------------------------------------------- + */ + +/* + * IDARcheck1 + * + * This routine completes the initialization of rootfinding memory + * information, and checks whether g has a zero both at and very near + * the initial point of the IVP. + * + * This routine returns an int equal to: + * IDA_RTFUNC_FAIL < 0 if the g function failed, or + * IDA_SUCCESS = 0 otherwise. + */ + +static int IDARcheck1(IDAMem IDA_mem) +{ + int i, retval; + realtype smallh, hratio, tplus; + booleantype zroot; + + 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; + + /* 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], + IDA_mem->ida_glo, IDA_mem->ida_user_data); + IDA_mem->ida_nge = 1; + if (retval != 0) return(IDA_RTFUNC_FAIL); + + zroot = SUNFALSE; + for (i = 0; i < IDA_mem->ida_nrtfn; i++) { + if (SUNRabs(IDA_mem->ida_glo[i]) == ZERO) { + zroot = SUNTRUE; + IDA_mem->ida_gactive[i] = SUNFALSE; + } + } + 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); + 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_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) { + IDA_mem->ida_gactive[i] = SUNTRUE; + IDA_mem->ida_glo[i] = IDA_mem->ida_ghi[i]; + } + } + return(IDA_SUCCESS); +} + +/* + * IDARcheck2 + * + * This routine checks for exact zeros of g at the last root found, + * if the last return was a root. It then checks for a close pair of + * zeros (an error condition), and for a new root at a nearby point. + * The array glo = g(tlo) at the left endpoint of the search interval + * is adjusted if necessary to assure that all g_i are nonzero + * there, before returning to do a root search in the interval. + * + * On entry, tlo = tretlast is the last value of tret returned by + * IDASolve. This may be the previous tn, the previous tout value, + * or the last root location. + * + * This routine returns an int equal to: + * IDA_RTFUNC_FAIL < 0 if the g function failed, or + * CLOSERT = 3 if a close pair of zeros was found, or + * RTFOUND = 1 if a new zero of g was found near tlo, or + * IDA_SUCCESS = 0 otherwise. + */ + +static int IDARcheck2(IDAMem IDA_mem) +{ + int i, retval; + realtype smallh, hratio, tplus; + booleantype zroot; + + 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); + IDA_mem->ida_nge++; + if (retval != 0) return(IDA_RTFUNC_FAIL); + + zroot = SUNFALSE; + for (i = 0; i < IDA_mem->ida_nrtfn; i++) + IDA_mem->ida_iroots[i] = 0; + for (i = 0; i < IDA_mem->ida_nrtfn; i++) { + if (!IDA_mem->ida_gactive[i]) continue; + if (SUNRabs(IDA_mem->ida_glo[i]) == ZERO) { + zroot = SUNTRUE; + IDA_mem->ida_iroots[i] = 1; + } + } + 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; + 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); + } 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_nge++; + if (retval != 0) return(IDA_RTFUNC_FAIL); + + /* Check for close roots (error return), for a new zero at tlo+smallh, + and for a g_i that changed from zero to nonzero. */ + zroot = SUNFALSE; + 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_iroots[i] == 1) return(CLOSERT); + zroot = SUNTRUE; + IDA_mem->ida_iroots[i] = 1; + } else { + if (IDA_mem->ida_iroots[i] == 1) + IDA_mem->ida_glo[i] = IDA_mem->ida_ghi[i]; + } + } + if (zroot) return(RTFOUND); + return(IDA_SUCCESS); +} + +/* + * IDARcheck3 + * + * This routine interfaces to IDARootfind to look for a root of g + * between tlo and either tn or tout, whichever comes first. + * Only roots beyond tlo in the direction of integration are sought. + * + * This routine returns an int equal to: + * IDA_RTFUNC_FAIL < 0 if the g function failed, or + * RTFOUND = 1 if a root of g was found, or + * IDA_SUCCESS = 0 otherwise. + */ + +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_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; + } + + /* Get y and y' at thi. */ + (void) IDAGetSolution(IDA_mem, IDA_mem->ida_thi, IDA_mem->ida_yy, IDA_mem->ida_yp); + + + /* 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_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; + ier = IDARootfind(IDA_mem); + if (ier == IDA_RTFUNC_FAIL) return(IDA_RTFUNC_FAIL); + for(i=0; i<IDA_mem->ida_nrtfn; i++) { + 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 (ier == IDA_SUCCESS) return(IDA_SUCCESS); + + /* If a root was found, interpolate to get y(trout) and return. */ + (void) IDAGetSolution(IDA_mem, IDA_mem->ida_trout, IDA_mem->ida_yy, IDA_mem->ida_yp); + return(RTFOUND); +} + +/* + * IDARootfind + * + * This routine solves for a root of g(t) between tlo and thi, if + * one exists. Only roots of odd multiplicity (i.e. with a change + * of sign in one of the g_i), or exact zeros, are found. + * Here the sign of tlo - thi is arbitrary, but if multiple roots + * are found, the one closest to tlo is returned. + * + * The method used is the Illinois algorithm, a modified secant method. + * Reference: Kathie L. Hiebert and Lawrence F. Shampine, Implicitly + * Defined Output Points for Solutions of ODEs, Sandia National + * Laboratory Report SAND80-0180, February 1980. + * + * This routine uses the following parameters for communication: + * + * nrtfn = number of functions g_i, or number of components of + * the vector-valued function g(t). Input only. + * + * gfun = user-defined function for g(t). Its form is + * (void) gfun(t, y, yp, gt, user_data) + * + * rootdir = in array specifying the direction of zero-crossings. + * If rootdir[i] > 0, search for roots of g_i only if + * g_i is increasing; if rootdir[i] < 0, search for + * roots of g_i only if g_i is decreasing; otherwise + * always search for roots of g_i. + * + * gactive = array specifying whether a component of g should + * or should not be monitored. gactive[i] is initially + * 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 + * corresponding g function moves away from 0.0. + * + * nge = cumulative counter for gfun calls. + * + * ttol = a convergence tolerance for trout. Input only. + * When a root at trout is found, it is located only to + * within a tolerance of ttol. Typically, ttol should + * be set to a value on the order of + * 100 * UROUND * max (SUNRabs(tlo), SUNRabs(thi)) + * where UROUND is the unit roundoff of the machine. + * + * tlo, thi = endpoints of the interval in which roots are sought. + * On input, these must be distinct, but tlo - thi may + * be of either sign. The direction of integration is + * assumed to be from tlo to thi. On return, tlo and thi + * are the endpoints of the final relevant interval. + * + * glo, ghi = arrays of length nrtfn containing the vectors g(tlo) + * and g(thi) respectively. Input and output. On input, + * none of the glo[i] should be zero. + * + * trout = root location, if a root was found, or thi if not. + * Output only. If a root was found other than an exact + * zero of g, trout is the endpoint thi of the final + * interval bracketing the root, with size at most ttol. + * + * grout = array of length nrtfn containing g(trout) on return. + * + * iroots = int array of length nrtfn with root information. + * Output only. If a root was found, iroots indicates + * which components g_i have a root at trout. For + * i = 0, ..., nrtfn-1, iroots[i] = 1 if g_i has a root + * and g_i is increasing, iroots[i] = -1 if g_i has a + * root and g_i is decreasing, and iroots[i] = 0 if g_i + * has no roots or g_i varies in the direction opposite + * to that indicated by rootdir[i]. + * + * This routine returns an int equal to: + * IDA_RTFUNC_FAIL < 0 if the g function failed, or + * RTFOUND = 1 if a root of g was found, or + * IDA_SUCCESS = 0 otherwise. + * + */ + +static int IDARootfind(IDAMem IDA_mem) +{ + realtype alph, tmid, gfrac, maxfrac, fracint, fracsub; + int i, retval, imax, side, sideprev; + booleantype zroot, sgnchg; + + imax = 0; + + /* First check for change in sign in ghi or for a zero in ghi. */ + maxfrac = ZERO; + zroot = SUNFALSE; + sgnchg = SUNFALSE; + 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) { + 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 (gfrac > maxfrac) { + sgnchg = SUNTRUE; + maxfrac = gfrac; + imax = i; + } + } + } + } + + /* 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. */ + if (!sgnchg) { + IDA_mem->ida_trout = IDA_mem->ida_thi; + for (i = 0; i < IDA_mem->ida_nrtfn; i++) + IDA_mem->ida_grout[i] = IDA_mem->ida_ghi[i]; + if (!zroot) return(IDA_SUCCESS); + for (i = 0; i < IDA_mem->ida_nrtfn; i++) { + 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_iroots[i] = IDA_mem->ida_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(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 + 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 = 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; + fracsub = (fracint > FIVE) ? PT1 : HALF/fracint; + tmid = IDA_mem->ida_thi - fracsub*(IDA_mem->ida_thi - IDA_mem->ida_tlo); + } + + (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_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. */ + maxfrac = ZERO; + zroot = SUNFALSE; + sgnchg = SUNFALSE; + sideprev = side; + 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) + 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) ) { + gfrac = SUNRabs(IDA_mem->ida_grout[i] / + (IDA_mem->ida_grout[i] - IDA_mem->ida_glo[i])); + if (gfrac > maxfrac) { + sgnchg = SUNTRUE; + maxfrac = gfrac; + imax = i; + } + } + } + } + if (sgnchg) { + /* Sign change found in (tlo,tmid); replace thi with tmid. */ + IDA_mem->ida_thi = tmid; + for (i = 0; i < IDA_mem->ida_nrtfn; i++) + 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; + continue; /* Return to looping point. */ + } + + if (zroot) { + /* No sign change in (tlo,tmid), but g = 0 at tmid; return root tmid. */ + IDA_mem->ida_thi = tmid; + for (i = 0; i < IDA_mem->ida_nrtfn; i++) + IDA_mem->ida_ghi[i] = IDA_mem->ida_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. */ + IDA_mem->ida_tlo = tmid; + for (i = 0; i < IDA_mem->ida_nrtfn; i++) + 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; + + } /* End of root-search loop */ + + /* Reset trout and grout, set iroots, and return RTFOUND. */ + IDA_mem->ida_trout = IDA_mem->ida_thi; + for (i = 0; i < IDA_mem->ida_nrtfn; i++) { + IDA_mem->ida_grout[i] = IDA_mem->ida_ghi[i]; + 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_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) ) + IDA_mem->ida_iroots[i] = IDA_mem->ida_glo[i] > 0 ? -1:1; + } + return(RTFOUND); +} + +/* + * ================================================================= + * Internal DQ approximations for sensitivity RHS + * ================================================================= + */ + +#undef user_dataS + +/* + * IDASensResDQ + * + * IDASensRhsDQ computes the residuals of the sensitivity equations + * by finite differences. It is of type IDASensResFn. + * Returns 0 if successful, <0 if an unrecoverable failure occurred, + * >0 for a recoverable error. + */ + +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 retval, is; + + for (is=0; is<Ns; is++) { + retval = IDASensRes1DQ(Ns, t, + yy, yp, resval, + is, yyS[is], ypS[is], resvalS[is], + user_dataS, + ytemp, yptemp, restemp); + if (retval != 0) return(retval); + } + return(0); +} + +/* + * IDASensRes1DQ + * + * IDASensRes1DQ computes the residual of the is-th sensitivity + * equation by finite differences. + * + * Returns 0 if successful or the return value of res if res fails + * (<0 if res fails unrecoverably, >0 if res has a recoverable error). + */ + +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) +{ + IDAMem IDA_mem; + int method; + int which; + int retval; + realtype psave, pbari; + realtype del , rdel; + realtype Delp, rDelp, r2Delp; + realtype Dely, rDely, r2Dely; + realtype Del , rDel , r2Del ; + realtype norms, ratio; + + /* user_dataS points to IDA_mem */ + IDA_mem = (IDAMem) user_dataS; + + /* Set base perturbation del */ + del = SUNRsqrt(SUNMAX(IDA_mem->ida_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; + rDelp = ONE/Delp; + norms = N_VWrmsNorm(yyS, IDA_mem->ida_ewt) * pbari; + rDely = SUNMAX(norms, rdel) / pbari; + Dely = ONE/rDely; + + if (IDA_mem->ida_DQrhomax == ZERO) { + /* No switching */ + method = (IDA_mem->ida_DQtype==IDA_CENTERED) ? CENTERED1 : FORWARD1; + } else { + /* switch between simultaneous/separate DQ */ + ratio = Dely * rDelp; + if ( SUNMAX(ONE/ratio, ratio) <= IDA_mem->ida_DQrhomax ) + method = (IDA_mem->ida_DQtype==IDA_CENTERED) ? CENTERED1 : FORWARD1; + else + method = (IDA_mem->ida_DQtype==IDA_CENTERED) ? CENTERED2 : FORWARD2; + } + + switch (method) { + + case CENTERED1: + + Del = SUNMIN(Dely, Delp); + r2Del = HALF/Del; + + /* Forward perturb y, y' and parameter */ + N_VLinearSum(Del, yyS, ONE, yy, ytemp); + N_VLinearSum(Del, ypS, ONE, yp, yptemp); + IDA_mem->ida_p[which] = psave + Del; + + /* 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, y' and parameter */ + N_VLinearSum(-Del, yyS, ONE, yy, ytemp); + N_VLinearSum(-Del, ypS, ONE, yp, yptemp); + IDA_mem->ida_p[which] = psave - Del; + + /* Save residual in restemp */ + retval = IDA_mem->ida_res(t, ytemp, yptemp, restemp, IDA_mem->ida_user_data); + IDA_mem->ida_nreS++; + if (retval != 0) return(retval); + + /* Estimate the residual for the i-th sensitivity equation */ + N_VLinearSum(r2Del, resvalS, -r2Del, restemp, resvalS); + + break; + + case CENTERED2: + + r2Delp = HALF/Delp; + r2Dely = HALF/Dely; + + /* 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); + + /* Save residual in restemp */ + retval = IDA_mem->ida_res(t, ytemp, yptemp, restemp, IDA_mem->ida_user_data); + IDA_mem->ida_nreS++; + if (retval != 0) return(retval); + + /* Save the first difference quotient in resvalS */ + N_VLinearSum(r2Dely, resvalS, -r2Dely, restemp, resvalS); + + /* Forward perturb parameter */ + IDA_mem->ida_p[which] = psave + Delp; + + /* Save residual in ytemp */ + retval = IDA_mem->ida_res(t, yy, yp, ytemp, IDA_mem->ida_user_data); + IDA_mem->ida_nreS++; + if (retval != 0) return(retval); + + /* Backward perturb parameter */ + IDA_mem->ida_p[which] = psave - Delp; + + /* Save residual in yptemp */ + 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: + + Del = SUNMIN(Dely, Delp); + rDel = ONE/Del; + + /* Forward perturb y, y' and parameter */ + N_VLinearSum(Del, yyS, ONE, yy, ytemp); + N_VLinearSum(Del, ypS, ONE, yp, yptemp); + IDA_mem->ida_p[which] = psave + Del; + + /* 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); + + /* Estimate the residual for the i-th sensitivity equation */ + N_VLinearSum(rDel, resvalS, -rDel, resval, resvalS); + + break; + + case FORWARD2: + + /* 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); + + /* Save the first difference quotient in resvalS */ + N_VLinearSum(rDely, resvalS, -rDely, resval, resvalS); + + /* Forward perturb parameter */ + IDA_mem->ida_p[which] = psave + Delp; + + /* Save residual in restemp */ + retval = IDA_mem->ida_res(t, yy, yp, restemp, IDA_mem->ida_user_data); + IDA_mem->ida_nreS++; + if (retval != 0) return(retval); + + /* Save the second difference quotient in restemp */ + N_VLinearSum(rDelp, restemp, -rDelp, resval, restemp); + + /* Add the difference quotients for the sensitivity residual */ + N_VLinearSum(ONE, resvalS, ONE, restemp, resvalS); + + break; + + } + + /* Restore original value of parameter */ + IDA_mem->ida_p[which] = psave; + + return(0); + +} + + +/* IDAQuadSensRhsInternalDQ - internal IDAQuadSensRhsFn + * + * IDAQuadSensRhsInternalDQ computes right hand side of all quadrature + * sensitivity equations by finite differences. All work is actually + * done in IDAQuadSensRhs1InternalDQ. + */ + +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, + 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; is<Ns; is++) { + retval = IDAQuadSensRhs1InternalDQ(IDA_mem, is, t, + yy, yp, yyS[is], ypS[is], + rrQ, resvalQS[is], + yytmp, yptmp, tmpQS); + if (retval!=0) return(retval); + } + + return(0); +} + +static int IDAQuadSensRhs1InternalDQ(IDAMem IDA_mem, int is, realtype t, + N_Vector yy, N_Vector yp, + N_Vector yyS, N_Vector ypS, + N_Vector resvalQ, N_Vector resvalQS, + N_Vector yytmp, N_Vector yptmp, N_Vector tmpQS) +{ + int retval, method; + int nfel = 0, which; + realtype psave, pbari; + realtype del , rdel; + realtype Delp; + realtype Dely, rDely; + realtype Del , r2Del ; + realtype norms; + + del = SUNRsqrt(SUNMAX(IDA_mem->ida_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; + + 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); + + IDA_mem->ida_p[which] = psave - Del; + + retval = IDA_mem->ida_rhsQ(t, yytmp, yptmp, tmpQS, IDA_mem->ida_user_data); + nfel++; + 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; + + 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 + * ================================================================= + */ + +/* + * 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 + * pointed to by ida_ehfun. + */ + +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 + (msgfmt is the last required argument to IDAProcessError) */ + + va_start(ap, msgfmt); + + /* Compose the message */ + + vsprintf(msg, msgfmt, ap); + + if (IDA_mem == NULL) { /* We write to stderr */ +#ifndef NO_FPRINTF_OUTPUT + fprintf(stderr, "\n[%s ERROR] %s\n ", module, fname); + fprintf(stderr, "%s\n\n", msg); +#endif + + } else { /* We can call ehfun */ + IDA_mem->ida_ehfun(error_code, module, fname, msg, IDA_mem->ida_eh_data); + } + + /* Finalize argument processing */ + va_end(ap); + + return; +} + +/* IDAErrHandler is the default error handling function. + It sends the error message to the stream pointed to by ida_errfp */ + +void IDAErrHandler(int error_code, const char *module, + const char *function, char *msg, void *data) +{ + IDAMem IDA_mem; + char err_type[10]; + + /* data points to IDA_mem here */ + + IDA_mem = (IDAMem) data; + + if (error_code == IDA_WARNING) + sprintf(err_type,"WARNING"); + else + sprintf(err_type,"ERROR"); + +#ifndef NO_FPRINTF_OUTPUT + 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); + } +#endif + + return; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_bbdpre.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_bbdpre.c new file mode 100644 index 0000000..ca32f73 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_bbdpre.c @@ -0,0 +1,908 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 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 + * linear solver interface. + * + * NOTE: With only one processor in use, a banded matrix results + * rather than a block-diagonal matrix with banded blocks. + * Diagonal blocking occurs at the processor level. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "idas_impl.h" +#include "idas_ls_impl.h" +#include "idas_bbdpre_impl.h" +#include <sundials/sundials_math.h> +#include <nvector/nvector_serial.h> + + +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) +#define TWO RCONST(2.0) + +/* Prototypes of IDABBDPrecSetup and IDABBDPrecSolve */ +static int IDABBDPrecSetup(realtype tt, N_Vector yy, N_Vector yp, + N_Vector rr, realtype c_j, void *prec_data); +static int IDABBDPrecSolve(realtype tt, N_Vector yy, N_Vector yp, + N_Vector rr, N_Vector rvec, N_Vector zvec, + realtype c_j, realtype delta, void *prec_data); + +/* Prototype for IDABBDPrecFree */ +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 ytemp, N_Vector yptemp, N_Vector gtemp); + +/* Wrapper functions for adjoint code */ +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, + N_Vector ypB, void *user_dataB); + +/* Prototype for the pfree routine for backward problems. */ +static int IDABBDPrecFreeB(IDABMem IDAB_mem); + + +/*================================================================ + PART I - forward problems + ================================================================*/ + +/*--------------------------------------------------------------- + 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, + IDABBDLocalFn Gres, IDABBDCommFn Gcomm) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + IBBDPrecData pdata; + sunindextype muk, mlk, storage_mu, lrw1, liw1; + long int lrw, liw; + int flag; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDALS_MEM_NULL, "IDASBBDPRE", + "IDABBDPrecInit", MSGBBD_MEM_NULL); + return(IDALS_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Test if the LS linear solver interface has been created */ + if (IDA_mem->ida_lmem == NULL) { + IDAProcessError(IDA_mem, IDALS_LMEM_NULL, "IDASBBDPRE", + "IDABBDPrecInit", MSGBBD_LMEM_NULL); + return(IDALS_LMEM_NULL); + } + idals_mem = (IDALsMem) IDA_mem->ida_lmem; + + /* Test compatibility of NVECTOR package with the BBD preconditioner */ + if(IDA_mem->ida_tempv1->ops->nvgetarraypointer == NULL) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDASBBDPRE", + "IDABBDPrecInit", MSGBBD_BAD_NVECTOR); + return(IDALS_ILL_INPUT); + } + + /* Allocate data memory. */ + pdata = NULL; + pdata = (IBBDPrecData) malloc(sizeof *pdata); + if (pdata == NULL) { + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDASBBDPRE", + "IDABBDPrecInit", MSGBBD_MEM_FAIL); + return(IDALS_MEM_FAIL); + } + + /* Set pointers to glocal and gcomm; load half-bandwidths. */ + pdata->ida_mem = IDA_mem; + pdata->glocal = Gres; + pdata->gcomm = Gcomm; + pdata->mudq = SUNMIN(Nlocal-1, SUNMAX(0, mudq)); + pdata->mldq = SUNMIN(Nlocal-1, SUNMAX(0, mldq)); + muk = SUNMIN(Nlocal-1, SUNMAX(0, mukeep)); + mlk = SUNMIN(Nlocal-1, SUNMAX(0, mlkeep)); + pdata->mukeep = muk; + pdata->mlkeep = mlk; + + /* Set extended upper half-bandwidth for PP (required for pivoting). */ + storage_mu = SUNMIN(Nlocal-1, muk+mlk); + + /* Allocate memory for preconditioner matrix. */ + pdata->PP = NULL; + pdata->PP = SUNBandMatrixStorage(Nlocal, muk, mlk, storage_mu); + if (pdata->PP == NULL) { + free(pdata); pdata = NULL; + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDASBBDPRE", + "IDABBDPrecInit", MSGBBD_MEM_FAIL); + return(IDALS_MEM_FAIL); + } + + /* Allocate memory for temporary N_Vectors */ + pdata->zlocal = NULL; + pdata->zlocal = N_VNewEmpty_Serial(Nlocal); + if (pdata->zlocal == NULL) { + SUNMatDestroy(pdata->PP); + free(pdata); pdata = NULL; + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDASBBDPRE", + "IDABBDPrecInit", MSGBBD_MEM_FAIL); + return(IDALS_MEM_FAIL); + } + pdata->rlocal = NULL; + pdata->rlocal = N_VNewEmpty_Serial(Nlocal); + if (pdata->rlocal == NULL) { + N_VDestroy(pdata->zlocal); + SUNMatDestroy(pdata->PP); + free(pdata); pdata = NULL; + 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); + if (pdata->tempv1 == NULL){ + N_VDestroy(pdata->rlocal); + N_VDestroy(pdata->zlocal); + SUNMatDestroy(pdata->PP); + free(pdata); pdata = NULL; + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDASBBDPRE", + "IDABBDPrecInit", MSGBBD_MEM_FAIL); + return(IDALS_MEM_FAIL); + } + pdata->tempv2 = NULL; + pdata->tempv2 = N_VClone(IDA_mem->ida_tempv1); + if (pdata->tempv2 == NULL){ + N_VDestroy(pdata->rlocal); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->tempv1); + SUNMatDestroy(pdata->PP); + free(pdata); pdata = NULL; + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDASBBDPRE", + "IDABBDPrecInit", MSGBBD_MEM_FAIL); + return(IDALS_MEM_FAIL); + } + pdata->tempv3 = NULL; + pdata->tempv3 = N_VClone(IDA_mem->ida_tempv1); + if (pdata->tempv3 == NULL){ + N_VDestroy(pdata->rlocal); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->tempv1); + N_VDestroy(pdata->tempv2); + SUNMatDestroy(pdata->PP); + free(pdata); pdata = NULL; + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDASBBDPRE", + "IDABBDPrecInit", MSGBBD_MEM_FAIL); + return(IDALS_MEM_FAIL); + } + pdata->tempv4 = NULL; + pdata->tempv4 = N_VClone(IDA_mem->ida_tempv1); + if (pdata->tempv4 == NULL){ + N_VDestroy(pdata->rlocal); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->tempv1); + N_VDestroy(pdata->tempv2); + N_VDestroy(pdata->tempv3); + SUNMatDestroy(pdata->PP); + free(pdata); pdata = NULL; + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDASBBDPRE", + "IDABBDPrecInit", MSGBBD_MEM_FAIL); + return(IDALS_MEM_FAIL); + } + + /* Allocate memory for banded linear solver */ + pdata->LS = NULL; + pdata->LS = SUNLinSol_Band(pdata->rlocal, pdata->PP); + if (pdata->LS == NULL) { + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + N_VDestroy(pdata->tempv1); + N_VDestroy(pdata->tempv2); + N_VDestroy(pdata->tempv3); + N_VDestroy(pdata->tempv4); + SUNMatDestroy(pdata->PP); + free(pdata); pdata = NULL; + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDASBBDPRE", + "IDABBDPrecInit", MSGBBD_MEM_FAIL); + return(IDALS_MEM_FAIL); + } + + /* initialize band linear solver object */ + flag = SUNLinSolInitialize(pdata->LS); + if (flag != SUNLS_SUCCESS) { + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + N_VDestroy(pdata->tempv1); + N_VDestroy(pdata->tempv2); + N_VDestroy(pdata->tempv3); + N_VDestroy(pdata->tempv4); + SUNMatDestroy(pdata->PP); + SUNLinSolFree(pdata->LS); + free(pdata); pdata = NULL; + IDAProcessError(IDA_mem, IDALS_SUNLS_FAIL, "IDASBBDPRE", + "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); + + /* Store Nlocal to be used in IDABBDPrecSetup */ + pdata->n_local = Nlocal; + + /* Set work space sizes and initialize nge. */ + pdata->rpwsize = 0; + pdata->ipwsize = 0; + if (IDA_mem->ida_tempv1->ops->nvspace) { + N_VSpace(IDA_mem->ida_tempv1, &lrw1, &liw1); + pdata->rpwsize += 4*lrw1; + pdata->ipwsize += 4*liw1; + } + if (pdata->rlocal->ops->nvspace) { + N_VSpace(pdata->rlocal, &lrw1, &liw1); + pdata->rpwsize += 2*lrw1; + pdata->ipwsize += 2*liw1; + } + if (pdata->PP->ops->space) { + flag = SUNMatSpace(pdata->PP, &lrw, &liw); + pdata->rpwsize += lrw; + pdata->ipwsize += liw; + } + if (pdata->LS->ops->space) { + flag = SUNLinSolSpace(pdata->LS, &lrw, &liw); + pdata->rpwsize += lrw; + pdata->ipwsize += liw; + } + pdata->nge = 0; + + /* make sure pdata is free from any previous allocations */ + if (idals_mem->pfree) + idals_mem->pfree(IDA_mem); + + /* Point to the new pdata field in the LS memory */ + idals_mem->pdata = pdata; + + /* Attach the pfree function */ + idals_mem->pfree = IDABBDPrecFree; + + /* Attach preconditioner solve and setup functions */ + flag = IDASetPreconditioner(ida_mem, IDABBDPrecSetup, + IDABBDPrecSolve); + + return(flag); +} + + +/*-------------------------------------------------------------*/ +int IDABBDPrecReInit(void *ida_mem, sunindextype mudq, + sunindextype mldq, realtype dq_rel_yy) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + IBBDPrecData pdata; + sunindextype Nlocal; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDALS_MEM_NULL, "IDASBBDPRE", + "IDABBDPrecReInit", MSGBBD_MEM_NULL); + return(IDALS_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Test if the LS linear solver interface has been created */ + if (IDA_mem->ida_lmem == NULL) { + IDAProcessError(IDA_mem, IDALS_LMEM_NULL, "IDASBBDPRE", + "IDABBDPrecReInit", MSGBBD_LMEM_NULL); + return(IDALS_LMEM_NULL); + } + idals_mem = (IDALsMem) IDA_mem->ida_lmem; + + /* Test if the preconditioner data is non-NULL */ + if (idals_mem->pdata == NULL) { + IDAProcessError(IDA_mem, IDALS_PMEM_NULL, "IDASBBDPRE", + "IDABBDPrecReInit", MSGBBD_PMEM_NULL); + return(IDALS_PMEM_NULL); + } + pdata = (IBBDPrecData) idals_mem->pdata; + + /* Load half-bandwidths. */ + Nlocal = pdata->n_local; + pdata->mudq = SUNMIN(Nlocal-1, SUNMAX(0, mudq)); + pdata->mldq = SUNMIN(Nlocal-1, SUNMAX(0, mldq)); + + /* 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); + + /* Re-initialize nge */ + pdata->nge = 0; + + return(IDALS_SUCCESS); +} + + +/*-------------------------------------------------------------*/ +int IDABBDPrecGetWorkSpace(void *ida_mem, + long int *lenrwBBDP, + long int *leniwBBDP) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + IBBDPrecData pdata; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDALS_MEM_NULL, "IDASBBDPRE", + "IDABBDPrecGetWorkSpace", MSGBBD_MEM_NULL); + return(IDALS_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_lmem == NULL) { + IDAProcessError(IDA_mem, IDALS_LMEM_NULL, "IDASBBDPRE", + "IDABBDPrecGetWorkSpace", MSGBBD_LMEM_NULL); + return(IDALS_LMEM_NULL); + } + idals_mem = (IDALsMem) IDA_mem->ida_lmem; + + if (idals_mem->pdata == NULL) { + IDAProcessError(IDA_mem, IDALS_PMEM_NULL, "IDASBBDPRE", + "IDABBDPrecGetWorkSpace", MSGBBD_PMEM_NULL); + return(IDALS_PMEM_NULL); + } + pdata = (IBBDPrecData) idals_mem->pdata; + + *lenrwBBDP = pdata->rpwsize; + *leniwBBDP = pdata->ipwsize; + + return(IDALS_SUCCESS); +} + + +/*-------------------------------------------------------------*/ +int IDABBDPrecGetNumGfnEvals(void *ida_mem, + long int *ngevalsBBDP) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + IBBDPrecData pdata; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDALS_MEM_NULL, "IDASBBDPRE", + "IDABBDPrecGetNumGfnEvals", MSGBBD_MEM_NULL); + return(IDALS_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_lmem == NULL) { + IDAProcessError(IDA_mem, IDALS_LMEM_NULL, "IDASBBDPRE", + "IDABBDPrecGetNumGfnEvals", MSGBBD_LMEM_NULL); + return(IDALS_LMEM_NULL); + } + idals_mem = (IDALsMem) IDA_mem->ida_lmem; + + if (idals_mem->pdata == NULL) { + IDAProcessError(IDA_mem, IDALS_PMEM_NULL, "IDASBBDPRE", + "IDABBDPrecGetNumGfnEvals", MSGBBD_PMEM_NULL); + return(IDALS_PMEM_NULL); + } + pdata = (IBBDPrecData) idals_mem->pdata; + + *ngevalsBBDP = pdata->nge; + + return(IDALS_SUCCESS); +} + + + + +/*--------------------------------------------------------------- + IDABBDPrecSetup: + + IDABBDPrecSetup generates a band-block-diagonal preconditioner + matrix, where the local block (on this processor) is a band + matrix. Each local block is computed by a difference quotient + 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 + 0 if successful, + > 0 for a recoverable error (step will be retried), or + < 0 for a nonrecoverable error (step fails). + ----------------------------------------------------------------*/ +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; + + pdata =(IBBDPrecData) bbd_data; + + IDA_mem = (IDAMem) pdata->ida_mem; + + /* Call IBBDDQJac for a new Jacobian calculation and store in PP. */ + retval = SUNMatZero(pdata->PP); + retval = IBBDDQJac(pdata, tt, c_j, yy, yp, pdata->tempv1, + pdata->tempv2, pdata->tempv3, pdata->tempv4); + if (retval < 0) { + IDAProcessError(IDA_mem, -1, "IDASBBDPRE", "IDABBDPrecSetup", + MSGBBD_FUNC_FAILED); + return(-1); + } + if (retval > 0) { + return(+1); + } + + /* Do LU factorization of matrix and return error flag */ + ier = SUNLinSolSetup_Band(pdata->LS, pdata->PP); + return(ier); +} + + +/*--------------------------------------------------------------- + IDABBDPrecSolve + + 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 + solver object. + ---------------------------------------------------------------*/ +static int IDABBDPrecSolve(realtype tt, N_Vector yy, N_Vector yp, + N_Vector rr, N_Vector rvec, N_Vector zvec, + realtype c_j, realtype delta, void *bbd_data) +{ + 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, + pdata->rlocal, ZERO); + + /* Detach local data arrays from rlocal and zlocal */ + N_VSetArrayPointer(NULL, pdata->rlocal); + N_VSetArrayPointer(NULL, pdata->zlocal); + + return(retval); +} + + +/*-------------------------------------------------------------*/ +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; + + SUNLinSolFree(pdata->LS); + N_VDestroy(pdata->rlocal); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->tempv1); + N_VDestroy(pdata->tempv2); + N_VDestroy(pdata->tempv3); + N_VDestroy(pdata->tempv4); + SUNMatDestroy(pdata->PP); + + free(pdata); + pdata = NULL; + + return(0); +} + + +/*--------------------------------------------------------------- + IBBDDQJac + + This routine generates a banded difference quotient approximation + 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 ytemp, N_Vector yptemp, N_Vector gtemp) +{ + IDAMem IDA_mem; + realtype inc, inc_inv; + int retval; + sunindextype group, i, j, width, ngroups, i1, i2; + realtype *ydata, *ypdata, *ytempdata, *yptempdata, *grefdata, *gtempdata; + realtype *cnsdata = NULL, *ewtdata; + realtype *col_j, conj, yj, ypj, ewtj; + + IDA_mem = (IDAMem) pdata->ida_mem; + + /* Initialize ytemp and yptemp. */ + N_VScale(ONE, yy, ytemp); + N_VScale(ONE, yp, yptemp); + + /* Obtain pointers as required to the data array of vectors. */ + ydata = N_VGetArrayPointer(yy); + ypdata = N_VGetArrayPointer(yp); + gtempdata = N_VGetArrayPointer(gtemp); + ewtdata = N_VGetArrayPointer(IDA_mem->ida_ewt); + if (IDA_mem->ida_constraints != NULL) + cnsdata = N_VGetArrayPointer(IDA_mem->ida_constraints); + ytempdata = N_VGetArrayPointer(ytemp); + yptempdata= N_VGetArrayPointer(yptemp); + grefdata = N_VGetArrayPointer(gref); + + /* Call gcomm and glocal to get base value of G(t,y,y'). */ + if (pdata->gcomm != NULL) { + retval = pdata->gcomm(pdata->n_local, tt, yy, yp, IDA_mem->ida_user_data); + if (retval != 0) return(retval); + } + + retval = pdata->glocal(pdata->n_local, tt, yy, yp, gref, IDA_mem->ida_user_data); + pdata->nge++; + if (retval != 0) return(retval); + + /* Set bandwidth and number of column groups for band differencing. */ + width = pdata->mldq + pdata->mudq + 1; + ngroups = SUNMIN(width, pdata->n_local); + + /* 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. */ + inc = pdata->rel_yy * + 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) { + 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;} + } + + /* 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); + pdata->nge++; + if (retval != 0) return(retval); + + /* Loop over components of the group again; restore ytemp and yptemp. */ + for(j = group-1; j < pdata->n_local; j += width) { + yj = ytempdata[j] = ydata[j]; + ypj = yptempdata[j] = ypdata[j]; + ewtj = ewtdata[j]; + + /* Set increment inc as before .*/ + inc = pdata->rel_yy * + 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) { + 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;} + } + + /* Form difference quotients and load into PP. */ + inc_inv = ONE/inc; + col_j = SUNBandMatrix_Column(pdata->PP,j); + i1 = SUNMAX(0, j-pdata->mukeep); + i2 = SUNMIN(j + pdata->mlkeep, pdata->n_local-1); + for(i = i1; i <= i2; i++) + SM_COLUMN_ELEMENT_B(col_j,i,j) = + inc_inv * (gtempdata[i] - grefdata[i]); + } + } + + return(0); +} + + +/*================================================================ + PART II - backward problems + ================================================================*/ + +/*--------------------------------------------------------------- + User-Callable Functions: initialization, reinit and free + ---------------------------------------------------------------*/ +int IDABBDPrecInitB(void *ida_mem, int which, sunindextype NlocalB, + sunindextype mudqB, sunindextype mldqB, + sunindextype mukeepB, sunindextype mlkeepB, + realtype dq_rel_yyB, IDABBDLocalFnB glocalB, + IDABBDCommFnB gcommB) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + IDABMem IDAB_mem; + IDABBDPrecDataB idabbdB_mem; + void *ida_memB; + int flag; + + /* Check if ida_mem is allright. */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDALS_MEM_NULL, "IDASBBDPRE", + "IDABBDPrecInitB", MSG_LS_IDAMEM_NULL); + return(IDALS_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDALS_NO_ADJ, "IDASBBDPRE", + "IDABBDPrecInitB", MSG_LS_NO_ADJ); + return(IDALS_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDASBBDPRE", + "IDABBDPrecInitB", MSG_LS_BAD_WHICH); + return(IDALS_ILL_INPUT); + } + + /* Find the IDABMem entry in the linked list corresponding to 'which'. */ + IDAB_mem = IDAADJ_mem->IDAB_mem; + while (IDAB_mem != NULL) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + /* ida_mem corresponding to 'which' problem. */ + ida_memB = (void *) IDAB_mem->IDA_mem; + + /* Initialize the BBD preconditioner for this backward problem. */ + flag = IDABBDPrecInit(ida_memB, NlocalB, mudqB, mldqB, mukeepB, + mlkeepB, dq_rel_yyB, IDAAglocal, IDAAgcomm); + if (flag != IDA_SUCCESS) return(flag); + + /* Allocate memory for IDABBDPrecDataB to store the user-provided + functions which will be called from the wrappers */ + idabbdB_mem = NULL; + idabbdB_mem = (IDABBDPrecDataB) malloc(sizeof(* idabbdB_mem)); + if (idabbdB_mem == NULL) { + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDASBBDPRE", + "IDABBDPrecInitB", MSGBBD_MEM_FAIL); + return(IDALS_MEM_FAIL); + } + + /* set pointers to user-provided functions */ + idabbdB_mem->glocalB = glocalB; + idabbdB_mem->gcommB = gcommB; + + /* Attach pmem and pfree */ + IDAB_mem->ida_pmem = idabbdB_mem; + IDAB_mem->ida_pfree = IDABBDPrecFreeB; + + return(IDALS_SUCCESS); +} + + +/*-------------------------------------------------------------*/ +int IDABBDPrecReInitB(void *ida_mem, int which, sunindextype mudqB, + sunindextype mldqB, realtype dq_rel_yyB) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + IDABMem IDAB_mem; + void *ida_memB; + int flag; + + /* Check if ida_mem is allright. */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDALS_MEM_NULL, "IDASBBDPRE", + "IDABBDPrecReInitB", MSG_LS_IDAMEM_NULL); + return(IDALS_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Is ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDALS_NO_ADJ, "IDASBBDPRE", + "IDABBDPrecReInitB", MSG_LS_NO_ADJ); + return(IDALS_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDASBBDPRE", + "IDABBDPrecReInitB", MSG_LS_BAD_WHICH); + return(IDALS_ILL_INPUT); + } + + /* Find the IDABMem entry in the linked list corresponding to 'which'. */ + IDAB_mem = IDAADJ_mem->IDAB_mem; + while (IDAB_mem != NULL) { + if( which == IDAB_mem->ida_index ) break; + /* advance */ + IDAB_mem = IDAB_mem->ida_next; + } + /* ida_mem corresponding to 'which' backward problem. */ + ida_memB = (void *) IDAB_mem->IDA_mem; + + /* ReInitialize the BBD preconditioner for this backward problem. */ + flag = IDABBDPrecReInit(ida_memB, mudqB, mldqB, dq_rel_yyB); + return(flag); +} + + +/*-------------------------------------------------------------*/ +static int IDABBDPrecFreeB(IDABMem IDAB_mem) +{ + free(IDAB_mem->ida_pmem); + IDAB_mem->ida_pmem = NULL; + return(0); +} + + +/*---------------------------------------------------------------- + Wrapper functions + ----------------------------------------------------------------*/ + +/*---------------------------------------------------------------- + IDAAglocal + + This routine interfaces to the IDALocalFnB routine + provided by the user. + ----------------------------------------------------------------*/ +static int IDAAglocal(sunindextype NlocalB, realtype tt, N_Vector yyB, + N_Vector ypB, N_Vector gvalB, void *ida_mem) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + IDABMem IDAB_mem; + IDABBDPrecDataB idabbdB_mem; + int flag; + + IDA_mem = (IDAMem) ida_mem; + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Get current backward problem. */ + IDAB_mem = IDAADJ_mem->ia_bckpbCrt; + + /* Get the preconditioner's memory. */ + idabbdB_mem = (IDABBDPrecDataB) IDAB_mem->ida_pmem; + + /* Get forward solution from interpolation. */ + if (IDAADJ_mem->ia_noInterp == SUNFALSE) { + 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, "IDASBBDPRE", "IDAAglocal", + MSGBBD_BAD_T); + return(-1); + } + } + /* Call user's adjoint LocalFnB function. */ + return idabbdB_mem->glocalB(NlocalB, tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, yyB, ypB, + gvalB, IDAB_mem->ida_user_data); +} + + +/*---------------------------------------------------------------- + IDAAgcomm + + This routine interfaces to the IDACommFnB routine + provided by the user. + ----------------------------------------------------------------*/ +static int IDAAgcomm(sunindextype NlocalB, realtype tt, + N_Vector yyB, N_Vector ypB, void *ida_mem) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + IDABMem IDAB_mem; + IDABBDPrecDataB idabbdB_mem; + int flag; + + IDA_mem = (IDAMem) ida_mem; + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Get current backward problem. */ + IDAB_mem = IDAADJ_mem->ia_bckpbCrt; + + /* Get the preconditioner's memory. */ + idabbdB_mem = (IDABBDPrecDataB) IDAB_mem->ida_pmem; + if (idabbdB_mem->gcommB == NULL) return(0); + + /* Get forward solution from interpolation. */ + if (IDAADJ_mem->ia_noInterp == SUNFALSE) { + 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, "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, + IDAB_mem->ida_user_data); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_bbdpre_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_bbdpre_impl.h new file mode 100644 index 0000000..45e409b --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_bbdpre_impl.h @@ -0,0 +1,107 @@ +/*----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 (private version) for the IDABBDPRE + * module, for a band-block-diagonal preconditioner, i.e. a + * block-diagonal matrix with banded blocks, for use with IDA + * and an IDASPILS linear solver. + *-----------------------------------------------------------------*/ + +#ifndef _IDASBBDPRE_IMPL_H +#define _IDASBBDPRE_IMPL_H + +#include <idas/idas_bbdpre.h> +#include <sunmatrix/sunmatrix_band.h> +#include <sunlinsol/sunlinsol_band.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* + * ----------------------------------------------------------------- + * Definition of IBBDPrecData + * ----------------------------------------------------------------- + */ + +typedef struct IBBDPrecDataRec { + + /* passed by user to IDABBDPrecAlloc and used by + IDABBDPrecSetup/IDABBDPrecSolve functions */ + sunindextype mudq, mldq, mukeep, mlkeep; + realtype rel_yy; + IDABBDLocalFn glocal; + IDABBDCommFn gcomm; + + /* set by IDABBDPrecSetup and used by IDABBDPrecSetup and + IDABBDPrecSolve functions */ + sunindextype n_local; + SUNMatrix PP; + SUNLinearSolver LS; + N_Vector zlocal; + N_Vector rlocal; + N_Vector tempv1; + N_Vector tempv2; + N_Vector tempv3; + N_Vector tempv4; + + /* available for optional output */ + long int rpwsize; + long int ipwsize; + long int nge; + + /* pointer to ida_mem */ + void *ida_mem; + +} *IBBDPrecData; + +/* + * ----------------------------------------------------------------- + * Type: IDABBDPrecDataB + * ----------------------------------------------------------------- + */ + +typedef struct IDABBDPrecDataRecB { + + /* BBD user functions (glocB and cfnB) for backward run */ + IDABBDLocalFnB glocalB; + IDABBDCommFnB gcommB; + +} *IDABBDPrecDataB; + + +/* + * ----------------------------------------------------------------- + * IDABBDPRE error messages + * ----------------------------------------------------------------- + */ + +#define MSGBBD_MEM_NULL "Integrator memory is NULL." +#define MSGBBD_LMEM_NULL "Linear solver memory is NULL. One of the SPILS linear solvers must be attached." +#define MSGBBD_MEM_FAIL "A memory request failed." +#define MSGBBD_BAD_NVECTOR "A required vector operation is not implemented." +#define MSGBBD_SUNMAT_FAIL "An error arose from a SUNBandMatrix routine." +#define MSGBBD_SUNLS_FAIL "An error arose from a SUNBandLinearSolver routine." +#define MSGBBD_PMEM_NULL "BBD peconditioner memory is NULL. IDABBDPrecInit must be called." +#define MSGBBD_FUNC_FAILED "The Glocal or Gcomm routine failed in an unrecoverable manner." + +#define MSGBBD_AMEM_NULL "idaadj_mem = NULL illegal." +#define MSGBBD_PDATAB_NULL "IDABBDPRE memory is NULL for the backward integration." +#define MSGBBD_BAD_T "Bad t for interpolation." + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_direct.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_direct.c new file mode 100644 index 0000000..ee1bf7c --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_direct.c @@ -0,0 +1,66 @@ +/*----------------------------------------------------------------- + * Programmer(s): 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 + *----------------------------------------------------------------- + * Implementation file for the deprecated direct linear solver interface in + * IDA; these routines now just wrap the updated IDA generic + * linear solver interface in idas_ls.h. + *-----------------------------------------------------------------*/ + +#include <idas/idas_ls.h> +#include <idas/idas_direct.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*================================================================= + Exported Functions (wrappers for equivalent routines in idas_ls.h) + =================================================================*/ + +int IDADlsSetLinearSolver(void *ida_mem, SUNLinearSolver LS, + SUNMatrix A) +{ return(IDASetLinearSolver(ida_mem, LS, A)); } + +int IDADlsSetJacFn(void *ida_mem, IDADlsJacFn jac) +{ return(IDASetJacFn(ida_mem, jac)); } + +int IDADlsGetWorkSpace(void *ida_mem, long int *lenrwLS, + long int *leniwLS) +{ return(IDAGetLinWorkSpace(ida_mem, lenrwLS, leniwLS)); } + +int IDADlsGetNumJacEvals(void *ida_mem, long int *njevals) +{ return(IDAGetNumJacEvals(ida_mem, njevals)); } + +int IDADlsGetNumResEvals(void *ida_mem, long int *nrevalsLS) +{ return(IDAGetNumLinResEvals(ida_mem, nrevalsLS)); } + +int IDADlsGetLastFlag(void *ida_mem, long int *flag) +{ return(IDAGetLastLinFlag(ida_mem, flag)); } + +char *IDADlsGetReturnFlagName(long int flag) +{ return(IDAGetLinReturnFlagName(flag)); } + +int IDADlsSetLinearSolverB(void *ida_mem, int which, + SUNLinearSolver LS, SUNMatrix A) +{ return(IDASetLinearSolverB(ida_mem, which, LS, A)); } + +int IDADlsSetJacFnB(void *ida_mem, int which, IDADlsJacFnB jacB) +{ return(IDASetJacFnB(ida_mem, which, jacB)); } + +int IDADlsSetJacFnBS(void *ida_mem, int which, IDADlsJacFnBS jacBS) +{ return(IDASetJacFnBS(ida_mem, which, jacBS)); } + +#ifdef __cplusplus +} +#endif + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_ic.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_ic.c new file mode 100644 index 0000000..0284d96 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_ic.c @@ -0,0 +1,1353 @@ +/* + * ----------------------------------------------------------------- + * $Revision$ + * $Date$ + * ----------------------------------------------------------------- + * Programmers: 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 IC calculation for IDAS. + * It is independent of the linear solver in use. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "idas_impl.h" +#include <sundials/sundials_math.h> + +/* + * ================================================================= + * IDA Constants + * ================================================================= + */ + +/* Private Constants */ + +#define ZERO RCONST(0.0) /* real 0.0 */ +#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 PT99 RCONST(0.99) /* real 0.99 */ +#define PT1 RCONST(0.1) /* real 0.1 */ +#define PT001 RCONST(0.001) /* real 0.001 */ + +/* IDACalcIC control constants */ + +#define ICRATEMAX RCONST(0.9) /* max. Newton conv. rate */ +#define ALPHALS RCONST(0.0001) /* alpha in linesearch conv. test */ + +/* Return values for lower level routines used by IDACalcIC */ + +#define IC_FAIL_RECOV 1 +#define IC_CONSTR_FAILED 2 +#define IC_LINESRCH_FAILED 3 +#define IC_CONV_FAIL 4 +#define IC_SLOW_CONVRG 5 + +/* + * ================================================================= + * Private Helper Functions Prototypes + * ================================================================= + */ + +extern int IDAInitialSetup(IDAMem IDA_mem); +extern realtype IDAWrmsNorm(IDAMem IDA_mem, N_Vector x, + N_Vector w, booleantype mask); +extern realtype IDASensWrmsNorm(IDAMem IDA_mem, N_Vector *xS, + N_Vector *wS, booleantype mask); +extern realtype IDASensWrmsNormUpdate(IDAMem IDA_mem, realtype old_nrm, + N_Vector *xS, N_Vector *wS, + booleantype mask); + +extern int IDASensEwtSet(IDAMem IDA_mem, N_Vector *yScur, N_Vector *weightS); + +static int IDANlsIC(IDAMem IDA_mem); + +static int IDANewtonIC(IDAMem IDA_mem); +static int IDALineSrch(IDAMem IDA_mem, realtype *delnorm, realtype *fnorm); +static int IDAfnorm(IDAMem IDA_mem, realtype *fnorm); +static int IDANewyyp(IDAMem IDA_mem, realtype lambda); +static int IDANewy(IDAMem IDA_mem); + +static int IDASensNewtonIC(IDAMem IDA_mem); +static int IDASensLineSrch(IDAMem IDA_mem, realtype *delnorm, realtype *fnorm); +static int IDASensNewyyp(IDAMem IDA_mem, realtype lambda); +static int IDASensfnorm(IDAMem IDA_mem, realtype *fnorm); +static int IDASensNlsIC(IDAMem IDA_mem); + +static int IDAICFailFlag(IDAMem IDA_mem, int retval); + + +/* + * ================================================================= + * EXPORTED FUNCTIONS IMPLEMENTATION + * ================================================================= + */ + +/* + * ----------------------------------------------------------------- + * IDACalcIC + * ----------------------------------------------------------------- + * IDACalcIC computes consistent initial conditions, given the + * user's initial guess for unknown components of yy0 and/or yp0. + * + * The return value is IDA_SUCCESS = 0 if no error occurred. + * + * The error return values (fully described in ida.h) are: + * IDA_MEM_NULL ida_mem is NULL + * IDA_NO_MALLOC ida_mem was not allocated + * IDA_ILL_INPUT bad value for icopt, tout1, or id + * IDA_LINIT_FAIL the linear solver linit routine failed + * IDA_BAD_EWT zero value of some component of ewt + * IDA_RES_FAIL res had a non-recoverable error + * IDA_FIRST_RES_FAIL res failed recoverably on the first call + * IDA_LSETUP_FAIL lsetup had a non-recoverable error + * IDA_LSOLVE_FAIL lsolve had a non-recoverable error + * IDA_NO_RECOVERY res, lsetup, or lsolve had a recoverable + * error, but IDACalcIC could not recover + * IDA_CONSTR_FAIL the inequality constraints could not be met + * IDA_LINESEARCH_FAIL if the linesearch failed (either on steptol test + * or on the maxbacks test) + * IDA_CONV_FAIL the Newton iterations failed to converge + * ----------------------------------------------------------------- + */ + +int IDACalcIC(void *ida_mem, int icopt, realtype tout1) +{ + int ewtsetOK; + int ier, nwt, nh, mxnh, icret, retval=0; + int is; + realtype tdist, troundoff, minid, hic, ypnorm; + IDAMem IDA_mem; + booleantype sensi_stg, sensi_sim; + + /* Check if IDA memory exists */ + + if(ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDACalcIC", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Check if problem was malloc'ed */ + + if(IDA_mem->ida_MallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_MALLOC, "IDAS", "IDACalcIC", MSG_NO_MALLOC); + return(IDA_NO_MALLOC); + } + + /* Check inputs to IDA for correctness and consistency */ + + ier = IDAInitialSetup(IDA_mem); + if(ier != IDA_SUCCESS) return(IDA_ILL_INPUT); + IDA_mem->ida_SetupDone = SUNTRUE; + + /* Check legality of input arguments, and set IDA memory copies. */ + + if(icopt != IDA_YA_YDP_INIT && icopt != IDA_Y_INIT) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDACalcIC", MSG_IC_BAD_ICOPT); + return(IDA_ILL_INPUT); + } + IDA_mem->ida_icopt = icopt; + + if(icopt == IDA_YA_YDP_INIT && (IDA_mem->ida_id == NULL)) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDACalcIC", MSG_IC_MISSING_ID); + return(IDA_ILL_INPUT); + } + + tdist = SUNRabs(tout1 - IDA_mem->ida_tn); + troundoff = TWO * IDA_mem->ida_uround * (SUNRabs(IDA_mem->ida_tn) + SUNRabs(tout1)); + if(tdist < troundoff) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDACalcIC", MSG_IC_TOO_CLOSE); + return(IDA_ILL_INPUT); + } + + /* Are we computing sensitivities? */ + sensi_stg = (IDA_mem->ida_sensi && (IDA_mem->ida_ism==IDA_STAGGERED)); + sensi_sim = (IDA_mem->ida_sensi && (IDA_mem->ida_ism==IDA_SIMULTANEOUS)); + + /* Allocate space and initialize temporary vectors */ + + IDA_mem->ida_yy0 = N_VClone(IDA_mem->ida_ee); + IDA_mem->ida_yp0 = N_VClone(IDA_mem->ida_ee); + IDA_mem->ida_t0 = IDA_mem->ida_tn; + N_VScale(ONE, IDA_mem->ida_phi[0], IDA_mem->ida_yy0); + N_VScale(ONE, IDA_mem->ida_phi[1], IDA_mem->ida_yp0); + + if (IDA_mem->ida_sensi) { + + /* Allocate temporary space required for sensitivity IC: yyS0 and ypS0. */ + IDA_mem->ida_yyS0 = N_VCloneVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_ee); + IDA_mem->ida_ypS0 = N_VCloneVectorArray(IDA_mem->ida_Ns, IDA_mem->ida_ee); + + /* Initialize sensitivity vector. */ + for (is=0; is<IDA_mem->ida_Ns; is++) { + N_VScale(ONE, IDA_mem->ida_phiS[0][is], IDA_mem->ida_yyS0[is]); + N_VScale(ONE, IDA_mem->ida_phiS[1][is], IDA_mem->ida_ypS0[is]); + } + + /* Initialize work space vectors needed for sensitivities. */ + IDA_mem->ida_savresS = IDA_mem->ida_phiS[2]; + IDA_mem->ida_delnewS = IDA_mem->ida_phiS[3]; + IDA_mem->ida_yyS0new = IDA_mem->ida_phiS[4]; + IDA_mem->ida_ypS0new = IDA_mem->ida_eeS; + } + + /* For use in the IDA_YA_YP_INIT case, set sysindex and tscale. */ + + IDA_mem->ida_sysindex = 1; + IDA_mem->ida_tscale = tdist; + if(icopt == IDA_YA_YDP_INIT) { + minid = N_VMin(IDA_mem->ida_id); + if(minid < ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDACalcIC", MSG_IC_BAD_ID); + return(IDA_ILL_INPUT); + } + if(minid > HALF) IDA_mem->ida_sysindex = 0; + } + + /* Set the test constant in the Newton convergence test */ + + IDA_mem->ida_epsNewt = IDA_mem->ida_epiccon; + + /* Initializations: + cjratio = 1 (for use in direct linear solvers); + set nbacktr = 0; */ + + IDA_mem->ida_cjratio = ONE; + IDA_mem->ida_nbacktr = 0; + + /* Set hic, hh, cj, and mxnh. */ + + hic = PT001*tdist; + ypnorm = IDAWrmsNorm(IDA_mem, IDA_mem->ida_yp0, IDA_mem->ida_ewt, IDA_mem->ida_suppressalg); + + if (sensi_sim) + ypnorm = IDASensWrmsNormUpdate(IDA_mem, ypnorm, IDA_mem->ida_ypS0, IDA_mem->ida_ewtS, SUNFALSE); + + if(ypnorm > HALF/hic) hic = HALF/ypnorm; + if(tout1 < IDA_mem->ida_tn) hic = -hic; + IDA_mem->ida_hh = hic; + if(icopt == IDA_YA_YDP_INIT) { + IDA_mem->ida_cj = ONE/hic; + mxnh = IDA_mem->ida_maxnh; + } + else { + IDA_mem->ida_cj = ZERO; + mxnh = 1; + } + + /* Loop over nwt = number of evaluations of ewt vector. */ + + for(nwt = 1; nwt <= 2; nwt++) { + + /* Loop over nh = number of h values. */ + for(nh = 1; nh <= mxnh; nh++) { + + /* Call the IC nonlinear solver function. */ + retval = IDANlsIC(IDA_mem); + + /* Cut h and loop on recoverable IDA_YA_YDP_INIT failure; else break. */ + if(retval == IDA_SUCCESS) break; + IDA_mem->ida_ncfn++; + if(retval < 0) break; + if(nh == mxnh) break; + + /* If looping to try again, reset yy0 and yp0 if not converging. */ + if(retval != IC_SLOW_CONVRG) { + N_VScale(ONE, IDA_mem->ida_phi[0], IDA_mem->ida_yy0); + N_VScale(ONE, IDA_mem->ida_phi[1], IDA_mem->ida_yp0); + if (sensi_sim) { + + /* Reset yyS0 and ypS0. */ + /* Copy phiS[0] and phiS[1] into yyS0 and ypS0. */ + for (is=0; is<IDA_mem->ida_Ns; is++) { + N_VScale(ONE, IDA_mem->ida_phiS[0][is], IDA_mem->ida_yyS0[is]); + N_VScale(ONE, IDA_mem->ida_phiS[1][is], IDA_mem->ida_ypS0[is]); + } + } + } + hic *= PT1; + IDA_mem->ida_cj = ONE/hic; + IDA_mem->ida_hh = hic; + } /* End of nh loop */ + + /* Break on failure */ + if(retval != IDA_SUCCESS) break; + + /* Reset ewt, save yy0, yp0 in phi, and loop. */ + ewtsetOK = IDA_mem->ida_efun(IDA_mem->ida_yy0, IDA_mem->ida_ewt, IDA_mem->ida_edata); + if(ewtsetOK != 0) { + retval = IDA_BAD_EWT; + break; + } + N_VScale(ONE, IDA_mem->ida_yy0, IDA_mem->ida_phi[0]); + N_VScale(ONE, IDA_mem->ida_yp0, IDA_mem->ida_phi[1]); + + if (sensi_sim) { + + /* Reevaluate ewtS. */ + ewtsetOK = IDASensEwtSet(IDA_mem, IDA_mem->ida_yyS0, IDA_mem->ida_ewtS); + if(ewtsetOK != 0) { + retval = IDA_BAD_EWT; + break; + } + + /* Save yyS0 and ypS0. */ + for (is=0; is<IDA_mem->ida_Ns; is++) { + N_VScale(ONE, IDA_mem->ida_yyS0[is], IDA_mem->ida_phiS[0][is]); + N_VScale(ONE, IDA_mem->ida_ypS0[is], IDA_mem->ida_phiS[1][is]); + } + } + + } /* End of nwt loop */ + + /* Load the optional outputs. */ + + if(icopt == IDA_YA_YDP_INIT) IDA_mem->ida_hused = hic; + + /* On any failure, free memory, print error message and return */ + + if(retval != IDA_SUCCESS) { + N_VDestroy(IDA_mem->ida_yy0); + N_VDestroy(IDA_mem->ida_yp0); + + if(IDA_mem->ida_sensi) { + N_VDestroyVectorArray(IDA_mem->ida_yyS0, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ypS0, IDA_mem->ida_Ns); + } + + icret = IDAICFailFlag(IDA_mem, retval); + return(icret); + } + + /* Unless using the STAGGERED approach for sensitivities, return now */ + + if (!sensi_stg) { + + N_VDestroy(IDA_mem->ida_yy0); + N_VDestroy(IDA_mem->ida_yp0); + + if(IDA_mem->ida_sensi) { + N_VDestroyVectorArray(IDA_mem->ida_yyS0, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ypS0, IDA_mem->ida_Ns); + } + + return(IDA_SUCCESS); + } + + /* Find consistent I.C. for sensitivities using a staggered approach */ + + + /* 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_t0, IDA_mem->ida_yy0, + IDA_mem->ida_yp0, IDA_mem->ida_delta, + IDA_mem->ida_user_data); + IDA_mem->ida_nre++; + if(retval < 0) + /* res function failed unrecoverably. */ + return(IDA_RES_FAIL); + + if(retval > 0) + /* res function failed recoverably but no recovery possible. */ + return(IDA_FIRST_RES_FAIL); + + /* Loop over nwt = number of evaluations of ewt vector. */ + for(nwt = 1; nwt <= 2; nwt++) { + + /* Loop over nh = number of h values. */ + for(nh = 1; nh <= mxnh; nh++) { + + retval = IDASensNlsIC(IDA_mem); + if(retval == IDA_SUCCESS) break; + + /* Increment the number of the sensitivity related corrector convergence failures. */ + IDA_mem->ida_ncfnS++; + + if(retval < 0) break; + if(nh == mxnh) break; + + /* If looping to try again, reset yyS0 and ypS0 if not converging. */ + if(retval != IC_SLOW_CONVRG) { + for (is=0; is<IDA_mem->ida_Ns; is++) { + N_VScale(ONE, IDA_mem->ida_phiS[0][is], IDA_mem->ida_yyS0[is]); + N_VScale(ONE, IDA_mem->ida_phiS[1][is], IDA_mem->ida_ypS0[is]); + } + } + hic *= PT1; + IDA_mem->ida_cj = ONE/hic; + IDA_mem->ida_hh = hic; + + } /* End of nh loop */ + + /* Break on failure */ + if(retval != IDA_SUCCESS) break; + + /* Since it was successful, reevaluate ewtS with the new values of yyS0, save + yyS0 and ypS0 in phiS[0] and phiS[1] and loop one more time to check and + maybe correct the new sensitivities IC with respect to the new weights. */ + + /* Reevaluate ewtS. */ + ewtsetOK = IDASensEwtSet(IDA_mem, IDA_mem->ida_yyS0, IDA_mem->ida_ewtS); + if(ewtsetOK != 0) { + retval = IDA_BAD_EWT; + break; + } + + /* Save yyS0 and ypS0. */ + for (is=0; is<IDA_mem->ida_Ns; is++) { + N_VScale(ONE, IDA_mem->ida_yyS0[is], IDA_mem->ida_phiS[0][is]); + N_VScale(ONE, IDA_mem->ida_ypS0[is], IDA_mem->ida_phiS[1][is]); + } + + } /* End of nwt loop */ + + + /* Load the optional outputs. */ + if(icopt == IDA_YA_YDP_INIT) IDA_mem->ida_hused = hic; + + /* Free temporary space */ + N_VDestroy(IDA_mem->ida_yy0); + N_VDestroy(IDA_mem->ida_yp0); + + /* Here sensi is SUNTRUE, so deallocate sensitivity temporary vectors. */ + N_VDestroyVectorArray(IDA_mem->ida_yyS0, IDA_mem->ida_Ns); + N_VDestroyVectorArray(IDA_mem->ida_ypS0, IDA_mem->ida_Ns); + + + /* On any failure, print message and return proper flag. */ + if(retval != IDA_SUCCESS) { + icret = IDAICFailFlag(IDA_mem, retval); + return(icret); + } + + /* Otherwise return success flag. */ + + return(IDA_SUCCESS); + +} + +/* + * ================================================================= + * PRIVATE FUNCTIONS IMPLEMENTATION + * ================================================================= + */ + +/* + * ----------------------------------------------------------------- + * IDANlsIC + * ----------------------------------------------------------------- + * IDANlsIC solves a nonlinear system for consistent initial + * conditions. It calls IDANewtonIC to do most of the work. + * + * The return value is IDA_SUCCESS = 0 if no error occurred. + * The error return values (positive) considered recoverable are: + * IC_FAIL_RECOV if res, lsetup, or lsolve failed recoverably + * IC_CONSTR_FAILED if the constraints could not be met + * IC_LINESRCH_FAILED if the linesearch failed (either on steptol test + * or on maxbacks test) + * IC_CONV_FAIL if the Newton iterations failed to converge + * IC_SLOW_CONVRG if the iterations are converging slowly + * (failed the convergence test, but showed + * norm reduction or convergence rate < 1) + * The error return values (negative) considered non-recoverable are: + * IDA_RES_FAIL if res had a non-recoverable error + * IDA_FIRST_RES_FAIL if res failed recoverably on the first call + * IDA_LSETUP_FAIL if lsetup had a non-recoverable error + * IDA_LSOLVE_FAIL if lsolve had a non-recoverable error + * ----------------------------------------------------------------- + */ + +static int IDANlsIC(IDAMem IDA_mem) +{ + int retval, nj, is; + N_Vector tv1, tv2, tv3; + booleantype sensi_sim; + + /* Are we computing sensitivities with the IDA_SIMULTANEOUS approach? */ + sensi_sim = (IDA_mem->ida_sensi && (IDA_mem->ida_ism==IDA_SIMULTANEOUS)); + + tv1 = IDA_mem->ida_ee; + tv2 = IDA_mem->ida_tempv2; + tv3 = IDA_mem->ida_phi[2]; + + /* Evaluate RHS. */ + retval = IDA_mem->ida_res(IDA_mem->ida_t0, IDA_mem->ida_yy0, IDA_mem->ida_yp0, + IDA_mem->ida_delta, IDA_mem->ida_user_data); + IDA_mem->ida_nre++; + if(retval < 0) return(IDA_RES_FAIL); + if(retval > 0) return(IDA_FIRST_RES_FAIL); + + /* Save the residual. */ + N_VScale(ONE, IDA_mem->ida_delta, IDA_mem->ida_savres); + + if(sensi_sim) { + + /*Evaluate sensitivity RHS and save it in savresS. */ + retval = IDA_mem->ida_resS(IDA_mem->ida_Ns, IDA_mem->ida_t0, + IDA_mem->ida_yy0, IDA_mem->ida_yp0, + IDA_mem->ida_delta, + IDA_mem->ida_yyS0, IDA_mem->ida_ypS0, + IDA_mem->ida_deltaS, + IDA_mem->ida_user_dataS, + IDA_mem->ida_tmpS1, IDA_mem->ida_tmpS2, + IDA_mem->ida_tmpS3); + IDA_mem->ida_nrSe++; + if(retval < 0) return(IDA_RES_FAIL); + if(retval > 0) return(IDA_FIRST_RES_FAIL); + + for(is=0; is<IDA_mem->ida_Ns; is++) + N_VScale(ONE, IDA_mem->ida_deltaS[is], IDA_mem->ida_savresS[is]); + } + + /* Loop over nj = number of linear solve Jacobian setups. */ + for(nj = 1; nj <= IDA_mem->ida_maxnj; nj++) { + + /* If there is a setup routine, call it. */ + if(IDA_mem->ida_lsetup) { + IDA_mem->ida_nsetups++; + retval = IDA_mem->ida_lsetup(IDA_mem, IDA_mem->ida_yy0, + IDA_mem->ida_yp0, IDA_mem->ida_delta, + tv1, tv2, tv3); + if(retval < 0) return(IDA_LSETUP_FAIL); + if(retval > 0) return(IC_FAIL_RECOV); + } + + /* Call the Newton iteration routine, and return if successful. */ + retval = IDANewtonIC(IDA_mem); + if(retval == IDA_SUCCESS) return(IDA_SUCCESS); + + /* If converging slowly and lsetup is nontrivial, retry. */ + if(retval == IC_SLOW_CONVRG && IDA_mem->ida_lsetup) { + N_VScale(ONE, IDA_mem->ida_savres, IDA_mem->ida_delta); + + if(sensi_sim) + for(is=0; is<IDA_mem->ida_Ns; is++) + N_VScale(ONE, IDA_mem->ida_savresS[is], IDA_mem->ida_deltaS[is]); + + continue; + } else { + return(retval); + } + + } /* End of nj loop */ + + /* No convergence after maxnj tries; return with retval=IC_SLOW_CONVRG */ + return(retval); + +} + +/* + * ----------------------------------------------------------------- + * IDANewtonIC + * ----------------------------------------------------------------- + * IDANewtonIC performs the Newton iteration to solve for consistent + * initial conditions. It calls IDALineSrch within each iteration. + * On return, savres contains the current residual vector. + * + * The return value is IDA_SUCCESS = 0 if no error occurred. + * The error return values (positive) considered recoverable are: + * IC_FAIL_RECOV if res or lsolve failed recoverably + * IC_CONSTR_FAILED if the constraints could not be met + * IC_LINESRCH_FAILED if the linesearch failed (either on steptol test + * or on maxbacks test) + * IC_CONV_FAIL if the Newton iterations failed to converge + * IC_SLOW_CONVRG if the iterations appear to be converging slowly. + * They failed the convergence test, but showed + * an overall norm reduction (by a factor of < 0.1) + * or a convergence rate <= ICRATEMAX). + * The error return values (negative) considered non-recoverable are: + * IDA_RES_FAIL if res had a non-recoverable error + * IDA_LSOLVE_FAIL if lsolve had a non-recoverable error + * ----------------------------------------------------------------- + */ + +static int IDANewtonIC(IDAMem IDA_mem) +{ + int retval, mnewt, is; + realtype delnorm, fnorm, fnorm0, oldfnrm, rate; + booleantype sensi_sim; + + /* Are we computing sensitivities with the IDA_SIMULTANEOUS approach? */ + sensi_sim = (IDA_mem->ida_sensi && (IDA_mem->ida_ism==IDA_SIMULTANEOUS)); + + /* Set pointer for vector delnew */ + IDA_mem->ida_delnew = IDA_mem->ida_phi[2]; + + /* Call the linear solve function to get the Newton step, delta. */ + retval = IDA_mem->ida_lsolve(IDA_mem, IDA_mem->ida_delta, + IDA_mem->ida_ewt, IDA_mem->ida_yy0, + IDA_mem->ida_yp0, IDA_mem->ida_savres); + if(retval < 0) return(IDA_LSOLVE_FAIL); + if(retval > 0) return(IC_FAIL_RECOV); + + /* Compute the norm of the step. */ + fnorm = IDAWrmsNorm(IDA_mem, IDA_mem->ida_delta, IDA_mem->ida_ewt, SUNFALSE); + + /* Call the lsolve function to get correction vectors deltaS. */ + if (sensi_sim) { + for(is=0;is<IDA_mem->ida_Ns;is++) { + retval = IDA_mem->ida_lsolve(IDA_mem, IDA_mem->ida_deltaS[is], + IDA_mem->ida_ewtS[is], IDA_mem->ida_yy0, + IDA_mem->ida_yp0, IDA_mem->ida_savres); + if(retval < 0) return(IDA_LSOLVE_FAIL); + if(retval > 0) return(IC_FAIL_RECOV); + } + /* Update the norm of delta. */ + fnorm = IDASensWrmsNormUpdate(IDA_mem, fnorm, IDA_mem->ida_deltaS, + IDA_mem->ida_ewtS, SUNFALSE); + } + + /* Test for convergence. Return now if the norm is small. */ + if(IDA_mem->ida_sysindex == 0) + fnorm *= IDA_mem->ida_tscale * SUNRabs(IDA_mem->ida_cj); + if(fnorm <= IDA_mem->ida_epsNewt) return(IDA_SUCCESS); + fnorm0 = fnorm; + + /* Initialize rate to avoid compiler warning message */ + rate = ZERO; + + /* Newton iteration loop */ + + for(mnewt = 0; mnewt < IDA_mem->ida_maxnit; mnewt++) { + + IDA_mem->ida_nni++; + delnorm = fnorm; + oldfnrm = fnorm; + + /* Call the Linesearch function and return if it failed. */ + retval = IDALineSrch(IDA_mem, &delnorm, &fnorm); + if(retval != IDA_SUCCESS) return(retval); + + /* Set the observed convergence rate and test for convergence. */ + rate = fnorm/oldfnrm; + if(fnorm <= IDA_mem->ida_epsNewt) return(IDA_SUCCESS); + + /* If not converged, copy new step vector, and loop. */ + N_VScale(ONE, IDA_mem->ida_delnew, IDA_mem->ida_delta); + + if(sensi_sim) { + /* Update the iteration's step for sensitivities. */ + for(is=0; is<IDA_mem->ida_Ns; is++) + N_VScale(ONE, IDA_mem->ida_delnewS[is], IDA_mem->ida_deltaS[is]); + } + + } /* End of Newton iteration loop */ + + /* Return either IC_SLOW_CONVRG or recoverable fail flag. */ + if(rate <= ICRATEMAX || fnorm < PT1*fnorm0) return(IC_SLOW_CONVRG); + return(IC_CONV_FAIL); +} + +/* + * ----------------------------------------------------------------- + * IDALineSrch + * ----------------------------------------------------------------- + * IDALineSrch performs the Linesearch algorithm with the + * calculation of consistent initial conditions. + * + * On entry, yy0 and yp0 are the current values of y and y', the + * Newton step is delta, the current residual vector F is savres, + * delnorm is WRMS-norm(delta), and fnorm is the norm of the vector + * J-inverse F. + * + * On a successful return, yy0, yp0, and savres have been updated, + * delnew contains the current value of J-inverse F, and fnorm is + * WRMS-norm(delnew). + * + * The return value is IDA_SUCCESS = 0 if no error occurred. + * The error return values (positive) considered recoverable are: + * IC_FAIL_RECOV if res or lsolve failed recoverably + * IC_CONSTR_FAILED if the constraints could not be met + * IC_LINESRCH_FAILED if the linesearch failed (either on steptol test + * or on maxbacks test) + * The error return values (negative) considered non-recoverable are: + * IDA_RES_FAIL if res had a non-recoverable error + * IDA_LSOLVE_FAIL if lsolve had a non-recoverable error + * ----------------------------------------------------------------- + */ + +static int IDALineSrch(IDAMem IDA_mem, realtype *delnorm, realtype *fnorm) +{ + booleantype conOK; + int retval, is, nbacks; + realtype f1norm, fnormp, f1normp, ratio, lambda, minlam, slpi; + N_Vector mc; + booleantype sensi_sim; + + /* Initialize work space pointers, f1norm, ratio. + (Use of mc in constraint check does not conflict with ypnew.) */ + mc = IDA_mem->ida_ee; + IDA_mem->ida_dtemp = IDA_mem->ida_phi[3]; + IDA_mem->ida_ynew = IDA_mem->ida_tempv2; + IDA_mem->ida_ypnew = IDA_mem->ida_ee; + f1norm = (*fnorm)*(*fnorm)*HALF; + ratio = ONE; + + /* If there are constraints, check and reduce step if necessary. */ + if(IDA_mem->ida_constraintsSet) { + + /* Update y and check constraints. */ + IDANewy(IDA_mem); + conOK = N_VConstrMask(IDA_mem->ida_constraints, + IDA_mem->ida_ynew, mc); + + if(!conOK) { + /* Not satisfied. Compute scaled step to satisfy constraints. */ + N_VProd(mc, IDA_mem->ida_delta, IDA_mem->ida_dtemp); + ratio = PT99*N_VMinQuotient(IDA_mem->ida_yy0, IDA_mem->ida_dtemp); + (*delnorm) *= ratio; + if((*delnorm) <= IDA_mem->ida_steptol) + return(IC_CONSTR_FAILED); + N_VScale(ratio, IDA_mem->ida_delta, IDA_mem->ida_delta); + } + + } /* End of constraints check */ + + slpi = -TWO*f1norm*ratio; + minlam = IDA_mem->ida_steptol / (*delnorm); + lambda = ONE; + nbacks = 0; + + /* Are we computing sensitivities with the IDA_SIMULTANEOUS approach? */ + sensi_sim = (IDA_mem->ida_sensi && (IDA_mem->ida_ism==IDA_SIMULTANEOUS)); + + /* In IDA_Y_INIT case, set ypnew = yp0 (fixed) for linesearch. */ + if(IDA_mem->ida_icopt == IDA_Y_INIT) { + N_VScale(ONE, IDA_mem->ida_yp0, IDA_mem->ida_ypnew); + + /* do the same for sensitivities. */ + if(sensi_sim) { + for(is=0; is<IDA_mem->ida_Ns; is++) + N_VScale(ONE, IDA_mem->ida_ypS0[is], IDA_mem->ida_ypS0new[is]); + } + } + + /* Loop on linesearch variable lambda. */ + + for(;;) { + + if (nbacks == IDA_mem->ida_maxbacks) + return(IC_LINESRCH_FAILED); + /* Get new (y,y') = (ynew,ypnew) and norm of new function value. */ + IDANewyyp(IDA_mem, lambda); + retval = IDAfnorm(IDA_mem, &fnormp); + if(retval != IDA_SUCCESS) return(retval); + + /* If lsoff option is on, break out. */ + if(IDA_mem->ida_lsoff) break; + + /* Do alpha-condition test. */ + f1normp = fnormp*fnormp*HALF; + if(f1normp <= f1norm + ALPHALS*slpi*lambda) break; + if(lambda < minlam) return(IC_LINESRCH_FAILED); + lambda /= TWO; + IDA_mem->ida_nbacktr++; nbacks++; + + } /* End of breakout linesearch loop */ + + /* Update yy0, yp0. */ + N_VScale(ONE, IDA_mem->ida_ynew, IDA_mem->ida_yy0); + + if(sensi_sim) { + /* Update yyS0 and ypS0. */ + for(is=0; is<IDA_mem->ida_Ns; is++) + N_VScale(ONE, IDA_mem->ida_yyS0new[is], IDA_mem->ida_yyS0[is]); + } + + if(IDA_mem->ida_icopt == IDA_YA_YDP_INIT) { + N_VScale(ONE, IDA_mem->ida_ypnew, IDA_mem->ida_yp0); + + if(sensi_sim) + for(is=0; is<IDA_mem->ida_Ns; is++) + N_VScale(ONE, IDA_mem->ida_ypS0new[is], IDA_mem->ida_ypS0[is]); + + } + /* Update fnorm, then return. */ + *fnorm = fnormp; + return(IDA_SUCCESS); + +} + +/* + * ----------------------------------------------------------------- + * IDAfnorm + * ----------------------------------------------------------------- + * IDAfnorm computes the norm of the current function value, by + * evaluating the DAE residual function, calling the linear + * system solver, and computing a WRMS-norm. + * + * On return, savres contains the current residual vector F, and + * delnew contains J-inverse F. + * + * The return value is IDA_SUCCESS = 0 if no error occurred, or + * IC_FAIL_RECOV if res or lsolve failed recoverably, or + * IDA_RES_FAIL if res had a non-recoverable error, or + * IDA_LSOLVE_FAIL if lsolve had a non-recoverable error. + * ----------------------------------------------------------------- + */ + +static int IDAfnorm(IDAMem IDA_mem, realtype *fnorm) +{ + int retval, is; + + /* Get residual vector F, return if failed, and save F in savres. */ + retval = IDA_mem->ida_res(IDA_mem->ida_t0, IDA_mem->ida_ynew, + IDA_mem->ida_ypnew, IDA_mem->ida_delnew, + IDA_mem->ida_user_data); + IDA_mem->ida_nre++; + if(retval < 0) return(IDA_RES_FAIL); + if(retval > 0) return(IC_FAIL_RECOV); + + N_VScale(ONE, IDA_mem->ida_delnew, IDA_mem->ida_savres); + + /* Call the linear solve function to get J-inverse F; return if failed. */ + retval = IDA_mem->ida_lsolve(IDA_mem, IDA_mem->ida_delnew, IDA_mem->ida_ewt, + IDA_mem->ida_ynew, IDA_mem->ida_ypnew, + IDA_mem->ida_savres); + if(retval < 0) return(IDA_LSOLVE_FAIL); + if(retval > 0) return(IC_FAIL_RECOV); + + /* Compute the WRMS-norm. */ + *fnorm = IDAWrmsNorm(IDA_mem, IDA_mem->ida_delnew, IDA_mem->ida_ewt, SUNFALSE); + + + /* Are we computing SENSITIVITIES with the IDA_SIMULTANEOUS approach? */ + + if(IDA_mem->ida_sensi && (IDA_mem->ida_ism==IDA_SIMULTANEOUS)) { + + /* Evaluate the residual for sensitivities. */ + retval = IDA_mem->ida_resS(IDA_mem->ida_Ns, IDA_mem->ida_t0, + IDA_mem->ida_ynew, IDA_mem->ida_ypnew, + IDA_mem->ida_savres, + IDA_mem->ida_yyS0new, + IDA_mem->ida_ypS0new, + IDA_mem->ida_delnewS, + IDA_mem->ida_user_dataS, + IDA_mem->ida_tmpS1, IDA_mem->ida_tmpS2, + IDA_mem->ida_tmpS3); + IDA_mem->ida_nrSe++; + if(retval < 0) return(IDA_RES_FAIL); + if(retval > 0) return(IC_FAIL_RECOV); + + /* Save delnewS in savresS. */ + for(is=0; is<IDA_mem->ida_Ns; is++) + N_VScale(ONE, IDA_mem->ida_delnewS[is], IDA_mem->ida_savresS[is]); + + /* Call the linear solve function to get J-inverse deltaS. */ + for(is=0; is<IDA_mem->ida_Ns; is++) { + + retval = IDA_mem->ida_lsolve(IDA_mem, IDA_mem->ida_delnewS[is], + IDA_mem->ida_ewtS[is], + IDA_mem->ida_ynew, + IDA_mem->ida_ypnew, + IDA_mem->ida_savres); + if(retval < 0) return(IDA_LSOLVE_FAIL); + if(retval > 0) return(IC_FAIL_RECOV); + } + + /* Include sensitivities in norm. */ + *fnorm = IDASensWrmsNormUpdate(IDA_mem, *fnorm, IDA_mem->ida_delnewS, + IDA_mem->ida_ewtS, SUNFALSE); + } + + /* Rescale norm if index = 0. */ + if(IDA_mem->ida_sysindex == 0) + (*fnorm) *= IDA_mem->ida_tscale * SUNRabs(IDA_mem->ida_cj); + + return(IDA_SUCCESS); + +} + +/* + * ----------------------------------------------------------------- + * IDANewyyp + * ----------------------------------------------------------------- + * IDANewyyp updates the vectors ynew and ypnew from yy0 and yp0, + * using the current step vector lambda*delta, in a manner + * depending on icopt and the input id vector. + * + * The return value is always IDA_SUCCESS = 0. + * ----------------------------------------------------------------- + */ + +static int IDANewyyp(IDAMem IDA_mem, realtype lambda) +{ + int retval; + + retval = IDA_SUCCESS; + + /* IDA_YA_YDP_INIT case: ynew = yy0 - lambda*delta where id_i = 0 + ypnew = yp0 - cj*lambda*delta where id_i = 1. */ + if(IDA_mem->ida_icopt == IDA_YA_YDP_INIT) { + + N_VProd(IDA_mem->ida_id, IDA_mem->ida_delta, IDA_mem->ida_dtemp); + N_VLinearSum(ONE, IDA_mem->ida_yp0, -IDA_mem->ida_cj*lambda, + IDA_mem->ida_dtemp, IDA_mem->ida_ypnew); + N_VLinearSum(ONE, IDA_mem->ida_delta, -ONE, + IDA_mem->ida_dtemp, IDA_mem->ida_dtemp); + N_VLinearSum(ONE, IDA_mem->ida_yy0, -lambda, + IDA_mem->ida_dtemp, IDA_mem->ida_ynew); + + }else if(IDA_mem->ida_icopt == IDA_Y_INIT) { + + /* IDA_Y_INIT case: ynew = yy0 - lambda*delta. (ypnew = yp0 preset.) */ + N_VLinearSum(ONE, IDA_mem->ida_yy0, -lambda, IDA_mem->ida_delta, + IDA_mem->ida_ynew); + } + + if(IDA_mem->ida_sensi && (IDA_mem->ida_ism==IDA_SIMULTANEOUS)) + retval = IDASensNewyyp(IDA_mem, lambda); + + return(retval); + +} + +/* + * ----------------------------------------------------------------- + * IDANewy + * ----------------------------------------------------------------- + * IDANewy updates the vector ynew from yy0, + * using the current step vector delta, in a manner + * depending on icopt and the input id vector. + * + * The return value is always IDA_SUCCESS = 0. + * ----------------------------------------------------------------- + */ + +static int IDANewy(IDAMem IDA_mem) +{ + + /* IDA_YA_YDP_INIT case: ynew = yy0 - delta where id_i = 0. */ + if(IDA_mem->ida_icopt == IDA_YA_YDP_INIT) { + N_VProd(IDA_mem->ida_id, IDA_mem->ida_delta, IDA_mem->ida_dtemp); + N_VLinearSum(ONE, IDA_mem->ida_delta, -ONE, + IDA_mem->ida_dtemp, IDA_mem->ida_dtemp); + N_VLinearSum(ONE, IDA_mem->ida_yy0, -ONE, + IDA_mem->ida_dtemp, IDA_mem->ida_ynew); + return(IDA_SUCCESS); + } + + /* IDA_Y_INIT case: ynew = yy0 - delta. */ + N_VLinearSum(ONE, IDA_mem->ida_yy0, -ONE, IDA_mem->ida_delta, + IDA_mem->ida_ynew); + return(IDA_SUCCESS); + +} +/* + * ----------------------------------------------------------------- + * Sensitivity I.C. functions + * ----------------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------- + * IDASensNlsIC + * ----------------------------------------------------------------- + * IDASensNlsIC solves nonlinear systems for sensitivities consistent + * initial conditions. It mainly relies on IDASensNewtonIC. + * + * The return value is IDA_SUCCESS = 0 if no error occurred. + * The error return values (positive) considered recoverable are: + * IC_FAIL_RECOV if res, lsetup, or lsolve failed recoverably + * IC_CONSTR_FAILED if the constraints could not be met + * IC_LINESRCH_FAILED if the linesearch failed (either on steptol test + * or on maxbacks test) + * IC_CONV_FAIL if the Newton iterations failed to converge + * IC_SLOW_CONVRG if the iterations are converging slowly + * (failed the convergence test, but showed + * norm reduction or convergence rate < 1) + * The error return values (negative) considered non-recoverable are: + * IDA_RES_FAIL if res had a non-recoverable error + * IDA_FIRST_RES_FAIL if res failed recoverably on the first call + * IDA_LSETUP_FAIL if lsetup had a non-recoverable error + * IDA_LSOLVE_FAIL if lsolve had a non-recoverable error + * ----------------------------------------------------------------- + */ +static int IDASensNlsIC(IDAMem IDA_mem) +{ + int retval; + int is, nj; + + retval = IDA_mem->ida_resS(IDA_mem->ida_Ns, IDA_mem->ida_t0, + IDA_mem->ida_yy0, IDA_mem->ida_yp0, + IDA_mem->ida_delta, IDA_mem->ida_yyS0, + IDA_mem->ida_ypS0, + IDA_mem->ida_deltaS, + IDA_mem->ida_user_dataS, + IDA_mem->ida_tmpS1, IDA_mem->ida_tmpS2, + IDA_mem->ida_tmpS3); + IDA_mem->ida_nrSe++; + if(retval < 0) return(IDA_RES_FAIL); + if(retval > 0) return(IDA_FIRST_RES_FAIL); + + /* Save deltaS */ + for(is=0; is<IDA_mem->ida_Ns; is++) + N_VScale(ONE, IDA_mem->ida_deltaS[is], IDA_mem->ida_savresS[is]); + + /* Loop over nj = number of linear solve Jacobian setups. */ + + for(nj = 1; nj <= 2; nj++) { + + /* Call the Newton iteration routine */ + retval = IDASensNewtonIC(IDA_mem); + if(retval == IDA_SUCCESS) return(IDA_SUCCESS); + + /* If converging slowly and lsetup is nontrivial and this is the first pass, + update Jacobian and retry. */ + if(retval == IC_SLOW_CONVRG && IDA_mem->ida_lsetup && nj==1) { + + /* Restore deltaS. */ + for(is=0; is<IDA_mem->ida_Ns; is++) + N_VScale(ONE, IDA_mem->ida_savresS[is], IDA_mem->ida_deltaS[is]); + + IDA_mem->ida_nsetupsS++; + retval = IDA_mem->ida_lsetup(IDA_mem, IDA_mem->ida_yy0, IDA_mem->ida_yp0, + IDA_mem->ida_delta, IDA_mem->ida_tmpS1, + IDA_mem->ida_tmpS2, IDA_mem->ida_tmpS3); + if(retval < 0) return(IDA_LSETUP_FAIL); + if(retval > 0) return(IC_FAIL_RECOV); + + continue; + } else { + return(retval); + } + } + + return(IDA_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * IDASensNewtonIC + * ----------------------------------------------------------------- + * IDANewtonIC performs the Newton iteration to solve for + * sensitivities consistent initial conditions. It calls + * IDASensLineSrch within each iteration. + * On return, savresS contains the current residual vectors. + * + * The return value is IDA_SUCCESS = 0 if no error occurred. + * The error return values (positive) considered recoverable are: + * IC_FAIL_RECOV if res or lsolve failed recoverably + * IC_CONSTR_FAILED if the constraints could not be met + * IC_LINESRCH_FAILED if the linesearch failed (either on steptol test + * or on maxbacks test) + * IC_CONV_FAIL if the Newton iterations failed to converge + * IC_SLOW_CONVRG if the iterations appear to be converging slowly. + * They failed the convergence test, but showed + * an overall norm reduction (by a factor of < 0.1) + * or a convergence rate <= ICRATEMAX). + * The error return values (negative) considered non-recoverable are: + * IDA_RES_FAIL if res had a non-recoverable error + * IDA_LSOLVE_FAIL if lsolve had a non-recoverable error + * ----------------------------------------------------------------- + */ +static int IDASensNewtonIC(IDAMem IDA_mem) +{ + int retval, is, mnewt; + realtype delnorm, fnorm, fnorm0, oldfnrm, rate; + + for(is=0;is<IDA_mem->ida_Ns;is++) { + + /* Call the linear solve function to get the Newton step, delta. */ + retval = IDA_mem->ida_lsolve(IDA_mem, IDA_mem->ida_deltaS[is], + IDA_mem->ida_ewtS[is], IDA_mem->ida_yy0, + IDA_mem->ida_yp0, IDA_mem->ida_delta); + if(retval < 0) return(IDA_LSOLVE_FAIL); + if(retval > 0) return(IC_FAIL_RECOV); + + } + /* Compute the norm of the step and return if it is small enough */ + fnorm = IDASensWrmsNorm(IDA_mem, IDA_mem->ida_deltaS, + IDA_mem->ida_ewtS, SUNFALSE); + if(IDA_mem->ida_sysindex == 0) + fnorm *= IDA_mem->ida_tscale * SUNRabs(IDA_mem->ida_cj); + if(fnorm <= IDA_mem->ida_epsNewt) return(IDA_SUCCESS); + fnorm0 = fnorm; + + rate = ZERO; + + /* Newton iteration loop */ + for(mnewt = 0; mnewt < IDA_mem->ida_maxnit; mnewt++) { + + IDA_mem->ida_nniS++; + delnorm = fnorm; + oldfnrm = fnorm; + + /* Call the Linesearch function and return if it failed. */ + retval = IDASensLineSrch(IDA_mem, &delnorm, &fnorm); + if(retval != IDA_SUCCESS) return(retval); + + /* Set the observed convergence rate and test for convergence. */ + rate = fnorm/oldfnrm; + if(fnorm <= IDA_mem->ida_epsNewt) return(IDA_SUCCESS); + + /* If not converged, copy new step vectors, and loop. */ + for(is=0; is<IDA_mem->ida_Ns; is++) + N_VScale(ONE, IDA_mem->ida_delnewS[is], IDA_mem->ida_deltaS[is]); + + } /* End of Newton iteration loop */ + + /* Return either IC_SLOW_CONVRG or recoverable fail flag. */ + if(rate <= ICRATEMAX || fnorm < PT1*fnorm0) return(IC_SLOW_CONVRG); + return(IC_CONV_FAIL); +} + +/* + * ----------------------------------------------------------------- + * IDASensLineSrch + * ----------------------------------------------------------------- + * IDASensLineSrch performs the Linesearch algorithm with the + * calculation of consistent initial conditions for sensitivities + * systems. + * + * On entry, yyS0 and ypS0 contain the current values, the Newton + * steps are contained in deltaS, the current residual vectors FS are + * savresS, delnorm is sens-WRMS-norm(deltaS), and fnorm is + * max { WRMS-norm( J-inverse FS[is] ) : is=1,2,...,Ns } + * + * On a successful return, yy0, yp0, and savres have been updated, + * delnew contains the current values of J-inverse FS, and fnorm is + * max { WRMS-norm(delnewS[is]) : is = 1,2,...Ns } + * + * The return value is IDA_SUCCESS = 0 if no error occurred. + * The error return values (positive) considered recoverable are: + * IC_FAIL_RECOV if res or lsolve failed recoverably + * IC_CONSTR_FAILED if the constraints could not be met + * IC_LINESRCH_FAILED if the linesearch failed (either on steptol test + * or on maxbacks test) + * The error return values (negative) considered non-recoverable are: + * IDA_RES_FAIL if res had a non-recoverable error + * IDA_LSOLVE_FAIL if lsolve had a non-recoverable error + * ----------------------------------------------------------------- + */ + +static int IDASensLineSrch(IDAMem IDA_mem, realtype *delnorm, realtype *fnorm) +{ + int is, retval, nbacks; + realtype f1norm, fnormp, f1normp, slpi, minlam; + realtype lambda, ratio; + + /* Set work space pointer. */ + IDA_mem->ida_dtemp = IDA_mem->ida_phi[3]; + + f1norm = (*fnorm)*(*fnorm)*HALF; + + /* Initialize local variables. */ + ratio = ONE; + slpi = -TWO*f1norm*ratio; + minlam = IDA_mem->ida_steptol / (*delnorm); + lambda = ONE; + nbacks = 0; + + for(;;) { + + if (nbacks == IDA_mem->ida_maxbacks) + return(IC_LINESRCH_FAILED); + /* Get new iteration in (ySnew, ypSnew). */ + IDASensNewyyp(IDA_mem, lambda); + + /* Get the norm of new function value. */ + retval = IDASensfnorm(IDA_mem, &fnormp); + if (retval!=IDA_SUCCESS) return retval; + + /* If lsoff option is on, break out. */ + if(IDA_mem->ida_lsoff) break; + + /* Do alpha-condition test. */ + f1normp = fnormp*fnormp*HALF; + if(f1normp <= f1norm + ALPHALS*slpi*lambda) break; + if(lambda < minlam) return(IC_LINESRCH_FAILED); + lambda /= TWO; + IDA_mem->ida_nbacktr++; nbacks++; + } + + /* Update yyS0, ypS0 and fnorm and return. */ + for(is=0; is<IDA_mem->ida_Ns; is++) { + N_VScale(ONE, IDA_mem->ida_yyS0new[is], IDA_mem->ida_yyS0[is]); + } + + if (IDA_mem->ida_icopt == IDA_YA_YDP_INIT) + for(is=0; is<IDA_mem->ida_Ns; is++) + N_VScale(ONE, IDA_mem->ida_ypS0new[is], IDA_mem->ida_ypS0[is]); + + *fnorm = fnormp; + return(IDA_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * IDASensfnorm + * ----------------------------------------------------------------- + * IDASensfnorm computes the norm of the current function value, by + * evaluating the sensitivity residual function, calling the linear + * system solver, and computing a WRMS-norm. + * + * On return, savresS contains the current residual vectors FS, and + * delnewS contains J-inverse FS. + * + * The return value is IDA_SUCCESS = 0 if no error occurred, or + * IC_FAIL_RECOV if res or lsolve failed recoverably, or + * IDA_RES_FAIL if res had a non-recoverable error, or + * IDA_LSOLVE_FAIL if lsolve had a non-recoverable error. + * ----------------------------------------------------------------- + */ + +static int IDASensfnorm(IDAMem IDA_mem, realtype *fnorm) +{ + int is, retval; + + /* Get sensitivity residual */ + retval = IDA_mem->ida_resS(IDA_mem->ida_Ns, IDA_mem->ida_t0, + IDA_mem->ida_yy0, IDA_mem->ida_yp0, + IDA_mem->ida_delta, + IDA_mem->ida_yyS0new, + IDA_mem->ida_ypS0new, + IDA_mem->ida_delnewS, + IDA_mem->ida_user_dataS, + IDA_mem->ida_tmpS1, IDA_mem->ida_tmpS2, + IDA_mem->ida_tmpS3); + IDA_mem->ida_nrSe++; + if(retval < 0) return(IDA_RES_FAIL); + if(retval > 0) return(IC_FAIL_RECOV); + + for(is=0; is<IDA_mem->ida_Ns; is++) + N_VScale(ONE, IDA_mem->ida_delnewS[is], IDA_mem->ida_savresS[is]); + + /* Call linear solve function */ + for(is=0; is<IDA_mem->ida_Ns; is++) { + + retval = IDA_mem->ida_lsolve(IDA_mem, IDA_mem->ida_delnewS[is], + IDA_mem->ida_ewtS[is], + IDA_mem->ida_yy0, + IDA_mem->ida_yp0, + IDA_mem->ida_delta); + if(retval < 0) return(IDA_LSOLVE_FAIL); + if(retval > 0) return(IC_FAIL_RECOV); + } + + /* Compute the WRMS-norm; rescale if index = 0. */ + *fnorm = IDASensWrmsNorm(IDA_mem, IDA_mem->ida_delnewS, IDA_mem->ida_ewtS, SUNFALSE); + if(IDA_mem->ida_sysindex == 0) + (*fnorm) *= IDA_mem->ida_tscale * SUNRabs(IDA_mem->ida_cj); + + return(IDA_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * IDASensNewyyp + * ----------------------------------------------------------------- + * IDASensNewyyp computes the Newton updates for each of the + * sensitivities systems using the current step vector lambda*delta, + * in a manner depending on icopt and the input id vector. + * + * The return value is always IDA_SUCCESS = 0. + * ----------------------------------------------------------------- + */ + +static int IDASensNewyyp(IDAMem IDA_mem, realtype lambda) +{ + int is; + + if(IDA_mem->ida_icopt == IDA_YA_YDP_INIT) { + + /* IDA_YA_YDP_INIT case: + - ySnew = yS0 - lambda*deltaS where id_i = 0 + - ypSnew = ypS0 - cj*lambda*delta where id_i = 1. */ + + for(is=0; is<IDA_mem->ida_Ns; is++) { + + /* It is ok to use dtemp as temporary vector here. */ + N_VProd(IDA_mem->ida_id, IDA_mem->ida_deltaS[is], IDA_mem->ida_dtemp); + N_VLinearSum(ONE, IDA_mem->ida_ypS0[is], -IDA_mem->ida_cj*lambda, + IDA_mem->ida_dtemp, IDA_mem->ida_ypS0new[is]); + N_VLinearSum(ONE, IDA_mem->ida_deltaS[is], -ONE, + IDA_mem->ida_dtemp, IDA_mem->ida_dtemp); + N_VLinearSum(ONE, IDA_mem->ida_yyS0[is], -lambda, + IDA_mem->ida_dtemp, IDA_mem->ida_yyS0new[is]); + } /* end loop is */ + }else { + + /* IDA_Y_INIT case: + - ySnew = yS0 - lambda*deltaS. (ypnew = yp0 preset.) */ + + for(is=0; is<IDA_mem->ida_Ns; is++) + N_VLinearSum(ONE, IDA_mem->ida_yyS0[is], -lambda, + IDA_mem->ida_deltaS[is], IDA_mem->ida_yyS0new[is]); + } /* end loop is */ + return(IDA_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * IDAICFailFlag + * ----------------------------------------------------------------- + * IDAICFailFlag prints a message and sets the IDACalcIC return + * value appropriate to the flag retval returned by IDANlsIC. + * ----------------------------------------------------------------- + */ + +static int IDAICFailFlag(IDAMem IDA_mem, int retval) +{ + + /* Depending on retval, print error message and return error flag. */ + switch(retval) { + + case IDA_RES_FAIL: + IDAProcessError(IDA_mem, IDA_RES_FAIL, "IDAS", "IDACalcIC", MSG_IC_RES_NONREC); + return(IDA_RES_FAIL); + + case IDA_FIRST_RES_FAIL: + IDAProcessError(IDA_mem, IDA_FIRST_RES_FAIL, "IDAS", "IDACalcIC", MSG_IC_RES_FAIL); + return(IDA_FIRST_RES_FAIL); + + case IDA_LSETUP_FAIL: + IDAProcessError(IDA_mem, IDA_LSETUP_FAIL, "IDAS", "IDACalcIC", MSG_IC_SETUP_FAIL); + return(IDA_LSETUP_FAIL); + + case IDA_LSOLVE_FAIL: + IDAProcessError(IDA_mem, IDA_LSOLVE_FAIL, "IDAS", "IDACalcIC", MSG_IC_SOLVE_FAIL); + return(IDA_LSOLVE_FAIL); + + case IC_FAIL_RECOV: + IDAProcessError(IDA_mem, IDA_NO_RECOVERY, "IDAS", "IDACalcIC", MSG_IC_NO_RECOVERY); + return(IDA_NO_RECOVERY); + + case IC_CONSTR_FAILED: + IDAProcessError(IDA_mem, IDA_CONSTR_FAIL, "IDAS", "IDACalcIC", MSG_IC_FAIL_CONSTR); + return(IDA_CONSTR_FAIL); + + case IC_LINESRCH_FAILED: + IDAProcessError(IDA_mem, IDA_LINESEARCH_FAIL, "IDAS", "IDACalcIC", MSG_IC_FAILED_LINS); + return(IDA_LINESEARCH_FAIL); + + case IC_CONV_FAIL: + IDAProcessError(IDA_mem, IDA_CONV_FAIL, "IDAS", "IDACalcIC", MSG_IC_CONV_FAILED); + return(IDA_CONV_FAIL); + + case IC_SLOW_CONVRG: + IDAProcessError(IDA_mem, IDA_CONV_FAIL, "IDAS", "IDACalcIC", MSG_IC_CONV_FAILED); + return(IDA_CONV_FAIL); + + case IDA_BAD_EWT: + IDAProcessError(IDA_mem, IDA_BAD_EWT, "IDAS", "IDACalcIC", MSG_IC_BAD_EWT); + return(IDA_BAD_EWT); + + } + return -99; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_impl.h new file mode 100644 index 0000000..c328511 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_impl.h @@ -0,0 +1,1157 @@ +/* + * ----------------------------------------------------------------- + * $Revision$ + * $Date$ + * ----------------------------------------------------------------- + * Programmer(s): 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 (private version) for the main IDAS solver. + * ----------------------------------------------------------------- + */ + +#ifndef _IDAS_IMPL_H +#define _IDAS_IMPL_H + +#include <stdarg.h> + +#include <idas/idas.h> +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_types.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +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 + * ================================================================= + */ + + +/* 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 */ +#define MXSTEP_DEFAULT 500 /* mxstep default value */ + +/* Return values for lower level routines used by IDASolve and functions + provided to the nonlinear solver */ + +#define IDA_RES_RECVR +1 +#define IDA_LSETUP_RECVR +2 +#define IDA_LSOLVE_RECVR +3 +#define IDA_CONSTR_RECVR +5 +#define IDA_NLS_SETUP_RECVR +6 + +#define IDA_QRHS_RECVR +10 +#define IDA_SRES_RECVR +11 +#define IDA_QSRHS_RECVR +12 + +/* itol */ +#define IDA_NN 0 +#define IDA_SS 1 +#define IDA_SV 2 +#define IDA_WF 3 +#define IDA_EE 4 + +/* + * ----------------------------------------------------------------- + * Types: struct IDAMemRec, IDAMem + * ----------------------------------------------------------------- + * The type IDAMem is type pointer to struct IDAMemRec. + * This structure contains fields to keep track of problem state. + * ----------------------------------------------------------------- + */ + +typedef struct IDAMemRec { + + realtype ida_uround; /* machine unit roundoff */ + + /*-------------------------- + Problem Specification Data + --------------------------*/ + + IDAResFn ida_res; /* F(t,y(t),y'(t))=0; the function F */ + void *ida_user_data; /* user pointer passed to res */ + + 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 */ + 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 + -----------------------*/ + + booleantype ida_quadr; + + IDAQuadRhsFn ida_rhsQ; + void *ida_user_dataQ; + + booleantype ida_errconQ; + + int ida_itolQ; + realtype ida_rtolQ; + realtype ida_SatolQ; /* scalar absolute tolerance for quadratures */ + N_Vector ida_VatolQ; /* vector absolute tolerance for quadratures */ + + /*------------------------ + Sensitivity Related Data + ------------------------*/ + + booleantype ida_sensi; + int ida_Ns; + int ida_ism; + + IDASensResFn ida_resS; + void *ida_user_dataS; + booleantype ida_resSDQ; + + realtype *ida_p; + realtype *ida_pbar; + int *ida_plist; + int ida_DQtype; + realtype ida_DQrhomax; + + 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. */ + + /*----------------------------------- + Quadrature Sensitivity Related Data + -----------------------------------*/ + + booleantype ida_quadr_sensi; /* SUNTRUE if computing sensitivities of quadrs. */ + + IDAQuadSensRhsFn ida_rhsQS; /* fQS = (dfQ/dy)*yS + (dfQ/dp) */ + void *ida_user_dataQS; /* data pointer passed to fQS */ + booleantype ida_rhsQSDQ; /* SUNTRUE if using internal DQ functions */ + + booleantype ida_errconQS; /* SUNTRUE if yQS are considered in err. con. */ + + int ida_itolQS; + realtype ida_rtolQS; /* relative tolerance for yQS */ + realtype *ida_SatolQS; /* scalar absolute tolerances for yQS */ + N_Vector *ida_VatolQS; /* vector absolute tolerances for yQS */ + + /*----------------------------------------------- + Divided differences array and associated arrays + -----------------------------------------------*/ + + N_Vector ida_phi[MXORDP1]; /* phi = (maxord+1) arrays of divided differences */ + + realtype ida_psi[MXORDP1]; /* differences in t (sums of recent step sizes) */ + realtype ida_alpha[MXORDP1]; /* ratios of current stepsize to psi values */ + realtype ida_beta[MXORDP1]; /* ratios of current to previous product of psi's */ + realtype ida_sigma[MXORDP1]; /* product successive alpha values and factorial */ + realtype ida_gamma[MXORDP1]; /* sum of reciprocals of psi values */ + + /*------------------------- + N_Vectors for integration + -------------------------*/ + + N_Vector ida_ewt; /* error weight vector */ + N_Vector ida_yy; /* work space for y vector (= user's yret) */ + N_Vector ida_yp; /* work space for y' vector (= user's ypret) */ + N_Vector ida_yypredict; /* predicted y vector */ + N_Vector ida_yppredict; /* predicted y' vector */ + N_Vector ida_delta; /* residual vector */ + N_Vector ida_id; /* bit vector for diff./algebraic components */ + N_Vector ida_constraints; /* vector of inequality constraint options */ + N_Vector ida_savres; /* saved residual vector */ + 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 */ + N_Vector ida_ynew; /* work vector for y in IDACalcIC (= tempv2) */ + N_Vector ida_ypnew; /* work vector for yp in IDACalcIC (= ee) */ + N_Vector ida_delnew; /* work vector for delta in IDACalcIC (= phi[2]) */ + N_Vector ida_dtemp; /* work vector in IDACalcIC (= phi[3]) */ + + + /*---------------------------- + Quadrature Related N_Vectors + ----------------------------*/ + + N_Vector ida_phiQ[MXORDP1]; + N_Vector ida_yyQ; + N_Vector ida_ypQ; + N_Vector ida_ewtQ; + N_Vector ida_eeQ; + + /*--------------------------- + Sensitivity Related Vectors + ---------------------------*/ + + N_Vector *ida_phiS[MXORDP1]; + N_Vector *ida_ewtS; + + N_Vector *ida_eeS; /* cumulative sensitivity corrections */ + + N_Vector *ida_yyS; /* allocated and used for: */ + N_Vector *ida_ypS; /* ism = SIMULTANEOUS */ + N_Vector *ida_yySpredict; /* ism = STAGGERED */ + N_Vector *ida_ypSpredict; + N_Vector *ida_deltaS; + + 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_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 */ + + N_Vector *ida_yyS0new; /* work vector in IDASensLineSrch (= phiS[4]) */ + N_Vector *ida_ypS0new; /* work vector in IDASensLineSrch (= eeS) */ + + /*-------------------------------------- + Quadrature Sensitivity Related Vectors + --------------------------------------*/ + + N_Vector *ida_phiQS[MXORDP1];/* Mod. div. diffs. for quadr. sensitivities */ + N_Vector *ida_ewtQS; /* error weight vectors for sensitivities */ + + N_Vector *ida_eeQS; /* cumulative quadr.sensi.corrections */ + + N_Vector *ida_yyQS; /* Unlike yS, yQS is not allocated by the user */ + N_Vector *ida_tempvQS; /* temporary storage vector (~ tempv) */ + N_Vector ida_savrhsQ; /* saved quadr. rhs (needed for rhsQS calls) */ + + /*------------------------------ + Variables for use by IDACalcIC + ------------------------------*/ + + realtype ida_t0; /* initial t */ + N_Vector ida_yy0; /* initial y vector (user-supplied). */ + N_Vector ida_yp0; /* initial y' vector (user-supplied). */ + + int ida_icopt; /* IC calculation user option */ + booleantype ida_lsoff; /* IC calculation linesearch turnoff option */ + int ida_maxnh; /* max. number of h tries in IC calculation */ + int ida_maxnj; /* max. number of J tries in IC calculation */ + int ida_maxnit; /* max. number of Netwon iterations in IC calc. */ + int ida_nbacktr; /* number of IC linesearch backtrack operations */ + int ida_sysindex; /* computed system index (0 or 1) */ + int ida_maxbacks; /* max backtracks per Newton step */ + realtype ida_epiccon; /* IC nonlinear convergence test constant */ + realtype ida_steptol; /* minimum Newton step size in IC calculation */ + realtype ida_tscale; /* time scale factor = abs(tout1 - t0) */ + + /* Tstop information */ + + booleantype ida_tstopset; + realtype ida_tstop; + + /* Step Data */ + + int ida_kk; /* current BDF method order */ + int ida_knew; /* order for next step from order decrease decision */ + int ida_phase; /* flag to trigger step doubling in first few steps */ + int ida_ns; /* counts steps at fixed stepsize and order */ + + realtype ida_hin; /* initial step */ + realtype ida_hh; /* current step size h */ + realtype ida_rr; /* rr = hnext / hused */ + realtype ida_tn; /* current internal value of t */ + realtype ida_tretlast; /* value of tret previously returned by IDASolve */ + realtype ida_cj; /* current value of scalar (-alphas/hh) in Jacobian */ + realtype ida_cjlast; /* cj value saved from last successful step */ + realtype ida_cjold; /* cj value saved from last call to lsetup */ + realtype ida_cjratio; /* ratio of cj values: cj/cjold */ + realtype ida_ss; /* scalar used in Newton iteration convergence test */ + realtype ida_oldnrm; /* norm of previous nonlinear solver update */ + realtype ida_epsNewt; /* test constant in Newton convergence test */ + realtype ida_epcon; /* coeficient of the Newton covergence test */ + realtype ida_toldel; /* tolerance in direct test on Newton corrections */ + + realtype ida_ssS; /* scalar ss for staggered sensitivities */ + + /*------ + Limits + ------*/ + + 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: */ + int ida_maxord_alloc; /* value of maxord used when allocating memory */ + 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 + --------*/ + + long int ida_nst; /* number of internal steps taken */ + + long int ida_nre; /* number of function (res) calls */ + long int ida_nrQe; + long int ida_nrSe; + long int ida_nrQSe; /* number of fQS calls */ + long int ida_nreS; + long int ida_nrQeS; /* number of fQ calls from sensi DQ */ + + + long int ida_ncfn; /* number of corrector convergence failures */ + long int ida_ncfnQ; + long int ida_ncfnS; + + long int ida_netf; /* number of error test failures */ + long int ida_netfQ; + long int ida_netfS; + long int ida_netfQS; /* number of quadr. sensi. error test failures */ + + long int ida_nni; /* number of Newton iterations performed */ + long int ida_nniS; + + long int ida_nsetups; /* number of lsetup calls */ + long int ida_nsetupsS; + + /*--------------------------- + Space requirements for IDAS + ---------------------------*/ + + sunindextype ida_lrw1; /* no. of realtype words in 1 N_Vector */ + sunindextype ida_liw1; /* no. of integer words in 1 N_Vector */ + sunindextype ida_lrw1Q; + sunindextype ida_liw1Q; + long int ida_lrw; /* number of realtype words in IDA work vectors */ + long int ida_liw; /* no. of integer words in IDA work vectors */ + + + /*------------------------------------------- + Error handler function and error ouput file + -------------------------------------------*/ + + IDAErrHandlerFn ida_ehfun; /* Error messages are handled by ehfun */ + void *ida_eh_data; /* dats pointer passed to ehfun */ + 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 */ + + 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 */ + + booleantype ida_VatolQMallocDone; + booleantype ida_quadMallocDone; + + booleantype ida_VatolSMallocDone; + booleantype ida_SatolSMallocDone; + booleantype ida_sensMallocDone; + + booleantype ida_VatolQSMallocDone; + booleantype ida_SatolQSMallocDone; + booleantype ida_quadSensMallocDone; + + /*--------------------- + Nonlinear Solver Data + ---------------------*/ + + SUNNonlinearSolver NLS; /* nonlinear solver object for DAE solves */ + booleantype ownNLS; /* flag indicating NLS ownership */ + + SUNNonlinearSolver NLSsim; /* nonlinear solver object for DAE+Sens solves + with the simultaneous corrector option */ + booleantype ownNLSsim; /* flag indicating NLS ownership */ + + SUNNonlinearSolver NLSstg; /* nonlinear solver object for DAE+Sens solves + with the staggered corrector option */ + booleantype ownNLSstg; /* flag indicating NLS ownership */ + + /* 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] + + Stagger: ycor0Stg = ida_deltaS + ycorStg = ida_eeS + ewtStg = ida_ewtS + */ + N_Vector ycor0Sim, ycorSim, ewtSim; + N_Vector ycor0Stg, ycorStg, ewtStg; + + /* flags indicating if vector wrappers for the simultaneous and staggered + correctors have been allocated */ + booleantype simMallocDone; + booleantype stgMallocDone; + + /*------------------ + Linear Solver Data + ------------------*/ + + /* Linear Solver functions to be called */ + + 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_lsolve)(struct IDAMemRec *idamem, N_Vector b, N_Vector weight, + N_Vector ycur, N_Vector ypcur, N_Vector rescur); + + int (*ida_lperf)(struct IDAMemRec *idamem, int perftask); + + int (*ida_lfree)(struct IDAMemRec *idamem); + + /* Linear Solver specific memory */ + + void *ida_lmem; + + /* Flag to request a call to the setup routine */ + + booleantype ida_forceSetup; + + /* Flag to indicate successful ida_linit call */ + + booleantype ida_linitOK; + + /*------------ + Saved Values + ------------*/ + + booleantype ida_constraintsSet; /* constraints vector present */ + booleantype ida_suppressalg; /* SUNTRUE if suppressing algebraic vars. + 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 */ + realtype ida_tolsf; /* tolerance scale factor (saved value) */ + + /*---------------- + Rootfinding Data + ----------------*/ + + IDARootFn ida_gfun; /* Function g for roots sought */ + int ida_nrtfn; /* number of components of g */ + int *ida_iroots; /* array for root information */ + int *ida_rootdir; /* array specifying direction of zero-crossing */ + realtype ida_tlo; /* nearest endpoint of interval in root search */ + realtype ida_thi; /* farthest endpoint of interval in root search */ + realtype ida_trout; /* t return value from rootfinder routine */ + realtype *ida_glo; /* saved array of g values at t = tlo */ + realtype *ida_ghi; /* saved array of g values at t = thi */ + realtype *ida_grout; /* array of g values at t = trout */ + realtype ida_toutc; /* copy of tout (if NORMAL mode) */ + realtype ida_ttol; /* tolerance on root location */ + int ida_taskc; /* copy of parameter itask */ + int ida_irfnd; /* flag showing whether last step had a root */ + long int ida_nge; /* counter for g evaluations */ + booleantype *ida_gactive; /* array with active/inactive event functions */ + int ida_mxgnull; /* number of warning messages about possible g==0 */ + + /* Arrays for Fused Vector Operations */ + + /* scalar arrays */ + realtype* ida_cvals; + realtype ida_dvals[MAXORD_DEFAULT]; + + /* vector arrays */ + N_Vector* ida_Xvecs; + N_Vector* ida_Zvecs; + + /*------------------------ + Adjoint sensitivity data + ------------------------*/ + + booleantype ida_adj; /* SUNTRUE if performing ASA */ + + struct IDAadjMemRec *ida_adj_mem; /* Pointer to adjoint memory structure */ + + booleantype ida_adjMallocDone; + +} *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 + * ================================================================= + */ + +/* + * ----------------------------------------------------------------- + * Forward references for pointers to various structures + * ----------------------------------------------------------------- + */ + +typedef struct IDAadjMemRec *IDAadjMem; +typedef struct CkpntMemRec *CkpntMem; +typedef struct DtpntMemRec *DtpntMem; +typedef struct IDABMemRec *IDABMem; + +/* + * ----------------------------------------------------------------- + * Types for functions provided by an interpolation module + * ----------------------------------------------------------------- + * IDAAMMallocFn: Type for a function that initializes the content + * 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 + * interpolated forward solution. + * IDAAStorePnt: Function type for a function that stores a new + * point in the structure d + * ----------------------------------------------------------------- + */ + +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, + N_Vector *yyS, N_Vector *ypS); +typedef int (*IDAAStorePntFn)(IDAMem IDA_mem, DtpntMem d); + +/* + * ----------------------------------------------------------------- + * Types : struct CkpntMemRec, CkpntMem + * ----------------------------------------------------------------- + * The type CkpntMem is type pointer to struct CkpntMemRec. + * This structure contains fields to store all information at a + * check point that is needed to 'hot' start IDAS. + * ----------------------------------------------------------------- + */ + +struct CkpntMemRec { + + /* Integration limits */ + realtype ck_t0; + realtype ck_t1; + + /* Modified divided difference array */ + N_Vector ck_phi[MXORDP1]; + + /* Do we need to carry quadratures? */ + booleantype ck_quadr; + + /* Modified divided difference array for quadratures */ + N_Vector ck_phiQ[MXORDP1]; + + /* Do we need to carry sensitivities? */ + booleantype ck_sensi; + + /* number of sensitivities */ + int ck_Ns; + + /* Modified divided difference array for sensitivities */ + N_Vector *ck_phiS[MXORDP1]; + + /* Do we need to carry quadrature sensitivities? */ + booleantype ck_quadr_sensi; + + /* Modified divided difference array for quadrature sensitivities */ + N_Vector *ck_phiQS[MXORDP1]; + + + /* Step data */ + long int ck_nst; + realtype ck_tretlast; + long int ck_ns; + int ck_kk; + int ck_kused; + int ck_knew; + int ck_phase; + + realtype ck_hh; + realtype ck_hused; + realtype ck_rr; + realtype ck_cj; + realtype ck_cjlast; + realtype ck_cjold; + realtype ck_cjratio; + realtype ck_ss; + realtype ck_ssS; + + realtype ck_psi[MXORDP1]; + realtype ck_alpha[MXORDP1]; + realtype ck_beta[MXORDP1]; + realtype ck_sigma[MXORDP1]; + realtype ck_gamma[MXORDP1]; + + /* How many phi, phiS, phiQ and phiQS were allocated? */ + int ck_phi_alloc; + + /* Pointer to next structure in list */ + struct CkpntMemRec *ck_next; +}; + +/* + * ----------------------------------------------------------------- + * Type : struct DtpntMemRec + * ----------------------------------------------------------------- + * This structure contains fields to store all information at a + * data point that is needed to interpolate solution of forward + * simulations. Its content field is interpType-dependent. + * ----------------------------------------------------------------- + */ + +struct DtpntMemRec { + realtype t; /* time */ + void *content; /* interpType-dependent content */ +}; + +/* Data for cubic Hermite interpolation */ +typedef struct HermiteDataMemRec { + N_Vector y; + N_Vector yd; + N_Vector *yS; + N_Vector *ySd; +} *HermiteDataMem; + +/* Data for polynomial interpolation */ +typedef struct PolynomialDataMemRec { + N_Vector y; + N_Vector *yS; + + /* yd and ySd store the derivative(s) only for the first dt + point. NULL otherwise. */ + N_Vector yd; + N_Vector *ySd; + int order; +} *PolynomialDataMem; + +/* + * ----------------------------------------------------------------- + * Type : struct IDABMemRec + * ----------------------------------------------------------------- + * The type IDABMemRec is a pointer to a structure which stores all + * information for ONE backward problem. + * The IDAadjMem struct contains a linked list of IDABMem pointers + * ----------------------------------------------------------------- + */ +struct IDABMemRec { + + /* Index of this backward problem */ + int ida_index; + + /* Time at which the backward problem is initialized. */ + realtype ida_t0; + + /* Memory for this backward problem */ + IDAMem IDA_mem; + + /* Flags to indicate that this backward problem's RHS or quad RHS + * require forward sensitivities */ + booleantype ida_res_withSensi; + booleantype ida_rhsQ_withSensi; + + /* Residual function for backward run */ + IDAResFnB ida_res; + IDAResFnBS ida_resS; + + /* 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 */ + void *ida_lmem; + + /* 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 */ + void *ida_pmem; + + /* Function to free any memory allocated by the preconditioner module */ + int (*ida_pfree)(IDABMem IDAB_mem); + + /* Time at which to extract solution / quadratures */ + realtype ida_tout; + + /* Workspace Nvectors */ + N_Vector ida_yy; + N_Vector ida_yp; + + /* Link to next structure in list. */ + struct IDABMemRec *ida_next; +}; + + +/* + * ----------------------------------------------------------------- + * Type : struct IDAadjMemRec + * ----------------------------------------------------------------- + * The type IDAadjMem is type pointer to struct IDAadjMemRec. + * This structure contins fields to store all information + * necessary for adjoint sensitivity analysis. + * ----------------------------------------------------------------- + */ + +struct IDAadjMemRec { + + /* -------------------- + * Forward problem data + * -------------------- */ + + /* Integration interval */ + realtype ia_tinitial, ia_tfinal; + + /* Flag for first call to IDASolveF */ + booleantype ia_firstIDAFcall; + + /* Flag if IDASolveF was called with TSTOP */ + booleantype ia_tstopIDAFcall; + realtype ia_tstopIDAF; + + /* ---------------------- + * Backward problems data + * ---------------------- */ + + /* Storage for backward problems */ + struct IDABMemRec *IDAB_mem; + + /* Number of backward problems. */ + int ia_nbckpbs; + + /* Address of current backward problem (iterator). */ + struct IDABMemRec *ia_bckpbCrt; + + /* Flag for first call to IDASolveB */ + booleantype ia_firstIDABcall; + + /* ---------------- + * Check point data + * ---------------- */ + + /* Storage for check point information */ + struct CkpntMemRec *ck_mem; + + /* address of the check point structure for which data is available */ + struct CkpntMemRec *ia_ckpntData; + + /* Number of checkpoints. */ + int ia_nckpnts; + + /* ------------------ + * Interpolation data + * ------------------ */ + + /* 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; + + /* Interpolation type */ + int ia_interpType; + + + /* Functions set by the interpolation module */ + IDAAStorePntFn ia_storePnt; /* store a new interpolation point */ + IDAAGetYFn ia_getY; /* interpolate forward solution */ + IDAAMMallocFn ia_malloc; /* allocate new data point */ + IDAAMFreeFn ia_free; /* destroys data point */ + + /* Flags controlling the interpolation module */ + booleantype ia_mallocDone; /* IM initialized? */ + booleantype ia_newData; /* new data available in dt_mem? */ + booleantype ia_storeSensi; /* store sensitivities? */ + booleantype ia_interpSensi; /* interpolate sensitivities? */ + + booleantype ia_noInterp; /* interpolations are temporarly */ + /* disabled ( IDACalcICB ) */ + + /* Workspace for polynomial interpolation */ + N_Vector ia_Y[MXORDP1]; /* pointers phi[i] */ + N_Vector *ia_YS[MXORDP1]; /* pointers phiS[i] */ + realtype ia_T[MXORDP1]; + + /* 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 + * ================================================================= + */ + +/* + * ----------------------------------------------------------------- + * 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 + * 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); + * ----------------------------------------------------------------- + * 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 + * 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); + * ----------------------------------------------------------------- + * 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 + * for an unrecoverable error. + * ----------------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------- + * 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. + * ----------------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------- + * 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 + * 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 + * ================================================================= + */ + +/* Prototype of internal ewtSet function */ + +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, ...); + +/* Prototype of internal errHandler function */ + +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.*/ + +realtype IDAWrmsNorm(IDAMem IDA_mem, N_Vector x, N_Vector w, + booleantype mask); + +realtype IDASensWrmsNorm(IDAMem IDA_mem, N_Vector *xS, N_Vector *wS, + booleantype mask); + +realtype IDASensWrmsNormUpdate(IDAMem IDA_mem, realtype old_nrm, + N_Vector *xS, N_Vector *wS, + booleantype mask); + +/* Nonlinear solver functions */ +int idaNlsInit(IDAMem IDA_mem); +int idaNlsInitSensSim(IDAMem IDA_mem); +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); + +/* + * ================================================================= + * I D A S E R R O R M E S S A G E S + * ================================================================= + */ + +#if defined(SUNDIALS_EXTENDED_PRECISION) + +#define MSG_TIME "t = %Lg, " +#define MSG_TIME_H "t = %Lg and h = %Lg, " +#define MSG_TIME_INT "t = %Lg is not between tcur - hu = %Lg and tcur = %Lg." +#define MSG_TIME_TOUT "tout = %Lg" +#define MSG_TIME_TSTOP "tstop = %Lg" + +#elif defined(SUNDIALS_DOUBLE_PRECISION) + +#define MSG_TIME "t = %lg, " +#define MSG_TIME_H "t = %lg and h = %lg, " +#define MSG_TIME_INT "t = %lg is not between tcur - hu = %lg and tcur = %lg." +#define MSG_TIME_TOUT "tout = %lg" +#define MSG_TIME_TSTOP "tstop = %lg" + +#else + +#define MSG_TIME "t = %g, " +#define MSG_TIME_H "t = %g and h = %g, " +#define MSG_TIME_INT "t = %g is not between tcur - hu = %g and tcur = %g." +#define MSG_TIME_TOUT "tout = %g" +#define MSG_TIME_TSTOP "tstop = %g" + +#endif + +/* General errors */ + +#define MSG_MEM_FAIL "A memory request failed." +#define MSG_NO_MEM "ida_mem = NULL illegal." +#define MSG_NO_MALLOC "Attempt to call before IDAMalloc." +#define MSG_BAD_NVECTOR "A required vector operation is not implemented." + +/* Initialization errors */ + +#define MSG_Y0_NULL "y0 = NULL illegal." +#define MSG_YP0_NULL "yp0 = NULL illegal." +#define MSG_BAD_ITOL "Illegal value for itol. The legal values are IDA_SS, IDA_SV, and IDA_WF." +#define MSG_RES_NULL "res = NULL illegal." +#define MSG_BAD_RTOL "rtol < 0 illegal." +#define MSG_ATOL_NULL "atol = NULL illegal." +#define MSG_BAD_ATOL "Some atol component < 0.0 illegal." +#define MSG_ROOT_FUNC_NULL "g = NULL illegal." + +#define MSG_MISSING_ID "id = NULL but suppressalg option on." +#define MSG_NO_TOLS "No integration tolerances have been specified." +#define MSG_FAIL_EWT "The user-provide EwtSet function failed." +#define MSG_BAD_EWT "Some initial ewt component = 0.0 illegal." +#define MSG_Y0_FAIL_CONSTR "y0 fails to satisfy constraints." +#define MSG_BAD_ISM_CONSTR "Constraints can not be enforced while forward sensitivity is used with simultaneous method." +#define MSG_LSOLVE_NULL "The linear solver's solve routine is NULL." +#define MSG_LINIT_FAIL "The linear solver's init routine failed." +#define MSG_NLS_INIT_FAIL "The nonlinear solver's init routine failed." + +#define MSG_NO_QUAD "Illegal attempt to call before calling IDAQuadInit." +#define MSG_BAD_EWTQ "Initial ewtQ has component(s) equal to zero (illegal)." +#define MSG_BAD_ITOLQ "Illegal value for itolQ. The legal values are IDA_SS and IDA_SV." +#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_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_PBAR "pbar has zero component(s) (illegal)." +#define MSG_BAD_PLIST "plist has negative component(s) (illegal)." +#define MSG_BAD_NS "NS <= 0 illegal." +#define MSG_NULL_YYS0 "yyS0 = NULL illegal." +#define MSG_NULL_YPS0 "ypS0 = NULL illegal." +#define MSG_BAD_ISM "Illegal value for ism. Legal values are: IDA_SIMULTANEOUS and IDA_STAGGERED." +#define MSG_BAD_IS "Illegal value for is." +#define MSG_NULL_DKYA "dkyA = NULL illegal." +#define MSG_BAD_DQTYPE "Illegal value for DQtype. Legal values are: IDA_CENTERED and IDA_FORWARD." +#define MSG_BAD_DQRHO "DQrhomax < 0 illegal." + +#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_NO_QUADSENSI "Forward sensitivity analysis for quadrature variables was not activated." +#define MSG_NULL_YQS0 "yQS0 = NULL illegal parameter." + + +/* IDACalcIC error messages */ + +#define MSG_IC_BAD_ICOPT "icopt has an illegal value." +#define MSG_IC_BAD_MAXBACKS "maxbacks <= 0 illegal." +#define MSG_IC_MISSING_ID "id = NULL conflicts with icopt." +#define MSG_IC_TOO_CLOSE "tout1 too close to t0 to attempt initial condition calculation." +#define MSG_IC_BAD_ID "id has illegal values." +#define MSG_IC_BAD_EWT "Some initial ewt component = 0.0 illegal." +#define MSG_IC_RES_NONREC "The residual function failed unrecoverably. " +#define MSG_IC_RES_FAIL "The residual function failed at the first call. " +#define MSG_IC_SETUP_FAIL "The linear solver setup failed unrecoverably." +#define MSG_IC_SOLVE_FAIL "The linear solver solve failed unrecoverably." +#define MSG_IC_NO_RECOVERY "The residual routine or the linear setup or solve routine had a recoverable error, but IDACalcIC was unable to recover." +#define MSG_IC_FAIL_CONSTR "Unable to satisfy the inequality constraints." +#define MSG_IC_FAILED_LINS "The linesearch algorithm failed: step too small or too many backtracks." +#define MSG_IC_CONV_FAILED "Newton/Linesearch algorithm failed to converge." + +/* IDASolve error messages */ + +#define MSG_YRET_NULL "yret = NULL illegal." +#define MSG_YPRET_NULL "ypret = NULL illegal." +#define MSG_TRET_NULL "tret = NULL illegal." +#define MSG_BAD_ITASK "itask has an illegal value." +#define MSG_TOO_CLOSE "tout too close to t0 to start integration." +#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_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." + +#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_BAD_K "Illegal value for k." +#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_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." +#define MSG_QRHSFUNC_UNREC "At " MSG_TIME ", the quadrature right-hand side failed in a recoverable manner, but no recovery is possible." +#define MSG_QRHSFUNC_REPTD "At " MSG_TIME "repeated recoverable quadrature right-hand side function errors." +#define MSG_QRHSFUNC_FIRST "The quadrature right-hand side routine failed at the first call." + +#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_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_FIRST "The quadrature right-hand side routine failed at the first call." + +/* IDASet* / IDAGet* error messages */ +#define MSG_NEG_MAXORD "maxord<=0 illegal." +#define MSG_BAD_MAXORD "Illegal attempt to increase maximum order." +#define MSG_NEG_HMAX "hmax < 0 illegal." +#define MSG_NEG_EPCON "epcon <= 0.0 illegal." +#define MSG_BAD_CONSTR "Illegal values in constraints vector." +#define MSG_BAD_EPICCON "epiccon <= 0.0 illegal." +#define MSG_BAD_MAXNH "maxnh <= 0 illegal." +#define MSG_BAD_MAXNJ "maxnj <= 0 illegal." +#define MSG_BAD_MAXNIT "maxnit <= 0 illegal." +#define MSG_BAD_STEPTOL "steptol <= 0.0 illegal." + +#define MSG_TOO_LATE "IDAGetConsistentIC can only be called before IDASolve." + +/* + * ================================================================= + * I D A A E R R O R M E S S A G E S + * ================================================================= + */ + +#define MSGAM_NULL_IDAMEM "ida_mem = NULL illegal." +#define MSGAM_NO_ADJ "Illegal attempt to call before calling IDAadjInit." +#define MSGAM_BAD_INTERP "Illegal value for interp." +#define MSGAM_BAD_STEPS "Steps nonpositive illegal." +#define MSGAM_BAD_WHICH "Illegal value for which." +#define MSGAM_NO_BCK "No backward problems have been defined yet." +#define MSGAM_NO_FWD "Illegal attempt to call before calling IDASolveF." +#define MSGAM_BAD_TB0 "The initial time tB0 is outside the interval over which the forward problem was solved." +#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_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." +#define MSGAM_MEM_FAIL "A memory request failed." +#define MSGAM_NO_INITBS "Illegal attempt to call before calling IDAInitBS." + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_io.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_io.c new file mode 100644 index 0000000..7423676 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_io.c @@ -0,0 +1,1986 @@ +/* + * ----------------------------------------------------------------- + * $Revision$ + * $Date$ + * ----------------------------------------------------------------- + * Programmer(s): Radu Serban and Cosmin Petra @ 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 optional inputs and + * outputs for the IDAS solver. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "idas_impl.h" +#include <sundials/sundials_math.h> +#include <sundials/sundials_types.h> + +#define ZERO RCONST(0.0) +#define HALF RCONST(0.5) +#define ONE RCONST(1.0) +#define TWOPT5 RCONST(2.5) + +/* + * ================================================================= + * IDA optional input functions + * ================================================================= + */ + +int IDASetErrHandlerFn(void *ida_mem, IDAErrHandlerFn ehfun, void *eh_data) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetErrHandlerFn", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + IDA_mem->ida_ehfun = ehfun; + IDA_mem->ida_eh_data = eh_data; + + return(IDA_SUCCESS); +} + + +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); + } + + IDA_mem = (IDAMem) ida_mem; + + IDA_mem->ida_errfp = errfp; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetUserData(void *ida_mem, void *user_data) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetUserData", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + IDA_mem->ida_user_data = user_data; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetMaxOrd(void *ida_mem, int maxord) +{ + IDAMem IDA_mem; + int maxord_alloc; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetMaxOrd", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (maxord <= 0) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetMaxOrd", MSG_NEG_MAXORD); + return(IDA_ILL_INPUT); + } + + /* Cannot increase maximum order beyond the value that + was used when allocating memory */ + maxord_alloc = IDA_mem->ida_maxord_alloc; + + 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); + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetMaxNumSteps(void *ida_mem, long int mxsteps) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetMaxNumSteps", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + /* Passing mxsteps=0 sets the default. Passing mxsteps<0 disables the test. */ + + if (mxsteps == 0) + IDA_mem->ida_mxstep = MXSTEP_DEFAULT; + else + IDA_mem->ida_mxstep = mxsteps; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetInitStep(void *ida_mem, realtype hin) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetInitStep", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + IDA_mem->ida_hin = hin; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetMaxStep(void *ida_mem, realtype hmax) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetMaxStep", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (hmax < 0) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetMaxStep", MSG_NEG_HMAX); + return(IDA_ILL_INPUT); + } + + /* Passing 0 sets hmax = infinity */ + if (hmax == ZERO) { + IDA_mem->ida_hmax_inv = HMAX_INV_DEFAULT; + return(IDA_SUCCESS); + } + + IDA_mem->ida_hmax_inv = ONE/hmax; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetStopTime(void *ida_mem, realtype tstop) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetStopTime", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + /* If IDASolve was called at least once, test if tstop is legal + * (i.e. if it was not already passed). + * If IDASetStopTime is called before the first call to IDASolve, + * tstop will be checked in IDASolve. */ + if (IDA_mem->ida_nst > 0) { + + if ( (tstop - IDA_mem->ida_tn) * IDA_mem->ida_hh < ZERO ) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASetStopTime", MSG_BAD_TSTOP, tstop, IDA_mem->ida_tn); + return(IDA_ILL_INPUT); + } + + } + + IDA_mem->ida_tstop = tstop; + IDA_mem->ida_tstopset = SUNTRUE; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetNonlinConvCoef(void *ida_mem, realtype epcon) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetNonlinConvCoef", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (epcon <= ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetNonlinConvCoef", MSG_NEG_EPCON); + return(IDA_ILL_INPUT); + } + + IDA_mem->ida_epcon = epcon; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetMaxErrTestFails(void *ida_mem, int maxnef) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetMaxErrTestFails", MSG_NO_MEM); + return (IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + IDA_mem->ida_maxnef = maxnef; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetMaxConvFails(void *ida_mem, int maxncf) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetMaxConvFails", MSG_NO_MEM); + return (IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + IDA_mem->ida_maxncf = maxncf; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetMaxNonlinIters(void *ida_mem, int maxcor) +{ + IDAMem IDA_mem; + booleantype sensi_sim; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", + "IDASetMaxNonlinIters", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + /* Are we computing sensitivities with the simultaneous approach? */ + sensi_sim = (IDA_mem->ida_sensi && (IDA_mem->ida_ism==IDA_SIMULTANEOUS)); + + if (sensi_sim) { + + /* check that the NLS is non-NULL */ + if (IDA_mem->NLSsim == NULL) { + IDAProcessError(NULL, IDA_MEM_FAIL, "IDAS", + "IDASetMaxNonlinIters", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + return(SUNNonlinSolSetMaxIters(IDA_mem->NLSsim, maxcor)); + + } else { + + /* check that the NLS is non-NULL */ + if (IDA_mem->NLS == NULL) { + IDAProcessError(NULL, IDA_MEM_FAIL, "IDAS", + "IDASetMaxNonlinIters", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + return(SUNNonlinSolSetMaxIters(IDA_mem->NLS, maxcor)); + } +} + +/*-----------------------------------------------------------------*/ + +int IDASetSuppressAlg(void *ida_mem, booleantype suppressalg) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetSuppressAlg", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + IDA_mem->ida_suppressalg = suppressalg; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetId(void *ida_mem, N_Vector id) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetId", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (id == NULL) { + if (IDA_mem->ida_idMallocDone) { + N_VDestroy(IDA_mem->ida_id); + IDA_mem->ida_lrw -= IDA_mem->ida_lrw1; + IDA_mem->ida_liw -= IDA_mem->ida_liw1; + } + IDA_mem->ida_idMallocDone = SUNFALSE; + return(IDA_SUCCESS); + } + + if ( !(IDA_mem->ida_idMallocDone) ) { + IDA_mem->ida_id = N_VClone(id); + IDA_mem->ida_lrw += IDA_mem->ida_lrw1; + IDA_mem->ida_liw += IDA_mem->ida_liw1; + IDA_mem->ida_idMallocDone = SUNTRUE; + } + + /* Load the id vector */ + + N_VScale(ONE, id, IDA_mem->ida_id); + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetConstraints(void *ida_mem, N_Vector constraints) +{ + IDAMem IDA_mem; + realtype temptest; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetConstraints", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (constraints == NULL) { + if (IDA_mem->ida_constraintsMallocDone) { + N_VDestroy(IDA_mem->ida_constraints); + IDA_mem->ida_lrw -= IDA_mem->ida_lrw1; + IDA_mem->ida_liw -= IDA_mem->ida_liw1; + } + IDA_mem->ida_constraintsMallocDone = SUNFALSE; + IDA_mem->ida_constraintsSet = SUNFALSE; + return(IDA_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) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetConstraints", MSG_BAD_NVECTOR); + return(IDA_ILL_INPUT); + } + + /* Check the constraints vector */ + + temptest = N_VMaxNorm(constraints); + if((temptest > TWOPT5) || (temptest < HALF)){ + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetConstraints", MSG_BAD_CONSTR); + return(IDA_ILL_INPUT); + } + + if ( !(IDA_mem->ida_constraintsMallocDone) ) { + IDA_mem->ida_constraints = N_VClone(constraints); + IDA_mem->ida_lrw += IDA_mem->ida_lrw1; + IDA_mem->ida_liw += IDA_mem->ida_liw1; + IDA_mem->ida_constraintsMallocDone = SUNTRUE; + } + + /* Load the constraints vector */ + + N_VScale(ONE, constraints, IDA_mem->ida_constraints); + + IDA_mem->ida_constraintsSet = SUNTRUE; + + return(IDA_SUCCESS); +} + +/* + * IDASetRootDirection + * + * Specifies the direction of zero-crossings to be monitored. + * The default is to monitor both crossings. + */ + +int IDASetRootDirection(void *ida_mem, int *rootdir) +{ + IDAMem IDA_mem; + int i, nrt; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetRootDirection", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + nrt = IDA_mem->ida_nrtfn; + if (nrt==0) { + IDAProcessError(NULL, IDA_ILL_INPUT, "IDAS", "IDASetRootDirection", MSG_NO_ROOT); + return(IDA_ILL_INPUT); + } + + for(i=0; i<nrt; i++) IDA_mem->ida_rootdir[i] = rootdir[i]; + + return(IDA_SUCCESS); +} + +/* + * IDASetNoInactiveRootWarn + * + * Disables issuing a warning if some root function appears + * to be identically zero at the beginning of the integration + */ + +int IDASetNoInactiveRootWarn(void *ida_mem) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetNoInactiveRootWarn", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + IDA_mem->ida_mxgnull = 0; + + return(IDA_SUCCESS); +} + + +/* + * ================================================================= + * IDA IC optional input functions + * ================================================================= + */ + +int IDASetNonlinConvCoefIC(void *ida_mem, realtype epiccon) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetNonlinConvCoefIC", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (epiccon <= ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetNonlinConvCoefIC", MSG_BAD_EPICCON); + return(IDA_ILL_INPUT); + } + + IDA_mem->ida_epiccon = epiccon; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetMaxNumStepsIC(void *ida_mem, int maxnh) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetMaxNumStepsIC", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (maxnh <= 0) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetMaxNumStepsIC", MSG_BAD_MAXNH); + return(IDA_ILL_INPUT); + } + + IDA_mem->ida_maxnh = maxnh; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetMaxNumJacsIC(void *ida_mem, int maxnj) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetMaxNumJacsIC", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (maxnj <= 0) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetMaxNumJacsIC", MSG_BAD_MAXNJ); + return(IDA_ILL_INPUT); + } + + IDA_mem->ida_maxnj = maxnj; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetMaxNumItersIC(void *ida_mem, int maxnit) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetMaxNumItersIC", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (maxnit <= 0) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetMaxNumItersIC", MSG_BAD_MAXNIT); + return(IDA_ILL_INPUT); + } + + IDA_mem->ida_maxnit = maxnit; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetMaxBacksIC(void *ida_mem, int maxbacks) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDA", "IDASetMaxBacksIC", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (maxbacks <= 0) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDA", "IDASetMaxBacksIC", MSG_IC_BAD_MAXBACKS); + return(IDA_ILL_INPUT); + } + + IDA_mem->ida_maxbacks = maxbacks; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetLineSearchOffIC(void *ida_mem, booleantype lsoff) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetLineSearchOffIC", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + IDA_mem->ida_lsoff = lsoff; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetStepToleranceIC(void *ida_mem, realtype steptol) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetStepToleranceIC", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (steptol <= ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetStepToleranceIC", MSG_BAD_STEPTOL); + return(IDA_ILL_INPUT); + } + + IDA_mem->ida_steptol = steptol; + + return(IDA_SUCCESS); +} + +/* + * ================================================================= + * Quadrature optional input functions + * ================================================================= + */ + +/*-----------------------------------------------------------------*/ + +int IDASetQuadErrCon(void *ida_mem, booleantype errconQ) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + 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); + return(IDA_NO_QUAD); + } + + IDA_mem->ida_errconQ = errconQ; + + return (IDA_SUCCESS); +} + +/* + * ================================================================= + * FSA optional input functions + * ================================================================= + */ + +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); + 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); + return(IDA_ILL_INPUT); + } + + if (DQrhomax < ZERO ) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetSensDQMethod", MSG_BAD_DQRHO); + return(IDA_ILL_INPUT); + } + + IDA_mem->ida_DQtype = DQtype; + IDA_mem->ida_DQrhomax = DQrhomax; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetSensErrCon(void *ida_mem, booleantype errconS) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetSensErrCon", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + IDA_mem->ida_errconS = errconS; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDASetSensMaxNonlinIters(void *ida_mem, int maxcorS) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", + "IDASetSensMaxNonlinIters", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + /* check that the NLS is non-NULL */ + if (IDA_mem->NLSstg == NULL) { + IDAProcessError(NULL, IDA_MEM_FAIL, "IDAS", + "IDASetSensMaxNonlinIters", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + return(SUNNonlinSolSetMaxIters(IDA_mem->NLSstg, maxcorS)); +} + +/*-----------------------------------------------------------------*/ + +int IDASetSensParams(void *ida_mem, realtype *p, realtype *pbar, int *plist) +{ + IDAMem IDA_mem; + int Ns, is; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetSensParams", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + /* Was sensitivity initialized? */ + + if (IDA_mem->ida_sensMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDASetSensParams", MSG_NO_SENSI); + return(IDA_NO_SENS); + } + + Ns = IDA_mem->ida_Ns; + + /* Parameters */ + + IDA_mem->ida_p = p; + + /* pbar */ + + if (pbar != NULL) + for (is=0; is<Ns; is++) { + if (pbar[is] == ZERO) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetSensParams", MSG_BAD_PBAR); + return(IDA_ILL_INPUT); + } + IDA_mem->ida_pbar[is] = SUNRabs(pbar[is]); + } + else + for (is=0; is<Ns; is++) + IDA_mem->ida_pbar[is] = ONE; + + /* plist */ + + if (plist != NULL) + for (is=0; is<Ns; is++) { + if ( plist[is] < 0 ) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDASetSensParams", MSG_BAD_PLIST); + return(IDA_ILL_INPUT); + } + IDA_mem->ida_plist[is] = plist[is]; + } + else + for (is=0; is<Ns; is++) + IDA_mem->ida_plist[is] = is; + + return(IDA_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function: IDASetQuadSensErrCon + * ----------------------------------------------------------------- + * IDASetQuadSensErrCon specifies if quadrature sensitivity variables + * are considered or not in the error control. + * ----------------------------------------------------------------- + */ +int IDASetQuadSensErrCon(void *ida_mem, booleantype errconQS) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDASetQuadSensErrCon", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Was sensitivity initialized? */ + if (IDA_mem->ida_sensMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDASetQuadSensErrCon", MSG_NO_SENSI); + return(IDA_NO_SENS); + } + + /* Was quadrature sensitivity initialized? */ + if (IDA_mem->ida_quadSensMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_QUADSENS, "IDAS", "IDASetQuadSensErrCon", MSG_NO_SENSI); + return(IDA_NO_QUADSENS); + } + + IDA_mem->ida_errconQS = errconQS; + + return(IDA_SUCCESS); +} + +/* + * ================================================================= + * IDA optional output functions + * ================================================================= + */ + +int IDAGetNumSteps(void *ida_mem, long int *nsteps) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetNumSteps", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *nsteps = IDA_mem->ida_nst; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetNumResEvals(void *ida_mem, long int *nrevals) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetNumResEvals", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *nrevals = IDA_mem->ida_nre; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetNumLinSolvSetups(void *ida_mem, long int *nlinsetups) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetNumLinSolvSetups", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *nlinsetups = IDA_mem->ida_nsetups; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetNumErrTestFails(void *ida_mem, long int *netfails) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetNumErrTestFails", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *netfails = IDA_mem->ida_netf; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetNumBacktrackOps(void *ida_mem, long int *nbacktracks) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetNumBacktrackOps", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *nbacktracks = IDA_mem->ida_nbacktr; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +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; + + if (IDA_mem->ida_kused != 0) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAGetConsistentIC", MSG_TOO_LATE); + return(IDA_ILL_INPUT); + } + + if(yy0 != NULL) N_VScale(ONE, IDA_mem->ida_phi[0], yy0); + if(yp0 != NULL) N_VScale(ONE, IDA_mem->ida_phi[1], yp0); + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetLastOrder(void *ida_mem, int *klast) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetLastOrder", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *klast = IDA_mem->ida_kused; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetCurrentOrder(void *ida_mem, int *kcur) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetCurrentOrder", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *kcur = IDA_mem->ida_kk; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetActualInitStep(void *ida_mem, realtype *hinused) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetActualInitStep", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *hinused = IDA_mem->ida_h0u; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetLastStep(void *ida_mem, realtype *hlast) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetLastStep", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *hlast = IDA_mem->ida_hused; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetCurrentStep(void *ida_mem, realtype *hcur) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetCurrentStep", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *hcur = IDA_mem->ida_hh; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetCurrentTime(void *ida_mem, realtype *tcur) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetCurrentTime", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *tcur = IDA_mem->ida_tn; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetTolScaleFactor(void *ida_mem, realtype *tolsfact) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetTolScaleFactor", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *tolsfact = IDA_mem->ida_tolsf; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +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; + + N_VScale(ONE, IDA_mem->ida_ewt, eweight); + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetEstLocalErrors(void *ida_mem, N_Vector ele) +{ + IDAMem IDA_mem; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetEstLocalErrors", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + N_VScale(ONE, IDA_mem->ida_ee, ele); + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetWorkSpace(void *ida_mem, long int *lenrw, long int *leniw) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetWorkSpace", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *leniw = IDA_mem->ida_liw; + *lenrw = IDA_mem->ida_lrw; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +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, + realtype *hcur, realtype *tcur) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetIntegratorStats", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *nsteps = IDA_mem->ida_nst; + *nrevals = IDA_mem->ida_nre; + *nlinsetups = IDA_mem->ida_nsetups; + *netfails = IDA_mem->ida_netf; + *klast = IDA_mem->ida_kused; + *kcur = IDA_mem->ida_kk; + *hinused = IDA_mem->ida_h0u; + *hlast = IDA_mem->ida_hused; + *hcur = IDA_mem->ida_hh; + *tcur = IDA_mem->ida_tn; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetNumGEvals(void *ida_mem, long int *ngevals) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetNumGEvals", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *ngevals = IDA_mem->ida_nge; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetRootInfo(void *ida_mem, int *rootsfound) +{ + IDAMem IDA_mem; + int i, nrt; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetRootInfo", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + nrt = IDA_mem->ida_nrtfn; + + for (i=0; i<nrt; i++) + rootsfound[i] = IDA_mem->ida_iroots[i]; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetNumNonlinSolvIters(void *ida_mem, long int *nniters) +{ + IDAMem IDA_mem; + long int nls_iters; + booleantype sensi_sim; + int retval; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", + "IDAGetNumNonlinSolvIters", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + /* get number of iterations for IC calc */ + *nniters = IDA_mem->ida_nni; + + /* are we computing sensitivities with the simultaneous approach? */ + sensi_sim = (IDA_mem->ida_sensi && (IDA_mem->ida_ism==IDA_SIMULTANEOUS)); + + /* get number of iterations from the NLS */ + if (sensi_sim) { + + /* check that the NLS is non-NULL */ + if (IDA_mem->NLSsim == NULL) { + IDAProcessError(NULL, IDA_MEM_FAIL, "IDAS", + "IDAGetNumNonlinSolvIters", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + retval = SUNNonlinSolGetNumIters(IDA_mem->NLSsim, &nls_iters); + if (retval != IDA_SUCCESS) return(retval); + + } else { + + /* check that the NLS is non-NULL */ + if (IDA_mem->NLS == NULL) { + IDAProcessError(NULL, IDA_MEM_FAIL, "IDAS", + "IDAGetNumNonlinSolvIters", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + retval = SUNNonlinSolGetNumIters(IDA_mem->NLS, &nls_iters); + if (retval != IDA_SUCCESS) return(retval); + } + + /* update the number of nonlinear iterations */ + *nniters += nls_iters; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetNumNonlinSolvConvFails(void *ida_mem, long int *nncfails) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetNumNonlinSolvConvFails", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *nncfails = IDA_mem->ida_ncfn; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetNonlinSolvStats(void *ida_mem, long int *nniters, long int *nncfails) +{ + IDAMem IDA_mem; + long int nls_iters; + booleantype sensi_sim; + int retval; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", + "IDAGetNonlinSolvStats", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + *nniters = IDA_mem->ida_nni; + *nncfails = IDA_mem->ida_ncfn; + + /* Are we computing sensitivities with the simultaneous approach? */ + sensi_sim = (IDA_mem->ida_sensi && (IDA_mem->ida_ism==IDA_SIMULTANEOUS)); + + /* get number of iterations from NLS */ + if (sensi_sim) { + + if (IDA_mem->NLSsim == NULL) { + IDAProcessError(NULL, IDA_MEM_FAIL, "IDAS", + "IDAGetNonlinSolvStats", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + retval = SUNNonlinSolGetNumIters(IDA_mem->NLSsim, &nls_iters); + if (retval != IDA_SUCCESS) return(retval); + + } else { + + if (IDA_mem->NLS == NULL) { + IDAProcessError(NULL, IDA_MEM_FAIL, "IDAS", + "IDAGetNonlinSolvStats", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + retval = SUNNonlinSolGetNumIters(IDA_mem->NLS, &nls_iters); + if (retval != IDA_SUCCESS) return(retval); + + } + + /* update the number of nonlinear iterations */ + *nniters += nls_iters; + + return(IDA_SUCCESS); +} + +/* + * ================================================================= + * Quadrature optional output functions + * ================================================================= + */ + +/*-----------------------------------------------------------------*/ + +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); + 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); + return(IDA_NO_QUAD); + } + + *nrQevals = IDA_mem->ida_nrQe; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +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); + 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); + return(IDA_NO_QUAD); + } + + *nQetfails = IDA_mem->ida_netfQ; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +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); + 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); + return(IDA_NO_QUAD); + } + + if(IDA_mem->ida_errconQ) + N_VScale(ONE, IDA_mem->ida_ewtQ, eQweight); + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +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); + 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); + return(IDA_NO_QUAD); + } + + *nrQevals = IDA_mem->ida_nrQe; + *nQetfails = IDA_mem->ida_netfQ; + + return(IDA_SUCCESS); +} + + +/* + * ================================================================= + * Quadrature FSA optional output functions + * ================================================================= + */ + +/*-----------------------------------------------------------------*/ + +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); + 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); + return(IDA_NO_QUADSENS); + } + + *nrhsQSevals = IDA_mem->ida_nrQSe; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +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); + 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); + return(IDA_NO_QUADSENS); + } + + *nQSetfails = IDA_mem->ida_netfQS; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetQuadSensErrWeights(void *ida_mem, N_Vector *eQSweight) +{ + IDAMem IDA_mem; + int is, Ns; + + if (ida_mem==NULL) { + 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); + return(IDA_NO_QUADSENS); + } + Ns = IDA_mem->ida_Ns; + + if (IDA_mem->ida_errconQS) + for (is=0; is<Ns; is++) + N_VScale(ONE, IDA_mem->ida_ewtQS[is], eQSweight[is]); + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetQuadSensStats(void *ida_mem, long int *nrhsQSevals, long int *nQSetfails) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + 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); + return(IDA_NO_QUADSENS); + } + + *nrhsQSevals = IDA_mem->ida_nrQSe; + *nQSetfails = IDA_mem->ida_netfQS; + + return(IDA_SUCCESS); +} + + + +/* + * ================================================================= + * FSA optional output functions + * ================================================================= + */ + +/*-----------------------------------------------------------------*/ + +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; + + if (IDA_mem->ida_sensi==SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAGetSensConsistentIC", MSG_NO_SENSI); + return(IDA_NO_SENS); + } + + if (IDA_mem->ida_kused != 0) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "IDAGetSensConsistentIC", MSG_TOO_LATE); + return(IDA_ILL_INPUT); + } + + if(yyS0 != NULL) { + for (is=0; is<IDA_mem->ida_Ns; is++) + N_VScale(ONE, IDA_mem->ida_phiS[0][is], yyS0[is]); + } + + if(ypS0 != NULL) { + for (is=0; is<IDA_mem->ida_Ns; is++) + N_VScale(ONE, IDA_mem->ida_phiS[1][is], ypS0[is]); + } + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +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); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_sensi==SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAGetSensNumResEvals", MSG_NO_SENSI); + return(IDA_NO_SENS); + } + + *nrSevals = IDA_mem->ida_nrSe; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +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); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_sensi==SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAGetNumResEvalsSens", MSG_NO_SENSI); + return(IDA_NO_SENS); + } + + *nrevalsS = IDA_mem->ida_nreS; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +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); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_sensi==SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAGetSensNumErrTestFails", MSG_NO_SENSI); + return(IDA_NO_SENS); + } + + *nSetfails = IDA_mem->ida_netfS; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +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); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_sensi==SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAGetSensNumLinSolvSetups", MSG_NO_SENSI); + return(IDA_NO_SENS); + } + + *nlinsetupsS = IDA_mem->ida_nsetupsS; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetSensErrWeights(void *ida_mem, N_Vector_S eSweight) +{ + IDAMem IDA_mem; + int is; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetSensErrWeights", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_sensi==SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAGetSensErrWeights", MSG_NO_SENSI); + return(IDA_NO_SENS); + } + + for (is=0; is<IDA_mem->ida_Ns; is++) + N_VScale(ONE, IDA_mem->ida_ewtS[is], eSweight[is]); + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetSensStats(void *ida_mem, long int *nrSevals, long int *nrevalsS, + long int *nSetfails, long int *nlinsetupsS) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetSensStats", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_sensi==SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAGetSensStats", MSG_NO_SENSI); + return(IDA_NO_SENS); + } + + *nrSevals = IDA_mem->ida_nrSe; + *nrevalsS = IDA_mem->ida_nreS; + *nSetfails = IDA_mem->ida_netfS; + *nlinsetupsS = IDA_mem->ida_nsetupsS; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetSensNumNonlinSolvIters(void *ida_mem, long int *nSniters) +{ + IDAMem IDA_mem; + long int nls_iters; + int retval; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", + "IDAGetSensNumNonlinSolvIters", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_sensi==SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", + "IDAGetSensNumNonlinSolvIters", MSG_NO_SENSI); + return(IDA_NO_SENS); + } + + *nSniters = IDA_mem->ida_nniS; + + /* check that the NLS is non-NULL */ + if (IDA_mem->NLSstg == NULL) { + IDAProcessError(NULL, IDA_MEM_FAIL, "IDAS", + "IDAGetSensNumNonlinSolvIters", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + /* get number of iterations from the NLS */ + retval = SUNNonlinSolGetNumIters(IDA_mem->NLSstg, &nls_iters); + if (retval != IDA_SUCCESS) return(retval); + + /* update the number of nonlinear iterations */ + *nSniters += nls_iters; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetSensNumNonlinSolvConvFails(void *ida_mem, long int *nSncfails) +{ + IDAMem IDA_mem; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "IDAGetSensNumNonlinSolvConvFails", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_sensi==SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", "IDAGetSensNumNonlinSolvConvFails", MSG_NO_SENSI); + return(IDA_NO_SENS); + } + + *nSncfails = IDA_mem->ida_ncfnS; + + return(IDA_SUCCESS); +} + +/*-----------------------------------------------------------------*/ + +int IDAGetSensNonlinSolvStats(void *ida_mem, long int *nSniters, long int *nSncfails) +{ + IDAMem IDA_mem; + long int nls_iters; + int retval; + + if (ida_mem==NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", + "IDAGetSensNonlinSolvstats", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + + IDA_mem = (IDAMem) ida_mem; + + if (IDA_mem->ida_sensi==SUNFALSE) { + IDAProcessError(IDA_mem, IDA_NO_SENS, "IDAS", + "IDAGetSensNonlinSolvStats", MSG_NO_SENSI); + return(IDA_NO_SENS); + } + + *nSniters = IDA_mem->ida_nniS; + *nSncfails = IDA_mem->ida_ncfnS; + + /* check that the NLS is non-NULL */ + if (IDA_mem->NLSstg == NULL) { + IDAProcessError(NULL, IDA_MEM_FAIL, "IDAS", + "IDAGetSensNumNonlinSolvStats", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + /* get number of iterations from the NLS */ + retval = SUNNonlinSolGetNumIters(IDA_mem->NLSstg, &nls_iters); + if (retval != IDA_SUCCESS) return(retval); + + /* update the number of nonlinear iterations */ + *nSniters += nls_iters; + + return(IDA_SUCCESS); +} + +/* + * ================================================================= + * IDAGetReturnFlagName + * ================================================================= + */ + + +char *IDAGetReturnFlagName(long int flag) +{ + char *name; + + name = (char *)malloc(24*sizeof(char)); + + switch(flag) { + case IDA_SUCCESS: + sprintf(name,"IDA_SUCCESS"); + break; + case IDA_TSTOP_RETURN: + sprintf(name,"IDA_TSTOP_RETURN"); + break; + case IDA_ROOT_RETURN: + sprintf(name,"IDA_ROOT_RETURN"); + break; + case IDA_TOO_MUCH_WORK: + sprintf(name,"IDA_TOO_MUCH_WORK"); + break; + case IDA_TOO_MUCH_ACC: + sprintf(name,"IDA_TOO_MUCH_ACC"); + break; + case IDA_ERR_FAIL: + sprintf(name,"IDA_ERR_FAIL"); + break; + case IDA_CONV_FAIL: + sprintf(name,"IDA_CONV_FAIL"); + break; + case IDA_LINIT_FAIL: + sprintf(name,"IDA_LINIT_FAIL"); + break; + case IDA_LSETUP_FAIL: + sprintf(name,"IDA_LSETUP_FAIL"); + break; + case IDA_LSOLVE_FAIL: + sprintf(name,"IDA_LSOLVE_FAIL"); + break; + case IDA_CONSTR_FAIL: + sprintf(name,"IDA_CONSTR_FAIL"); + break; + case IDA_RES_FAIL: + sprintf(name,"IDA_RES_FAIL"); + break; + case IDA_FIRST_RES_FAIL: + sprintf(name,"IDA_FIRST_RES_FAIL"); + break; + case IDA_REP_RES_ERR: + sprintf(name,"IDA_REP_RES_ERR"); + break; + case IDA_RTFUNC_FAIL: + sprintf(name,"IDA_RTFUNC_FAIL"); + break; + case IDA_MEM_FAIL: + sprintf(name,"IDA_MEM_FAIL"); + break; + case IDA_MEM_NULL: + sprintf(name,"IDA_MEM_NULL"); + break; + case IDA_ILL_INPUT: + sprintf(name,"IDA_ILL_INPUT"); + break; + case IDA_NO_MALLOC: + sprintf(name,"IDA_NO_MALLOC"); + break; + case IDA_BAD_T: + sprintf(name,"IDA_BAD_T"); + break; + case IDA_BAD_K: + sprintf(name,"IDA_BAD_K"); + break; + case IDA_BAD_DKY: + sprintf(name,"IDA_BAD_DKY"); + break; + case IDA_BAD_EWT: + sprintf(name,"IDA_BAD_EWT"); + break; + case IDA_NO_RECOVERY: + sprintf(name,"IDA_NO_RECOVERY"); + break; + case IDA_LINESEARCH_FAIL: + sprintf(name,"IDA_LINESEARCH_FAIL"); + break; + case IDA_NO_SENS: + sprintf(name,"IDA_NO_SENS"); + break; + case IDA_SRES_FAIL: + sprintf(name, "IDA_SRES_FAIL"); + break; + case IDA_REP_SRES_ERR: + sprintf(name, "IDA_REP_SRES_ERR"); + break; + case IDA_BAD_IS: + sprintf(name,"IDA_BAD_IS"); + break; + case IDA_NO_QUAD: + sprintf(name,"IDA_NO_QUAD"); + break; + case IDA_NO_QUADSENS: + sprintf(name, "IDA_NO_QUADSENS"); + break; + case IDA_QSRHS_FAIL: + sprintf(name, "IDA_QSRHS_FAIL"); + break; + + /* IDAA flags follow below. */ + case IDA_NO_ADJ: + sprintf(name, "IDA_NO_ADJ"); + break; + case IDA_BAD_TB0: + sprintf(name, "IDA_BAD_TB0"); + break; + case IDA_REIFWD_FAIL: + sprintf(name, "IDA_REIFWD_FAIL"); + break; + case IDA_FWD_FAIL: + sprintf(name, "IDA_FWD_FAIL"); + break; + case IDA_GETY_BADT: + sprintf(name, "IDA_GETY_BADT"); + break; + case IDA_NO_BCK: + sprintf(name, "IDA_NO_BCK"); + break; + case IDA_NO_FWD: + sprintf(name,"IDA_NO_FWD"); + break; + default: + sprintf(name,"NONE"); + } + + return(name); +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_ls.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_ls.c new file mode 100644 index 0000000..e757266 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_ls.c @@ -0,0 +1,2416 @@ +/*----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 + *----------------------------------------------------------------- + * Implementation file for IDAS' linear solver interface + *-----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "idas_impl.h" +#include "idas_ls_impl.h" +#include <sundials/sundials_math.h> +#include <sunmatrix/sunmatrix_band.h> +#include <sunmatrix/sunmatrix_dense.h> +#include <sunmatrix/sunmatrix_sparse.h> + +/* constants */ +#define MAX_ITERS 3 /* max. number of attempts to recover in DQ J*v */ +#define ZERO RCONST(0.0) +#define PT25 RCONST(0.25) +#define PT05 RCONST(0.05) +#define PT9 RCONST(0.9) +#define ONE RCONST(1.0) +#define TWO RCONST(2.0) + + +/*================================================================= + PRIVATE FUNCTION PROTOTYPES + =================================================================*/ + +static int idaLsJacBWrapper(realtype tt, realtype c_jB, N_Vector yyB, + N_Vector ypB, N_Vector rBr, SUNMatrix JacB, + void *ida_mem, N_Vector tmp1B, + N_Vector tmp2B, N_Vector tmp3B); +static int idaLsJacBSWrapper(realtype tt, realtype c_jB, N_Vector yyB, + N_Vector ypB, N_Vector rBr, SUNMatrix JacB, + void *ida_mem, N_Vector tmp1B, + N_Vector tmp2B, N_Vector tmp3B); + +static int idaLsPrecSetupB(realtype tt, N_Vector yyB, + N_Vector ypB, N_Vector rrB, + realtype c_jB, void *idaadj_mem); +static int idaLsPrecSetupBS(realtype tt, N_Vector yyB, + N_Vector ypB, N_Vector rrB, + realtype c_jB, void *idaadj_mem); + +static int idaLsPrecSolveB(realtype tt, N_Vector yyB, + N_Vector ypB, N_Vector rrB, + N_Vector rvecB, N_Vector zvecB, + realtype c_jB, realtype deltaB, + void *idaadj_mem); +static int idaLsPrecSolveBS(realtype tt, N_Vector yyB, + N_Vector ypB, N_Vector rrB, + N_Vector rvecB, N_Vector zvecB, + realtype c_jB, realtype deltaB, + void *idaadj_mem); + +static int idaLsJacTimesSetupB(realtype tt, N_Vector yyB, + N_Vector ypB, N_Vector rrB, + realtype c_jB, void *idaadj_mem); +static int idaLsJacTimesSetupBS(realtype tt, N_Vector yyB, + N_Vector ypB, N_Vector rrB, + realtype c_jB, void *idaadj_mem); + +static int idaLsJacTimesVecB(realtype tt, N_Vector yyB, + N_Vector ypB, N_Vector rrB, + N_Vector vB, N_Vector JvB, + realtype c_jB, void *idaadj_mem, + N_Vector tmp1B, N_Vector tmp2B); +static int idaLsJacTimesVecBS(realtype tt, N_Vector yyB, + N_Vector ypB, N_Vector rrB, + N_Vector vB, N_Vector JvB, + realtype c_jB, void *idaadj_mem, + N_Vector tmp1B, N_Vector tmp2B); + + +/*================================================================ + PART I - forward problems + ================================================================*/ + + +/*--------------------------------------------------------------- + IDASLS Exported functions -- Required + ---------------------------------------------------------------*/ + +/* IDASetLinearSolver specifies the linear solver */ +int IDASetLinearSolver(void *ida_mem, SUNLinearSolver LS, SUNMatrix A) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval, LSType; + + /* Return immediately if any input is NULL */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDALS_MEM_NULL, "IDASLS", + "IDASetLinearSolver", MSG_LS_IDAMEM_NULL); + return(IDALS_MEM_NULL); + } + if (LS == NULL) { + IDAProcessError(NULL, IDALS_ILL_INPUT, "IDASLS", + "IDASetLinearSolver", + "LS must be non-NULL"); + return(IDALS_ILL_INPUT); + } + 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) ) { + 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) ) { + 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 ( ( (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", + "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 */ + if (IDA_mem->ida_lfree) IDA_mem->ida_lfree(IDA_mem); + + /* Set four main system linear solver function fields in IDA_mem */ + IDA_mem->ida_linit = idaLsInitialize; + IDA_mem->ida_lsetup = idaLsSetup; + IDA_mem->ida_lsolve = idaLsSolve; + 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; + + /* Allocate memory for IDALsMemRec */ + idals_mem = NULL; + idals_mem = (IDALsMem) malloc(sizeof(struct IDALsMemRec)); + if (idals_mem == NULL) { + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDASLS", + "IDASetLinearSolver", MSG_LS_MEM_FAIL); + return(IDALS_MEM_FAIL); + } + memset(idals_mem, 0, sizeof(struct IDALsMemRec)); + + /* set SUNLinearSolver pointer */ + idals_mem->LS = LS; + + /* Set defaults for Jacobian-related fields */ + idals_mem->J = A; + if (A != NULL) { + idals_mem->jacDQ = SUNTRUE; + idals_mem->jac = idaLsDQJac; + idals_mem->J_data = IDA_mem; + } else { + idals_mem->jacDQ = SUNFALSE; + idals_mem->jac = NULL; + idals_mem->J_data = NULL; + } + idals_mem->jtimesDQ = SUNTRUE; + idals_mem->jtsetup = NULL; + idals_mem->jtimes = idaLsDQJtimes; + idals_mem->jt_data = IDA_mem; + + /* Set defaults for preconditioner-related fields */ + idals_mem->pset = NULL; + idals_mem->psolve = NULL; + idals_mem->pfree = NULL; + idals_mem->pdata = IDA_mem->ida_user_data; + + /* Initialize counters */ + idaLsInitializeCounters(idals_mem); + + /* Set default values for the rest of the Ls parameters */ + idals_mem->eplifac = PT05; + idals_mem->dqincfac = ONE; + idals_mem->last_flag = IDALS_SUCCESS; + + /* Attach default IDALs interface routines to LS object */ + if (LS->ops->setatimes) { + retval = SUNLinSolSetATimes(LS, IDA_mem, idaLsATimes); + if (retval != SUNLS_SUCCESS) { + IDAProcessError(IDA_mem, IDALS_SUNLS_FAIL, "IDASLS", + "IDASetLinearSolver", + "Error in calling SUNLinSolSetATimes"); + free(idals_mem); idals_mem = NULL; + return(IDALS_SUNLS_FAIL); + } + } + if (LS->ops->setpreconditioner) { + retval = SUNLinSolSetPreconditioner(LS, IDA_mem, NULL, NULL); + if (retval != SUNLS_SUCCESS) { + IDAProcessError(IDA_mem, IDALS_SUNLS_FAIL, "IDASLS", + "IDASetLinearSolver", + "Error in calling SUNLinSolSetPreconditioner"); + free(idals_mem); idals_mem = NULL; + return(IDALS_SUNLS_FAIL); + } + } + + /* Allocate memory for ytemp, yptemp and x */ + idals_mem->ytemp = N_VClone(IDA_mem->ida_tempv1); + if (idals_mem->ytemp == NULL) { + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDASLS", + "IDASetLinearSolver", MSG_LS_MEM_FAIL); + free(idals_mem); idals_mem = NULL; + return(IDALS_MEM_FAIL); + } + + idals_mem->yptemp = N_VClone(IDA_mem->ida_tempv1); + if (idals_mem->yptemp == NULL) { + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDASLS", + "IDASetLinearSolver", MSG_LS_MEM_FAIL); + N_VDestroy(idals_mem->ytemp); + free(idals_mem); idals_mem = NULL; + return(IDALS_MEM_FAIL); + } + + idals_mem->x = N_VClone(IDA_mem->ida_tempv1); + if (idals_mem->x == NULL) { + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDASLS", + "IDASetLinearSolver", MSG_LS_MEM_FAIL); + N_VDestroy(idals_mem->ytemp); + N_VDestroy(idals_mem->yptemp); + free(idals_mem); idals_mem = NULL; + 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) ); + + /* Attach linear solver memory to integrator memory */ + IDA_mem->ida_lmem = idals_mem; + + return(IDALS_SUCCESS); +} + + +/*--------------------------------------------------------------- + IDASLS Exported functions -- Optional input/output + ---------------------------------------------------------------*/ + +/* IDASetJacFn specifies the Jacobian function */ +int IDASetJacFn(void *ida_mem, IDALsJacFn jac) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure */ + retval = idaLs_AccessLMem(ida_mem, "IDALsSetJacFn", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* return with failure if jac cannot be used */ + if ((jac != NULL) && (idals_mem->J == NULL)) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDASLS", "IDASetJacFn", + "Jacobian routine cannot be supplied for NULL SUNMatrix"); + return(IDALS_ILL_INPUT); + } + + /* set Jacobian routine pointer, and update relevant flags */ + if (jac != NULL) { + idals_mem->jacDQ = SUNFALSE; + idals_mem->jac = jac; + idals_mem->J_data = IDA_mem->ida_user_data; + } else { + idals_mem->jacDQ = SUNTRUE; + idals_mem->jac = idaLsDQJac; + idals_mem->J_data = IDA_mem; + } + + return(IDALS_SUCCESS); +} + + +/* IDASetEpsLin specifies the nonlinear -> linear tolerance scale factor */ +int IDASetEpsLin(void *ida_mem, realtype eplifac) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure */ + retval = idaLs_AccessLMem(ida_mem, "IDASetEpsLin", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* Check for legal eplifac */ + if (eplifac < ZERO) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDASLS", + "IDASetEpsLin", MSG_LS_NEG_EPLIFAC); + return(IDALS_ILL_INPUT); + } + + idals_mem->eplifac = (eplifac == ZERO) ? PT05 : eplifac; + + return(IDALS_SUCCESS); +} + + +/* IDASetIncrementFactor specifies increment factor for DQ approximations to Jv */ +int IDASetIncrementFactor(void *ida_mem, realtype dqincfac) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure */ + retval = idaLs_AccessLMem(ida_mem, "IDASetIncrementFactor", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* Check for legal dqincfac */ + if (dqincfac <= ZERO) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDASLS", + "IDASetIncrementFactor", MSG_LS_NEG_DQINCFAC); + return(IDALS_ILL_INPUT); + } + + idals_mem->dqincfac = dqincfac; + + return(IDALS_SUCCESS); +} + + +/* IDASetPreconditioner specifies the user-supplied psetup and psolve routines */ +int IDASetPreconditioner(void *ida_mem, + IDALsPrecSetupFn psetup, + IDALsPrecSolveFn psolve) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + PSetupFn idals_psetup; + PSolveFn idals_psolve; + int retval; + + /* access IDALsMem structure */ + retval = idaLs_AccessLMem(ida_mem, "IDASetPreconditioner", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* store function pointers for user-supplied routines in IDALs interface */ + idals_mem->pset = psetup; + idals_mem->psolve = psolve; + + /* issue error if LS object does not allow user-supplied preconditioning */ + if (idals_mem->LS->ops->setpreconditioner == NULL) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDASLS", + "IDASetPreconditioner", + "SUNLinearSolver object does not support user-supplied preconditioning"); + return(IDALS_ILL_INPUT); + } + + /* notify iterative linear solver to call IDALs interface routines */ + idals_psetup = (psetup == NULL) ? NULL : idaLsPSetup; + idals_psolve = (psolve == NULL) ? NULL : idaLsPSolve; + retval = SUNLinSolSetPreconditioner(idals_mem->LS, IDA_mem, + idals_psetup, idals_psolve); + if (retval != SUNLS_SUCCESS) { + IDAProcessError(IDA_mem, IDALS_SUNLS_FAIL, "IDASLS", + "IDASetPreconditioner", + "Error in calling SUNLinSolSetPreconditioner"); + return(IDALS_SUNLS_FAIL); + } + + return(IDALS_SUCCESS); +} + + +/* IDASetJacTimes specifies the user-supplied Jacobian-vector product + setup and multiply routines */ +int IDASetJacTimes(void *ida_mem, IDALsJacTimesSetupFn jtsetup, + IDALsJacTimesVecFn jtimes) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure */ + retval = idaLs_AccessLMem(ida_mem, "IDASetJacTimes", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* issue error if LS object does not allow user-supplied ATimes */ + if (idals_mem->LS->ops->setatimes == NULL) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDASLS", + "IDASetJacTimes", + "SUNLinearSolver object does not support user-supplied ATimes routine"); + return(IDALS_ILL_INPUT); + } + + /* store function pointers for user-supplied routines in IDALs + interface (NULL jtimes implies use of DQ default) */ + if (jtimes != NULL) { + idals_mem->jtimesDQ = SUNFALSE; + idals_mem->jtsetup = jtsetup; + idals_mem->jtimes = jtimes; + idals_mem->jt_data = IDA_mem->ida_user_data; + } else { + idals_mem->jtimesDQ = SUNTRUE; + idals_mem->jtsetup = NULL; + idals_mem->jtimes = idaLsDQJtimes; + idals_mem->jt_data = IDA_mem; + } + + return(IDALS_SUCCESS); +} + + +/* IDAGetLinWorkSpace returns the length of workspace allocated + for the IDALS linear solver interface */ +int IDAGetLinWorkSpace(void *ida_mem, long int *lenrwLS, + long int *leniwLS) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + sunindextype lrw1, liw1; + long int lrw, liw; + int retval; + + /* access IDALsMem structure */ + retval = idaLs_AccessLMem(ida_mem, "IDAGetLinWorkSpace", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* start with fixed sizes plus vector/matrix pointers */ + *lenrwLS = 3; + *leniwLS = 34; + + /* add N_Vector sizes */ + if (IDA_mem->ida_tempv1->ops->nvspace) { + N_VSpace(IDA_mem->ida_tempv1, &lrw1, &liw1); + *lenrwLS += 3*lrw1; + *leniwLS += 3*liw1; + } + + /* add LS sizes */ + if (idals_mem->LS->ops->space) { + retval = SUNLinSolSpace(idals_mem->LS, &lrw, &liw); + if (retval == 0) { + *lenrwLS += lrw; + *leniwLS += liw; + } + } + + return(IDALS_SUCCESS); +} + + +/* IDAGetNumJacEvals returns the number of Jacobian evaluations */ +int IDAGetNumJacEvals(void *ida_mem, long int *njevals) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure; store output and return */ + retval = idaLs_AccessLMem(ida_mem, "IDAGetNumJacEvals", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + *njevals = idals_mem->nje; + return(IDALS_SUCCESS); +} + + +/* IDAGetNumPrecEvals returns the number of preconditioner evaluations */ +int IDAGetNumPrecEvals(void *ida_mem, long int *npevals) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure; store output and return */ + retval = idaLs_AccessLMem(ida_mem, "IDAGetNumPrecEvals", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + *npevals = idals_mem->npe; + return(IDALS_SUCCESS); +} + + +/* IDAGetNumPrecSolves returns the number of preconditioner solves */ +int IDAGetNumPrecSolves(void *ida_mem, long int *npsolves) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure; store output and return */ + retval = idaLs_AccessLMem(ida_mem, "IDAGetNumPrecSolves", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + *npsolves = idals_mem->nps; + return(IDALS_SUCCESS); +} + + +/* IDAGetNumLinIters returns the number of linear iterations */ +int IDAGetNumLinIters(void *ida_mem, long int *nliters) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure; store output and return */ + retval = idaLs_AccessLMem(ida_mem, "IDAGetNumLinIters", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + *nliters = idals_mem->nli; + return(IDALS_SUCCESS); +} + + +/* IDAGetNumLinConvFails returns the number of linear convergence failures */ +int IDAGetNumLinConvFails(void *ida_mem, long int *nlcfails) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure; store output and return */ + retval = idaLs_AccessLMem(ida_mem, "IDAGetNumLinConvFails", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + *nlcfails = idals_mem->ncfl; + return(IDALS_SUCCESS); +} + + +/* IDAGetNumJTSetupEvals returns the number of calls to the + user-supplied Jacobian-vector product setup routine */ +int IDAGetNumJTSetupEvals(void *ida_mem, long int *njtsetups) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure; store output and return */ + retval = idaLs_AccessLMem(ida_mem, "IDAGetNumJTSetupEvals", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + *njtsetups = idals_mem->njtsetup; + return(IDALS_SUCCESS); +} + + +/* IDAGetNumJtimesEvals returns the number of calls to the + Jacobian-vector product multiply routine */ +int IDAGetNumJtimesEvals(void *ida_mem, long int *njvevals) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure; store output and return */ + retval = idaLs_AccessLMem(ida_mem, "IDAGetNumJtimesEvals", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + *njvevals = idals_mem->njtimes; + return(IDALS_SUCCESS); +} + + +/* IDAGetNumLinResEvals returns the number of calls to the DAE + residual needed for the DQ Jacobian approximation or J*v + product approximation */ +int IDAGetNumLinResEvals(void *ida_mem, long int *nrevalsLS) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure; store output and return */ + retval = idaLs_AccessLMem(ida_mem, "IDAGetNumLinResEvals", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + *nrevalsLS = idals_mem->nreDQ; + return(IDALS_SUCCESS); +} + + +/* IDAGetLastLinFlag returns the last flag set in a IDALS function */ +int IDAGetLastLinFlag(void *ida_mem, long int *flag) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure; store output and return */ + retval = idaLs_AccessLMem(ida_mem, "IDAGetLastLinFlag", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + *flag = idals_mem->last_flag; + return(IDALS_SUCCESS); +} + + +/* IDAGetLinReturnFlagName translates from the integer error code + returned by an IDALs routine to the corresponding string + equivalent for that flag */ +char *IDAGetLinReturnFlagName(long int flag) +{ + char *name = (char *)malloc(30*sizeof(char)); + + switch(flag) { + case IDALS_SUCCESS: + sprintf(name,"IDALS_SUCCESS"); + break; + case IDALS_MEM_NULL: + sprintf(name,"IDALS_MEM_NULL"); + break; + case IDALS_LMEM_NULL: + sprintf(name,"IDALS_LMEM_NULL"); + break; + case IDALS_ILL_INPUT: + sprintf(name,"IDALS_ILL_INPUT"); + break; + case IDALS_MEM_FAIL: + sprintf(name,"IDALS_MEM_FAIL"); + break; + case IDALS_PMEM_NULL: + sprintf(name,"IDALS_PMEM_NULL"); + break; + case IDALS_JACFUNC_UNRECVR: + sprintf(name,"IDALS_JACFUNC_UNRECVR"); + break; + case IDALS_JACFUNC_RECVR: + sprintf(name,"IDALS_JACFUNC_RECVR"); + break; + case IDALS_SUNMAT_FAIL: + sprintf(name,"IDALS_SUNMAT_FAIL"); + break; + case IDALS_SUNLS_FAIL: + sprintf(name,"IDALS_SUNLS_FAIL"); + break; + default: + sprintf(name,"NONE"); + } + + return(name); +} + +/*----------------------------------------------------------------- + IDASLS Private functions + -----------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + idaLsATimes: + + This routine generates the matrix-vector product z = Jv, where + J is the system Jacobian, by calling either the user provided + routine or the internal DQ routine. The return value is + the same as the value returned by jtimes -- + 0 if successful, nonzero otherwise. + ---------------------------------------------------------------*/ +int idaLsATimes(void *ida_mem, N_Vector v, N_Vector z) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure */ + retval = idaLs_AccessLMem(ida_mem, "idaLsATimes", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* call Jacobian-times-vector product routine + (either user-supplied or internal DQ) */ + retval = idals_mem->jtimes(IDA_mem->ida_tn, idals_mem->ycur, + idals_mem->ypcur, idals_mem->rcur, + v, z, IDA_mem->ida_cj, + idals_mem->jt_data, idals_mem->ytemp, + idals_mem->yptemp); + idals_mem->njtimes++; + return(retval); +} + + +/*--------------------------------------------------------------- + idaLsPSetup: + + This routine interfaces between the generic iterative linear + solvers and the user's psetup routine. It passes to psetup all + required state information from ida_mem. Its return value + is the same as that returned by psetup. Note that the generic + iterative linear solvers guarantee that idaLsPSetup will only + be called in the case that the user's psetup routine is non-NULL. + ---------------------------------------------------------------*/ +int idaLsPSetup(void *ida_mem) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure */ + retval = idaLs_AccessLMem(ida_mem, "idaLsPSetup", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* Call user pset routine to update preconditioner and possibly + reset jcur (pass !jbad as update suggestion) */ + retval = idals_mem->pset(IDA_mem->ida_tn, idals_mem->ycur, + idals_mem->ypcur, idals_mem->rcur, + IDA_mem->ida_cj, idals_mem->pdata); + idals_mem->npe++; + return(retval); +} + + +/*--------------------------------------------------------------- + idaLsPSolve: + + This routine interfaces between the generic SUNLinSolSolve + routine and the user's psolve routine. It passes to psolve all + required state information from ida_mem. Its return value is + the same as that returned by psolve. Note that the generic + SUNLinSol solver guarantees that IDASilsPSolve will not be + called in the case in which preconditioning is not done. This + is the only case in which the user's psolve routine is allowed + to be NULL. + ---------------------------------------------------------------*/ +int idaLsPSolve(void *ida_mem, N_Vector r, N_Vector z, realtype tol, int lr) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure */ + retval = idaLs_AccessLMem(ida_mem, "idaLsPSolve", + &IDA_mem, &idals_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* call the user-supplied psolve routine, and accumulate count */ + retval = idals_mem->psolve(IDA_mem->ida_tn, idals_mem->ycur, + idals_mem->ypcur, idals_mem->rcur, + r, z, IDA_mem->ida_cj, tol, + idals_mem->pdata); + idals_mem->nps++; + return(retval); +} + + +/*--------------------------------------------------------------- + idaLsDQJac: + + This routine is a wrapper for the Dense and Band + implementations of the difference quotient Jacobian + approximation routines. +---------------------------------------------------------------*/ +int idaLsDQJac(realtype t, realtype c_j, N_Vector y, N_Vector yp, + N_Vector r, SUNMatrix Jac, void *ida_mem, + N_Vector tmp1, N_Vector tmp2, N_Vector tmp3) +{ + int retval; + IDAMem IDA_mem; + IDA_mem = (IDAMem) ida_mem; + + /* access IDAMem structure */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDALS_MEM_NULL, "IDASLS", + "idaLsDQJac", MSG_LS_IDAMEM_NULL); + return(IDALS_MEM_NULL); + } + + /* verify that Jac is non-NULL */ + if (Jac == NULL) { + IDAProcessError(IDA_mem, IDALS_LMEM_NULL, "IDASLS", + "idaLsDQJac", MSG_LS_LMEM_NULL); + return(IDALS_LMEM_NULL); + } + + /* 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 || + IDA_mem->ida_tempv1->ops->nvgetarraypointer == NULL || + IDA_mem->ida_tempv1->ops->nvsetarraypointer == NULL) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDASLS", + "idaLsDQJac", MSG_LS_BAD_NVECTOR); + return(IDALS_ILL_INPUT); + } + + /* Call the matrix-structure-specific DQ approximation routine */ + if (SUNMatGetID(Jac) == SUNMATRIX_DENSE) { + retval = idaLsDenseDQJac(t, c_j, y, yp, r, Jac, IDA_mem, tmp1); + } else if (SUNMatGetID(Jac) == SUNMATRIX_BAND) { + retval = idaLsBandDQJac(t, c_j, y, yp, r, Jac, IDA_mem, tmp1, tmp2, tmp3); + } else { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDASLS", + "idaLsDQJac", + "unrecognized matrix type for idaLsDQJac"); + retval = IDA_ILL_INPUT; + } + return(retval); +} + + +/*--------------------------------------------------------------- + idaLsDenseDQJac + + This routine generates a dense difference quotient approximation + to the Jacobian F_y + c_j*F_y'. It assumes a dense SUNmatrix + input (stored column-wise, and that elements within each column + are contiguous). The address of the jth column of J is obtained + via the function SUNDenseMatrix_Column() and this pointer is + associated with an N_Vector using the + N_VGetArrayPointer/N_VSetArrayPointer functions. Finally, the + actual computation of the jth column of the Jacobian is + done with a call to N_VLinearSum. +---------------------------------------------------------------*/ +int idaLsDenseDQJac(realtype tt, realtype c_j, N_Vector yy, + N_Vector yp, N_Vector rr, SUNMatrix Jac, + IDAMem IDA_mem, N_Vector tmp1) +{ + realtype inc, inc_inv, yj, ypj, srur, conj; + realtype *y_data, *yp_data, *ewt_data, *cns_data = NULL; + N_Vector rtemp, jthCol; + sunindextype j, N; + IDALsMem idals_mem; + int retval = 0; + + /* access LsMem interface structure */ + idals_mem = (IDALsMem) IDA_mem->ida_lmem; + + /* access matrix dimension */ + N = SUNDenseMatrix_Rows(Jac); + + /* Rename work vectors for readibility */ + rtemp = tmp1; + + /* Create an empty vector for matrix column calculations */ + jthCol = N_VCloneEmpty(tmp1); + + /* Obtain pointers to the data for ewt, yy, yp. */ + ewt_data = N_VGetArrayPointer(IDA_mem->ida_ewt); + y_data = N_VGetArrayPointer(yy); + yp_data = N_VGetArrayPointer(yp); + if(IDA_mem->ida_constraints!=NULL) + cns_data = N_VGetArrayPointer(IDA_mem->ida_constraints); + + srur = SUNRsqrt(IDA_mem->ida_uround); + + for (j=0; j < N; j++) { + + /* Generate the jth col of J(tt,yy,yp) as delta(F)/delta(y_j). */ + + /* Set data address of jthCol, and save y_j and yp_j values. */ + N_VSetArrayPointer(SUNDenseMatrix_Column(Jac,j), jthCol); + yj = y_data[j]; + ypj = yp_data[j]; + + /* Set increment inc to y_j based on sqrt(uround)*abs(y_j), with + adjustments using yp_j and ewt_j if this is small, and a further + adjustment to give it the same sign as hh*yp_j. */ + + inc = SUNMAX( srur * SUNMAX( SUNRabs(yj), SUNRabs(IDA_mem->ida_hh*ypj) ), + ONE/ewt_data[j] ); + + if (IDA_mem->ida_hh*ypj < ZERO) inc = -inc; + inc = (yj + inc) - yj; + + /* Adjust sign(inc) again if y_j has an inequality constraint. */ + if (IDA_mem->ida_constraints != NULL) { + 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;} + } + + /* Increment y_j and yp_j, call res, and break on error return. */ + y_data[j] += inc; + yp_data[j] += c_j*inc; + + retval = IDA_mem->ida_res(tt, yy, yp, rtemp, IDA_mem->ida_user_data); + idals_mem->nreDQ++; + if (retval != 0) break; + + /* Construct difference quotient in jthCol */ + inc_inv = ONE/inc; + N_VLinearSum(inc_inv, rtemp, -inc_inv, rr, jthCol); + + /* reset y_j, yp_j */ + y_data[j] = yj; + yp_data[j] = ypj; + } + + /* Destroy jthCol vector */ + N_VSetArrayPointer(NULL, jthCol); /* SHOULDN'T BE NEEDED */ + N_VDestroy(jthCol); + + return(retval); +} + + +/*--------------------------------------------------------------- + idaLsBandDQJac + + This routine generates a banded difference quotient approximation + JJ to the DAE system Jacobian J. It assumes a band SUNMatrix + input (stored column-wise, and that elements within each column + are contiguous). This makes it possible to get the address + of a column of JJ via the function SUNBandMatrix_Column(). The + columns of the Jacobian are constructed using mupper + mlower + 1 + calls to the res routine, and appropriate differencing. + The return value is either IDABAND_SUCCESS = 0, or the nonzero + value returned by the res routine, if any. + ---------------------------------------------------------------*/ +int idaLsBandDQJac(realtype tt, realtype c_j, N_Vector yy, + N_Vector yp, N_Vector rr, SUNMatrix Jac, + IDAMem IDA_mem, N_Vector tmp1, N_Vector tmp2, + N_Vector tmp3) +{ + realtype inc, inc_inv, yj, ypj, srur, conj, ewtj; + realtype *y_data, *yp_data, *ewt_data, *cns_data = NULL; + realtype *ytemp_data, *yptemp_data, *rtemp_data, *r_data, *col_j; + N_Vector rtemp, ytemp, yptemp; + sunindextype i, j, i1, i2, width, ngroups, group; + sunindextype N, mupper, mlower; + IDALsMem idals_mem; + int retval = 0; + + /* access LsMem interface structure */ + idals_mem = (IDALsMem) IDA_mem->ida_lmem; + + /* access matrix dimensions */ + N = SUNBandMatrix_Columns(Jac); + mupper = SUNBandMatrix_UpperBandwidth(Jac); + mlower = SUNBandMatrix_LowerBandwidth(Jac); + + /* Rename work vectors for use as temporary values of r, y and yp */ + rtemp = tmp1; + ytemp = tmp2; + yptemp= tmp3; + + /* Obtain pointers to the data for all eight vectors used. */ + ewt_data = N_VGetArrayPointer(IDA_mem->ida_ewt); + r_data = N_VGetArrayPointer(rr); + y_data = N_VGetArrayPointer(yy); + yp_data = N_VGetArrayPointer(yp); + rtemp_data = N_VGetArrayPointer(rtemp); + ytemp_data = N_VGetArrayPointer(ytemp); + yptemp_data = N_VGetArrayPointer(yptemp); + if (IDA_mem->ida_constraints != NULL) + cns_data = N_VGetArrayPointer(IDA_mem->ida_constraints); + + /* Initialize ytemp and yptemp. */ + N_VScale(ONE, yy, ytemp); + N_VScale(ONE, yp, yptemp); + + /* Compute miscellaneous values for the Jacobian computation. */ + srur = SUNRsqrt(IDA_mem->ida_uround); + width = mlower + mupper + 1; + ngroups = SUNMIN(width, N); + + /* Loop over column groups. */ + for (group=1; group <= ngroups; group++) { + + /* Increment all yy[j] and yp[j] for j in this group. */ + for (j=group-1; j<N; j+=width) { + yj = y_data[j]; + ypj = yp_data[j]; + ewtj = ewt_data[j]; + + /* Set increment inc to yj based on sqrt(uround)*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. */ + inc = SUNMAX( srur * SUNMAX( SUNRabs(yj), 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) { + 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;} + } + + /* Increment yj and ypj. */ + ytemp_data[j] += inc; + yptemp_data[j] += IDA_mem->ida_cj*inc; + } + + /* Call res routine with incremented arguments. */ + retval = IDA_mem->ida_res(tt, ytemp, yptemp, rtemp, IDA_mem->ida_user_data); + idals_mem->nreDQ++; + if (retval != 0) break; + + /* Loop over the indices j in this group again. */ + for (j=group-1; j<N; j+=width) { + + /* Reset ytemp and yptemp components that were perturbed. */ + yj = ytemp_data[j] = y_data[j]; + ypj = yptemp_data[j] = yp_data[j]; + col_j = SUNBandMatrix_Column(Jac, j); + ewtj = ewt_data[j]; + + /* Set increment inc exactly as above. */ + inc = SUNMAX( srur * SUNMAX( SUNRabs(yj), 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) { + 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;} + } + + /* Load the difference quotient Jacobian elements for column j */ + inc_inv = ONE/inc; + i1 = SUNMAX(0, j-mupper); + i2 = SUNMIN(j+mlower,N-1); + for (i=i1; i<=i2; i++) + SM_COLUMN_ELEMENT_B(col_j,i,j) = inc_inv * (rtemp_data[i]-r_data[i]); + } + } + + return(retval); +} + + +/*--------------------------------------------------------------- + idaLsDQJtimes + + This routine generates a difference quotient approximation to + the matrix-vector product z = Jv, where J is the system + Jacobian. The approximation is + Jv = [F(t,y1,yp1) - F(t,y,yp)]/sigma, + where + y1 = y + sigma*v, yp1 = yp + cj*sigma*v, + sigma = sqrt(Neq)*dqincfac. + The return value from the call to res is saved in order to set + the return flag from idaLsSolve. + ---------------------------------------------------------------*/ +int idaLsDQJtimes(realtype tt, N_Vector yy, N_Vector yp, N_Vector rr, + N_Vector v, N_Vector Jv, realtype c_j, + void *ida_mem, N_Vector work1, N_Vector work2) +{ + IDAMem IDA_mem; + IDALsMem idals_mem; + N_Vector y_tmp, yp_tmp; + realtype sig, siginv; + int iter, retval; + + /* 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 */ + + /* Rename work1 and work2 for readibility */ + y_tmp = work1; + yp_tmp = work2; + + for (iter=0; iter<MAX_ITERS; iter++) { + + /* Set y_tmp = yy + sig*v, yp_tmp = yp + cj*sig*v. */ + N_VLinearSum(sig, v, ONE, yy, y_tmp); + N_VLinearSum(c_j*sig, v, ONE, yp, yp_tmp); + + /* Call res for Jv = F(t, y_tmp, yp_tmp), and return if it failed. */ + retval = IDA_mem->ida_res(tt, y_tmp, yp_tmp, Jv, IDA_mem->ida_user_data); + idals_mem->nreDQ++; + if (retval == 0) break; + if (retval < 0) return(-1); + + sig *= PT25; + } + + if (retval > 0) return(+1); + + /* Set Jv to [Jv - rr]/sig and return. */ + siginv = ONE/sig; + N_VLinearSum(siginv, Jv, -siginv, rr, Jv); + + return(0); +} + + +/*--------------------------------------------------------------- + idaLsInitialize + + This routine performs remaining initializations specific + to the iterative linear solver interface (and solver itself) +---------------------------------------------------------------*/ +int idaLsInitialize(IDAMem IDA_mem) +{ + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure */ + if (IDA_mem->ida_lmem == NULL) { + IDAProcessError(IDA_mem, IDALS_LMEM_NULL, "IDASLS", + "idaLsInitialize", MSG_LS_LMEM_NULL); + return(IDALS_LMEM_NULL); + } + idals_mem = (IDALsMem) IDA_mem->ida_lmem; + + + /* Test for valid combinations of matrix & Jacobian routines: */ + if (idals_mem->J == NULL) { + + /* If SUNMatrix A is NULL: ensure 'jac' function pointer is NULL */ + idals_mem->jacDQ = SUNFALSE; + idals_mem->jac = NULL; + idals_mem->J_data = NULL; + + } else if (idals_mem->jacDQ) { + + /* If J is non-NULL, and 'jac' is not user-supplied: + - if J is dense or band, ensure that our DQ approx. is used + - otherwise => error */ + retval = 0; + if (idals_mem->J->ops->getid) { + + if ( (SUNMatGetID(idals_mem->J) == SUNMATRIX_DENSE) || + (SUNMatGetID(idals_mem->J) == SUNMATRIX_BAND) ) { + idals_mem->jac = idaLsDQJac; + idals_mem->J_data = IDA_mem; + } else { + retval++; + } + + } else { + retval++; + } + if (retval) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDASLS", "idaLsInitialize", + "No Jacobian constructor available for SUNMatrix type"); + idals_mem->last_flag = IDALS_ILL_INPUT; + return(IDALS_ILL_INPUT); + } + + } else { + + /* If J is non-NULL, and 'jac' is user-supplied, + reset J_data pointer (just in case) */ + idals_mem->J_data = IDA_mem->ida_user_data; + } + + /* reset counters */ + idaLsInitializeCounters(idals_mem); + + /* Set Jacobian-related fields, based on jtimesDQ */ + if (idals_mem->jtimesDQ) { + idals_mem->jtsetup = NULL; + idals_mem->jtimes = idaLsDQJtimes; + idals_mem->jt_data = IDA_mem; + } else { + idals_mem->jt_data = IDA_mem->ida_user_data; + } + + /* if J is NULL and psetup is not present, then idaLsSetup does + not need to be called, so set the lsetup function to NULL */ + if ( (idals_mem->J == NULL) && (idals_mem->pset == NULL) ) + IDA_mem->ida_lsetup = NULL; + + /* Call LS initialize routine */ + idals_mem->last_flag = SUNLinSolInitialize(idals_mem->LS); + return(idals_mem->last_flag); +} + + +/*--------------------------------------------------------------- + idaLsSetup + + This calls the Jacobian evaluation routine (if using a SUNMatrix + object), updates counters, and calls the LS 'setup' routine to + prepare for subsequent calls to the LS 'solve' routine. +---------------------------------------------------------------*/ +int idaLsSetup(IDAMem IDA_mem, N_Vector y, N_Vector yp, N_Vector r, + N_Vector vt1, N_Vector vt2, N_Vector vt3) +{ + IDALsMem idals_mem; + int retval; + + /* access IDALsMem structure */ + if (IDA_mem->ida_lmem == NULL) { + IDAProcessError(IDA_mem, IDALS_LMEM_NULL, "IDASLS", + "idaLsSetup", MSG_LS_LMEM_NULL); + return(IDALS_LMEM_NULL); + } + idals_mem = (IDALsMem) IDA_mem->ida_lmem; + + /* Set IDALs N_Vector pointers to inputs */ + idals_mem->ycur = y; + idals_mem->ypcur = yp; + idals_mem->rcur = r; + + /* recompute if J if it is non-NULL */ + if (idals_mem->J) { + + /* 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); + } + + /* Call Jacobian routine */ + retval = idals_mem->jac(IDA_mem->ida_tn, IDA_mem->ida_cj, y, + yp, r, idals_mem->J, + idals_mem->J_data, vt1, vt2, vt3); + if (retval < 0) { + IDAProcessError(IDA_mem, IDALS_JACFUNC_UNRECVR, "IDASLS", + "idaLsSetup", MSG_LS_JACFUNC_FAILED); + idals_mem->last_flag = IDALS_JACFUNC_UNRECVR; + return(-1); + } + if (retval > 0) { + idals_mem->last_flag = IDALS_JACFUNC_RECVR; + return(1); + } + + } + + /* Call LS setup routine -- the LS will call idaLsPSetup if applicable */ + idals_mem->last_flag = SUNLinSolSetup(idals_mem->LS, idals_mem->J); + return(idals_mem->last_flag); +} + + +/*--------------------------------------------------------------- + idaLsSolve + + This routine interfaces between IDA and the generic + SUNLinearSolver object LS, by setting the appropriate tolerance + and scaling vectors, calling the solver, accumulating + statistics from the solve for use/reporting by IDA, and scaling + the result if using a non-NULL SUNMatrix and cjratio does not + equal one. +---------------------------------------------------------------*/ +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; + realtype tol, w_mean; + + /* access IDALsMem structure */ + if (IDA_mem->ida_lmem == NULL) { + IDAProcessError(IDA_mem, IDALS_LMEM_NULL, "IDASLS", + "idaLsSolve", MSG_LS_LMEM_NULL); + return(IDALS_LMEM_NULL); + } + 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) ) { + tol = idals_mem->sqrtN * idals_mem->eplifac * IDA_mem->ida_epsNewt; + } else { + tol = ZERO; + } + + /* Set vectors ycur, ypcur and rcur for use by the Atimes and + Psolve interface routines */ + idals_mem->ycur = ycur; + 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); + if (retval != SUNLS_SUCCESS) { + IDAProcessError(IDA_mem, IDALS_SUNLS_FAIL, "IDASLS", "idaLsSolve", + "Error in calling SUNLinSolSetScalingVectors"); + idals_mem->last_flag = IDALS_SUNLS_FAIL; + return(idals_mem->last_flag); + } + + /* If solver is iterative and does not support scaling vectors, update the + tolerance in an attempt to account for weight vector. We make the + following assumptions: + 1. w_i = w_mean, for i=0,...,n-1 (i.e. the weights are homogeneous) + 2. the linear solver uses a basic 2-norm to measure convergence + Hence (using the notation from sunlinsol_spgmr.h, with S = diag(w)), + || bbar - Abar xbar ||_2 < tol + <=> || S b - S A x ||_2 < tol + <=> || S (b - A x) ||_2 < tol + <=> \sum_{i=0}^{n-1} (w_i (b - A x)_i)^2 < tol^2 + <=> 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) ) { + + w_mean = SUNRsqrt( N_VDotProd(weight, weight) ) / idals_mem->sqrtN; + tol /= w_mean; + + } + + /* 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, + IDA_mem->ida_cj, idals_mem->jt_data); + idals_mem->njtsetup++; + if (idals_mem->last_flag != 0) { + IDAProcessError(IDA_mem, retval, "IDASLS", + "idaLsSolve", MSG_LS_JTSETUP_FAILED); + return(idals_mem->last_flag); + } + } + + /* Call solver */ + retval = SUNLinSolSolve(idals_mem->LS, idals_mem->J, + idals_mem->x, b, tol); + + /* Copy appropriate result to b (depending on solver type) */ + if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || + (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { + + /* Retrieve solver statistics */ + nli_inc = SUNLinSolNumIters(idals_mem->LS); + + /* Copy x (or preconditioned residual vector if no iterations required) to b */ + if (nli_inc == 0) N_VScale(ONE, SUNLinSolResid(idals_mem->LS), b); + else N_VScale(ONE, idals_mem->x, b); + + /* Increment nli counter */ + idals_mem->nli += nli_inc; + + } else { + + /* Copy x to b */ + N_VScale(ONE, idals_mem->x, b); + + } + + /* 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) ) + N_VScale(TWO/(ONE + IDA_mem->ida_cjratio), b, b); + + /* Increment ncfl counter */ + if (retval != SUNLS_SUCCESS) idals_mem->ncfl++; + + /* Interpret solver return value */ + idals_mem->last_flag = retval; + + switch(retval) { + + case SUNLS_SUCCESS: + return(0); + break; + case SUNLS_RES_REDUCED: + case SUNLS_CONV_FAIL: + case SUNLS_PSOLVE_FAIL_REC: + case SUNLS_PACKAGE_FAIL_REC: + case SUNLS_QRFACT_FAIL: + case SUNLS_LUFACT_FAIL: + return(1); + break; + case SUNLS_MEM_NULL: + case SUNLS_ILL_INPUT: + case SUNLS_MEM_FAIL: + case SUNLS_GS_FAIL: + case SUNLS_QRSOL_FAIL: + return(-1); + break; + case SUNLS_PACKAGE_FAIL_UNREC: + IDAProcessError(IDA_mem, SUNLS_PACKAGE_FAIL_UNREC, "IDASLS", + "idaLsSolve", + "Failure in SUNLinSol external package"); + return(-1); + break; + case SUNLS_PSOLVE_FAIL_UNREC: + IDAProcessError(IDA_mem, SUNLS_PSOLVE_FAIL_UNREC, "IDASLS", + "idaLsSolve", MSG_LS_PSOLVE_FAILED); + return(-1); + break; + } + + return(0); +} + + +/*--------------------------------------------------------------- + idaLsPerf: accumulates performance statistics information + for IDA +---------------------------------------------------------------*/ +int idaLsPerf(IDAMem IDA_mem, int perftask) +{ + IDALsMem idals_mem; + realtype rcfn, rcfl; + long int nstd, nnid; + booleantype lcfn, lcfl; + + /* access IDALsMem structure */ + if (IDA_mem->ida_lmem == NULL) { + IDAProcessError(IDA_mem, IDALS_LMEM_NULL, "IDASLS", + "idaLsPerf", MSG_LS_LMEM_NULL); + return(IDALS_LMEM_NULL); + } + idals_mem = (IDALsMem) IDA_mem->ida_lmem; + + /* when perftask == 0, store current performance statistics */ + if (perftask == 0) { + idals_mem->nst0 = IDA_mem->ida_nst; + idals_mem->nni0 = IDA_mem->ida_nni; + idals_mem->ncfn0 = IDA_mem->ida_ncfn; + idals_mem->ncfl0 = idals_mem->ncfl; + idals_mem->nwarn = 0; + return(0); + } + + /* Compute statistics since last call + + Note: the performance monitor that checked whether the average + number of linear iterations was too close to maxl has been + removed, since the 'maxl' value is no longer owned by the + IDALs interface. + */ + nstd = IDA_mem->ida_nst - idals_mem->nst0; + 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) ); + lcfn = (rcfn > PT9); + lcfl = (rcfl > PT9); + if (!(lcfn || lcfl)) return(0); + idals_mem->nwarn++; + if (idals_mem->nwarn > 10) return(1); + if (lcfn) + IDAProcessError(IDA_mem, IDA_WARNING, "IDASLS", "idaLsPerf", + MSG_LS_CFN_WARN, IDA_mem->ida_tn, rcfn); + if (lcfl) + IDAProcessError(IDA_mem, IDA_WARNING, "IDASLS", "idaLsPerf", + MSG_LS_CFL_WARN, IDA_mem->ida_tn, rcfl); + return(0); +} + + +/*--------------------------------------------------------------- + idaLsFree frees memory associates with the IDALs system + solver interface. +---------------------------------------------------------------*/ +int idaLsFree(IDAMem IDA_mem) +{ + IDALsMem idals_mem; + + /* Return immediately if IDA_mem or IDA_mem->ida_lmem are NULL */ + if (IDA_mem == NULL) return (IDALS_SUCCESS); + if (IDA_mem->ida_lmem == NULL) return(IDALS_SUCCESS); + idals_mem = (IDALsMem) IDA_mem->ida_lmem; + + /* Free N_Vector memory */ + if (idals_mem->ytemp) { + N_VDestroy(idals_mem->ytemp); + idals_mem->ytemp = NULL; + } + if (idals_mem->yptemp) { + N_VDestroy(idals_mem->yptemp); + idals_mem->yptemp = NULL; + } + if (idals_mem->x) { + N_VDestroy(idals_mem->x); + idals_mem->x = NULL; + } + + /* Nullify other N_Vector pointers */ + idals_mem->ycur = NULL; + idals_mem->ypcur = NULL; + idals_mem->rcur = NULL; + + /* Nullify SUNMatrix pointer */ + idals_mem->J = NULL; + + /* Free preconditioner memory (if applicable) */ + if (idals_mem->pfree) idals_mem->pfree(IDA_mem); + + /* free IDALs interface structure */ + free(IDA_mem->ida_lmem); + + return(IDALS_SUCCESS); +} + + +/*--------------------------------------------------------------- + idaLsInitializeCounters resets all counters from an + IDALsMem structure. +---------------------------------------------------------------*/ +int idaLsInitializeCounters(IDALsMem idals_mem) +{ + idals_mem->nje = 0; + idals_mem->nreDQ = 0; + idals_mem->npe = 0; + idals_mem->nli = 0; + idals_mem->nps = 0; + idals_mem->ncfl = 0; + idals_mem->njtsetup = 0; + idals_mem->njtimes = 0; + return(0); +} + + +/*--------------------------------------------------------------- + idaLs_AccessLMem + + This routine unpacks the IDA_mem and idals_mem structures from + the void* ida_mem pointer. If either is missing it returns + IDALS_MEM_NULL or IDALS_LMEM_NULL. + ---------------------------------------------------------------*/ +int idaLs_AccessLMem(void* ida_mem, const char* fname, + IDAMem* IDA_mem, IDALsMem* idals_mem) +{ + if (ida_mem==NULL) { + IDAProcessError(NULL, IDALS_MEM_NULL, "IDASLS", + fname, MSG_LS_IDAMEM_NULL); + return(IDALS_MEM_NULL); + } + *IDA_mem = (IDAMem) ida_mem; + if ((*IDA_mem)->ida_lmem==NULL) { + IDAProcessError(*IDA_mem, IDALS_LMEM_NULL, "IDASLS", + fname, MSG_LS_LMEM_NULL); + return(IDALS_LMEM_NULL); + } + *idals_mem = (IDALsMem) (*IDA_mem)->ida_lmem; + return(IDALS_SUCCESS); +} + + + +/*================================================================ + PART II - backward problems + ================================================================*/ + + +/*--------------------------------------------------------------- + IDASLS Exported functions -- Required + ---------------------------------------------------------------*/ + +/* IDASetLinearSolverB specifies the iterative linear solver + for backward integration */ +int IDASetLinearSolverB(void *ida_mem, int which, + SUNLinearSolver LS, SUNMatrix A) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + IDABMem IDAB_mem; + IDALsMemB idalsB_mem; + void *ida_memB; + int retval; + + /* Check if ida_mem exists */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDALS_MEM_NULL, "IDASLS", + "IDASetLinearSolverB", MSG_LS_IDAMEM_NULL); + return(IDALS_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* Was ASA initialized? */ + if (IDA_mem->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(IDA_mem, IDALS_NO_ADJ, "IDASLS", + "IDASetLinearSolverB", MSG_LS_NO_ADJ); + return(IDALS_NO_ADJ); + } + IDAADJ_mem = IDA_mem->ida_adj_mem; + + /* Check the value of which */ + if ( which >= IDAADJ_mem->ia_nbckpbs ) { + IDAProcessError(IDA_mem, IDALS_ILL_INPUT, "IDASLS", + "IDASetLinearSolverB", MSG_LS_BAD_WHICH); + return(IDALS_ILL_INPUT); + } + + /* Find the IDABMem entry in the linked list corresponding to 'which'. */ + IDAB_mem = IDAADJ_mem->IDAB_mem; + while (IDAB_mem != NULL) { + if( which == IDAB_mem->ida_index ) break; + IDAB_mem = IDAB_mem->ida_next; + } + + /* Get memory for IDALsMemRecB */ + idalsB_mem = NULL; + idalsB_mem = (IDALsMemB) malloc(sizeof(struct IDALsMemRecB)); + if (idalsB_mem == NULL) { + IDAProcessError(IDA_mem, IDALS_MEM_FAIL, "IDASLS", + "IDASetLinearSolverB", MSG_LS_MEM_FAIL); + return(IDALS_MEM_FAIL); + } + + /* initialize Jacobian and preconditioner functions */ + idalsB_mem->jacB = NULL; + idalsB_mem->jacBS = NULL; + idalsB_mem->jtsetupB = NULL; + idalsB_mem->jtsetupBS = NULL; + idalsB_mem->jtimesB = NULL; + idalsB_mem->jtimesBS = NULL; + idalsB_mem->psetB = NULL; + idalsB_mem->psetBS = NULL; + idalsB_mem->psolveB = NULL; + idalsB_mem->psolveBS = NULL; + idalsB_mem->P_dataB = NULL; + + /* free any existing system solver attached to IDAB */ + if (IDAB_mem->ida_lfree) IDAB_mem->ida_lfree(IDAB_mem); + + /* Attach lmemB data and lfreeB function. */ + IDAB_mem->ida_lmem = idalsB_mem; + IDAB_mem->ida_lfree = idaLsFreeB; + + /* set the linear solver for this backward problem */ + ida_memB = (void *)IDAB_mem->IDA_mem; + retval = IDASetLinearSolver(ida_memB, LS, A); + if (retval != IDALS_SUCCESS) { + free(idalsB_mem); + idalsB_mem = NULL; + } + + return(retval); +} + + +/*--------------------------------------------------------------- + IDASLS Exported functions -- Optional input/output + ---------------------------------------------------------------*/ + +int IDASetJacFnB(void *ida_mem, int which, IDALsJacFnB jacB) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + IDABMem IDAB_mem; + IDALsMemB idalsB_mem; + void *ida_memB; + int retval; + + /* access relevant memory structures */ + retval = idaLs_AccessLMemB(ida_mem, which, "IDASetJacFnB", &IDA_mem, + &IDAADJ_mem, &IDAB_mem, &idalsB_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* set jacB function pointer */ + idalsB_mem->jacB = jacB; + + /* call corresponding routine for IDAB_mem structure */ + ida_memB = (void*) IDAB_mem->IDA_mem; + if (jacB != NULL) { + retval = IDASetJacFn(ida_memB, idaLsJacBWrapper); + } else { + retval = IDASetJacFn(ida_memB, NULL); + } + + return(retval); +} + + +int IDASetJacFnBS(void *ida_mem, int which, IDALsJacFnBS jacBS) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + IDABMem IDAB_mem; + IDALsMemB idalsB_mem; + void *ida_memB; + int retval; + + /* access relevant memory structures */ + retval = idaLs_AccessLMemB(ida_mem, which, "IDASetJacFnBS", &IDA_mem, + &IDAADJ_mem, &IDAB_mem, &idalsB_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* set jacBS function pointer */ + idalsB_mem->jacBS = jacBS; + + /* call corresponding routine for IDAB_mem structure */ + ida_memB = (void*) IDAB_mem->IDA_mem; + if (jacBS != NULL) { + retval = IDASetJacFn(ida_memB, idaLsJacBSWrapper); + } else { + retval = IDASetJacFn(ida_memB, NULL); + } + + return(retval); +} + + +int IDASetEpsLinB(void *ida_mem, int which, realtype eplifacB) +{ + 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, "IDASetEpsLinB", &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(IDASetEpsLin(ida_memB, eplifacB)); +} + + +int IDASetIncrementFactorB(void *ida_mem, int which, realtype dqincfacB) +{ + 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, "IDASetIncrementFactorB", + &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(IDASetIncrementFactor(ida_memB, dqincfacB)); +} + + +int IDASetPreconditionerB(void *ida_mem, int which, + IDALsPrecSetupFnB psetupB, + IDALsPrecSolveFnB psolveB) +{ + IDAadjMem IDAADJ_mem; + IDAMem IDA_mem; + IDABMem IDAB_mem; + void *ida_memB; + IDALsMemB idalsB_mem; + IDALsPrecSetupFn idals_psetup; + IDALsPrecSolveFn idals_psolve; + int retval; + + /* access relevant memory structures */ + retval = idaLs_AccessLMemB(ida_mem, which, "IDASetPreconditionerB", + &IDA_mem, &IDAADJ_mem, &IDAB_mem, &idalsB_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* Set preconditioners for the backward problem. */ + idalsB_mem->psetB = psetupB; + idalsB_mem->psolveB = psolveB; + + /* Call the corresponding "set" routine for the backward problem */ + ida_memB = (void *) IDAB_mem->IDA_mem; + idals_psetup = (psetupB == NULL) ? NULL : idaLsPrecSetupB; + idals_psolve = (psolveB == NULL) ? NULL : idaLsPrecSolveB; + return(IDASetPreconditioner(ida_memB, idals_psetup, idals_psolve)); +} + + +int IDASetPreconditionerBS(void *ida_mem, int which, + IDALsPrecSetupFnBS psetupBS, + IDALsPrecSolveFnBS psolveBS) +{ + IDAadjMem IDAADJ_mem; + IDAMem IDA_mem; + IDABMem IDAB_mem; + void *ida_memB; + IDALsMemB idalsB_mem; + IDALsPrecSetupFn idals_psetup; + IDALsPrecSolveFn idals_psolve; + int retval; + + /* access relevant memory structures */ + retval = idaLs_AccessLMemB(ida_mem, which, "IDASetPreconditionerBS", + &IDA_mem, &IDAADJ_mem, &IDAB_mem, &idalsB_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* Set preconditioners for the backward problem. */ + idalsB_mem->psetBS = psetupBS; + idalsB_mem->psolveBS = psolveBS; + + /* Call the corresponding "set" routine for the backward problem */ + ida_memB = (void *) IDAB_mem->IDA_mem; + idals_psetup = (psetupBS == NULL) ? NULL : idaLsPrecSetupBS; + idals_psolve = (psolveBS == NULL) ? NULL : idaLsPrecSolveBS; + return(IDASetPreconditioner(ida_memB, idals_psetup, idals_psolve)); +} + + +int IDASetJacTimesB(void *ida_mem, int which, + IDALsJacTimesSetupFnB jtsetupB, + IDALsJacTimesVecFnB jtimesB) +{ + IDAadjMem IDAADJ_mem; + IDAMem IDA_mem; + IDABMem IDAB_mem; + void *ida_memB; + IDALsMemB idalsB_mem; + IDALsJacTimesSetupFn idals_jtsetup; + IDALsJacTimesVecFn idals_jtimes; + int retval; + + /* access relevant memory structures */ + retval = idaLs_AccessLMemB(ida_mem, which, "IDASetJacTimesB", &IDA_mem, + &IDAADJ_mem, &IDAB_mem, &idalsB_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* Set jacobian routines for the backward problem. */ + idalsB_mem->jtsetupB = jtsetupB; + idalsB_mem->jtimesB = jtimesB; + + /* Call the corresponding "set" routine for the backward problem */ + ida_memB = (void *) IDAB_mem->IDA_mem; + idals_jtsetup = (jtsetupB == NULL) ? NULL : idaLsJacTimesSetupB; + idals_jtimes = (jtimesB == NULL) ? NULL : idaLsJacTimesVecB; + return(IDASetJacTimes(ida_memB, idals_jtsetup, idals_jtimes)); +} + + +int IDASetJacTimesBS(void *ida_mem, int which, + IDALsJacTimesSetupFnBS jtsetupBS, + IDALsJacTimesVecFnBS jtimesBS) +{ + IDAadjMem IDAADJ_mem; + IDAMem IDA_mem; + IDABMem IDAB_mem; + void *ida_memB; + IDALsMemB idalsB_mem; + IDALsJacTimesSetupFn idals_jtsetup; + IDALsJacTimesVecFn idals_jtimes; + int retval; + + /* access relevant memory structures */ + retval = idaLs_AccessLMemB(ida_mem, which, "IDASetJacTimesBS", &IDA_mem, + &IDAADJ_mem, &IDAB_mem, &idalsB_mem); + if (retval != IDALS_SUCCESS) return(retval); + + /* Set jacobian routines for the backward problem. */ + idalsB_mem->jtsetupBS = jtsetupBS; + idalsB_mem->jtimesBS = jtimesBS; + + /* Call the corresponding "set" routine for the backward problem */ + ida_memB = (void *) IDAB_mem->IDA_mem; + idals_jtsetup = (jtsetupBS == NULL) ? NULL : idaLsJacTimesSetupBS; + idals_jtimes = (jtimesBS == NULL) ? NULL : idaLsJacTimesVecBS; + return(IDASetJacTimes(ida_memB, idals_jtsetup, idals_jtimes)); +} + + +/*----------------------------------------------------------------- + IDASLS Private functions for backwards problems + -----------------------------------------------------------------*/ + +/* idaLsJacBWrapper interfaces to the IDAJacFnB routine provided + by the user. idaLsJacBWrapper is of type IDALsJacFn. */ +static int idaLsJacBWrapper(realtype tt, realtype c_jB, N_Vector yyB, + N_Vector ypB, N_Vector rrB, SUNMatrix JacB, + void *ida_mem, N_Vector tmp1B, + N_Vector tmp2B, N_Vector tmp3B) +{ + IDAadjMem IDAADJ_mem; + IDAMem IDA_mem; + IDABMem IDAB_mem; + IDALsMemB idalsB_mem; + int retval; + + /* access relevant memory structures */ + retval = idaLs_AccessLMemBCur(ida_mem, "idaLsJacBWrapper", &IDA_mem, + &IDAADJ_mem, &IDAB_mem, &idalsB_mem); + + /* Forward solution from interpolation */ + if (IDAADJ_mem->ia_noInterp == SUNFALSE) { + retval = IDAADJ_mem->ia_getY(IDA_mem, tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, NULL, NULL); + if (retval != IDA_SUCCESS) { + IDAProcessError(IDAB_mem->IDA_mem, -1, "IDASLS", + "idaLsJacBWrapper", MSG_LS_BAD_T); + return(-1); + } + } + + /* Call user's adjoint jacB routine */ + return(idalsB_mem->jacB(tt, c_jB, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, yyB, ypB, + rrB, JacB, IDAB_mem->ida_user_data, + tmp1B, tmp2B, tmp3B)); +} + +/* idaLsJacBSWrapper interfaces to the IDAJacFnBS routine provided + by the user. idaLsJacBSWrapper is of type IDALsJacFn. */ +static int idaLsJacBSWrapper(realtype tt, realtype c_jB, N_Vector yyB, + N_Vector ypB, N_Vector rrB, SUNMatrix JacB, + void *ida_mem, N_Vector tmp1B, + N_Vector tmp2B, N_Vector tmp3B) +{ + IDAadjMem IDAADJ_mem; + IDAMem IDA_mem; + IDABMem IDAB_mem; + IDALsMemB idalsB_mem; + int retval; + + /* access relevant memory structures */ + retval = idaLs_AccessLMemBCur(ida_mem, "idaLsJacBSWrapper", &IDA_mem, + &IDAADJ_mem, &IDAB_mem, &idalsB_mem); + + /* Get forward solution from interpolation. */ + if(IDAADJ_mem->ia_noInterp == SUNFALSE) { + if (IDAADJ_mem->ia_interpSensi) + retval = IDAADJ_mem->ia_getY(IDA_mem, tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, IDAADJ_mem->ia_yySTmp, + IDAADJ_mem->ia_ypSTmp); + else + retval = IDAADJ_mem->ia_getY(IDA_mem, tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, NULL, NULL); + + if (retval != IDA_SUCCESS) { + IDAProcessError(IDAB_mem->IDA_mem, -1, "IDASLS", + "idaLsJacBSWrapper", MSG_LS_BAD_T); + return(-1); + } + } + + /* Call user's adjoint jacBS routine */ + return(idalsB_mem->jacBS(tt, c_jB, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, IDAADJ_mem->ia_yySTmp, + IDAADJ_mem->ia_ypSTmp, yyB, ypB, rrB, JacB, + IDAB_mem->ida_user_data, tmp1B, tmp2B, tmp3B)); +} + + +/* idaLsPrecSetupB interfaces to the IDALsPrecSetupFnB + routine provided by the user */ +static int idaLsPrecSetupB(realtype tt, N_Vector yyB, N_Vector ypB, + N_Vector rrB, realtype c_jB, void *ida_mem) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + IDALsMemB idalsB_mem; + IDABMem IDAB_mem; + int retval; + + /* access relevant memory structures */ + retval = idaLs_AccessLMemBCur(ida_mem, "idaLsPrecSetupB", &IDA_mem, + &IDAADJ_mem, &IDAB_mem, &idalsB_mem); + + /* Get forward solution from interpolation. */ + if (IDAADJ_mem->ia_noInterp==SUNFALSE) { + retval = IDAADJ_mem->ia_getY(IDA_mem, tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, NULL, NULL); + if (retval != IDA_SUCCESS) { + IDAProcessError(IDAB_mem->IDA_mem, -1, "IDASLS", + "idaLsPrecSetupB", MSG_LS_BAD_T); + return(-1); + } + } + + /* Call user's adjoint precondB routine */ + return(idalsB_mem->psetB(tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, yyB, ypB, rrB, + c_jB, IDAB_mem->ida_user_data)); +} + + +/* idaLsPrecSetupBS interfaces to the IDALsPrecSetupFnBS routine + provided by the user */ +static int idaLsPrecSetupBS(realtype tt, N_Vector yyB, N_Vector ypB, + N_Vector rrB, realtype c_jB, void *ida_mem) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + IDALsMemB idalsB_mem; + IDABMem IDAB_mem; + int retval; + + /* access relevant memory structures */ + retval = idaLs_AccessLMemBCur(ida_mem, "idaLsPrecSetupBS", &IDA_mem, + &IDAADJ_mem, &IDAB_mem, &idalsB_mem); + + /* Get forward solution from interpolation. */ + if(IDAADJ_mem->ia_noInterp == SUNFALSE) { + if (IDAADJ_mem->ia_interpSensi) + retval = IDAADJ_mem->ia_getY(IDA_mem, tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, + IDAADJ_mem->ia_yySTmp, + IDAADJ_mem->ia_ypSTmp); + else + retval = IDAADJ_mem->ia_getY(IDA_mem, tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, NULL, NULL); + if (retval != IDA_SUCCESS) { + IDAProcessError(IDAB_mem->IDA_mem, -1, "IDASLS", + "idaLsPrecSetupBS", MSG_LS_BAD_T); + return(-1); + } + } + + /* Call user's adjoint precondBS routine */ + return(idalsB_mem->psetBS(tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, + IDAADJ_mem->ia_yySTmp, + IDAADJ_mem->ia_ypSTmp, yyB, ypB, + rrB, c_jB, IDAB_mem->ida_user_data)); +} + + +/* idaLsPrecSolveB interfaces to the IDALsPrecSolveFnB routine + provided by the user */ +static int idaLsPrecSolveB(realtype tt, N_Vector yyB, N_Vector ypB, + N_Vector rrB, N_Vector rvecB, + N_Vector zvecB, realtype c_jB, + realtype deltaB, void *ida_mem) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + IDALsMemB idalsB_mem; + IDABMem IDAB_mem; + int retval; + + /* access relevant memory structures */ + retval = idaLs_AccessLMemBCur(ida_mem, "idaLsPrecSolveB", &IDA_mem, + &IDAADJ_mem, &IDAB_mem, &idalsB_mem); + + /* Get forward solution from interpolation. */ + if (IDAADJ_mem->ia_noInterp==SUNFALSE) { + retval = IDAADJ_mem->ia_getY(IDA_mem, tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, NULL, NULL); + if (retval != IDA_SUCCESS) { + IDAProcessError(IDAB_mem->IDA_mem, -1, "IDASLS", + "idaLsPrecSolveB", MSG_LS_BAD_T); + return(-1); + } + } + + /* Call user's adjoint psolveB routine */ + return(idalsB_mem->psolveB(tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, yyB, ypB, + rrB, rvecB, zvecB, c_jB, deltaB, + IDAB_mem->ida_user_data)); +} + + +/* idaLsPrecSolveBS interfaces to the IDALsPrecSolveFnBS routine + provided by the user */ +static int idaLsPrecSolveBS(realtype tt, N_Vector yyB, N_Vector ypB, + N_Vector rrB, N_Vector rvecB, + N_Vector zvecB, realtype c_jB, + realtype deltaB, void *ida_mem) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + IDALsMemB idalsB_mem; + IDABMem IDAB_mem; + int retval; + + /* access relevant memory structures */ + retval = idaLs_AccessLMemBCur(ida_mem, "idaLsPrecSolveBS", &IDA_mem, + &IDAADJ_mem, &IDAB_mem, &idalsB_mem); + + /* Get forward solution from interpolation. */ + if(IDAADJ_mem->ia_noInterp == SUNFALSE) { + if (IDAADJ_mem->ia_interpSensi) + retval = IDAADJ_mem->ia_getY(IDA_mem, tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, + IDAADJ_mem->ia_yySTmp, + IDAADJ_mem->ia_ypSTmp); + else + retval = IDAADJ_mem->ia_getY(IDA_mem, tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, NULL, NULL); + if (retval != IDA_SUCCESS) { + IDAProcessError(IDAB_mem->IDA_mem, -1, "IDASLS", + "idaLsPrecSolveBS", MSG_LS_BAD_T); + return(-1); + } + } + + /* Call user's adjoint psolveBS routine */ + return(idalsB_mem->psolveBS(tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, + IDAADJ_mem->ia_yySTmp, + IDAADJ_mem->ia_ypSTmp, + yyB, ypB, rrB, rvecB, zvecB, c_jB, + deltaB, IDAB_mem->ida_user_data)); +} + + +/* idaLsJacTimesSetupB interfaces to the IDALsJacTimesSetupFnB + routine provided by the user */ +static int idaLsJacTimesSetupB(realtype tt, N_Vector yyB, N_Vector ypB, + N_Vector rrB, realtype c_jB, void *ida_mem) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + IDALsMemB idalsB_mem; + IDABMem IDAB_mem; + int retval; + + /* access relevant memory structures */ + retval = idaLs_AccessLMemBCur(ida_mem, "idaLsJacTimesSetupB", &IDA_mem, + &IDAADJ_mem, &IDAB_mem, &idalsB_mem); + + /* Get forward solution from interpolation. */ + if (IDAADJ_mem->ia_noInterp==SUNFALSE) { + retval = IDAADJ_mem->ia_getY(IDA_mem, tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, NULL, NULL); + if (retval != IDA_SUCCESS) { + IDAProcessError(IDAB_mem->IDA_mem, -1, "IDASLS", + "idaLsJacTimesSetupB", MSG_LS_BAD_T); + return(-1); + } + } + /* Call user's adjoint jtsetupB routine */ + return(idalsB_mem->jtsetupB(tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, yyB, + ypB, rrB, c_jB, IDAB_mem->ida_user_data)); +} + + +/* idaLsJacTimesSetupBS interfaces to the IDALsJacTimesSetupFnBS + routine provided by the user */ +static int idaLsJacTimesSetupBS(realtype tt, N_Vector yyB, N_Vector ypB, + N_Vector rrB, realtype c_jB, void *ida_mem) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + IDALsMemB idalsB_mem; + IDABMem IDAB_mem; + int retval; + + /* access relevant memory structures */ + retval = idaLs_AccessLMemBCur(ida_mem, "idaLsJacTimesSetupBS", &IDA_mem, + &IDAADJ_mem, &IDAB_mem, &idalsB_mem); + + /* Get forward solution from interpolation. */ + if(IDAADJ_mem->ia_noInterp == SUNFALSE) { + if (IDAADJ_mem->ia_interpSensi) + retval = IDAADJ_mem->ia_getY(IDA_mem, tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, + IDAADJ_mem->ia_yySTmp, + IDAADJ_mem->ia_ypSTmp); + else + retval = IDAADJ_mem->ia_getY(IDA_mem, tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, NULL, NULL); + if (retval != IDA_SUCCESS) { + IDAProcessError(IDAB_mem->IDA_mem, -1, "IDASLS", + "idaLsJacTimesSetupBS", MSG_LS_BAD_T); + return(-1); + } + } + + /* Call user's adjoint jtimesBS routine */ + return(idalsB_mem->jtsetupBS(tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, + IDAADJ_mem->ia_yySTmp, + IDAADJ_mem->ia_ypSTmp, + yyB, ypB, rrB, c_jB, + IDAB_mem->ida_user_data)); +} + + +/* idaLsJacTimesVecB interfaces to the IDALsJacTimesVecFnB routine + provided by the user */ +static int idaLsJacTimesVecB(realtype tt, N_Vector yyB, N_Vector ypB, + N_Vector rrB, N_Vector vB, N_Vector JvB, + realtype c_jB, void *ida_mem, + N_Vector tmp1B, N_Vector tmp2B) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + IDALsMemB idalsB_mem; + IDABMem IDAB_mem; + int retval; + + /* access relevant memory structures */ + retval = idaLs_AccessLMemBCur(ida_mem, "idaLsJacTimesVecB", &IDA_mem, + &IDAADJ_mem, &IDAB_mem, &idalsB_mem); + + /* Get forward solution from interpolation. */ + if (IDAADJ_mem->ia_noInterp==SUNFALSE) { + retval = IDAADJ_mem->ia_getY(IDA_mem, tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, NULL, NULL); + if (retval != IDA_SUCCESS) { + IDAProcessError(IDAB_mem->IDA_mem, -1, "IDASLS", + "idaLsJacTimesVecB", MSG_LS_BAD_T); + return(-1); + } + } + + /* Call user's adjoint jtimesB routine */ + return(idalsB_mem->jtimesB(tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, yyB, + ypB, rrB, vB, JvB, c_jB, + IDAB_mem->ida_user_data, + tmp1B, tmp2B)); +} + + +/* idaLsJacTimesVecBS interfaces to the IDALsJacTimesVecFnBS routine + provided by the user */ +static int idaLsJacTimesVecBS(realtype tt, N_Vector yyB, N_Vector ypB, + N_Vector rrB, N_Vector vB, N_Vector JvB, + realtype c_jB, void *ida_mem, + N_Vector tmp1B, N_Vector tmp2B) +{ + IDAMem IDA_mem; + IDAadjMem IDAADJ_mem; + IDALsMemB idalsB_mem; + IDABMem IDAB_mem; + int retval; + + /* access relevant memory structures */ + retval = idaLs_AccessLMemBCur(ida_mem, "idaLsJacTimesVecBS", &IDA_mem, + &IDAADJ_mem, &IDAB_mem, &idalsB_mem); + + /* Get forward solution from interpolation. */ + if(IDAADJ_mem->ia_noInterp == SUNFALSE) { + if (IDAADJ_mem->ia_interpSensi) + retval = IDAADJ_mem->ia_getY(IDA_mem, tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, + IDAADJ_mem->ia_yySTmp, + IDAADJ_mem->ia_ypSTmp); + else + retval = IDAADJ_mem->ia_getY(IDA_mem, tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, NULL, NULL); + if (retval != IDA_SUCCESS) { + IDAProcessError(IDAB_mem->IDA_mem, -1, "IDASLS", + "idaLsJacTimesVecBS", MSG_LS_BAD_T); + return(-1); + } + } + + /* Call user's adjoint jtimesBS routine */ + return(idalsB_mem->jtimesBS(tt, IDAADJ_mem->ia_yyTmp, + IDAADJ_mem->ia_ypTmp, + IDAADJ_mem->ia_yySTmp, + IDAADJ_mem->ia_ypSTmp, + yyB, ypB, rrB, vB, JvB, c_jB, + IDAB_mem->ida_user_data, tmp1B, tmp2B)); +} + + +/* idaLsFreeB frees memory associated with the IDASLS wrapper */ +int idaLsFreeB(IDABMem IDAB_mem) +{ + IDALsMemB idalsB_mem; + + /* Return immediately if IDAB_mem or IDAB_mem->ida_lmem are NULL */ + if (IDAB_mem == NULL) return(IDALS_SUCCESS); + if (IDAB_mem->ida_lmem == NULL) return(IDALS_SUCCESS); + idalsB_mem = (IDALsMemB) IDAB_mem->ida_lmem; + + /* free IDALsMemB interface structure */ + free(idalsB_mem); + + return(IDALS_SUCCESS); +} + + +/* idaLs_AccessLMemB unpacks the IDA_mem, IDAADJ_mem, IDAB_mem and + idalsB_mem structures from the void* ida_mem pointer. + If any are missing it returns IDALS_MEM_NULL, IDALS_NO_ADJ, + IDAS_ILL_INPUT, or IDALS_LMEMB_NULL. */ +int idaLs_AccessLMemB(void *ida_mem, int which, const char *fname, + IDAMem *IDA_mem, IDAadjMem *IDAADJ_mem, + IDABMem *IDAB_mem, IDALsMemB *idalsB_mem) +{ + + /* access IDAMem structure */ + if (ida_mem==NULL) { + IDAProcessError(NULL, IDALS_MEM_NULL, "IDASLS", + fname, MSG_LS_IDAMEM_NULL); + return(IDALS_MEM_NULL); + } + *IDA_mem = (IDAMem) ida_mem; + + /* access IDAadjMem structure */ + if ((*IDA_mem)->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(*IDA_mem, IDALS_NO_ADJ, "IDASLS", + fname, MSG_LS_NO_ADJ); + return(IDALS_NO_ADJ); + } + *IDAADJ_mem = (*IDA_mem)->ida_adj_mem; + + /* Check the value of which */ + if ( which >= (*IDAADJ_mem)->ia_nbckpbs ) { + IDAProcessError(*IDA_mem, IDALS_ILL_INPUT, "IDASLS", + fname, MSG_LS_BAD_WHICH); + return(IDALS_ILL_INPUT); + } + + /* Find the IDABMem entry in the linked list corresponding to which */ + *IDAB_mem = (*IDAADJ_mem)->IDAB_mem; + while ((*IDAB_mem) != NULL) { + if ( which == (*IDAB_mem)->ida_index ) break; + *IDAB_mem = (*IDAB_mem)->ida_next; + } + + /* access IDALsMemB structure */ + if ((*IDAB_mem)->ida_lmem == NULL) { + IDAProcessError(*IDA_mem, IDALS_LMEMB_NULL, "IDASLS", + fname, MSG_LS_LMEMB_NULL); + return(IDALS_LMEMB_NULL); + } + *idalsB_mem = (IDALsMemB) ((*IDAB_mem)->ida_lmem); + + return(IDALS_SUCCESS); +} + + +/* idaLs_AccessLMemBCur unpacks the ida_mem, ca_mem, idaB_mem and + idalsB_mem structures from the void* idaode_mem pointer. + If any are missing it returns IDALS_MEM_NULL, IDALS_NO_ADJ, + or IDALS_LMEMB_NULL. */ +int idaLs_AccessLMemBCur(void *ida_mem, const char *fname, + IDAMem *IDA_mem, IDAadjMem *IDAADJ_mem, + IDABMem *IDAB_mem, IDALsMemB *idalsB_mem) +{ + + /* access IDAMem structure */ + if (ida_mem==NULL) { + IDAProcessError(NULL, IDALS_MEM_NULL, "IDASLS", + fname, MSG_LS_IDAMEM_NULL); + return(IDALS_MEM_NULL); + } + *IDA_mem = (IDAMem) ida_mem; + + /* access IDAadjMem structure */ + if ((*IDA_mem)->ida_adjMallocDone == SUNFALSE) { + IDAProcessError(*IDA_mem, IDALS_NO_ADJ, "IDASLS", + fname, MSG_LS_NO_ADJ); + return(IDALS_NO_ADJ); + } + *IDAADJ_mem = (*IDA_mem)->ida_adj_mem; + + /* get current backward problem */ + if ((*IDAADJ_mem)->ia_bckpbCrt == NULL) { + IDAProcessError(*IDA_mem, IDALS_LMEMB_NULL, "IDASLS", + fname, MSG_LS_LMEMB_NULL); + return(IDALS_LMEMB_NULL); + } + *IDAB_mem = (*IDAADJ_mem)->ia_bckpbCrt; + + /* access IDALsMemB structure */ + if ((*IDAB_mem)->ida_lmem == NULL) { + IDAProcessError(*IDA_mem, IDALS_LMEMB_NULL, "IDASLS", + fname, MSG_LS_LMEMB_NULL); + return(IDALS_LMEMB_NULL); + } + *idalsB_mem = (IDALsMemB) ((*IDAB_mem)->ida_lmem); + + return(IDALS_SUCCESS); +} + + +/*--------------------------------------------------------------- + EOF + ---------------------------------------------------------------*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_ls_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_ls_impl.h new file mode 100644 index 0000000..3cb3dc9 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_ls_impl.h @@ -0,0 +1,238 @@ +/*----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 + *----------------------------------------------------------------- + * Implementation header file for IDAS's linear solver interface. + *-----------------------------------------------------------------*/ + +#ifndef _IDASLS_IMPL_H +#define _IDASLS_IMPL_H + +#include <idas/idas_ls.h> +#include "idas_impl.h" + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*----------------------------------------------------------------- + Types : struct IDALsMemRec, struct *IDALsMem + + The type IDALsMem is a pointer to a IDALsMemRec, which is a + structure containing fields that must be accessible by LS module + routines. + -----------------------------------------------------------------*/ +typedef struct IDALsMemRec { + + /* Jacobian construction & storage */ + booleantype jacDQ; /* SUNTRUE if using internal DQ Jacobian approx. */ + IDALsJacFn jac; /* Jacobian routine to be called */ + void *J_data; /* J_data is passed to jac */ + + /* Linear solver, matrix and vector objects/pointers */ + SUNLinearSolver LS; /* generic linear solver object */ + SUNMatrix J; /* J = dF/dy + cj*dF/dy' */ + N_Vector ytemp; /* temp vector used by IDAAtimesDQ */ + N_Vector yptemp; /* temp vector used by IDAAtimesDQ */ + N_Vector x; /* temp vector used by the solve function */ + N_Vector ycur; /* current y vector in Newton iteration */ + N_Vector ypcur; /* current yp vector in Newton iteration */ + N_Vector rcur; /* rcur = F(tn, ycur, ypcur) */ + + /* Iterative solver tolerance */ + realtype sqrtN; /* sqrt(N) */ + realtype eplifac; /* eplifac = linear convergence factor */ + + /* Statistics and associated parameters */ + realtype dqincfac; /* dqincfac = optional increment factor in Jv */ + long int nje; /* nje = no. of calls to jac */ + long int npe; /* npe = total number of precond calls */ + long int nli; /* nli = total number of linear iterations */ + long int nps; /* nps = total number of psolve calls */ + long int ncfl; /* ncfl = total number of convergence failures */ + long int nreDQ; /* nreDQ = total number of calls to res */ + long int njtsetup; /* njtsetup = total number of calls to jtsetup */ + long int njtimes; /* njtimes = total number of calls to jtimes */ + long int nst0; /* nst0 = saved nst (for performance monitor) */ + long int nni0; /* nni0 = saved nni (for performance monitor) */ + long int ncfn0; /* ncfn0 = saved ncfn (for performance monitor) */ + 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 */ + + /* Preconditioner computation + (a) user-provided: + - pdata == user_data + - pfree == NULL (the user dealocates memory) + (b) internal preconditioner module + - pdata == ida_mem + - pfree == set by the prec. module and called in idaLsFree */ + IDALsPrecSetupFn pset; + IDALsPrecSolveFn psolve; + int (*pfree)(IDAMem IDA_mem); + void *pdata; + + /* Jacobian times vector compuation + (a) jtimes function provided by the user: + - jt_data == user_data + - jtimesDQ == SUNFALSE + (b) internal jtimes + - jt_data == ida_mem + - jtimesDQ == SUNTRUE */ + booleantype jtimesDQ; + IDALsJacTimesSetupFn jtsetup; + IDALsJacTimesVecFn jtimes; + void *jt_data; + +} *IDALsMem; + + +/*----------------------------------------------------------------- + Prototypes of internal functions + -----------------------------------------------------------------*/ + +/* Interface routines called by system SUNLinearSolver */ +int idaLsATimes(void *ida_mem, N_Vector v, N_Vector z); +int idaLsPSetup(void *ida_mem); +int idaLsPSolve(void *ida_mem, N_Vector r, N_Vector z, + realtype tol, int lr); + +/* Difference quotient approximation for Jac times vector */ +int idaLsDQJtimes(realtype tt, N_Vector yy, N_Vector yp, + N_Vector rr, N_Vector v, N_Vector Jv, + realtype c_j, void *data, + N_Vector work1, N_Vector work2); + +/* Difference-quotient Jacobian approximation routines */ +int idaLsDQJac(realtype tt, realtype c_j, N_Vector yy, N_Vector yp, + N_Vector rr, SUNMatrix Jac, void *data, + N_Vector tmp1, N_Vector tmp2, N_Vector tmp3); +int idaLsDenseDQJac(realtype tt, realtype c_j, N_Vector yy, + N_Vector yp, N_Vector rr, SUNMatrix Jac, + IDAMem IDA_mem, N_Vector tmp1); +int idaLsBandDQJac(realtype tt, realtype c_j, N_Vector yy, + N_Vector yp, N_Vector rr, SUNMatrix Jac, + IDAMem IDA_mem, N_Vector tmp1, + N_Vector tmp2, N_Vector tmp3); + +/* Generic linit/lsetup/lsolve/lperf/lfree interface routines for IDA to call */ +int idaLsInitialize(IDAMem IDA_mem); +int idaLsSetup(IDAMem IDA_mem, N_Vector y, N_Vector yp, N_Vector r, + N_Vector vt1, N_Vector vt2, N_Vector vt3); +int idaLsSolve(IDAMem IDA_mem, N_Vector b, N_Vector weight, + N_Vector ycur, N_Vector ypcur, N_Vector rescur); +int idaLsPerf(IDAMem IDA_mem, int perftask); +int idaLsFree(IDAMem IDA_mem); + + +/* Auxilliary functions */ +int idaLsInitializeCounters(IDALsMem idals_mem); +int idaLs_AccessLMem(void* ida_mem, const char* fname, + IDAMem* IDA_mem, IDALsMem* idals_mem); + + +/*--------------------------------------------------------------- + Error and Warning Messages + ---------------------------------------------------------------*/ + +#if defined(SUNDIALS_EXTENDED_PRECISION) +#define MSG_LS_TIME "at t = %Lg, " +#define MSG_LS_FRMT "%Le." +#elif defined(SUNDIALS_DOUBLE_PRECISION) +#define MSG_LS_TIME "at t = %lg, " +#define MSG_LS_FRMT "%le." +#else +#define MSG_LS_TIME "at t = %g, " +#define MSG_LS_FRMT "%e." +#endif + +/* Error Messages */ +#define MSG_LS_IDAMEM_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_GSTYPE "gstype has an illegal value." +#define MSG_LS_NEG_MAXRS "maxrs < 0 illegal." +#define MSG_LS_NEG_EPLIFAC "eplifac < 0.0 illegal." +#define MSG_LS_NEG_DQINCFAC "dqincfac < 0.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." +#define MSG_LS_JTSETUP_FAILED "The Jacobian x vector setup routine failed in an unrecoverable manner." +#define MSG_LS_JTIMES_FAILED "The Jacobian x vector routine failed in an unrecoverable manner." +#define MSG_LS_JACFUNC_FAILED "The Jacobian routine failed in an unrecoverable manner." +#define MSG_LS_MATZERO_FAILED "The SUNMatZero routine failed in an unrecoverable manner." + +/* Warning Messages */ +#define MSG_LS_WARN "Warning: " MSG_LS_TIME "poor iterative algorithm performance. " +#define MSG_LS_CFN_WARN MSG_LS_WARN "Nonlinear convergence failure rate is " MSG_LS_FRMT +#define MSG_LS_CFL_WARN MSG_LS_WARN "Linear convergence failure rate is " MSG_LS_FRMT + + +/*----------------------------------------------------------------- + PART II - backward problems + -----------------------------------------------------------------*/ + +/*----------------------------------------------------------------- + Types : IDALsMemRecB, IDALsMemB + + IDASetLinearSolverB attaches such a structure to the lmemB + field of IDAadjMem + -----------------------------------------------------------------*/ +typedef struct IDALsMemRecB { + + IDALsJacFnB jacB; + IDALsJacFnBS jacBS; + IDALsJacTimesSetupFnB jtsetupB; + IDALsJacTimesSetupFnBS jtsetupBS; + IDALsJacTimesVecFnB jtimesB; + IDALsJacTimesVecFnBS jtimesBS; + IDALsPrecSetupFnB psetB; + IDALsPrecSetupFnBS psetBS; + IDALsPrecSolveFnB psolveB; + IDALsPrecSolveFnBS psolveBS; + void *P_dataB; + +} *IDALsMemB; + + +/*----------------------------------------------------------------- + Prototypes of internal functions + -----------------------------------------------------------------*/ + +int idaLsFreeB(IDABMem IDAB_mem); +int idaLs_AccessLMemB(void *ida_mem, int which, const char *fname, + IDAMem *IDA_mem, IDAadjMem *IDAADJ_mem, + IDABMem *IDAB_mem, IDALsMemB *idalsB_mem); +int idaLs_AccessLMemBCur(void *ida_mem, const char *fname, + IDAMem *IDA_mem, IDAadjMem *IDAADJ_mem, + IDABMem *IDAB_mem, IDALsMemB *idalsB_mem); + + +/*----------------------------------------------------------------- + Error Messages + -----------------------------------------------------------------*/ +#define MSG_LS_CAMEM_NULL "idaadj_mem = NULL illegal." +#define MSG_LS_LMEMB_NULL "Linear solver memory is NULL for the backward integration." +#define MSG_LS_BAD_T "Bad t for interpolation." +#define MSG_LS_BAD_WHICH "Illegal value for which." +#define MSG_LS_NO_ADJ "Illegal attempt to call before calling IDAAdjInit." + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_nls.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_nls.c new file mode 100644 index 0000000..831c859 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_nls.c @@ -0,0 +1,291 @@ +/* ----------------------------------------------------------------------------- + * 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 the implementation file for the IDA nonlinear solver interface. + * ---------------------------------------------------------------------------*/ + +#include "idas_impl.h" +#include "sundials/sundials_math.h" + +/* constant macros */ +#define PT0001 RCONST(0.0001) /* real 0.0001 */ +#define ONE RCONST(1.0) /* real 1.0 */ +#define TWENTY RCONST(20.0) /* real 20.0 */ + +/* nonlinear solver parameters */ +#define MAXIT 4 /* default max number of nonlinear iterations */ +#define RATEMAX RCONST(0.9) /* max convergence rate used in divergence check */ + +/* 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 idaNlsConvTest(SUNNonlinearSolver NLS, N_Vector ycor, N_Vector del, + realtype tol, N_Vector ewt, void* ida_mem); + +/* ----------------------------------------------------------------------------- + * Exported functions + * ---------------------------------------------------------------------------*/ + +int IDASetNonlinearSolver(void *ida_mem, SUNNonlinearSolver NLS) +{ + IDAMem IDA_mem; + int retval; + + /* return immediately if IDA memory is NULL */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", + "IDASetNonlinearSolver", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* return immediately if NLS memory is NULL */ + if (NLS == NULL) { + IDAProcessError(NULL, IDA_ILL_INPUT, "IDAS", + "IDASetNonlinearSolver", + "NLS must be non-NULL"); + return(IDA_ILL_INPUT); + } + + /* 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", + "IDASetNonlinearSolver", + "NLS does not support required operations"); + return(IDA_ILL_INPUT); + } + + /* check for allowed nonlinear solver types */ + if (SUNNonlinSolGetType(NLS) != SUNNONLINEARSOLVER_ROOTFIND) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", + "IDASetNonlinearSolver", + "NLS type must be SUNNONLINEARSOLVER_ROOTFIND"); + return(IDA_ILL_INPUT); + } + + /* free any existing nonlinear solver */ + if ((IDA_mem->NLS != NULL) && (IDA_mem->ownNLS)) + retval = SUNNonlinSolFree(IDA_mem->NLS); + + /* set SUNNonlinearSolver pointer */ + IDA_mem->NLS = NLS; + + /* Set NLS ownership flag. If this function was called to attach the default + NLS, IDA will set the flag to SUNTRUE after this function returns. */ + IDA_mem->ownNLS = SUNFALSE; + + /* set the nonlinear residual function */ + retval = SUNNonlinSolSetSysFn(IDA_mem->NLS, idaNlsResidual); + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", + "IDASetNonlinearSolver", + "Setting nonlinear system function failed"); + return(IDA_ILL_INPUT); + } + + /* set convergence test function */ + retval = SUNNonlinSolSetConvTestFn(IDA_mem->NLS, idaNlsConvTest); + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", + "IDASetNonlinearSolver", + "Setting convergence test function failed"); + return(IDA_ILL_INPUT); + } + + /* set max allowed nonlinear iterations */ + retval = SUNNonlinSolSetMaxIters(IDA_mem->NLS, MAXIT); + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", + "IDASetNonlinearSolver", + "Setting maximum number of nonlinear iterations failed"); + return(IDA_ILL_INPUT); + } + + return(IDA_SUCCESS); +} + + +/* ----------------------------------------------------------------------------- + * Private functions + * ---------------------------------------------------------------------------*/ + +int idaNlsInit(IDAMem IDA_mem) +{ + int retval; + + /* set the linear solver setup wrapper function */ + if (IDA_mem->ida_lsetup) + retval = SUNNonlinSolSetLSetupFn(IDA_mem->NLS, idaNlsLSetup); + else + retval = SUNNonlinSolSetLSetupFn(IDA_mem->NLS, NULL); + + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "idaNlsInit", + "Setting the linear solver setup function failed"); + return(IDA_NLS_INIT_FAIL); + } + + /* set the linear solver solve wrapper function */ + if (IDA_mem->ida_lsolve) + retval = SUNNonlinSolSetLSolveFn(IDA_mem->NLS, idaNlsLSolve); + else + retval = SUNNonlinSolSetLSolveFn(IDA_mem->NLS, NULL); + + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "idaNlsInit", + "Setting linear solver solve function failed"); + return(IDA_NLS_INIT_FAIL); + } + + /* initialize nonlinear solver */ + retval = SUNNonlinSolInitialize(IDA_mem->NLS); + + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "idaNlsInit", + MSG_NLS_INIT_FAIL); + return(IDA_NLS_INIT_FAIL); + } + + return(IDA_SUCCESS); +} + + +static int idaNlsLSetup(N_Vector ycor, N_Vector res, booleantype jbad, + booleantype* jcur, void* ida_mem) +{ + IDAMem IDA_mem; + int retval; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "idaNlsLSetup", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + 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); + + /* update Jacobian status */ + *jcur = SUNTRUE; + + /* update convergence test constants */ + IDA_mem->ida_cjold = IDA_mem->ida_cj; + IDA_mem->ida_cjratio = ONE; + IDA_mem->ida_ss = TWENTY; + IDA_mem->ida_ssS = TWENTY; + + if (retval < 0) return(IDA_LSETUP_FAIL); + if (retval > 0) return(IDA_LSETUP_RECVR); + + return(IDA_SUCCESS); +} + + +static int idaNlsLSolve(N_Vector ycor, N_Vector delta, void* ida_mem) +{ + IDAMem IDA_mem; + int retval; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "idaNlsLSolve", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + 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, + IDA_mem->ida_savres); + + if (retval < 0) return(IDA_LSOLVE_FAIL); + if (retval > 0) return(IDA_LSOLVE_RECVR); + + return(IDA_SUCCESS); +} + + +static int idaNlsResidual(N_Vector ycor, N_Vector res, void* ida_mem) +{ + IDAMem IDA_mem; + int retval; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "idaNlsResidual", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* update yy and yp based on the current correction */ + N_VLinearSum(ONE, IDA_mem->ida_yypredict, ONE, ycor, IDA_mem->ida_yy); + N_VLinearSum(ONE, IDA_mem->ida_yppredict, IDA_mem->ida_cj, ycor, IDA_mem->ida_yp); + + /* evaluate residual */ + retval = IDA_mem->ida_res(IDA_mem->ida_tn, IDA_mem->ida_yy, IDA_mem->ida_yp, + res, IDA_mem->ida_user_data); + + /* increment the number of residual evaluations */ + IDA_mem->ida_nre++; + + /* save a copy of the residual vector in savres */ + N_VScale(ONE, res, IDA_mem->ida_savres); + + if (retval < 0) return(IDA_RES_FAIL); + if (retval > 0) return(IDA_RES_RECVR); + + return(IDA_SUCCESS); +} + + +static int idaNlsConvTest(SUNNonlinearSolver NLS, N_Vector ycor, N_Vector del, + realtype tol, N_Vector ewt, void* ida_mem) +{ + IDAMem IDA_mem; + int m, retval; + realtype delnrm; + realtype rate; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "idaNlsConvTest", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* compute the norm of the correction */ + delnrm = N_VWrmsNorm(del, ewt); + + /* get the current nonlinear solver iteration count */ + retval = SUNNonlinSolGetCurIter(NLS, &m); + if (retval != IDA_SUCCESS) return(IDA_MEM_NULL); + + /* test for convergence, first directly, then with rate estimate. */ + if (m == 0){ + IDA_mem->ida_oldnrm = delnrm; + if (delnrm <= PT0001 * IDA_mem->ida_toldel) return(SUN_NLS_SUCCESS); + } else { + rate = SUNRpowerR( delnrm/IDA_mem->ida_oldnrm, ONE/m ); + if (rate > RATEMAX) return(SUN_NLS_CONV_RECVR); + IDA_mem->ida_ss = rate/(ONE - rate); + } + + if (IDA_mem->ida_ss*delnrm <= tol) return(SUN_NLS_SUCCESS); + + /* not yet converged */ + return(SUN_NLS_CONTINUE); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_nls_sim.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_nls_sim.c new file mode 100644 index 0000000..ce6fc5a --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_nls_sim.c @@ -0,0 +1,408 @@ +/* ----------------------------------------------------------------------------- + * 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 the implementation file for the IDA nonlinear solver interface. + * ---------------------------------------------------------------------------*/ + +#include "idas_impl.h" +#include "sundials/sundials_math.h" +#include "sundials/sundials_nvector_senswrapper.h" + +/* constant macros */ +#define PT0001 RCONST(0.0001) /* real 0.0001 */ +#define ONE RCONST(1.0) /* real 1.0 */ +#define TWENTY RCONST(20.0) /* real 20.0 */ + +/* nonlinear solver parameters */ +#define MAXIT 4 /* default max number of nonlinear iterations */ +#define RATEMAX RCONST(0.9) /* max convergence rate used in divergence check */ + +/* 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 idaNlsConvTestSensSim(SUNNonlinearSolver NLS, N_Vector ycor, N_Vector del, + realtype tol, N_Vector ewt, void* ida_mem); + +/* ----------------------------------------------------------------------------- + * Exported functions + * ---------------------------------------------------------------------------*/ + +int IDASetNonlinearSolverSensSim(void *ida_mem, SUNNonlinearSolver NLS) +{ + IDAMem IDA_mem; + int retval, is; + + /* return immediately if IDA memory is NULL */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", + "IDASetNonlinearSolverSensSim", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* return immediately if NLS memory is NULL */ + if (NLS == NULL) { + IDAProcessError(NULL, IDA_ILL_INPUT, "IDAS", + "IDASetNonlinearSolverSensSim", + "NLS must be non-NULL"); + return(IDA_ILL_INPUT); + } + + /* 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", + "NLS does not support required operations"); + return(IDA_ILL_INPUT); + } + + /* check for allowed nonlinear solver types */ + if (SUNNonlinSolGetType(NLS) != SUNNONLINEARSOLVER_ROOTFIND) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", + "IDASetNonlinearSolverSensSim", + "NLS type must be SUNNONLINEARSOLVER_ROOTFIND"); + return(IDA_ILL_INPUT); + } + + /* check that sensitivities were initialized */ + if (!(IDA_mem->ida_sensi)) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", + "IDASetNonlinearSolverSensSim", + MSG_NO_SENSI); + return(IDA_ILL_INPUT); + } + + /* check that the simultaneous corrector was selected */ + if (IDA_mem->ida_ism != IDA_SIMULTANEOUS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", + "IDASetNonlinearSolverSensSim", + "Sensitivity solution method is not IDA_SIMULTANEOUS"); + return(IDA_ILL_INPUT); + } + + /* free any existing nonlinear solver */ + if ((IDA_mem->NLSsim != NULL) && (IDA_mem->ownNLSsim)) + retval = SUNNonlinSolFree(IDA_mem->NLSsim); + + /* set SUNNonlinearSolver pointer */ + IDA_mem->NLSsim = NLS; + + /* Set NLS ownership flag. If this function was called to attach the default + NLS, IDA will set the flag to SUNTRUE after this function returns. */ + IDA_mem->ownNLSsim = SUNFALSE; + + /* set the nonlinear residual function */ + retval = SUNNonlinSolSetSysFn(IDA_mem->NLSsim, idaNlsResidualSensSim); + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", + "IDASetNonlinearSolverSensSim", + "Setting nonlinear system function failed"); + return(IDA_ILL_INPUT); + } + + /* set convergence test function */ + retval = SUNNonlinSolSetConvTestFn(IDA_mem->NLSsim, idaNlsConvTestSensSim); + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", + "IDASetNonlinearSolverSensSim", + "Setting convergence test function failed"); + return(IDA_ILL_INPUT); + } + + /* set max allowed nonlinear iterations */ + retval = SUNNonlinSolSetMaxIters(IDA_mem->NLSsim, MAXIT); + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", + "IDASetNonlinearSolverSensSim", + "Setting maximum number of nonlinear iterations failed"); + return(IDA_ILL_INPUT); + } + + /* 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) { + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", + "IDASetNonlinearSolverSensSim", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + IDA_mem->ycorSim = N_VNewEmpty_SensWrapper(IDA_mem->ida_Ns+1); + if (IDA_mem->ycorSim == NULL) { + N_VDestroy(IDA_mem->ycor0Sim); + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", + "IDASetNonlinearSolverSensSim", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + 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->ycorSim); + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", + "IDASetNonlinearSolverSensSim", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + IDA_mem->simMallocDone = SUNTRUE; + } + + /* 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; + + 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]; + } + + return(IDA_SUCCESS); +} + + +/* ----------------------------------------------------------------------------- + * Private functions + * ---------------------------------------------------------------------------*/ + +int idaNlsInitSensSim(IDAMem IDA_mem) +{ + int retval; + + /* set the linear solver setup wrapper function */ + if (IDA_mem->ida_lsetup) + retval = SUNNonlinSolSetLSetupFn(IDA_mem->NLSsim, idaNlsLSetupSensSim); + else + retval = SUNNonlinSolSetLSetupFn(IDA_mem->NLSsim, NULL); + + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "idaNlsInitSnesSim", + "Setting the linear solver setup function failed"); + return(IDA_NLS_INIT_FAIL); + } + + /* set the linear solver solve wrapper function */ + if (IDA_mem->ida_lsolve) + retval = SUNNonlinSolSetLSolveFn(IDA_mem->NLSsim, idaNlsLSolveSensSim); + else + retval = SUNNonlinSolSetLSolveFn(IDA_mem->NLSsim, NULL); + + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "idaNlsInitSnesSim", + "Setting linear solver solve function failed"); + return(IDA_NLS_INIT_FAIL); + } + + /* initialize nonlinear solver */ + retval = SUNNonlinSolInitialize(IDA_mem->NLSsim); + + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "idaNlsInitSnesSim", + MSG_NLS_INIT_FAIL); + return(IDA_NLS_INIT_FAIL); + } + + return(IDA_SUCCESS); +} + + +static int idaNlsLSetupSensSim(N_Vector ycorSim, N_Vector resSim, + 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", + "idaNlsLSetupSensSim", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + 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); + + /* update Jacobian status */ + *jcur = SUNTRUE; + + /* update convergence test constants */ + IDA_mem->ida_cjold = IDA_mem->ida_cj; + IDA_mem->ida_cjratio = ONE; + IDA_mem->ida_ss = TWENTY; + IDA_mem->ida_ssS = TWENTY; + + if (retval < 0) return(IDA_LSETUP_FAIL); + if (retval > 0) return(IDA_LSETUP_RECVR); + + return(IDA_SUCCESS); +} + + +static int idaNlsLSolveSensSim(N_Vector ycorSim, N_Vector deltaSim, void* ida_mem) +{ + IDAMem IDA_mem; + int retval, is; + N_Vector delta; + N_Vector *deltaS; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", + "idaNlsLSolveSensSim", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* extract state update vector from the vector wrapper */ + delta = NV_VEC_SW(deltaSim,0); + + /* solve the state linear system */ + 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); + if (retval > 0) return(IDA_LSOLVE_RECVR); + + /* extract sensitivity deltas from the vector wrapper */ + deltaS = NV_VECS_SW(deltaSim)+1; + + /* solve the sensitivity linear systems */ + for(is=0; is<IDA_mem->ida_Ns; is++) { + retval = IDA_mem->ida_lsolve(IDA_mem, deltaS[is], IDA_mem->ida_ewtS[is], + IDA_mem->ida_yy, IDA_mem->ida_yp, + IDA_mem->ida_savres); + + if (retval < 0) return(IDA_LSOLVE_FAIL); + if (retval > 0) return(IDA_LSOLVE_RECVR); + } + + return(IDA_SUCCESS); +} + + +static int idaNlsResidualSensSim(N_Vector ycorSim, N_Vector resSim, void* ida_mem) +{ + IDAMem IDA_mem; + int retval; + N_Vector ycor, res; + N_Vector *ycorS, *resS; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", + "idaNlsResidualSensSim", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* extract state and residual vectors from the vector wrapper */ + ycor = NV_VEC_SW(ycorSim,0); + res = NV_VEC_SW(resSim,0); + + /* update yy and yp based on the current correction */ + N_VLinearSum(ONE, IDA_mem->ida_yypredict, ONE, ycor, IDA_mem->ida_yy); + N_VLinearSum(ONE, IDA_mem->ida_yppredict, IDA_mem->ida_cj, ycor, IDA_mem->ida_yp); + + /* evaluate residual */ + retval = IDA_mem->ida_res(IDA_mem->ida_tn, IDA_mem->ida_yy, IDA_mem->ida_yp, + res, IDA_mem->ida_user_data); + + /* increment the number of residual evaluations */ + IDA_mem->ida_nre++; + + /* save a copy of the residual vector in savres */ + N_VScale(ONE, res, IDA_mem->ida_savres); + + if (retval < 0) return(IDA_RES_FAIL); + if (retval > 0) return(IDA_RES_RECVR); + + /* extract sensitivity and residual vectors from the vector wrapper */ + ycorS = NV_VECS_SW(ycorSim)+1; + resS = NV_VECS_SW(resSim)+1; + + /* update yS and ypS based on the current correction */ + N_VLinearSumVectorArray(IDA_mem->ida_Ns, + ONE, IDA_mem->ida_yySpredict, + ONE, ycorS, IDA_mem->ida_yyS); + N_VLinearSumVectorArray(IDA_mem->ida_Ns, + ONE, IDA_mem->ida_ypSpredict, + IDA_mem->ida_cj, ycorS, IDA_mem->ida_ypS); + + /* evaluate sens residual */ + retval = IDA_mem->ida_resS(IDA_mem->ida_Ns, IDA_mem->ida_tn, + IDA_mem->ida_yy, IDA_mem->ida_yp, res, + IDA_mem->ida_yyS, IDA_mem->ida_ypS, resS, + IDA_mem->ida_user_dataS, IDA_mem->ida_tmpS1, + IDA_mem->ida_tmpS2, IDA_mem->ida_tmpS3); + + /* increment the number of sens residual evaluations */ + IDA_mem->ida_nrSe++; + + if (retval < 0) return(IDA_SRES_FAIL); + if (retval > 0) return(IDA_SRES_RECVR); + + return(IDA_SUCCESS); +} + + +static int idaNlsConvTestSensSim(SUNNonlinearSolver NLS, N_Vector ycor, N_Vector del, + realtype tol, N_Vector ewt, void* ida_mem) +{ + IDAMem IDA_mem; + int m, retval; + realtype delnrm; + realtype rate; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "idaNlsConvTestSensSim", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* compute the norm of the correction */ + delnrm = N_VWrmsNorm(del, ewt); + + /* get the current nonlinear solver iteration count */ + retval = SUNNonlinSolGetCurIter(NLS, &m); + if (retval != IDA_SUCCESS) return(IDA_MEM_NULL); + + /* test for convergence, first directly, then with rate estimate. */ + if (m == 0){ + IDA_mem->ida_oldnrm = delnrm; + if (delnrm <= PT0001 * IDA_mem->ida_toldel) return(SUN_NLS_SUCCESS); + } else { + rate = SUNRpowerR( delnrm/IDA_mem->ida_oldnrm, ONE/m ); + if (rate > RATEMAX) return(SUN_NLS_CONV_RECVR); + IDA_mem->ida_ss = rate/(ONE - rate); + } + + if (IDA_mem->ida_ss*delnrm <= tol) return(SUN_NLS_SUCCESS); + + /* not yet converged */ + return(SUN_NLS_CONTINUE); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_nls_stg.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_nls_stg.c new file mode 100644 index 0000000..0efd6bf --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_nls_stg.c @@ -0,0 +1,351 @@ +/* ----------------------------------------------------------------------------- + * 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 the implementation file for the IDA nonlinear solver interface. + * ---------------------------------------------------------------------------*/ + +#include "idas_impl.h" +#include "sundials/sundials_math.h" +#include "sundials/sundials_nvector_senswrapper.h" + +/* constant macros */ +#define PT0001 RCONST(0.0001) /* real 0.0001 */ +#define ONE RCONST(1.0) /* real 1.0 */ +#define TWENTY RCONST(20.0) /* real 20.0 */ + +/* nonlinear solver parameters */ +#define MAXIT 4 /* default max number of nonlinear iterations */ +#define RATEMAX RCONST(0.9) /* max convergence rate used in divergence check */ + +/* 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 idaNlsConvTestSensStg(SUNNonlinearSolver NLS, N_Vector ycor, N_Vector del, + realtype tol, N_Vector ewt, void* ida_mem); + +/* ----------------------------------------------------------------------------- + * Exported functions + * ---------------------------------------------------------------------------*/ + +int IDASetNonlinearSolverSensStg(void *ida_mem, SUNNonlinearSolver NLS) +{ + IDAMem IDA_mem; + int retval, is; + + /* return immediately if IDA memory is NULL */ + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", + "IDASetNonlinearSolverSensStg", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* return immediately if NLS memory is NULL */ + if (NLS == NULL) { + IDAProcessError(NULL, IDA_ILL_INPUT, "IDAS", + "IDASetNonlinearSolverSensStg", + "NLS must be non-NULL"); + return(IDA_ILL_INPUT); + } + + /* 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", + "NLS does not support required operations"); + return(IDA_ILL_INPUT); + } + + /* check for allowed nonlinear solver types */ + if (SUNNonlinSolGetType(NLS) != SUNNONLINEARSOLVER_ROOTFIND) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", + "IDASetNonlinearSolverSensStg", + "NLS type must be SUNNONLINEARSOLVER_ROOTFIND"); + return(IDA_ILL_INPUT); + } + + /* check that sensitivities were initialized */ + if (!(IDA_mem->ida_sensi)) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", + "IDASetNonlinearSolverSensStg", + MSG_NO_SENSI); + return(IDA_ILL_INPUT); + } + + /* check that the staggered corrector was selected */ + if (IDA_mem->ida_ism != IDA_STAGGERED) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", + "IDASetNonlinearSolverSensStg", + "Sensitivity solution method is not IDA_STAGGERED"); + return(IDA_ILL_INPUT); + } + + /* free any existing nonlinear solver */ + if ((IDA_mem->NLSstg != NULL) && (IDA_mem->ownNLSstg)) + retval = SUNNonlinSolFree(IDA_mem->NLSstg); + + /* set SUNNonlinearSolver pointer */ + IDA_mem->NLSstg = NLS; + + /* Set NLS ownership flag. If this function was called to attach the default + NLS, IDA will set the flag to SUNTRUE after this function returns. */ + IDA_mem->ownNLSstg = SUNFALSE; + + /* set the nonlinear residual function */ + retval = SUNNonlinSolSetSysFn(IDA_mem->NLSstg, idaNlsResidualSensStg); + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", + "IDASetNonlinearSolverSensStg", + "Setting nonlinear system function failed"); + return(IDA_ILL_INPUT); + } + + /* set convergence test function */ + retval = SUNNonlinSolSetConvTestFn(IDA_mem->NLSstg, idaNlsConvTestSensStg); + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", + "IDASetNonlinearSolverSensStg", + "Setting convergence test function failed"); + return(IDA_ILL_INPUT); + } + + /* set max allowed nonlinear iterations */ + retval = SUNNonlinSolSetMaxIters(IDA_mem->NLSstg, MAXIT); + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", + "IDASetNonlinearSolverSensStg", + "Setting maximum number of nonlinear iterations failed"); + return(IDA_ILL_INPUT); + } + + /* 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) { + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", + "IDASetNonlinearSolverSensStg", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + IDA_mem->ycorStg = N_VNewEmpty_SensWrapper(IDA_mem->ida_Ns); + if (IDA_mem->ycorStg == NULL) { + N_VDestroy(IDA_mem->ycor0Stg); + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", + "IDASetNonlinearSolverSensStg", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + IDA_mem->ewtStg = N_VNewEmpty_SensWrapper(IDA_mem->ida_Ns); + if (IDA_mem->ewtStg == NULL) { + N_VDestroy(IDA_mem->ycor0Stg); + N_VDestroy(IDA_mem->ycorStg); + IDAProcessError(IDA_mem, IDA_MEM_FAIL, "IDAS", + "IDASetNonlinearSolverSensStg", MSG_MEM_FAIL); + return(IDA_MEM_FAIL); + } + + IDA_mem->stgMallocDone = SUNTRUE; + } + + /* 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]; + } + + return(IDA_SUCCESS); +} + + +/* ----------------------------------------------------------------------------- + * Private functions + * ---------------------------------------------------------------------------*/ + +int idaNlsInitSensStg(IDAMem IDA_mem) +{ + int retval; + + /* set the linear solver setup wrapper function */ + if (IDA_mem->ida_lsetup) + retval = SUNNonlinSolSetLSetupFn(IDA_mem->NLSstg, idaNlsLSetupSensStg); + else + retval = SUNNonlinSolSetLSetupFn(IDA_mem->NLSstg, NULL); + + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "idaNlsInitSensStg", + "Setting the linear solver setup function failed"); + return(IDA_NLS_INIT_FAIL); + } + + /* set the linear solver solve wrapper function */ + if (IDA_mem->ida_lsolve) + retval = SUNNonlinSolSetLSolveFn(IDA_mem->NLSstg, idaNlsLSolveSensStg); + else + retval = SUNNonlinSolSetLSolveFn(IDA_mem->NLSstg, NULL); + + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "idaNlsInitSensStg", + "Setting linear solver solve function failed"); + return(IDA_NLS_INIT_FAIL); + } + + /* initialize nonlinear solver */ + retval = SUNNonlinSolInitialize(IDA_mem->NLSstg); + + if (retval != IDA_SUCCESS) { + IDAProcessError(IDA_mem, IDA_ILL_INPUT, "IDAS", "idaNlsInitSensStg", + MSG_NLS_INIT_FAIL); + return(IDA_NLS_INIT_FAIL); + } + + return(IDA_SUCCESS); +} + + +static int idaNlsLSetupSensStg(N_Vector ycorStg, N_Vector resStg, booleantype jbad, + booleantype* jcur, void* ida_mem) +{ + IDAMem IDA_mem; + int retval; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "idaNlsLSetupSensStg", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + IDA_mem->ida_nsetupsS++; + + retval = IDA_mem->ida_lsetup(IDA_mem, IDA_mem->ida_yy, IDA_mem->ida_yp, IDA_mem->ida_delta, + IDA_mem->ida_tmpS1, IDA_mem->ida_tmpS2, IDA_mem->ida_tmpS3); + + /* update Jacobian status */ + *jcur = SUNTRUE; + + /* update convergence test constants */ + IDA_mem->ida_cjold = IDA_mem->ida_cj; + IDA_mem->ida_cjratio = ONE; + IDA_mem->ida_ss = TWENTY; + IDA_mem->ida_ssS = TWENTY; + + if (retval < 0) return(IDA_LSETUP_FAIL); + if (retval > 0) return(IDA_LSETUP_RECVR); + + return(IDA_SUCCESS); +} + + +static int idaNlsLSolveSensStg(N_Vector ycorStg, N_Vector deltaStg, void* ida_mem) +{ + IDAMem IDA_mem; + int retval, is; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "idaNlsLSolveSensStg", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + for(is=0;is<IDA_mem->ida_Ns;is++) { + retval = IDA_mem->ida_lsolve(IDA_mem, NV_VEC_SW(deltaStg,is), + IDA_mem->ida_ewtS[is], IDA_mem->ida_yy, + IDA_mem->ida_yp, IDA_mem->ida_delta); + + if (retval < 0) return(IDA_LSOLVE_FAIL); + if (retval > 0) return(IDA_LSOLVE_RECVR); + } + + return(IDA_SUCCESS); +} + + +static int idaNlsResidualSensStg(N_Vector ycorStg, N_Vector resStg, void* ida_mem) +{ + IDAMem IDA_mem; + int retval; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "idaNlsResidualSensStg", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* update yS and ypS based on the current correction */ + N_VLinearSumVectorArray(IDA_mem->ida_Ns, + ONE, IDA_mem->ida_yySpredict, + ONE, NV_VECS_SW(ycorStg), IDA_mem->ida_yyS); + N_VLinearSumVectorArray(IDA_mem->ida_Ns, + ONE, IDA_mem->ida_ypSpredict, + IDA_mem->ida_cj, NV_VECS_SW(ycorStg), IDA_mem->ida_ypS); + + /* evaluate sens residual */ + retval = IDA_mem->ida_resS(IDA_mem->ida_Ns, IDA_mem->ida_tn, + IDA_mem->ida_yy, IDA_mem->ida_yp, IDA_mem->ida_delta, + IDA_mem->ida_yyS, IDA_mem->ida_ypS, NV_VECS_SW(resStg), + IDA_mem->ida_user_dataS, IDA_mem->ida_tmpS1, + IDA_mem->ida_tmpS2, IDA_mem->ida_tmpS3); + + /* increment the number of sens residual evaluations */ + IDA_mem->ida_nrSe++; + + if (retval < 0) return(IDA_SRES_FAIL); + if (retval > 0) return(IDA_SRES_RECVR); + + return(IDA_SUCCESS); +} + + +static int idaNlsConvTestSensStg(SUNNonlinearSolver NLS, N_Vector ycor, N_Vector del, + realtype tol, N_Vector ewt, void* ida_mem) +{ + IDAMem IDA_mem; + int m, retval; + realtype delnrm; + realtype rate; + + if (ida_mem == NULL) { + IDAProcessError(NULL, IDA_MEM_NULL, "IDAS", "idaNlsConvTestSensStg", MSG_NO_MEM); + return(IDA_MEM_NULL); + } + IDA_mem = (IDAMem) ida_mem; + + /* compute the norm of the correction */ + delnrm = N_VWrmsNorm(del, ewt); + + /* get the current nonlinear solver iteration count */ + retval = SUNNonlinSolGetCurIter(NLS, &m); + if (retval != IDA_SUCCESS) return(IDA_MEM_NULL); + + /* test for convergence, first directly, then with rate estimate. */ + if (m == 0){ + IDA_mem->ida_oldnrm = delnrm; + if (delnrm <= IDA_mem->ida_toldel) return(SUN_NLS_SUCCESS); + } else { + rate = SUNRpowerR( delnrm/IDA_mem->ida_oldnrm, ONE/m ); + if (rate > RATEMAX) return(SUN_NLS_CONV_RECVR); + IDA_mem->ida_ssS = rate/(ONE - rate); + } + + if (IDA_mem->ida_ssS*delnrm <= tol) return(SUN_NLS_SUCCESS); + + /* not yet converged */ + return(SUN_NLS_CONTINUE); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_spils.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_spils.c new file mode 100644 index 0000000..26d20b1 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/idas/idas_spils.c @@ -0,0 +1,114 @@ +/*----------------------------------------------------------------- + * Programmer(s): 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 + *----------------------------------------------------------------- + * Implementation file for the deprecated Scaled and Preconditioned + * Iterative Linear Solver interface in IDAS; these routines now just + * wrap the updated IDA generic linear solver interface in idas_ls.h. + *-----------------------------------------------------------------*/ + +#include <idas/idas_ls.h> +#include <idas/idas_spils.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*================================================================= + Exported Functions (wrappers for equivalent routines in idas_ls.h) + =================================================================*/ + +int IDASpilsSetLinearSolver(void *ida_mem, SUNLinearSolver LS) +{ return(IDASetLinearSolver(ida_mem, LS, NULL)); } + +int IDASpilsSetPreconditioner(void *ida_mem, IDASpilsPrecSetupFn pset, + IDASpilsPrecSolveFn psolve) +{ return(IDASetPreconditioner(ida_mem, pset, psolve)); } + +int IDASpilsSetJacTimes(void *ida_mem, IDASpilsJacTimesSetupFn jtsetup, + IDASpilsJacTimesVecFn jtimes) +{ return(IDASetJacTimes(ida_mem, jtsetup, jtimes)); } + +int IDASpilsSetEpsLin(void *ida_mem, realtype eplifac) +{ return(IDASetEpsLin(ida_mem, eplifac)); } + +int IDASpilsSetIncrementFactor(void *ida_mem, realtype dqincfac) +{ return(IDASetIncrementFactor(ida_mem, dqincfac)); } + +int IDASpilsGetWorkSpace(void *ida_mem, long int *lenrwLS, + long int *leniwLS) +{ return(IDAGetLinWorkSpace(ida_mem, lenrwLS, leniwLS)); } + +int IDASpilsGetNumPrecEvals(void *ida_mem, long int *npevals) +{ return(IDAGetNumPrecEvals(ida_mem, npevals)); } + +int IDASpilsGetNumPrecSolves(void *ida_mem, long int *npsolves) +{ return(IDAGetNumPrecSolves(ida_mem, npsolves)); } + +int IDASpilsGetNumLinIters(void *ida_mem, long int *nliters) +{ return(IDAGetNumLinIters(ida_mem, nliters)); } + +int IDASpilsGetNumConvFails(void *ida_mem, long int *nlcfails) +{ return(IDAGetNumLinConvFails(ida_mem, nlcfails)); } + +int IDASpilsGetNumJTSetupEvals(void *ida_mem, long int *njtsetups) +{ return(IDAGetNumJTSetupEvals(ida_mem, njtsetups)); } + +int IDASpilsGetNumJtimesEvals(void *ida_mem, long int *njvevals) +{ return(IDAGetNumJtimesEvals(ida_mem, njvevals)); } + +int IDASpilsGetNumResEvals(void *ida_mem, long int *nrevalsLS) +{ return(IDAGetNumLinResEvals(ida_mem, nrevalsLS)); } + +int IDASpilsGetLastFlag(void *ida_mem, long int *flag) +{ return(IDAGetLastLinFlag(ida_mem, flag)); } + +char *IDASpilsGetReturnFlagName(long int flag) +{ return(IDAGetLinReturnFlagName(flag)); } + +int IDASpilsSetLinearSolverB(void *ida_mem, int which, + SUNLinearSolver LS) +{ return(IDASetLinearSolverB(ida_mem, which, LS, NULL)); } + +int IDASpilsSetEpsLinB(void *ida_mem, int which, realtype eplifacB) +{ return(IDASetEpsLinB(ida_mem, which, eplifacB)); } + +int IDASpilsSetIncrementFactorB(void *ida_mem, int which, + realtype dqincfacB) +{ return(IDASetIncrementFactorB(ida_mem, which, dqincfacB)); } + +int IDASpilsSetPreconditionerB(void *ida_mem, int which, + IDASpilsPrecSetupFnB psetB, + IDASpilsPrecSolveFnB psolveB) +{ return(IDASetPreconditionerB(ida_mem, which, psetB, psolveB)); } + +int IDASpilsSetPreconditionerBS(void *ida_mem, int which, + IDASpilsPrecSetupFnBS psetBS, + IDASpilsPrecSolveFnBS psolveBS) +{ return(IDASetPreconditionerBS(ida_mem, which, psetBS, psolveBS)); } + +int IDASpilsSetJacTimesB(void *ida_mem, int which, + IDASpilsJacTimesSetupFnB jtsetupB, + IDASpilsJacTimesVecFnB jtimesB) +{ return(IDASetJacTimesB(ida_mem, which, jtsetupB, jtimesB)); } + +int IDASpilsSetJacTimesBS(void *ida_mem, int which, + IDASpilsJacTimesSetupFnBS jtsetupBS, + IDASpilsJacTimesVecFnBS jtimesBS) +{ return(IDASetJacTimesBS(ida_mem, which, jtsetupBS, jtimesBS)); } + + + +#ifdef __cplusplus +} +#endif + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinband.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinband.c new file mode 100644 index 0000000..b68f90e --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinband.c @@ -0,0 +1,117 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Radu Serban @ LLNL + * 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 + * ----------------------------------------------------------------- + * Fortran/C interface routines for KINSOL/KINLS, for the case + * of a user-supplied Jacobian approximation routine. + * -----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "fkinsol.h" /* standard interfaces and global vars.*/ +#include "kinsol_impl.h" /* definition of KINMem type */ + +#include <kinsol/kinsol_ls.h> +#include <sunmatrix/sunmatrix_band.h> + +/* + * ---------------------------------------------------------------- + * prototypes of the user-supplied fortran routines + * ---------------------------------------------------------------- + */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +extern void FK_BJAC(long int* N, long int* MU, long int* ML, + long int* EBAND, + realtype* UU, realtype* FU, + realtype* BJAC, + realtype* WK1, realtype* WK2, int* IER); + +#ifdef __cplusplus +} +#endif + +/* + * ---------------------------------------------------------------- + * Function : FKIN_BANDSETJAC + * ---------------------------------------------------------------- + */ + +void FKIN_BANDSETJAC(int *flag, int *ier) +{ + if (*flag == 0) { + *ier = KINSetJacFn(KIN_kinmem, NULL); + } + else { + *ier = KINSetJacFn(KIN_kinmem, FKINBandJac); + } + + return; +} + +/* + * ---------------------------------------------------------------- + * Function : FKINBandJac + * ---------------------------------------------------------------- + * C function FKINBandJac interfaces between KINSOL and a Fortran + * subroutine FKBJAC for solution of a linear system with band + * Jacobian approximation. Addresses are passed to FKBJAC for + * the banded Jacobian and vector data. + * Auxiliary data is assumed to be communicated by common blocks. + * ---------------------------------------------------------------- + */ + +int FKINBandJac(N_Vector uu, N_Vector fval, + SUNMatrix J, void *user_data, + N_Vector vtemp1, N_Vector vtemp2) +{ + realtype *uu_data, *fval_data, *jacdata, *v1_data, *v2_data; + long int N, mupper, mlower, smu, eband; + int ier; + + /* Initialize all pointers to NULL */ + uu_data = fval_data = jacdata = v1_data = v2_data = NULL; + + /* NOTE: The user-supplied routine should set ier to an + appropriate value, but we preset the value to zero + (meaning SUCCESS) so the user need only reset the + value if an error occurred */ + ier = 0; + + /* Get pointers to vector data */ + uu_data = N_VGetArrayPointer(uu); + fval_data = N_VGetArrayPointer(fval); + v1_data = N_VGetArrayPointer(vtemp1); + v2_data = N_VGetArrayPointer(vtemp2); + + N = SUNBandMatrix_Columns(J); + mupper = SUNBandMatrix_UpperBandwidth(J); + mlower = SUNBandMatrix_LowerBandwidth(J); + smu = SUNBandMatrix_StoredUpperBandwidth(J); + eband = smu + mlower + 1; + jacdata = SUNBandMatrix_Column(J,0) - mupper; + + /* Call user-supplied routine */ + FK_BJAC(&N, &mupper, &mlower, &eband, + uu_data, fval_data, + jacdata, + v1_data, v2_data, &ier); + + return(ier); +} + + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinbbd.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinbbd.c new file mode 100644 index 0000000..2ed5b46 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinbbd.c @@ -0,0 +1,152 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Allan Taylor, Alan Hindmarsh, Radu Serban, and + * Aaron Collier @ LLNL + * 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 module contains the routines necessary to interface with + * the KINBBDPRE module and user-supplied Fortran routines. Generic + * names are used (e.g. FK_COMMFN). The routines here call the + * generically named routines and provide a standard interface to + * the C code of the KINBBDPRE package. + * ----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "fkinsol.h" /* standard interfaces and global variables */ +#include "fkinbbd.h" /* prototypes of interfaces to KINBBDPRE */ + +#include <kinsol/kinsol_bbdpre.h> /* prototypes of KINBBDPRE functions and macros */ + +/* + * ---------------------------------------------------------------- + * private constants + * ---------------------------------------------------------------- + */ + +#define ZERO RCONST(0.0) + +/* + * ---------------------------------------------------------------- + * prototypes of the user-supplied fortran routines + * ---------------------------------------------------------------- + */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +extern void FK_LOCFN(long int* NLOC, realtype* ULOC, realtype* GLOC, int* IER); +extern void FK_COMMFN(long int* NLOC, realtype* ULOC, int* IER); + +#ifdef __cplusplus +} +#endif + +/* + * ---------------------------------------------------------------- + * Function : FKIN_BBDINIT + * ---------------------------------------------------------------- + */ + +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); + + return; +} + +/* + * ---------------------------------------------------------------- + * Function : FKINgloc + * ---------------------------------------------------------------- + * C function FKINgloc is the interface between the KINBBDPRE + * module and the Fortran subroutine FK_LOCFN. + * ---------------------------------------------------------------- + */ + +int FKINgloc(long int Nloc, N_Vector uu, N_Vector gval, void *user_data) +{ + realtype *uloc, *gloc; + int ier; + + /* Initialize all pointers to NULL */ + uloc = gloc = NULL; + + /* NOTE: The user-supplied routine should set ier to an + appropriate value, but we preset the value to zero + (meaning SUCCESS) so the user need only reset the + value if an error occurred */ + ier = 0; + + /* Get pointers to vector data */ + uloc = N_VGetArrayPointer(uu); + gloc = N_VGetArrayPointer(gval); + + /* Call user-supplied routine */ + FK_LOCFN(&Nloc, uloc, gloc, &ier); + + return(ier); +} + +/* + * ---------------------------------------------------------------- + * Function : FKINgcomm + * ---------------------------------------------------------------- + * C function FKINgcomm is the interface between the KINBBDPRE + * module and the Fortran subroutine FK_COMMFN. + * ---------------------------------------------------------------- + */ + +int FKINgcomm(long int Nloc, N_Vector uu, void *user_data) +{ + realtype *uloc; + int ier; + + /* Initialize all pointers to NULL */ + uloc = NULL; + + /* NOTE: The user-supplied routine should set ier to an + appropriate value, but we preset the value to zero + (meaning SUCCESS) so the user need only reset the + value if an error occurred */ + ier = 0; + + /* Get pointers to vector data */ + uloc = N_VGetArrayPointer(uu); + + /* Call user-supplied routine */ + FK_COMMFN(&Nloc, uloc, &ier); + + return(ier); +} + +/* + * ---------------------------------------------------------------- + * Function : FKIN_BBDOPT + * ---------------------------------------------------------------- + * C function FKIN_BBDOPT is used to access optional outputs + * realated to the BBD preconditioner. + * ---------------------------------------------------------------- + */ + +void FKIN_BBDOPT(long int *lenrpw, long int *lenipw, long int *nge) +{ + KINBBDPrecGetWorkSpace(KIN_kinmem, lenrpw, lenipw); + KINBBDPrecGetNumGfnEvals(KIN_kinmem, nge); + + return; +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinbbd.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinbbd.h new file mode 100644 index 0000000..fb04965 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinbbd.h @@ -0,0 +1,317 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Allan Taylor, Alan Hindmarsh, Radu Serban, 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 Fortran interface include file for the BBD + * preconditioner module KINBBDPRE. + * -----------------------------------------------------------------*/ + +/******************************************************************************* + + FKINBBD Interface Package + + The FKINBBD Interface Package is a package of C functions which support the + use of the KINSOL solver and MPI-parallel N_Vector module, along with the + KINBBDPRE preconditioner module, for the solution of nonlinear systems in a + mixed Fortran/C setting. The combination of KINSOL and KINBBDPRE solves systems + linear system arising from the solution of f(u) = 0 using a Krylov iterative + linear solver via the KINSPILS interface, and with a preconditioner that is + block-diagonal with banded blocks. While KINSOL and KINBBDPRE are written in C, + it is assumed here that the user's calling program and user-supplied + problem-defining routines are written in Fortran. + + The user-callable functions in this package, with the corresponding KINSOL and + KINBBDPRE functions, are as follows: + + FKINBBDINIT : interfaces to KINBBDPrecInit + FKINBBDOPT : accesses optional outputs + FKINBBDFREE : interfaces to KINBBDPrecFree + + In addition to the Fortran system function FKFUN, and optional Jacobian vector + product routine FKJTIMES, the following are the user-supplied functions + required by this package, each with the corresponding interface function which + calls it (and its type within KINBBDPRE): + + FKLOCFN : called by the interface function FKINgloc of type KINBBDLocalFn + FKCOMMFN : called by the interface function FKINgcomm of type KINBBDCommFn + + Note: The names of all user-supplied routines here are fixed, in order to + maximize portability for the resulting mixed-language program. + + Note: The names used within this interface package make use of the preprocessor + to expand them appropriately for different machines/platforms. Later in this + file, each name is expanded appropriately. For example, FKIN_BBDINIT is + replaced with either fkinbbdinit, fkinbbdinit_, or fkinbbdinit__ depending + upon the platform. + + ============================================================================== + + Usage of the FKINSOL/FKINBBD Interface Packages + + The usage of combined interface packages FKINSOL and FKINBBD requires calls + to several interface functions, and a few user-supplied routines which define + the problem to be solved and indirectly define the preconditioner. These + function calls and user routines are summarized separately below. + + Some details have been omitted, and the user is referred to the KINSOL User + Guide for more complete information. + + (1) User-supplied system function routine: FKFUN + + The user must in all cases supply the following Fortran routine: + + SUBROUTINE FKFUN (UU, FVAL, IER) + DIMENSION UU(*), FVAL(*) + + It must set the FVAL array to f(u), the system function, as a function + of the array UU = u. Here UU and FVAL are vectors (distributed in the + parallel case). IER is a return flag (currently not used). + + (2) Optional user-supplied Jacobian-vector product routine: FKJTIMES + + As an option, the user may supply a routine that computes the product + of the system Jacobian and a given vector. The user-supplied function + must have the following form: + + SUBROUTINE FKJTIMES (V, Z, NEWU, UU, IER) + DIMENSION V(*), Z(*), UU(*) + + This must set the array Z to the product J*V, where J is the Jacobian + matrix J = dF/du, and V is a given array. Here UU is an array containing + the current value of the unknown vector u, and NEWU is an input integer + indicating whether UU has changed since FKJTIMES was last called + (1 = yes, 0 = no). If FKJTIMES computes and saves Jacobian data, then + no such computation is necessary when NEWU = 0. Here V, Z, and UU are + arrays of length NLOC - the local length of all distributed vectors. + FKJTIMES should return IER = 0 if successful, or a nonzero IER otherwise. + + (3) User-supplied routines to define preconditoner: FKLOCFN and FKCOMMFN + + The routines in the KINBBDPRE (kinbbdpre.c) module provide a preconditioner + matrix for KINSOL that is block-diagonal with banded blocks. The blocking + corresponds to the distribution of the dependent variable vector u + amongst the processes. Each preconditioner block is generated from the + Jacobian of the local part (associated with the current process) of a given + function g(u) approximating f(u). The blocks are generated by a difference + quotient scheme (independently by each process), utilizing the assumed + banded structure with given half-bandwidths. + + (3.1) Local approximate function: FKLOCFN + + The user must supply a subroutine of the following form: + + SUBROUTINE FKLOCFN (NLOC, ULOC, GLOC, IER) + DIMENSION ULOC(*), GLOC(*) + + The routine is used to compute the function g(u) which approximates the + system function f(u). This function is to be computed locally, i.e. + without inter-process communication. Note: The case where g is + mathematically identical to f is allowed. It takes as input the local + vector length (NLOC) and the local real solution array ULOC. It is to + compute the local part of g(u) and store the result in the realtype + array GLOC. IER is a return flag (currently not used). + + (3.2) Communication function: FKCOMMFN + + The user must also supply a subroutine of the following form: + + SUBROUTINE FKCOMMFN (NLOC, ULOC, IER) + DIMENSION ULOC(*) + + The routine is used to perform all inter-process communication necessary + to evaluate the approximate system function g described above. This + function takes as input the local vector length (NLOC), and the local real + dependent variable array ULOC. It is expected to save communicated data in + work space defined by the user, and made available to FKLOCFN. Each call + to the FKCOMMFN function is preceded by a call to FKFUN with the same + arguments. Thus FKCOMMFN can omit any communications done by FKFUN if + relevant to the evaluation of g. IER is a return flag (currently not + used). + + (4) Initialization: FNVINITP, FKINMALLOC, FKINBBDINIT, and FKINBBDSP* + + (4.1) To initialize the parallel machine environment, the user must make the + following call: + + CALL FNVINITP (5, NLOCAL, NGLOBAL, IER) + + The arguments are: + NLOCAL = local size of vectors associated with process + NGLOBAL = the system size, and the global size of vectors (the sum + of all values of NLOCAL) + IER = return completion flag. Values are 0 = success, and + -1 = failure. + + (4.2) To allocate internal memory for KINSOL, make the following call: + + CALL FKINMALLOC (MSBPRE, FNORMTOL, SCSTEPTOL, CONSTRAINTS, + OPTIN, IOPT, ROPT, IER) + + The arguments are: + MSBPRE = maximum number of preconditioning solve calls without + calling the preconditioning setup routine + Note: 0 indicates default (10). + FNORMTOL = tolerance on the norm of f(u) to accept convergence + SCSTEPTOL = tolerance on minimum scaled step size + CONSTRAINTS = array of constraint values on components of the + solution vector UU + INOPT = integer used as a flag to indicate whether possible + input values in IOPT[] array are to be used for + input: 0 = no and 1 = yes. + IOPT = array for integer optional inputs and outputs (declare + as INTEGER*8 + ROPT = array of real optional inputs and outputs + IER = return completion flag. Values are 0 = success, and + -1 = failure. + + Note: See printed message for details in case of failure. + + (4.3) Initialize and attach one of the SPILS linear solvers. Make one of the + following calls to initialize a solver (see fkinsol.h for more details): + + CALL FSUNPCGINIT(3, PRETYPE, MAXL, IER) + CALL FSUNSPBCGSINIT(3, PRETYPE, MAXL, IER) + CALL FSUNSPFGMRINIT(3, PRETYPE, MAXL, IER) + CALL FSUNSPGMRINIT(3, PRETYPE, MAXL, IER) + CALL FSUNSPTFQMRINIT(3, PRETYPE, MAXL, IER) + + Then to attach the iterative linear solver structure the user must call: + + CALL FKINSPILSINIT(IER) + + (4.4) To allocate memory and initialize data associated with the BBD + preconditioner, make the following call: + + CALL FKINBBDINIT(NLOCAL, MUDQ, MLDQ, MU, ML, IER) + + The arguments are: + NLOCAL = local vector size on this process [long int, input] + MUDQ = upper half-bandwidth to be used in the computation + of the local Jacobian blocks by difference + quotients. These may be smaller than the true + half-bandwidths of the Jacobian of the local block + of g, when smaller values may provide greater + efficiency [long int, input] + MLDQ = lower half-bandwidth to be used in the computation + of the local Jacobian blocks by difference + quotients [long int, input] + MU = upper half-bandwidth of the band matrix that is + retained as an approximation of the local Jacobian + block (may be smaller than MUDQ) [long int, input] + ML = lower half-bandwidth of the band matrix that is + retained as an approximation of the local Jacobian + block (may be smaller than MLDQ) [long int, input] + IER = return completion flag [int, output]: + 0 = success + <0 = an error occurred + + (5) To solve the system, make the following call: + + CALL FKINSOL (UU, GLOBALSTRAT, USCALE, FSCALE, IER) + + The arguments are: + UU = array containing the initial guess when called and the + solution upon termination + GLOBALSTRAT = (INTEGER) a number defining the global strategy choice: + 1 = inexact Newton, 2 = line search. + USCALE = array of scaling factors for the UU vector + FSCALE = array of scaling factors for the FVAL (function) vector + IER = integer error flag as returned by KINSOL. + + Note: See the KINSOL documentation for further information. + + (6) Optional outputs: FKINBBDOPT + + In addition to the optional inputs and outputs available with the FKINSOL + interface package, there are optional outputs specific to the KINBBDPRE + module. These are accessed by making the following call: + + CALL FKINBBDOPT (LENRPW, LENIPW, NGE) + + The arguments returned are: + LENRPW = length of real preconditioner work space, in realtype words + Note: This size is local to the current process. + LENIPW = length of integer preconditioner work space, in integer words + Note: This size is local to the current process. + NGE = number of g(u) evaluations (calls to FKLOCFN) + + (7) Memory freeing: FKINFREE + + To the free the internal memory created by the calls to FNVINITP + and FKINMALLOC, make the following call: + + CALL FKINFREE + +*******************************************************************************/ + +#ifndef _FKINBBD_H +#define _FKINBBD_H + +/* + * ----------------------------------------------------------------- + * header files + * ----------------------------------------------------------------- + */ +#include <sundials/sundials_nvector.h> /* definition of type N_Vector */ +#include <sundials/sundials_types.h> /* definition of type realtype */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* + * ----------------------------------------------------------------- + * generic names are translated through the define statements below + * ----------------------------------------------------------------- + */ + +#if defined(SUNDIALS_F77_FUNC) + +#define FKIN_BBDINIT SUNDIALS_F77_FUNC(fkinbbdinit, FKINBBDINIT) +#define FKIN_BBDOPT SUNDIALS_F77_FUNC(fkinbbdopt, FKINBBDOPT) +#define FK_COMMFN SUNDIALS_F77_FUNC(fkcommfn, FKCOMMFN) +#define FK_LOCFN SUNDIALS_F77_FUNC(fklocfn, FKLOCFN) + +#else + +#define FKIN_BBDINIT fkinbbdinit_ +#define FKIN_BBDOPT fkinbbdopt_ +#define FK_COMMFN fkcommfn_ +#define FK_LOCFN fklocfn_ + +#endif + +/* + * ----------------------------------------------------------------- + * Prototypes: exported functions + * ----------------------------------------------------------------- + */ + +void FKIN_BBDINIT(long int *nlocal, long int *mudq, long int *mldq, + long int *mu, long int *ml, int *ier); +void FKIN_BBDOPT(long int *lenrpw, long int *lenipw, long int *nge); + +/* + * ----------------------------------------------------------------- + * Prototypes: FKINgloc and FKINgcomm + * ----------------------------------------------------------------- + */ + +int FKINgloc(long int Nloc, N_Vector uu, N_Vector gval, void *user_data); +int FKINgcomm(long int Nloc, N_Vector uu, void *user_data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkindense.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkindense.c new file mode 100644 index 0000000..b630313 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkindense.c @@ -0,0 +1,104 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Aaron Collier @ LLNL + * 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 + * ----------------------------------------------------------------- + * Fortran/C interface routines for KINSOL/KINLS, for the case + * of a user-supplied Jacobian approximation routine. + * -----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "fkinsol.h" /* prototypes of standard interfaces and global vars.*/ +#include "kinsol_impl.h" /* definition of KINMem type */ + +#include <kinsol/kinsol_ls.h> +#include <sunmatrix/sunmatrix_dense.h> + +/* + * ---------------------------------------------------------------- + * prototypes of the user-supplied fortran routines + * ---------------------------------------------------------------- + */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +extern void FK_DJAC(long int* N, realtype* uudata , realtype* fdata, + realtype* jacdata, realtype* v1, realtype* v2, + int* ier); + +#ifdef __cplusplus +} +#endif + +/* + * ---------------------------------------------------------------- + * Function : FKIN_DENSESETJAC + * ---------------------------------------------------------------- + */ + +void FKIN_DENSESETJAC(int *flag, int *ier) +{ + if (*flag == 0) { + *ier = KINSetJacFn(KIN_kinmem, NULL); + } + else { + *ier = KINSetJacFn(KIN_kinmem, FKINDenseJac); + } + return; +} + +/* + * ---------------------------------------------------------------- + * Function : FKINDenseJac + * ---------------------------------------------------------------- + * C function FKINDenseJac interfaces between KINSOL and a Fortran + * subroutine FKDJAC for solution of a linear system with dense + * Jacobian approximation. Addresses are passed to FKDJAC, using + * the SUNDenseMatrix_Columns function. Auxiliary data is assumed + * to be communicated by Common. + * ---------------------------------------------------------------- + */ + +int FKINDenseJac(N_Vector uu, N_Vector fval, SUNMatrix J, + void *user_data, N_Vector vtemp1, N_Vector vtemp2) +{ + realtype *uu_data, *fval_data, *jacdata, *v1_data, *v2_data; + long int N; + int ier; + + /* Initialize all pointers to NULL */ + uu_data = fval_data = jacdata = v1_data = v2_data = NULL; + + /* NOTE: The user-supplied routine should set ier to an + appropriate value, but we preset the value to zero + (meaning SUCCESS) so the user need only reset the + value if an error occurred */ + ier = 0; + + /* Get pointers to vector data */ + uu_data = N_VGetArrayPointer(uu); + fval_data = N_VGetArrayPointer(fval); + v1_data = N_VGetArrayPointer(vtemp1); + v2_data = N_VGetArrayPointer(vtemp2); + + N = SUNDenseMatrix_Columns(J); + jacdata = SUNDenseMatrix_Column(J,0); + + /* Call user-supplied routine */ + FK_DJAC(&N, uu_data, fval_data, jacdata, v1_data, v2_data, &ier); + + return(ier); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinjtimes.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinjtimes.c new file mode 100644 index 0000000..7d8d600 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinjtimes.c @@ -0,0 +1,82 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Allan Taylor, Alan Hindmarsh and + * Radu Serban @ LLNL + * 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 + * ----------------------------------------------------------------- + * Routines used to interface between KINSOL and a Fortran + * user-supplied routine FKJTIMES (Jacobian J times vector v). + * -----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "fkinsol.h" +#include "kinsol_impl.h" + +#include <kinsol/kinsol_ls.h> + +/*------------------------------------------------------------------ + prototype of the user-supplied fortran routine + ------------------------------------------------------------------*/ +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +extern void FK_JTIMES(realtype* vdata, realtype* Jvdata, int* new_uu, + realtype* uudata, int* ier); + +#ifdef __cplusplus +} +#endif + +/*------------------------------------------------------------------ + Function : FKIN_LSSETJAC + ------------------------------------------------------------------*/ +void FKIN_LSSETJAC(int *flag, int *ier) +{ + if ((*flag) == 0) KINSetJacTimesVecFn(KIN_kinmem, NULL); + else KINSetJacTimesVecFn(KIN_kinmem, FKINJtimes); + + return; +} + +/*------------------------------------------------------------------ + Function : FKIN_SPILSSETJAC -- DEPRECATED + ------------------------------------------------------------------*/ +void FKIN_SPILSSETJAC(int *flag, int *ier) +{ FKIN_LSSETJAC(flag, ier); } + +/*------------------------------------------------------------------ + Function : FKINJtimes + ------------------------------------------------------------------ + C function FKINJtimes is used to interface between + KINSp* / KINSp*JTimes and FK_JTIMES (user-supplied Fortran + routine). + ------------------------------------------------------------------*/ +int FKINJtimes(N_Vector v, N_Vector Jv, + N_Vector uu, booleantype *new_uu, + void *user_data) +{ + int retcode; + realtype *vdata, *Jvdata, *uudata; + + vdata = Jvdata = uudata = NULL; + + vdata = N_VGetArrayPointer(v); + uudata = N_VGetArrayPointer(uu); + Jvdata = N_VGetArrayPointer(Jv); + + FK_JTIMES(vdata, Jvdata, (int *) new_uu, uudata, &retcode); + + return(retcode); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinnulllinsol.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinnulllinsol.c new file mode 100644 index 0000000..6c6d997 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinnulllinsol.c @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * File that provides a globally-defined, but NULL-valued, + * SUNLinearSolver object, to ensure that F2C_KINSOL_linsol is + * defined for cases when no linear solver object is linked in + * with the main executable. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "fkinsol.h" +#include "kinsol_impl.h" + +/*=============================================================*/ + +/* Define global linear solver variable */ + +SUNLinearSolver F2C_KINSOL_linsol; + +/*=============================================================*/ + +/* C routine that is called when using fixed-point solver */ +void FKINNullLinsol() +{ + F2C_KINSOL_linsol = NULL; +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinnullmatrix.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinnullmatrix.c new file mode 100644 index 0000000..6390ffd --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinnullmatrix.c @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------- + * Programmer(s): 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 + *--------------------------------------------------------------- + * File that provides a globally-defined, but NULL-valued, + * SUNMatrix object, to ensure that F2C_KINSOL_matrix is defined + * for cases when no matrix object is linked in with the main + * executable. + *--------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include "fkinsol.h" +#include "kinsol_impl.h" + +/*=============================================================*/ + +/* Define global matrix variable */ + +SUNMatrix F2C_KINSOL_matrix; + +/*=============================================================*/ + +/* C routine that is called when using matrix-free linear solvers + or fixed-point nonlinear solver */ +void FKINNullMatrix() +{ + F2C_KINSOL_matrix = NULL; +} + +/*=============================================================== + EOF +===============================================================*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinpreco.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinpreco.c new file mode 100644 index 0000000..33352cf --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinpreco.c @@ -0,0 +1,142 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Allan Taylor, Alan 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 file contains the interfaces between KINSOL and the + * user-supplied Fortran routines FK_PSET and FK_PSOL. + * + * The C function FKINPSet is used to interface between KINSOL and + * the Fortran user-supplied preconditioner setup routine. + * + * The C function FKINPSol is used to interface between KINSOL and + * the Fortran user-supplied preconditioner solve routine. + * + * Note: The use of the generic names FK_PSET and FK_PSOL below. + * -----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "fkinsol.h" +#include "kinsol_impl.h" + +#include <kinsol/kinsol_ls.h> + +/*------------------------------------------------------------------ + prototype of the user-supplied fortran routine + ------------------------------------------------------------------*/ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +extern void FK_PSET(realtype* uudata, realtype* uscaledata, + realtype* fvaldata, realtype* fscaledata, + int* ier); + +extern void FK_PSOL(realtype* uudata, realtype* uscaledata, + realtype* fvaldata, realtype* fscaledata, + realtype* vvdata, int* ier); + +#ifdef __cplusplus +} +#endif + +/*------------------------------------------------------------------ + Function : FKIN_LSSETPREC + ------------------------------------------------------------------*/ +void FKIN_LSSETPREC(int *flag, int *ier) +{ + if ((*flag) == 0) { + *ier = KINSetPreconditioner(KIN_kinmem, NULL, NULL); + } else { + *ier = KINSetPreconditioner(KIN_kinmem, FKINPSet, FKINPSol); + } + + return; +} + +/*------------------------------------------------------------------ + Function : FKIN_SPILSSETPREC -- DEPRECATED + ------------------------------------------------------------------*/ +void FKIN_SPILSSETPREC(int *flag, int *ier) +{ FKIN_LSSETPREC(flag,ier); } + +/*------------------------------------------------------------------ + Function : FKINPSet + ------------------------------------------------------------------ + C function FKINPSet is used to interface between FK_PSET and + the user-supplied Fortran preconditioner setup routine. + ------------------------------------------------------------------*/ +int FKINPSet(N_Vector uu, N_Vector uscale, + N_Vector fval, N_Vector fscale, + void *user_data) +{ + realtype *udata, *uscaledata, *fdata, *fscaledata; + int ier; + + /* Initialize all pointers to NULL */ + udata = uscaledata = fdata = fscaledata = NULL; + + /* NOTE: The user-supplied routine should set ier to an + appropriate value, but we preset the value to zero + (meaning SUCCESS) so the user need only reset the + value if an error occurred */ + ier = 0; + + /* Get pointers to vector data */ + udata = N_VGetArrayPointer(uu); + uscaledata = N_VGetArrayPointer(uscale); + fdata = N_VGetArrayPointer(fval); + fscaledata = N_VGetArrayPointer(fscale); + + /* Call user-supplied routine */ + FK_PSET(udata, uscaledata, fdata, fscaledata, &ier); + + return(ier); +} + +/*------------------------------------------------------------------ + Function : FKINPSol + ------------------------------------------------------------------ + C function FKINPSol is used to interface between FK_PSOL and + the user-supplied Fortran preconditioner solve routine. + ------------------------------------------------------------------*/ +int FKINPSol(N_Vector uu, N_Vector uscale, + N_Vector fval, N_Vector fscale, + N_Vector vv, void *user_data) +{ + realtype *udata, *uscaledata, *fdata, *fscaledata, *vvdata; + int ier; + + /* Initialize all pointers to NULL */ + udata = uscaledata = fdata = fscaledata = vvdata = NULL; + + /* NOTE: The user-supplied routine should set ier to an + appropriate value, but we preset the value to zero + (meaning SUCCESS) so the user need only reset the + value if an error occurred */ + ier = 0; + + /* Get pointers to vector data */ + udata = N_VGetArrayPointer(uu); + uscaledata = N_VGetArrayPointer(uscale); + fdata = N_VGetArrayPointer(fval); + fscaledata = N_VGetArrayPointer(fscale); + vvdata = N_VGetArrayPointer(vv); + + /* Call user-supplied routine */ + FK_PSOL(udata, uscaledata, fdata, fscaledata, vvdata, &ier); + + return(ier); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinsol.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinsol.c new file mode 100644 index 0000000..6daf153 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinsol.c @@ -0,0 +1,401 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Allan Taylor, Alan Hindmarsh, Radu Serban, and + * Aaron Collier @ LLNL + * 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 is the implementation file for the Fortran interface to + * the KINSOL package. See fkinsol.h for usage. + * + * Note: Some routines are necessarily stored elsewhere to avoid + * linking problems. See also, therefore, fkinpreco.c, fkinjtimes.c, + * and fkinbbd.c. + * -----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "fkinsol.h" /* prototypes of interfaces and global vars. */ +#include "kinsol_impl.h" /* definition of KINMem type */ + +#include <kinsol/kinsol_ls.h> /* KINLS interface routine prototypes */ + +/*------------------------------------------------------------------ + definitions of global variables shared amongst various routines + ------------------------------------------------------------------*/ + +void *KIN_kinmem; +long int *KIN_iout; +realtype *KIN_rout; + +/*------------------------------------------------------------------ + private constants + ------------------------------------------------------------------*/ + +#define ZERO RCONST(0.0) + +/*------------------------------------------------------------------ + prototype of user-supplied fortran routine + ------------------------------------------------------------------*/ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +extern void FK_FUN(realtype*, realtype*, int*); + +#ifdef __cplusplus +} +#endif + +/*------------------------------------------------------------------ + Function : FKIN_CREATE + ------------------------------------------------------------------*/ + +void FKIN_CREATE(int *ier) +{ + + *ier = 0; + /* check for required vector operations */ + if ((F2C_KINSOL_vec->ops->nvgetarraypointer == NULL) || + (F2C_KINSOL_vec->ops->nvsetarraypointer == NULL)) { + *ier = -1; + fprintf(stderr, "FKINCREATE: A required vector operation is not implemented.\n\n"); + return; + } + + /* Initialize pointers to NULL */ + KIN_kinmem = NULL; + + /* Create KINSOL object */ + KIN_kinmem = KINCreate(); + if (KIN_kinmem == NULL) { + *ier = -1; + return; + } +} + +/*------------------------------------------------------------------ + Function : FKIN_INIT + ------------------------------------------------------------------*/ + +void FKIN_INIT(long int *iout, realtype *rout, int *ier) +{ + + /* Call KINInit */ + *ier = 0; + *ier = KINInit(KIN_kinmem, FKINfunc, F2C_KINSOL_vec); + + /* On failure, exit */ + if (*ier != KIN_SUCCESS) { + *ier = -1; + return; + } + + /* Grab optional output arrays and store them in global variables */ + KIN_iout = iout; + KIN_rout = rout; + + return; +} + +/*------------------------------------------------------------------ + Function : FKIN_MALLOC + ------------------------------------------------------------------*/ + +void FKIN_MALLOC(long int *iout, realtype *rout, int *ier) +{ + + /* check for required vector operations */ + if ((F2C_KINSOL_vec->ops->nvgetarraypointer == NULL) || + (F2C_KINSOL_vec->ops->nvsetarraypointer == NULL)) { + *ier = -1; + fprintf(stderr, "A required vector operation is not implemented.\n\n"); + return; + } + + /* Initialize pointers to NULL */ + KIN_kinmem = NULL; + + /* Create KINSOL object */ + KIN_kinmem = KINCreate(); + if (KIN_kinmem == NULL) { + *ier = -1; + return; + } + + /* Call KINInit */ + *ier = 0; + *ier = KINInit(KIN_kinmem, FKINfunc, F2C_KINSOL_vec); + + /* On failure, exit */ + if (*ier != KIN_SUCCESS) { + *ier = -1; + return; + } + + /* Grab optional output arrays and store them in global variables */ + KIN_iout = iout; + KIN_rout = rout; + + return; +} + +/*------------------------------------------------------------------ + Function : FKIN_SETIIN + ------------------------------------------------------------------*/ + +void FKIN_SETIIN(char key_name[], long int *ival, int *ier) +{ + if (!strncmp(key_name,"PRNT_LEVEL",10)) + *ier = KINSetPrintLevel(KIN_kinmem, (int) *ival); + else if (!strncmp(key_name,"MAX_NITERS",10)) + *ier = KINSetNumMaxIters(KIN_kinmem, (long int) *ival); + else if (!strncmp(key_name,"ETA_FORM",8)) + *ier = KINSetEtaForm(KIN_kinmem, (int) *ival); + else if (!strncmp(key_name,"MAA",3)) + *ier = KINSetMAA(KIN_kinmem, (long int) *ival); + else if (!strncmp(key_name,"MAX_SETUPS",10)) + *ier = KINSetMaxSetupCalls(KIN_kinmem, (long int) *ival); + else if (!strncmp(key_name,"MAX_SP_SETUPS",13)) + *ier = KINSetMaxSubSetupCalls(KIN_kinmem, (long int) *ival); + else if (!strncmp(key_name,"NO_INIT_SETUP",13)) + *ier = KINSetNoInitSetup(KIN_kinmem, (booleantype) *ival); + else if (!strncmp(key_name,"NO_MIN_EPS",10)) + *ier = KINSetNoMinEps(KIN_kinmem, (booleantype) *ival); + else if (!strncmp(key_name,"NO_RES_MON",10)) + *ier = KINSetNoResMon(KIN_kinmem, (booleantype) *ival); + else { + *ier = -99; + fprintf(stderr, "FKINSETIIN: Unrecognized key.\n\n"); + } + +} + +/*------------------------------------------------------------------ + Function : FKIN_SETRIN + ------------------------------------------------------------------*/ + +void FKIN_SETRIN(char key_name[], realtype *rval, int *ier) +{ + + if (!strncmp(key_name,"FNORM_TOL",9)) + *ier = KINSetFuncNormTol(KIN_kinmem, *rval); + else if (!strncmp(key_name,"SSTEP_TOL",9)) + *ier = KINSetScaledStepTol(KIN_kinmem, *rval); + else if (!strncmp(key_name,"MAX_STEP",8)) + *ier = KINSetMaxNewtonStep(KIN_kinmem, *rval); + else if (!strncmp(key_name,"RERR_FUNC",9)) + *ier = KINSetRelErrFunc(KIN_kinmem, *rval); + else if (!strncmp(key_name,"ETA_CONST",9)) + *ier = KINSetEtaConstValue(KIN_kinmem, *rval); + else if (!strncmp(key_name,"ETA_PARAMS",10)) + *ier = KINSetEtaParams(KIN_kinmem, rval[0], rval[1]); + else if (!strncmp(key_name,"RMON_CONST",10)) + *ier = KINSetResMonConstValue(KIN_kinmem, *rval); + else if (!strncmp(key_name,"RMON_PARAMS",11)) + *ier = KINSetResMonParams(KIN_kinmem, rval[0], rval[1]); + else { + *ier = -99; + fprintf(stderr, "FKINSETRIN: Unrecognized key.\n\n"); + } + +} + +/*------------------------------------------------------------------ + Function : FKIN_SETVIN + ------------------------------------------------------------------*/ + +void FKIN_SETVIN(char key_name[], realtype *vval, int *ier) +{ + N_Vector Vec; + + if (!strncmp(key_name,"CONSTR_VEC",10)) { + Vec = NULL; + Vec = N_VCloneEmpty(F2C_KINSOL_vec); + if (Vec == NULL) { + *ier = -1; + return; + } + *ier = 0; + N_VSetArrayPointer(vval, Vec); + KINSetConstraints(KIN_kinmem, Vec); + N_VDestroy(Vec); + } else { + *ier = -99; + fprintf(stderr, "FKINSETVIN: Unrecognized key.\n\n"); + } + +} + +/*------------------------------------------------------------------ + Function : FKIN_LSINIT + ------------------------------------------------------------------*/ + +/* Fortran interface to C routine KINSetLinearSolver */ +void FKIN_LSINIT(int *ier) { + if ( (KIN_kinmem == NULL) || (F2C_KINSOL_linsol == NULL) ) { + *ier = -1; + return; + } + *ier = KINSetLinearSolver(KIN_kinmem, F2C_KINSOL_linsol, + F2C_KINSOL_matrix); + return; +} + +/*------------------------------------------------------------------ + Function : FKIN_DLSINIT -- DEPRECATED + ------------------------------------------------------------------*/ + +void FKIN_DLSINIT(int *ier) +{ FKIN_LSINIT(ier); } + +/*------------------------------------------------------------------ + Function : FKIN_SPILSINIT -- DEPRECATED + ------------------------------------------------------------------*/ + +void FKIN_SPILSINIT(int *ier) +{ FKIN_LSINIT(ier); } + +/*------------------------------------------------------------------ + Function : FKIN_SOL + ------------------------------------------------------------------*/ + +void FKIN_SOL(realtype *uu, int *globalstrategy, + realtype *uscale , realtype *fscale, int *ier) + +{ + N_Vector uuvec, uscalevec, fscalevec; + + *ier = 0; + uuvec = uscalevec = fscalevec = NULL; + + uuvec = F2C_KINSOL_vec; + N_VSetArrayPointer(uu, uuvec); + + uscalevec = NULL; + uscalevec = N_VCloneEmpty(F2C_KINSOL_vec); + if (uscalevec == NULL) { + *ier = -4; /* KIN_MEM_FAIL */ + return; + } + N_VSetArrayPointer(uscale, uscalevec); + + fscalevec = NULL; + fscalevec = N_VCloneEmpty(F2C_KINSOL_vec); + if (fscalevec == NULL) { + N_VDestroy(uscalevec); + *ier = -4; /* KIN_MEM_FAIL */ + return; + } + N_VSetArrayPointer(fscale, fscalevec); + + /* If using the fixed-point solver, initialize F2C_KINSOL_linsol + and F2C_KINSOL_matrix to NULL */ + if (*globalstrategy == KIN_FP) { + FKINNullMatrix(); + FKINNullLinsol(); + } + + /* Call main solver function */ + *ier = KINSol(KIN_kinmem, uuvec, *globalstrategy, uscalevec, fscalevec); + + N_VSetArrayPointer(NULL, uuvec); + + N_VSetArrayPointer(NULL, uscalevec); + N_VDestroy(uscalevec); + + N_VSetArrayPointer(NULL, fscalevec); + N_VDestroy(fscalevec); + + /* load optional outputs into iout[] and rout[] */ + KINGetWorkSpace(KIN_kinmem, &KIN_iout[0], &KIN_iout[1]); /* LENRW & LENIW */ + KINGetNumNonlinSolvIters(KIN_kinmem, &KIN_iout[2]); /* NNI */ + KINGetNumFuncEvals(KIN_kinmem, &KIN_iout[3]); /* NFE */ + KINGetNumBetaCondFails(KIN_kinmem, &KIN_iout[4]); /* NBCF */ + KINGetNumBacktrackOps(KIN_kinmem, &KIN_iout[5]); /* NBCKTRK */ + + KINGetFuncNorm(KIN_kinmem, &KIN_rout[0]); /* FNORM */ + KINGetStepLength(KIN_kinmem, &KIN_rout[1]); /* SSTEP */ + + KINGetLinWorkSpace(KIN_kinmem, &KIN_iout[6], &KIN_iout[7]); /* LRW & LIW */ + KINGetLastLinFlag(KIN_kinmem, &KIN_iout[8]); /* LSTF */ + KINGetNumLinFuncEvals(KIN_kinmem, &KIN_iout[9]); /* NFE */ + KINGetNumJacEvals(KIN_kinmem, &KIN_iout[10]); /* NJE */ + KINGetNumJtimesEvals(KIN_kinmem, &KIN_iout[11]); /* NJT */ + KINGetNumPrecEvals(KIN_kinmem, &KIN_iout[12]); /* NPE */ + KINGetNumPrecSolves(KIN_kinmem, &KIN_iout[13]); /* NPS */ + KINGetNumLinIters(KIN_kinmem, &KIN_iout[14]); /* NLI */ + KINGetNumLinConvFails(KIN_kinmem, &KIN_iout[15]); /* NCFL */ + + return; +} + +/*------------------------------------------------------------------ + Function : FKIN_FREE + ------------------------------------------------------------------*/ + +void FKIN_FREE(void) +{ + KINMem kin_mem; + + kin_mem = (KINMem) KIN_kinmem; + + /* free LS interface */ + if (kin_mem->kin_lfree) + kin_mem->kin_lfree(kin_mem); + kin_mem->kin_lmem = NULL; + + /* free user_data structure */ + if (kin_mem->kin_user_data) + free(kin_mem->kin_user_data); + kin_mem->kin_user_data = NULL; + + /* free main solver memory structure */ + KINFree(&KIN_kinmem); + + /* free interface vectors / matrices / linear solvers */ + N_VSetArrayPointer(NULL, F2C_KINSOL_vec); + N_VDestroy(F2C_KINSOL_vec); + if (F2C_KINSOL_matrix) + SUNMatDestroy(F2C_KINSOL_matrix); + if (F2C_KINSOL_linsol) + SUNLinSolFree(F2C_KINSOL_linsol); + + return; +} + + +/*------------------------------------------------------------------ + Function : FKINfunc + ------------------------------------------------------------------ + The C function FKINfunc acts as an interface between KINSOL and + the Fortran user-supplied subroutine FKFUN. Addresses of the + data uu and fdata are passed to FKFUN, using the routine + N_VGetArrayPointer from the NVECTOR module. The data in the + returned N_Vector fval is set using N_VSetArrayPointer. Auxiliary + data is assumed to be communicated by 'Common'. + ------------------------------------------------------------------*/ + +int FKINfunc(N_Vector uu, N_Vector fval, void *user_data) +{ + realtype *udata, *fdata; + int ier; + + udata = N_VGetArrayPointer(uu); + fdata = N_VGetArrayPointer(fval); + + FK_FUN(udata, fdata, &ier); + + return(ier); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinsol.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinsol.h new file mode 100644 index 0000000..26ca4d4 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinsol.h @@ -0,0 +1,783 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Allan Taylor, Alan Hindmarsh, Radu Serban, and + * Aaron Collier @ LLNL + * Daniel R. Reynolds @ SMU + * 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 is the header file for the FKINSOL Interface Package. + * See below for usage details. + * -----------------------------------------------------------------*/ + +/*************************************************************************** + + FKINSOL Interface Package + + The FKINSOL Interface Package is a package of C functions which support the + use of the KINSOL solver for the solution of nonlinear systems f(u) = 0, + in a mixed Fortran/C setting. While KINSOL 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 KINSOL for the serial and parallel NVECTOR + implementations. + + The user-callable functions, with the corresponding KINSOL functions, + are as follows: + + FNVINITS, FNVINITP, FNVINITOMP, FNVINITPTS + initialize serial, distributed memory parallel, or threaded + vector computations + FKINMALLOC interfaces to KINInit + FKINCREATE interfaces to KINCreate + FKININIT interfaces to KINInit + FKINSETIIN, FKINSETRIN, FKINSETVIN interface to KINSet* functions + FKINSOL interfaces to KINSol and KINGet* functions + FKINFREE interfaces to KINFree + FKINLSINIT interface to KINSetLinearSolver + FKINDENSESETJAC interface to KINSetJacFn + FKINBANDSETJAC interface to KINSetJacFn + FKINSPARSESETJAC interface to KINSetJacFn + FKINLSSETJAC interface to KINSetJacTimes + FKINLSSETPREC interface to KINSetPreconditioner + + The user-supplied functions, each with the corresponding interface function + which calls it (and its type within KINSOL), are as follows: + + FKFUN : called by the interface function FKINfunc of type KINSysFn + FKDJAC : called by the interface function FKINDenseJac of type + KINLsJacFn + FKBJAC : called by the interface function FKINBandJac of type + KINLsJacFn + FKINSPJAC: called by the interface function FKINSparseJac of type + KINLsJacFn + FKJTIMES : called by the interface function FKINJtimes of type + KINLsJacTimesVecFn + FKPSOL : called by the interface function FKINPSol of type + KINLsPrecSolveFn + FKPSET : called by the interface function FKINPSet of type + KINLsPrecSetupFn + + In contrast to the case of direct use of KINSOL, the names of all + user-supplied routines here are fixed, in order to maximize portability for + the resulting mixed-language program. + + Important note on portability: + In this package, the names of the interface functions, and the names of + the Fortran user routines called by them, appear as dummy names + which are mapped to actual values by a series of definitions, in this + and other header files. + + ========================================================================= + + Usage of the FKINSOL Interface Package + + The usage of FKINSOL requires calls to several interface functions, and + to a few user-supplied routines which define the problem to be solved. + These function calls and user routines are summarized separately below. + + Some details are omitted, and the user is referred to the KINSOL manual + for more complete documentation. Information on the arguments of any + given user-callable interface routine, or of a given user-supplied + function called by an interface function, can be found in the + documentation on the corresponding function in the KINSOL package. + + The number labels on the instructions below end with "s" for instructions + that apply to the serial version of KINSOL only, and end with "p" for + those that apply to the parallel version only. + + (1) User-supplied system routine: FKFUN + + The user must in all cases supply the following Fortran routine: + + SUBROUTINE FKFUN (UU, FVAL, IER) + DIMENSION UU(*), FVAL(*) + + It must set the FVAL array to f(u), the system function, as a + function of the array UU = u. Here UU and FVAL are arrays representing + vectors, which are distributed vectors in the parallel case. + IER is a return flag, which should be 0 if FKFUN was successful. + Return IER > 0 if a recoverable error occurred (and KINSOL is to try + to recover). Return IER < 0 if an unrecoverable error occurred. + + (2s) Optional user-supplied dense Jacobian approximation routine: FKDJAC + + As an option when using the DENSE linear solver, the user may supply a + routine that computes a dense approximation of the system Jacobian + J = df/dy. If supplied, it must have the following form: + + SUBROUTINE FKDJAC(N, UU, FU, DJAC, WK1, WK2, IER) + DIMENSION UU(*), FU(*), DJAC(N,*), WK1(*), WK2(*) + + This routine must compute the Jacobian and store it columnwise in DJAC. + FKDJAC should return IER = 0 if successful, or a nonzero IER otherwise. + + (3s) Optional user-supplied band Jacobian approximation routine: FKBJAC + + As an option when using the BAND linear solver, the user may supply a + routine that computes a band approximation of the system Jacobian + J = df/dy. If supplied, it must have the following form: + + SUBROUTINE FKBJAC(N, MU, ML, MDIM, UU, FU, BJAC, WK1, WK2, IER) + DIMENSION UU(*), FU(*), BJAC(MDIM,*), WK1(*), WK2(*) + + This routine must load the MDIM by N array BJAC with the Jacobian matrix. + FKBJAC should return IER = 0 if successful, or a nonzero IER otherwise. + + (4) Optional user-supplied Jacobian-vector product routine: FKJTIMES + + As an option, the user may supply a routine that computes the product + of the system Jacobian and a given vector. This has the following form: + + SUBROUTINE FKJTIMES(V, Z, NEWU, UU, IER) + DIMENSION V(*), Z(*), UU(*) + + This must set the array Z to the product J*V, where J is the Jacobian + matrix J = dF/du, and V is a given array. Here UU is an array containing + the current value of the unknown vector u. NEWU is an input integer + indicating whether UU has changed since FKJTIMES was last called + (1 = yes, 0 = no). If FKJTIMES computes and saves Jacobian data, then + no such computation is necessary when NEWU = 0. Here V, Z, and UU are + arrays of length NEQ, the problem size, or the local length of all + distributed vectors in the parallel case. FKJTIMES should return IER = 0 + if successful, or a nonzero IER otherwise. + + (4.1s) User-supplied sparse Jacobian approximation routine: FKINSPJAC + + Required when using the KINKLU or KINSuperLUMT linear solvers, the + user must supply a routine that computes a compressed-sparse-column + [or compressed-sparse-row] approximation of the system Jacobian + J = dF(y)/dy. If supplied, it must have the following form: + + SUBROUTINE FKINSPJAC(Y, FY, N, NNZ, JDATA, JRVALS, + & JCPTRS, WK1, WK2, IER) + + Typically this routine will use only N, NNZ, JDATA, JRVALS and + JCPTRS. It must load the N by N compressed sparse column [or compressed + 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 + more information). + + The arguments are: + Y -- array containing state variables [realtype, input] + FY -- array containing residual values [realtype, input] + N -- number of matrix rows/columns in Jacobian [int, input] + NNZ -- allocated length of nonzero storage [int, input] + JDATA -- nonzero values in Jacobian + [realtype of length NNZ, output] + JRVALS -- row [or column] indices for each nonzero in Jacobian + [int of length NNZ, output] + JCPTRS -- pointers to each Jacobian column [or row] in preceding arrays + [int of length N+1, output] + WK* -- array containing temporary workspace of same size as Y + [realtype, input] + IER -- return flag [int, output]: + 0 if successful, + >0 if a recoverable error occurred, + <0 if an unrecoverable error ocurred. + + (5) Initialization: FNVINITS/FNVINITP/FNVINITOMP/FNVINITPTS and + FKINCREATE and FKININIT + + (5.1s) To initialize the serial machine environment, the user must make + the following call: + + CALL FNVINITS (3, NEQ, IER) + + The arguments are: + NEQ = size of vectors + IER = return completion flag. Values are 0 = success, -1 = failure. + + (5.1p) To initialize the distributed memory parallel machine environment, + the user must make the following call: + + CALL FNVINITP (3, NLOCAL, NGLOBAL, IER) + + The arguments are: + NLOCAL = local size of vectors for this process + NGLOBAL = the system size, and the global size of vectors + (the sum of all values of NLOCAL) + IER = return completion flag. Values are 0 = success, + -1 = failure. + + (5.1omp) To initialize the openMP threaded vector kernel, + the user must make the following call: + + CALL FNVINITOMP (3, NEQ, NUM_THREADS, IER) + + The arguments are: + NEQ = size of vectors + NUM_THREADS = number of threads + IER = return completion flag. Values are 0 = success, -1 = failure. + + (5.1pts) To initialize the Pthreads threaded vector kernel, + the user must make the following call: + + CALL FNVINITOMP (3, NEQ, NUM_THREADS, IER) + + The arguments are: + NEQ = size of vectors + NUM_THREADS = number of threads + IER = return completion flag. Values are 0 = success, -1 = failure. + + (5.2) To create the internal memory structure, make the following call: + + CALL FKINCREATE(IER) + + The arguments are: + IER = return completion flag. Values are 0 = success, and + -1 = failure. + + Note: See printed message for details in case of failure. + + (5.3) To set various integer optional inputs, make the folowing call: + + CALL FKINSETIIN(KEY, VALUE, IER) + + to set the optional input specified by the character key KEY to the + integer value VALUE. + KEY is one of the following: 'PRNT_LEVEL', 'MAX_NITERS', 'ETA_FORM', 'MAA', + 'MAX_SETUPS', 'MAX_SP_SETUPS', 'NO_INIT_SETUP', 'NO_MIN_EPS', 'NO_RES_MON'. + + To set various real optional inputs, make the folowing call: + + CALL FKINSETRIN(KEY, VALUE, IER) + + to set the optional input specified by the character key KEY to the + real value VALUE. + KEY is one of the following: 'FNORM_TOL', 'SSTEP_TOL', 'MAX_STEP', + 'RERR_FUNC', 'ETA_CONST', 'ETA_PARAMS', 'RMON_CONST', 'RMON_PARAMS'. + Note that if KEY is 'ETA_PARAMS' or 'RMON_PARAMS', then VALUE must be an + array of dimension 2. + + To set the vector of constraints on the solution, make the following call: + + CALL FKINSETVIN(KEY, ARRAY, IER) + + where ARRAY is an array of reals and KEY is 'CONSTR_VEC'. + + FKINSETIIN, FKINSETRIN, and FKINSETVIN return IER=0 if successful and + IER<0 if an error occured. + + (5.4) To allocate and initialize the internal memory structure, + make the following call: + + CALL FKININIT(IOUT, ROUT, IER) + + The arguments are: + IOUT = array of length at least 16 for integer optional outputs + (declare as INTEGER*8) + ROUT = array of length at least 2 for real optional outputs + IER = return completion flag. Values are 0 = success, and + -1 = failure. + + Note: See printed message for details in case of failure. + + (6) Specification of linear system solution method: + + The solution method in KINSOL involves the solution of linear systems + related to the Jacobian J = dF/du of the nonlinear system. + + (6.1s) DENSE treatment of the linear systems (NVECTOR_SERIAL only): + + To initialize a dense matrix structure for storing the system Jacobian + and for use within a direct linear solver, the user must call: + + CALL FSUNDENSEMATINIT(3, M, N, IER) + + The integer 3 is the KINSOL solver ID and the other arguments are: + M = the number of rows of the matrix [long int, input] + N = the number of columns of the matrix [long int, input] + IER = return completion flag [int, output]: + 0 = success, + -1 = failure. + + To initialize a dense linear solver structure the user must call + the following to use the SUNDIALS or LAPACK dense solvers: + + CALL FSUNDENSELINSOLINIT(3, IER) + + OR + + CALL FSUNLAPACKDENSEINIT(3, IER) + + In the above routines, 3 is the KINSOL solver ID and IER is the return + return completion flag (0 = success and -1 = failure). + + To attach the dense linear solver structure the user must call + the following: + + CALL FKINLSINIT(IER) + + The arguments are: + IER = return completion flag [int, output]: + 0 = SUCCESS, + -1 = failure (see printed message for failure details). + + If the user program includes the FKDJAC routine for the evaluation + of the dense approximation to the system Jacobian, the following call + must be made: + + CALL FKINDENSESETJAC(FLAG, IER) + + with FLAG = 1 to specify that FKDJAC is provided. (FLAG = 0 specifies + using the internal finite difference approximation to the Jacobian.) + + (6.2s) BAND treatment of the linear systems (NVECTOR_SERIAL only): + + To initialize a banded matrix structure for stroing the system Jacobian + and for use within a banded linear solver, the user must call: + + CALL FSUNBANDMATINIT(3, N, MU, ML, SMU, IER) + + The integer 3 is the KINSOL solver ID and the other arguments are: + N = the number of columns of the matrix [long int, input] + MU = the number of upper bands (diagonal not included) in a banded + matrix [long int, input] + ML = the number of lower bands (diagonal not included) in a banded + matrix [long int, input] + SMU = the number of upper bands to store (diagonal not included) + for factorization of a banded matrix [long int, input] + + To initialize a banded linear solver structure the user must call + the following to use the SUNDIALS or LAPACK banded solvers: + + CALL FSUNBANDLINSOLINIT(3, IER) + + OR + + CALL FSUNLAPACKBANDINIT(3, IER) + + In the above routines, 3 is the KINSOL solver ID and IER is the return + return completion flag (0 = success and -1 = failure). + + To attach the banded linear solver structure the user must call + the following: + + CALL FKINLSINIT(IER) + + The arguments are: + IER = return completion flag [int, output]: + 0 = SUCCESS, + -1 = failure (see printed message for failure details). + + If the user program includes the FKBJAC routine for the evaluation + of the band approximation to the system Jacobian, the following call + must be made: + + CALL FKINBANDSETJAC(FLAG, IER) + + with FLAG = 1 to specify that FKBJAC is provided. (FLAG = 0 specifies + using the internal finite difference approximation to the Jacobian.) + + (6.3s) SPARSE treatment of the linear system using the KLU or SuperLU_MT solver. + + To initialize a sparse matrix structure for stroing the system Jacobian + and for use within a sparse linear solver, the user must call: + + CALL FSUNSPARSEMATINIT(3, M, N, NNZ, SPARSETYPE, IER) + + The integer 3 is the KINSOL solver ID and the other arguments are: + M = the number of rows of the matrix [long int, input] + N = the number of columns of the matrix [long int, input] + NNZ = the storage size (upper bound on the number of nonzeros) for + a sparse matrix [long int, input] + SPARSETYPE = integer denoting use of CSC (0) vs CSR (1) storage + for a sparse matrix [int, input] + IER = return completion flag [int, output]: + 0 = success, + -1 = failure. + + To initialize a sparse linear solver structure the user must call + the following to use the KLU or SuperLU_MT sparse solvers: + + CALL FSUNKLUINIT(3, IER) + + OR + + CALL FSUNSUPERLUMTINIT(3, NUM_THREADS, IER) + + In the above routines, 3 is the KINSOL solver ID, NUM_THREADS is the number + of threads, and IER is the return completion flag (0 = success and + -1 = failure). + + To attach the sparse linear solver structure the user must call + the following: + + CALL FKINLSINIT(IER) + + The arguments are: + IER = return completion flag [int, output]: + 0 = SUCCESS, + -1 = failure (see printed message for failure details). + + When using a sparse solver the user must provide the FKINSPJAC routine for the + evalution of the sparse approximation to the Jacobian. To indicate that this + routine has been provided, after the call to FKINKLU, the following call must + be made + + CALL FKINSPARSESETJAC(IER) + + The int return flag IER=0 if successful, and nonzero otherwise. + + The KLU solver will reuse much of the factorization information from one + nonlinear iteration to the next. If at any time the user wants to force a full + refactorization or if the number of nonzeros in the Jacobian matrix changes, the + user should make the call: + + CALL FKINKLUREINIT(NEQ, NNZ, REINIT_TYPE) + + The arguments are: + NEQ = the problem size [int; input] + NNZ = the maximum number of nonzeros [int; input] + REINIT_TYPE = 1 or 2. For a value of 1, the matrix will be destroyed and + a new one will be allocated with NNZ nonzeros. For a value of 2, + only symbolic and numeric factorizations will be completed. + + At this time, there is no reinitialization capability for the SUNDIALS + interface to the SuperLUMT solver. + + Once these the solvers have been initialized, their solver parameters may be + modified via calls to the functions: + + CALL FSUNKLUSETORDERING(3, ORD_CHOICE, IER) + CALL FSUNSUPERLUMTSETORDERING(3, ORD_CHOICE, IER) + + In the above routines, 3 is the KINSOL solver ID and ORD_CHOICE is an integer + denoting ordering choice (see SUNKLUSetOrdering and SUNSuperLUMTSetOrdering + documentation for details), and IER is the return completion flag (0 = success + and -1 = failure). + + (6.4) Scaled Preconditioned Iterative linear Solvers (SPILS): + + To initialize a SPILS treatment of the linear system, the user must call one + of the following: + + CALL FSUNPCGINIT(3, PRETYPE, MAXL, IER) + CALL FSUNSPBCGSINIT(3, PRETYPE, MAXL, IER) + CALL FSUNSPFGMRINIT(3, PRETYPE, MAXL, IER) + CALL FSUNSPGMRINIT(3, PRETYPE, MAXL, IER) + CALL FSUNSPTFQMRINIT(3, PRETYPE, MAXL, IER) + + The integer 3 is the KINSOL solver ID and the other arguments are: + PRETYPE = type of preconditioning to perform (0=none, 1=left, + 2=right, 3=both) [int, input] + MAXL = maximum Krylov subspace dimension [int, input] + IER = return completion flag [int, output]: + 0 = success, + -1 = failure. + + To attach the iterative linear solver structure the user must call + the following: + + CALL FKINLSINIT(IER) + + The arguments are: + IER = return completion flag [int, output]: + 0 = SUCCESS, + -1 = failure (see printed message for failure details). + + Once these the solvers have been initialized, their solver parameters may be + modified via calls to the functions: + + CALL FSUNPCGSETPRECTYPE(3, PRETYPE, IER) + CALL FSUNPCGSETMAXL(3, MAXL, IER) + + CALL FSUNSPBCGSSETPRECTYPE(3, PRETYPE, IER) + CALL FSUNSPBCGSSETMAXL(3, MAXL, IER) + + CALL FSUNSPFGMRSETGSTYPE(3, GSTYPE, IER) + CALL FSUNSPFGMRSETPRECTYPE(3, PRETYPE, IER) + + CALL FSUNSPGMRSETGSTYPE(3, GSTYPE, IER) + CALL FSUNSPGMRSETPRECTYPE(3, PRETYPE, IER) + + CALL FSUNSPTFQMRSETPRECTYPE(3, PRETYPE, IER) + CALL FSUNSPTFQMRSETMAXL(3, MAXL, IER) + + The integer 3 is the KINSOL solver ID and the other arguments are: + PRETYPE = type of preconditioning to perform (0=none, 1=left, + 2=right, 3=both) [int, input] + GSTYPE = choice of Gram-Schmidt orthogonalization algorithm + (0=modified, 1=classical) [int, input] + IER = return completion flag [int, output]: + 0 = success, + -1 = failure. + + (6.5) Specifying user-provided functions for the iterative linear solvers (SPILS) + + If the user program includes the FKJTIMES routine for the evaluation + of the Jacobian-vector product, the following call must be made: + + CALL FKINLSSETJAC(FLAG, IER) + + The argument FLAG = 0 specifies using the internal finite differences + approximation to the Jacobian-vector product, while FLAG = 1 specifies + that FKJTIMES is provided. + + Usage of the user-supplied routines FKPSET and FKPSOL for the setup and + solution of the preconditioned linear system is specified by calling: + + CALL FKINLSSETPREC(FLAG, IER) + + where FLAG = 0 indicates no FKPSET or FKPSOL (default) and FLAG = 1 + specifies using FKPSET and FKPSOL. The user-supplied routines FKPSET + and FKPSOL must be of the form: + + SUBROUTINE FKPSET (UU, USCALE, FVAL, FSCALE, IER) + DIMENSION UU(*), USCALE(*), FVAL(*), FSCALE(*) + + It must perform any evaluation of Jacobian-related data and + preprocessing needed for the solution of the preconditioned linear + systems by FKPSOL. The variables UU through FSCALE are for use in the + preconditioning setup process. Typically, the system function FKFUN is + called, so that FVAL will have been updated. UU is the current solution + iterate. If scaling is being used, USCALE and FSCALE are available for + those operatins requiring scaling. + + On return, set IER = 0 if FKPSET was successful, set IER = 1 if + an error occurred. + + SUBROUTINE FKPSOL (UU, USCALE, FVAL, FSCALE, VTEM, IER) + DIMENSION UU(*), USCALE(*), FVAL(*), FSCALE(*), VTEM(*) + + Typically this routine will use only UU, FVAL, and VTEM. + It must solve the preconditioned linear system Pz = r, where + r = VTEM is input, and store the solution z in VTEM as well. Here + P is the right preconditioner. If scaling is being used, the + routine supplied must also account for scaling on either coordinate + or function value. + + (7) The solver: FKINSOL + + Solving the nonlinear system is accomplished by making the following + call: + + CALL FKINSOL (UU, GLOBALSTRAT, USCALE, FSCALE, IER) + + The arguments are: + UU = array containing the initial guess on input, and the + solution on return + GLOBALSTRAT = (INTEGER) a number defining the global strategy choice: + 0 = No globalization, 1 = LineSearch, 2 = Picard, + 3 = Fixed Point + USCALE = array of scaling factors for the UU vector + FSCALE = array of scaling factors for the FVAL (function) vector + IER = INTEGER error flag as returned by KINSOL: + 0 means success, + 1 means initial guess satisfies f(u) = 0 (approx.), + 2 means apparent stalling (small step), + a value < 0 means other error or failure. + + Note: See KINSOL documentation for detailed information. + + (8) Memory freeing: FKINFREE + + To the free the internal memory created by the calls to FKINCREATE and + FKININIT and any FNVINIT**, make the following call: + + CALL FKINFREE + + (9) Optional outputs: IOUT/ROUT + + The optional outputs available by way of IOUT and ROUT have the + following names, locations, and descriptions. For further details see + the KINSOL documentation. + + LENRW = IOUT(1) = real workspace size + LENRW = IOUT(2) = real workspace size + NNI = IOUT(3) = number of Newton iterations + NFE = IOUT(4) = number of f evaluations + NBCF = IOUT(5) = number of line search beta condition failures + NBKTRK = IOUT(6) = number of line search backtracks + + FNORM = ROUT(1) = final scaled norm of f(u) + STEPL = ROUT(2) = scaled last step length + + The following optional outputs arise from the KINLS module: + + LRW = IOUT( 7) = real workspace size for the linear solver module + LIW = IOUT( 8) = integer workspace size for the linear solver module + LSTF = IOUT( 9) = last flag returned by linear solver + NFE = IOUT(10) = number of f evaluations for DQ Jacobian or + Jacobian*vector approximation + NJE = IOUT(11) = number of Jacobian evaluations + NJT = IOUT(12) = number of Jacobian-vector product evaluations + NPE = IOUT(13) = number of preconditioner evaluations + NPS = IOUT(14) = number of preconditioner solves + NLI = IOUT(15) = number of linear (Krylov) iterations + NCFL = IOUT(16) = number of linear convergence failures + +*******************************************************************************/ + +#ifndef _FKINSOL_H +#define _FKINSOL_H + +/*------------------------------------------------------------------ + header files + ------------------------------------------------------------------*/ + +#include <kinsol/kinsol.h> +#include <sundials/sundials_linearsolver.h> /* definition of SUNLinearSolver */ +#include <sundials/sundials_matrix.h> /* definition of SUNMatrix */ +#include <sundials/sundials_nvector.h> /* definition of type N_Vector */ +#include <sundials/sundials_types.h> /* definition of type realtype */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*------------------------------------------------------------------ + generic names are translated through the define statements below + ------------------------------------------------------------------*/ + +#if defined(SUNDIALS_F77_FUNC) + +#define FKIN_MALLOC SUNDIALS_F77_FUNC(fkinmalloc, FKINMALLOC) +#define FKIN_CREATE SUNDIALS_F77_FUNC(fkincreate, FKINCREATE) +#define FKIN_INIT SUNDIALS_F77_FUNC(fkininit, FKININIT) +#define FKIN_SETIIN SUNDIALS_F77_FUNC(fkinsetiin, FKINSETIIN) +#define FKIN_SETRIN SUNDIALS_F77_FUNC(fkinsetrin, FKINSETRIN) +#define FKIN_SETVIN SUNDIALS_F77_FUNC(fkinsetvin, FKINSETVIN) +#define FKIN_SOL SUNDIALS_F77_FUNC(fkinsol, FKINSOL) +#define FKIN_FREE SUNDIALS_F77_FUNC(fkinfree, FKINFREE) +#define FKIN_LSINIT SUNDIALS_F77_FUNC(fkinlsinit, FKINLSINIT) +#define FKIN_LSSETJAC SUNDIALS_F77_FUNC(fkinlssetjac, FKINLSSETJAC) +#define FKIN_LSSETPREC SUNDIALS_F77_FUNC(fkinlssetprec, FKINLSSETPREC) +#define FK_PSET SUNDIALS_F77_FUNC(fkpset, FKPSET) +#define FK_PSOL SUNDIALS_F77_FUNC(fkpsol, FKPSOL) +#define FKIN_DENSESETJAC SUNDIALS_F77_FUNC(fkindensesetjac, FKINDENSESETJAC) +#define FK_DJAC SUNDIALS_F77_FUNC(fkdjac, FKDJAC) +#define FKIN_BANDSETJAC SUNDIALS_F77_FUNC(fkinbandsetjac, FKINBANDSETJAC) +#define FK_BJAC SUNDIALS_F77_FUNC(fkbjac, FKBJAC) +#define FKIN_SPARSESETJAC SUNDIALS_F77_FUNC(fkinsparsesetjac, FKINSPARSESETJAC) +#define FKIN_SPJAC SUNDIALS_F77_FUNC(fkinspjac, FKINSPJAC) +#define FK_JTIMES SUNDIALS_F77_FUNC(fkjtimes, FKJTIMES) +#define FK_FUN SUNDIALS_F77_FUNC(fkfun, FKFUN) + +/*---DEPRECATED---*/ +#define FKIN_DLSINIT SUNDIALS_F77_FUNC(fkindlsinit, FKINDLSINIT) +#define FKIN_SPILSINIT SUNDIALS_F77_FUNC(fkinspilsinit, FKINSPILSINIT) +#define FKIN_SPILSSETJAC SUNDIALS_F77_FUNC(fkinspilssetjac, FKINSPILSSETJAC) +#define FKIN_SPILSSETPREC SUNDIALS_F77_FUNC(fkinspilssetprec, FKINSPILSSETPREC) +/*----------------*/ + +#else + +#define FKIN_MALLOC fkinmalloc_ +#define FKIN_CREATE fkincreate_ +#define FKIN_INIT fkininit_ +#define FKIN_SETIIN fkinsetiin_ +#define FKIN_SETRIN fkinsetrin_ +#define FKIN_SETVIN fkinsetvin_ +#define FKIN_SOL fkinsol_ +#define FKIN_FREE fkinfree_ +#define FKIN_LSINIT fkinlsinit_ +#define FKIN_LSSETJAC fkinlssetjac_ +#define FK_JTIMES fkjtimes_ +#define FKIN_LSSETPREC fkinlssetprec_ +#define FKIN_DENSESETJAC fkindensesetjac_ +#define FK_DJAC fkdjac_ +#define FKIN_BANDSETJAC fkinbandsetjac_ +#define FK_BJAC fkbjac_ +#define FKIN_SPARSESETJAC fkinsparsesetjac_ +#define FKIN_SPJAC fkinspjac_ +#define FK_PSET fkpset_ +#define FK_PSOL fkpsol_ +#define FK_FUN fkfun_ + +/*---DEPRECATED---*/ +#define FKIN_DLSINIT fkindlsinit_ +#define FKIN_SPILSINIT fkinspilsinit_ +#define FKIN_SPILSSETJAC fkinspilssetjac_ +#define FKIN_SPILSSETPREC fkinspilssetprec_ +/*----------------*/ + +#endif + +/*------------------------------------------------------------------ + Prototypes : exported functions + ------------------------------------------------------------------*/ + +void FKIN_MALLOC(long int *iout, realtype *rout, int *ier); +void FKIN_CREATE(int *ier); +void FKIN_INIT(long int *iout, realtype *rout, int *ier); + +void FKIN_SETIIN(char key_name[], long int *ival, int *ier); +void FKIN_SETRIN(char key_name[], realtype *rval, int *ier); +void FKIN_SETVIN(char key_name[], realtype *vval, int *ier); + +void FKIN_LSINIT(int *ier); +void FKIN_LSSETJAC(int *flag, int *ier); +void FKIN_LSSETPREC(int *flag, int *ier); +void FKIN_DENSESETJAC(int *flag, int *ier); +void FKIN_BANDSETJAC(int *flag, int *ier); +void FKIN_SPARSESETJAC(int *ier); + +/*---DEPRECATED---*/ +void FKIN_DLSINIT(int *ier); +void FKIN_SPILSINIT(int *ier); +void FKIN_SPILSSETJAC(int *flag, int *ier); +void FKIN_SPILSSETPREC(int *flag, int *ier); +/*----------------*/ + +void FKIN_SOL(realtype *uu, int *globalstrategy, + realtype *uscale , realtype *fscale, int *ier); + +void FKIN_FREE(void); + +/*------------------------------------------------------------------ + Prototypes : functions called by the solver + ------------------------------------------------------------------*/ + +int FKINfunc(N_Vector uu, N_Vector fval, void *user_data); + +int FKINDenseJac(N_Vector uu, N_Vector fval, SUNMatrix J, + void *user_data, N_Vector vtemp1, N_Vector vtemp2); + +int FKINBandJac(N_Vector uu, N_Vector fval, SUNMatrix J, + void *user_data, N_Vector vtemp1, N_Vector vtemp2); + +int FKINSparseJac(N_Vector uu, N_Vector fval, SUNMatrix J, + void *user_data, N_Vector vtemp1, N_Vector vtemp2); + +int FKINJtimes(N_Vector v, N_Vector Jv, N_Vector uu, + booleantype *new_uu, void *user_data); + +int FKINPSet(N_Vector uu, N_Vector uscale, + N_Vector fval, N_Vector fscale, + void *user_data); + +int FKINPSol(N_Vector uu, N_Vector uscale, + N_Vector fval, N_Vector fscale, + N_Vector vv, void *user_data); + +void FKINNullMatrix(); +void FKINNullLinsol(); + +/*------------------------------------------------------------------ + declarations for global variables shared amongst various routines + ------------------------------------------------------------------*/ + +extern N_Vector F2C_KINSOL_vec; /* defined in FNVECTOR module */ +extern SUNMatrix F2C_KINSOL_matrix; /* defined in FSUNMATRIX module */ +extern SUNLinearSolver F2C_KINSOL_linsol; /* defined in FSUNLINSOL module */ +extern void *KIN_kinmem; /* defined in fkinsol.c */ +extern long int *KIN_iout; /* defined in fkinsol.c */ +extern realtype *KIN_rout; /* defined in fkinsol.c */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinsparse.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinsparse.c new file mode 100644 index 0000000..80af78f --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/fcmix/fkinsparse.c @@ -0,0 +1,88 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Carol Woodward @ LLNL + * Daniel R. Reynolds @ SMU + * 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 + * -----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "fkinsol.h" +#include "kinsol_impl.h" + +#include <kinsol/kinsol_ls.h> +#include <sunmatrix/sunmatrix_sparse.h> + +/*=============================================================*/ + +/* Prototype of the Fortran routine */ + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +extern void FKIN_SPJAC(realtype *Y, realtype *FY, long int *N, + long int *NNZ, realtype *JDATA, + sunindextype *JRVALS, sunindextype *JCPTRS, + realtype *V1, realtype *V2, int *ier); + +#ifdef __cplusplus +} +#endif + +/*=============================================================*/ + +/* Fortran interface to C routine KINSlsSetSparseJacFn; see + fkinsol.h for further information */ +void FKIN_SPARSESETJAC(int *ier) +{ +#if defined(SUNDIALS_INT32_T) + KINProcessError((KINMem) KIN_kinmem, KIN_ILL_INPUT, "KIN", + "FKINSPARSESETJAC", + "Sparse Fortran users must configure SUNDIALS with 64-bit integers."); + *ier = 1; +#else + *ier = KINSetJacFn(KIN_kinmem, FKINSparseJac); +#endif +} + +/*=============================================================*/ + +/* C interface to user-supplied Fortran routine FKINSPJAC; see + fkinsol.h for additional information */ +int FKINSparseJac(N_Vector y, N_Vector fy, SUNMatrix J, + void *user_data, N_Vector vtemp1, + N_Vector vtemp2) +{ + int ier; + realtype *ydata, *fydata, *v1data, *v2data, *Jdata; + long int NP, NNZ; + sunindextype *indexvals, *indexptrs; + + ydata = N_VGetArrayPointer(y); + fydata = N_VGetArrayPointer(fy); + v1data = N_VGetArrayPointer(vtemp1); + v2data = N_VGetArrayPointer(vtemp2); + + NP = SUNSparseMatrix_NP(J); + NNZ = SUNSparseMatrix_NNZ(J); + Jdata = SUNSparseMatrix_Data(J); + indexvals = SUNSparseMatrix_IndexValues(J); + indexptrs = SUNSparseMatrix_IndexPointers(J); + + FKIN_SPJAC(ydata, fydata, &NP, &NNZ, + Jdata, indexvals, indexptrs, + v1data, v2data, &ier); + return(ier); +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol.c new file mode 100644 index 0000000..a9ad2e9 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol.c @@ -0,0 +1,2507 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Allan Taylor, Alan Hindmarsh, Radu Serban, Carol Woodward, + * John Loffeld, 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 implementation file for the main KINSol solver. + * It is independent of the KINSol linear solver in use. + * ----------------------------------------------------------------- + * + * EXPORTED FUNCTIONS + * ------------------ + * Creation and allocation functions + * KINCreate + * KINInit + * Main solver function + * KINSol + * Deallocation function + * KINFree + * + * PRIVATE FUNCTIONS + * ----------------- + * KINCheckNvector + * Memory allocation/deallocation + * KINAllocVectors + * KINFreeVectors + * Initial setup + * KINSolInit + * Step functions + * KINLinSolDrv + * KINFullNewton + * KINLineSearch + * KINConstraint + * KINFP + * KINPicardAA + * Stopping tests + * KINStop + * KINForcingTerm + * Norm functions + * KINScFNorm + * KINScSNorm + * KINSOL Verbose output functions + * KINPrintInfo + * KINInfoHandler + * KINSOL Error Handling functions + * KINProcessError + * KINErrHandler + * ----------------------------------------------------------------- + */ + +/* + * ================================================================= + * IMPORTED HEADER FILES + * ================================================================= + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> + +#include <math.h> + +#include "kinsol_impl.h" +#include <sundials/sundials_math.h> + +/* + * ================================================================= + * KINSOL PRIVATE CONSTANTS + * ================================================================= + */ + +#define HALF RCONST(0.5) +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) +#define ONEPT5 RCONST(1.5) +#define TWO RCONST(2.0) +#define THREE RCONST(3.0) +#define FIVE RCONST(5.0) +#define TWELVE RCONST(12.0) +#define POINT1 RCONST(0.1) +#define POINT01 RCONST(0.01) +#define POINT99 RCONST(0.99) +#define THOUSAND RCONST(1000.0) +#define ONETHIRD RCONST(0.3333333333333333) +#define TWOTHIRDS RCONST(0.6666666666666667) +#define POINT9 RCONST(0.9) +#define POINT0001 RCONST(0.0001) + +/* + * ================================================================= + * KINSOL ROUTINE-SPECIFIC CONSTANTS + * ================================================================= + */ + +/* + * Control constants for lower-level functions used by KINSol + * ---------------------------------------------------------- + * + * KINStop return value requesting more iterations + * RETRY_ITERATION + * CONTINUE_ITERATIONS + * + * KINFullNewton, KINLineSearch, KINFP, and KINPicardAA return values: + * KIN_SUCCESS + * KIN_SYSFUNC_FAIL + * STEP_TOO_SMALL + * + * KINConstraint return values: + * KIN_SUCCESS + * CONSTR_VIOLATED + */ + +#define RETRY_ITERATION -998 +#define CONTINUE_ITERATIONS -999 +#define STEP_TOO_SMALL -997 +#define CONSTR_VIOLATED -996 + +/* + * Algorithmic constants + * --------------------- + * + * MAX_RECVR max. no. of attempts to correct a recoverable func error + */ + +#define MAX_RECVR 5 + +/* + * Keys for KINPrintInfo + * --------------------- + */ + +#define PRNT_RETVAL 1 +#define PRNT_NNI 2 +#define PRNT_TOL 3 +#define PRNT_FMAX 4 +#define PRNT_PNORM 5 +#define PRNT_PNORM1 6 +#define PRNT_FNORM 7 +#define PRNT_LAM 8 +#define PRNT_ALPHA 9 +#define PRNT_BETA 10 +#define PRNT_ALPHABETA 11 +#define PRNT_ADJ 12 + +/* + * ================================================================= + * PRIVATE FUNCTION PROTOTYPES + * ================================================================= + */ + +static booleantype KINCheckNvector(N_Vector tmpl); +static booleantype KINAllocVectors(KINMem kin_mem, N_Vector tmpl); +static int KINSolInit(KINMem kin_mem); +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, + realtype *f1normp, booleantype *maxStepTaken); +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 KINLinSolDrv(KINMem kinmem); +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); + +/* + * ================================================================= + * EXPORTED FUNCTIONS IMPLEMENTATION + * ================================================================= + */ + +/* + * ----------------------------------------------------------------- + * Creation and allocation functions + * ----------------------------------------------------------------- + */ + +/* + * Function : KINCreate + * + * 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. + */ + +void *KINCreate(void) +{ + KINMem kin_mem; + realtype uround; + + kin_mem = NULL; + kin_mem = (KINMem) malloc(sizeof(struct KINMemRec)); + if (kin_mem == NULL) { + KINProcessError(kin_mem, 0, "KINSOL", "KINCreate", MSG_MEM_FAIL); + return(NULL); + } + + /* Zero out kin_mem */ + memset(kin_mem, 0, sizeof(struct KINMemRec)); + + /* 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_uscale = NULL; + kin_mem->kin_fscale = NULL; + kin_mem->kin_fold_aa = NULL; + kin_mem->kin_gold_aa = NULL; + kin_mem->kin_df_aa = NULL; + kin_mem->kin_dg_aa = NULL; + kin_mem->kin_q_aa = NULL; + kin_mem->kin_gamma_aa = NULL; + kin_mem->kin_R_aa = NULL; + kin_mem->kin_cv = NULL; + kin_mem->kin_Xv = NULL; + kin_mem->kin_m_aa = ZERO; + kin_mem->kin_aamem_aa = 0; + kin_mem->kin_setstop_aa = 0; + kin_mem->kin_constraintsSet = SUNFALSE; + kin_mem->kin_ehfun = KINErrHandler; + kin_mem->kin_eh_data = kin_mem; + kin_mem->kin_errfp = stderr; + kin_mem->kin_ihfun = KINInfoHandler; + kin_mem->kin_ih_data = kin_mem; + kin_mem->kin_infofp = stdout; + kin_mem->kin_printfl = PRINTFL_DEFAULT; + kin_mem->kin_mxiter = MXITER_DEFAULT; + kin_mem->kin_noInitSetup = SUNFALSE; + kin_mem->kin_msbset = MSBSET_DEFAULT; + kin_mem->kin_noResMon = SUNFALSE; + kin_mem->kin_msbset_sub = MSBSET_SUB_DEFAULT; + kin_mem->kin_update_fnorm_sub = SUNFALSE; + kin_mem->kin_mxnbcf = MXNBCF_DEFAULT; + kin_mem->kin_sthrsh = TWO; + kin_mem->kin_noMinEps = SUNFALSE; + kin_mem->kin_mxnstepin = ZERO; + kin_mem->kin_sqrt_relfunc = SUNRsqrt(uround); + kin_mem->kin_scsteptol = SUNRpowerR(uround,TWOTHIRDS); + kin_mem->kin_fnormtol = SUNRpowerR(uround,ONETHIRD); + kin_mem->kin_etaflag = KIN_ETACHOICE1; + kin_mem->kin_eta = POINT1; /* default for KIN_ETACONSTANT */ + kin_mem->kin_eta_alpha = TWO; /* default for KIN_ETACHOICE2 */ + kin_mem->kin_eta_gamma = POINT9; /* default for KIN_ETACHOICE2 */ + kin_mem->kin_MallocDone = SUNFALSE; + kin_mem->kin_eval_omega = SUNTRUE; + kin_mem->kin_omega = ZERO; /* default to using min/max */ + kin_mem->kin_omega_min = OMEGA_MIN; + kin_mem->kin_omega_max = OMEGA_MAX; + + /* initialize lrw and liw */ + + kin_mem->kin_lrw = 17; + kin_mem->kin_liw = 22; + + /* NOTE: needed since KINInit could be called after KINSetConstraints */ + + kin_mem->kin_lrw1 = 0; + kin_mem->kin_liw1 = 0; + + return((void *) kin_mem); +} + +/* + * Function : KINInit + * + * 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. + */ + +int KINInit(void *kinmem, KINSysFn func, N_Vector tmpl) +{ + sunindextype liw1, lrw1; + KINMem kin_mem; + booleantype allocOK, nvectorOK; + + /* check kinmem */ + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINInit", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + kin_mem = (KINMem) kinmem; + + if (func == NULL) { + KINProcessError(kin_mem, KIN_ILL_INPUT, "KINSOL", "KINInit", MSG_FUNC_NULL); + return(KIN_ILL_INPUT); + } + + /* check if all required vector operations are implemented */ + + nvectorOK = KINCheckNvector(tmpl); + if (!nvectorOK) { + KINProcessError(kin_mem, KIN_ILL_INPUT, "KINSOL", "KINInit", MSG_BAD_NVECTOR); + return(KIN_ILL_INPUT); + } + + /* set space requirements for one N_Vector */ + + if (tmpl->ops->nvspace != NULL) { + N_VSpace(tmpl, &lrw1, &liw1); + kin_mem->kin_lrw1 = lrw1; + kin_mem->kin_liw1 = liw1; + } + else { + kin_mem->kin_lrw1 = 0; + kin_mem->kin_liw1 = 0; + } + + /* allocate necessary vectors */ + + allocOK = KINAllocVectors(kin_mem, tmpl); + if (!allocOK) { + KINProcessError(kin_mem, KIN_MEM_FAIL, "KINSOL", "KINInit", MSG_MEM_FAIL); + free(kin_mem); kin_mem = NULL; + return(KIN_MEM_FAIL); + } + + /* copy the input parameter into KINSol state */ + + kin_mem->kin_func = func; + + /* set the linear solver addresses to NULL */ + + kin_mem->kin_linit = NULL; + kin_mem->kin_lsetup = NULL; + 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; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Main solver function + * ----------------------------------------------------------------- + */ + +/* + * Function : KINSol + * + * KINSol (main KINSOL driver routine) manages the computational + * process of computing an approximate solution of the nonlinear + * system F(uu) = 0. The KINSol routine calls the following + * subroutines: + * + * KINSolInit checks if initial guess satisfies user-supplied + * constraints and initializes linear solver + * + * KINLinSolDrv interfaces with linear solver to find a + * solution of the system J(uu)*x = b (calculate + * Newton step) + * + * KINFullNewton/KINLineSearch implement the global strategy + * + * KINForcingTerm computes the forcing term (eta) + * + * KINStop determines if an approximate solution has been found + */ + +int KINSol(void *kinmem, N_Vector u, int strategy_in, + N_Vector u_scale, N_Vector f_scale) +{ + realtype fnormp, f1normp, epsmin, fmax=ZERO; + KINMem kin_mem; + int ret, sflag; + booleantype maxStepTaken; + + /* intialize to avoid compiler warning messages */ + + maxStepTaken = SUNFALSE; + f1normp = fnormp = -ONE; + + /* initialize epsmin to avoid compiler warning message */ + + epsmin = ZERO; + + /* check for kinmem non-NULL */ + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSol", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + kin_mem = (KINMem) kinmem; + + if(kin_mem->kin_MallocDone == SUNFALSE) { + KINProcessError(NULL, KIN_NO_MALLOC, "KINSOL", "KINSol", MSG_NO_MALLOC); + return(KIN_NO_MALLOC); + } + + /* load input arguments */ + + kin_mem->kin_uu = u; + kin_mem->kin_uscale = u_scale; + kin_mem->kin_fscale = f_scale; + kin_mem->kin_globalstrategy = strategy_in; + + /* 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 ) { + if (kin_mem->kin_uu == NULL) { + KINProcessError(kin_mem, KIN_ILL_INPUT, "KINSOL", "KINSol", MSG_UU_NULL); + return(KIN_ILL_INPUT); + } + + if (kin_mem->kin_constraintsSet != SUNFALSE) { + KINProcessError(kin_mem, KIN_ILL_INPUT, "KINSOL", "KINSol", MSG_CONSTRAINTS_NOTOK); + return(KIN_ILL_INPUT); + } + + if (kin_mem->kin_printfl > 0) + 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); + + switch(ret) { + case KIN_SYSFUNC_FAIL: + KINProcessError(kin_mem, KIN_SYSFUNC_FAIL, "KINSOL", "KINSol", MSG_SYSFUNC_FAILED); + break; + case KIN_MAXITER_REACHED: + KINProcessError(kin_mem, KIN_MAXITER_REACHED, "KINSOL", "KINSol", MSG_MAXITER_REACHED); + break; + } + + return(ret); + } + + /* initialize solver */ + ret = KINSolInit(kin_mem); + if (ret != KIN_SUCCESS) return(ret); + + kin_mem->kin_ncscmx = 0; + + /* Note: The following logic allows the choice of whether or not + to force a call to the linear solver setup upon a given call to + KINSol */ + + if (kin_mem->kin_noInitSetup) kin_mem->kin_sthrsh = ONE; + else kin_mem->kin_sthrsh = TWO; + + /* 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 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; + + + /* 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; + ret = KINPicardAA(kin_mem, &(kin_mem->kin_nni), kin_mem->kin_R_aa, kin_mem->kin_gamma_aa, &fmax); + + return(ret); + } + + + for(;;){ + + kin_mem->kin_retry_nni = SUNFALSE; + + kin_mem->kin_nni++; + + /* calculate the epsilon (stopping criteria for iterative linear solver) + for this iteration based on eta from the routine KINForcingTerm */ + + if (kin_mem->kin_inexact_ls) { + kin_mem->kin_eps = (kin_mem->kin_eta + kin_mem->kin_uround) * kin_mem->kin_fnorm; + if(!(kin_mem->kin_noMinEps)) kin_mem->kin_eps = SUNMAX(epsmin, kin_mem->kin_eps); + } + + repeat_nni: + + /* call the appropriate routine to calculate an acceptable step pp */ + + sflag = 0; + + if (kin_mem->kin_globalstrategy == KIN_NONE) { + + /* Full Newton Step*/ + + /* call KINLinSolDrv to calculate the (approximate) Newton step, pp */ + ret = KINLinSolDrv(kin_mem); + if (ret != KIN_SUCCESS) break; + + sflag = KINFullNewton(kin_mem, &fnormp, &f1normp, &maxStepTaken); + + /* if sysfunc failed unrecoverably, stop */ + if ((sflag == KIN_SYSFUNC_FAIL) || (sflag == KIN_REPTD_SYSFUNC_ERR)) { + ret = sflag; + break; + } + + } else if (kin_mem->kin_globalstrategy == KIN_LINESEARCH) { + + /* Line Search */ + + /* call KINLinSolDrv to calculate the (approximate) Newton step, pp */ + ret = KINLinSolDrv(kin_mem); + if (ret != KIN_SUCCESS) break; + + sflag = KINLineSearch(kin_mem, &fnormp, &f1normp, &maxStepTaken); + + /* if sysfunc failed unrecoverably, stop */ + if ((sflag == KIN_SYSFUNC_FAIL) || (sflag == KIN_REPTD_SYSFUNC_ERR)) { + ret = sflag; + break; + } + + /* if too many beta condition failures, then stop iteration */ + if (kin_mem->kin_nbcf > kin_mem->kin_mxnbcf) { + ret = KIN_LINESEARCH_BCFAIL; + break; + } + + } + + 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); + + if (ret == RETRY_ITERATION) { + kin_mem->kin_retry_nni = SUNTRUE; + goto repeat_nni; + } + } + + /* update uu after the iteration */ + N_VScale(ONE, kin_mem->kin_unew, kin_mem->kin_uu); + + kin_mem->kin_f1norm = f1normp; + + /* print the current nni, fnorm, and nfe values if printfl > 0 */ + + 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; + + fflush(kin_mem->kin_errfp); + + } /* end of loop; return */ + + + + if (kin_mem->kin_printfl > 0) + KINPrintInfo(kin_mem, PRNT_RETVAL, "KINSOL", "KINSol", INFO_RETVAL, ret); + + switch(ret) { + case KIN_SYSFUNC_FAIL: + KINProcessError(kin_mem, KIN_SYSFUNC_FAIL, "KINSOL", "KINSol", MSG_SYSFUNC_FAILED); + break; + case KIN_REPTD_SYSFUNC_ERR: + KINProcessError(kin_mem, KIN_REPTD_SYSFUNC_ERR, "KINSOL", "KINSol", MSG_SYSFUNC_REPTD); + break; + case KIN_LSETUP_FAIL: + KINProcessError(kin_mem, KIN_LSETUP_FAIL, "KINSOL", "KINSol", MSG_LSETUP_FAILED); + break; + case KIN_LSOLVE_FAIL: + KINProcessError(kin_mem, KIN_LSOLVE_FAIL, "KINSOL", "KINSol", MSG_LSOLVE_FAILED); + break; + case KIN_LINSOLV_NO_RECOVERY: + KINProcessError(kin_mem, KIN_LINSOLV_NO_RECOVERY, "KINSOL", "KINSol", MSG_LINSOLV_NO_RECOVERY); + break; + case KIN_LINESEARCH_NONCONV: + KINProcessError(kin_mem, KIN_LINESEARCH_NONCONV, "KINSOL", "KINSol", MSG_LINESEARCH_NONCONV); + break; + case KIN_LINESEARCH_BCFAIL: + KINProcessError(kin_mem, KIN_LINESEARCH_BCFAIL, "KINSOL", "KINSol", MSG_LINESEARCH_BCFAIL); + break; + case KIN_MAXITER_REACHED: + KINProcessError(kin_mem, KIN_MAXITER_REACHED, "KINSOL", "KINSol", MSG_MAXITER_REACHED); + break; + case KIN_MXNEWT_5X_EXCEEDED: + KINProcessError(kin_mem, KIN_MXNEWT_5X_EXCEEDED, "KINSOL", "KINSol", MSG_MXNEWT_5X_EXCEEDED); + break; + } + + return(ret); +} + +/* + * ----------------------------------------------------------------- + * Deallocation function + * ----------------------------------------------------------------- + */ + +/* + * Function : KINFree + * + * This routine frees the problem memory allocated by KINInit. + * Such memory includes all the vectors allocated by + * KINAllocVectors, and the memory lmem for the linear solver + * (deallocated by a call to lfree). + */ + +void KINFree(void **kinmem) +{ + KINMem kin_mem; + + if (*kinmem == NULL) return; + + kin_mem = (KINMem) (*kinmem); + KINFreeVectors(kin_mem); + + /* call lfree if non-NULL */ + + if (kin_mem->kin_lfree != NULL) kin_mem->kin_lfree(kin_mem); + + free(*kinmem); + *kinmem = NULL; +} + +/* + * ================================================================= + * PRIVATE FUNCTIONS + * ================================================================= + */ + +/* + * Function : KINCheckNvector + * + * This routine checks if all required vector operations are + * implemented (excluding those required by KINConstraint). If all + * necessary operations are present, then KINCheckNvector returns + * SUNTRUE. Otherwise, SUNFALSE is returned. + */ + +static booleantype KINCheckNvector(N_Vector tmpl) +{ + if ((tmpl->ops->nvclone == NULL) || + (tmpl->ops->nvdestroy == NULL) || + (tmpl->ops->nvlinearsum == NULL) || + (tmpl->ops->nvprod == NULL) || + (tmpl->ops->nvdiv == NULL) || + (tmpl->ops->nvscale == NULL) || + (tmpl->ops->nvabs == NULL) || + (tmpl->ops->nvinv == NULL) || + (tmpl->ops->nvmaxnorm == NULL) || + (tmpl->ops->nvmin == NULL) || + (tmpl->ops->nvwl2norm == NULL)) return(SUNFALSE); + else return(SUNTRUE); +} + +/* + * ----------------------------------------------------------------- + * Memory allocation/deallocation + * ----------------------------------------------------------------- + */ + +/* + * Function : KINAllocVectors + * + * This routine allocates the KINSol vectors. If all memory + * allocations are successful, KINAllocVectors returns SUNTRUE. + * Otherwise all allocated memory is freed and KINAllocVectors + * returns SUNFALSE. + */ + +static booleantype KINAllocVectors(KINMem kin_mem, N_Vector tmpl) +{ + /* 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_fval == NULL) { + N_VDestroy(kin_mem->kin_unew); + 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); + 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); + 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); + return(SUNFALSE); + } + + /* update solver workspace lengths */ + + kin_mem->kin_liw += 5*kin_mem->kin_liw1; + kin_mem->kin_lrw += 5*kin_mem->kin_lrw1; + + 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_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_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_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_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); + } + } + + 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_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_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_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); + } + + /* 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) { + 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); + } + 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); +} + +/* + * KINFreeVectors + * + * This routine frees the KINSol vectors allocated by + * KINAllocVectors. + */ + +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_globalstrategy == KIN_PICARD) && (kin_mem->kin_gval != NULL) ) + N_VDestroy(kin_mem->kin_gval); + + if ( ((kin_mem->kin_globalstrategy == KIN_PICARD) || (kin_mem->kin_globalstrategy == KIN_FP)) && (kin_mem->kin_m_aa > 0) ) { + free(kin_mem->kin_R_aa); + free(kin_mem->kin_gamma_aa); + free(kin_mem->kin_ipt_map); + } + + 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; + } + } + + kin_mem->kin_lrw -= 5*kin_mem->kin_lrw1; + kin_mem->kin_liw -= 5*kin_mem->kin_liw1; + + if (kin_mem->kin_constraintsSet) { + if (kin_mem->kin_constraints != NULL) N_VDestroy(kin_mem->kin_constraints); + kin_mem->kin_lrw -= kin_mem->kin_lrw1; + kin_mem->kin_liw -= kin_mem->kin_liw1; + } + + return; +} + +/* + * ----------------------------------------------------------------- + * Initial setup + * ----------------------------------------------------------------- + */ + +/* + * KINSolInit + * + * KINSolInit initializes the problem for the specific input + * received in this call to KINSol (which calls KINSolInit). 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 possible return values for KINSolInit are: + * KIN_SUCCESS : indicates a normal initialization + * + * KIN_ILL_INPUT : indicates that an input error has been found + * + * KIN_INITIAL_GUESS_OK : indicates that the guess uu + * satisfied the system func(uu) = 0 + * within the tolerances specified + */ + +static int KINSolInit(KINMem kin_mem) +{ + int retval; + realtype fmax; + + /* check for illegal input parameters */ + + if (kin_mem->kin_uu == NULL) { + KINProcessError(kin_mem, KIN_ILL_INPUT, "KINSOL", "KINSolInit", MSG_UU_NULL); + 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) ) { + KINProcessError(kin_mem, KIN_ILL_INPUT, "KINSOL", "KINSolInit", MSG_BAD_GLSTRAT); + return(KIN_ILL_INPUT); + } + + if (kin_mem->kin_uscale == NULL) { + KINProcessError(kin_mem, KIN_ILL_INPUT, "KINSOL", "KINSolInit", MSG_BAD_USCALE); + return(KIN_ILL_INPUT); + } + + if (N_VMin(kin_mem->kin_uscale) <= ZERO){ + KINProcessError(kin_mem, KIN_ILL_INPUT, "KINSOL", "KINSolInit", MSG_USCALE_NONPOSITIVE); + return(KIN_ILL_INPUT); + } + + if (kin_mem->kin_fscale == NULL) { + KINProcessError(kin_mem, KIN_ILL_INPUT, "KINSOL", "KINSolInit", MSG_BAD_FSCALE); + return(KIN_ILL_INPUT); + } + + if (N_VMin(kin_mem->kin_fscale) <= ZERO){ + KINProcessError(kin_mem, KIN_ILL_INPUT, "KINSOL", "KINSolInit", MSG_FSCALE_NONPOSITIVE); + return(KIN_ILL_INPUT); + } + + 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) + 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)) { + KINProcessError(kin_mem, KIN_ILL_INPUT, "KINSOL", "KINSolInit", MSG_BAD_NVECTOR); + return(KIN_ILL_INPUT); + } + } + + /* check the initial guess uu against the constraints */ + + if (kin_mem->kin_constraintsSet) { + if (!N_VConstrMask(kin_mem->kin_constraints, kin_mem->kin_uu, kin_mem->kin_vtemp1)) { + KINProcessError(kin_mem, KIN_ILL_INPUT, "KINSOL", "KINSolInit", MSG_INITIAL_CNSTRNT); + return(KIN_ILL_INPUT); + } + } + + /* all error checking is complete at this point */ + + if (kin_mem->kin_printfl > 0) + KINPrintInfo(kin_mem, PRNT_TOL, "KINSOL", "KINSolInit", INFO_TOL, kin_mem->kin_scsteptol, kin_mem->kin_fnormtol); + + /* calculate the default value for mxnewtstep (maximum Newton step) */ + + if (kin_mem->kin_mxnstepin == ZERO) kin_mem->kin_mxnewtstep = THOUSAND * N_VWL2Norm(kin_mem->kin_uu, kin_mem->kin_uscale); + else kin_mem->kin_mxnewtstep = kin_mem->kin_mxnstepin; + + if (kin_mem->kin_mxnewtstep < ONE) kin_mem->kin_mxnewtstep = ONE; + + /* additional set-up for inexact linear solvers */ + + if (kin_mem->kin_inexact_ls) { + + /* set up the coefficients for the eta calculation */ + + kin_mem->kin_callForcingTerm = (kin_mem->kin_etaflag != KIN_ETACONSTANT); + + /* this value is always used for choice #1 */ + + 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 + KIN_ETACONSTANT option */ + + if (kin_mem->kin_etaflag != KIN_ETACONSTANT) kin_mem->kin_eta = HALF; + + /* disable residual monitoring if using an inexact linear solver */ + + kin_mem->kin_noResMon = SUNTRUE; + + } else { + + kin_mem->kin_callForcingTerm = SUNFALSE; + + } + + /* initialize counters */ + + 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; + + /* see if the initial guess uu satisfies the nonlinear system */ + 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); + return(KIN_SYSFUNC_FAIL); + } else if (retval > 0) { + KINProcessError(kin_mem, KIN_FIRST_SYSFUNC_ERR, "KINSOL", "KINSolInit", + MSG_SYSFUNC_FIRST); + return(KIN_FIRST_SYSFUNC_ERR); + } + + fmax = KINScFNorm(kin_mem, kin_mem->kin_fval, kin_mem->kin_fscale); + if (fmax <= (POINT01 * kin_mem->kin_fnormtol)) { + kin_mem->kin_fnorm = N_VWL2Norm(kin_mem->kin_fval, kin_mem->kin_fscale); + return(KIN_INITIAL_GUESS_OK); + } + + 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) { + retval = kin_mem->kin_linit(kin_mem); + if (retval != 0) { + KINProcessError(kin_mem, KIN_LINIT_FAIL, "KINSOL", "KINSolInit", MSG_LINIT_FAIL); + return(KIN_LINIT_FAIL); + } + } + + /* initialize the L2 (Euclidean) norms of f for the linear iteration steps */ + + kin_mem->kin_fnorm = N_VWL2Norm(kin_mem->kin_fval, kin_mem->kin_fscale); + kin_mem->kin_f1norm = HALF * kin_mem->kin_fnorm * kin_mem->kin_fnorm; + 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); + + /* problem has now been successfully initialized */ + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Step functions + * ----------------------------------------------------------------- + */ + +/* + * KINLinSolDrv + * + * 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. + */ + +static int KINLinSolDrv(KINMem kin_mem) +{ + N_Vector x, b; + int retval; + + if ((kin_mem->kin_nni - kin_mem->kin_nnilset) >= kin_mem->kin_msbset) { + kin_mem->kin_sthrsh = TWO; + kin_mem->kin_update_fnorm_sub = SUNTRUE; + } + + for(;;){ + + kin_mem->kin_jacCurrent = SUNFALSE; + + if ((kin_mem->kin_sthrsh > ONEPT5) && (kin_mem->kin_lsetup != NULL)) { + retval = kin_mem->kin_lsetup(kin_mem); + kin_mem->kin_jacCurrent = SUNTRUE; + kin_mem->kin_nnilset = kin_mem->kin_nni; + kin_mem->kin_nnilset_sub = kin_mem->kin_nni; + if (retval != 0) return(KIN_LSETUP_FAIL); + } + + /* rename vectors for readability */ + + b = kin_mem->kin_unew; + x = kin_mem->kin_pp; + + /* load b with the current value of -fval */ + + N_VScale(-ONE, kin_mem->kin_fval, b); + + /* 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)); + + 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 + and Jacobian information is not current */ + + kin_mem->kin_sthrsh = TWO; + + } +} + +/* + * KINFullNewton + * + * This routine is the main driver for the Full Newton + * 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. + */ + +static int KINFullNewton(KINMem kin_mem, realtype *fnormp, realtype *f1normp, + booleantype *maxStepTaken) +{ + realtype pnorm, ratio; + booleantype fOK; + int ircvr, retval; + + *maxStepTaken = SUNFALSE; + pnorm = N_VWL2Norm(kin_mem->kin_pp, kin_mem->kin_uscale); + ratio = ONE; + if (pnorm > kin_mem->kin_mxnewtstep) { + ratio = kin_mem->kin_mxnewtstep / pnorm; + N_VScale(ratio, kin_mem->kin_pp, kin_mem->kin_pp); + pnorm = kin_mem->kin_mxnewtstep; + } + + if (kin_mem->kin_printfl > 0) + KINPrintInfo(kin_mem, PRNT_PNORM, "KINSOL", "KINFullNewton", INFO_PNORM, pnorm); + + /* If constraints are active, then constrain the step accordingly */ + + kin_mem->kin_stepl = pnorm; + kin_mem->kin_stepmul = ONE; + if (kin_mem->kin_constraintsSet) { + retval = KINConstraint(kin_mem); + if (retval == CONSTR_VIOLATED) { + /* Apply stepmul set in KINConstraint */ + ratio *= kin_mem->kin_stepmul; + N_VScale(kin_mem->kin_stepmul, kin_mem->kin_pp, kin_mem->kin_pp); + pnorm *= kin_mem->kin_stepmul; + kin_mem->kin_stepl = pnorm; + if (kin_mem->kin_printfl > 0) + KINPrintInfo(kin_mem, PRNT_PNORM, "KINSOL", "KINFullNewton", INFO_PNORM, pnorm); + if (pnorm <= kin_mem->kin_scsteptol) { + N_VLinearSum(ONE, kin_mem->kin_uu, ONE, kin_mem->kin_pp, kin_mem->kin_unew); + 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++) { + + /* compute the iterate unew = uu + pp */ + N_VLinearSum(ONE, kin_mem->kin_uu, ONE, kin_mem->kin_pp, kin_mem->kin_unew); + + /* evaluate func(unew) and its norm, and return */ + retval = kin_mem->kin_func(kin_mem->kin_unew, kin_mem->kin_fval, kin_mem->kin_user_data); kin_mem->kin_nfe++; + + /* if func was successful, accept pp */ + if (retval == 0) {fOK = SUNTRUE; break;} + + /* if func failed unrecoverably, give up */ + else if (retval < 0) return(KIN_SYSFUNC_FAIL); + + /* func failed recoverably; cut step in half and try again */ + ratio *= HALF; + N_VScale(HALF, kin_mem->kin_pp, kin_mem->kin_pp); + pnorm *= HALF; + kin_mem->kin_stepl = pnorm; + } + + /* If func() failed recoverably MAX_RECVR times, give up */ + + if (!fOK) return(KIN_REPTD_SYSFUNC_ERR); + + /* Evaluate function norms */ + + *fnormp = N_VWL2Norm(kin_mem->kin_fval, kin_mem->kin_fscale); + *f1normp = HALF * (*fnormp) * (*fnormp); + + /* scale sFdotJp and sJpnorm by ratio for later use in KINForcingTerm */ + + kin_mem->kin_sFdotJp *= ratio; + kin_mem->kin_sJpnorm *= ratio; + + 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; + + return(KIN_SUCCESS); +} + +/* + * KINLineSearch + * + * The routine KINLineSearch implements the LineSearch algorithm. + * Its purpose is to find unew = uu + rl * pp in the direction pp + * from uu so that: + * t + * func(unew) <= func(uu) + alpha * g (unew - uu) (alpha = 1.e-4) + * + * and + * t + * func(unew) >= func(uu) + beta * g (unew - uu) (beta = 0.9) + * + * where 0 < rlmin <= rl <= rlmax. + * + * Note: + * mxnewtstep + * rlmax = ---------------- if uu+pp is feasible + * ||uscale*pp||_L2 + * + * rlmax = 1 otherwise + * + * and + * + * scsteptol + * rlmin = -------------------------- + * || pp || + * || -------------------- ||_L-infinity + * || (1/uscale + SUNRabs(uu)) || + * + * + * 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). + * 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 + * recoverable system function failures, we set rlmax=1 to ensure + * 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) + */ + +static int KINLineSearch(KINMem kin_mem, realtype *fnormp, realtype *f1normp, + booleantype *maxStepTaken) +{ + realtype pnorm, ratio, slpi, rlmin, rlength, rl, rlmax, rldiff; + realtype rltmp, rlprev, pt1trl, f1nprv, rllo, rlinc, alpha, beta; + realtype alpha_cond, beta_cond, rl_a, tmp1, rl_b, tmp2, disc; + int ircvr, nbktrk_l, retval; + booleantype firstBacktrack, fOK; + + /* Initializations */ + + nbktrk_l = 0; /* local backtracking counter */ + ratio = ONE; /* step change ratio */ + alpha = POINT0001; + beta = POINT9; + + firstBacktrack = SUNTRUE; + *maxStepTaken = SUNFALSE; + + rlprev = f1nprv = ZERO; + + /* Compute length of Newton step */ + + pnorm = N_VWL2Norm(kin_mem->kin_pp, kin_mem->kin_uscale); + rlmax = kin_mem->kin_mxnewtstep / pnorm; + kin_mem->kin_stepl = pnorm; + + /* If the full Newton step is too large, set it to the maximum allowable value */ + + if(pnorm > kin_mem->kin_mxnewtstep ) { + ratio = kin_mem->kin_mxnewtstep / pnorm; + N_VScale(ratio, kin_mem->kin_pp, kin_mem->kin_pp); + pnorm = kin_mem->kin_mxnewtstep; + rlmax = ONE; + kin_mem->kin_stepl = pnorm; + } + + /* If constraint checking is activated, check and correct violations */ + + kin_mem->kin_stepmul = ONE; + + if(kin_mem->kin_constraintsSet){ + retval = KINConstraint(kin_mem); + if(retval == CONSTR_VIOLATED){ + /* Apply stepmul set in KINConstraint */ + N_VScale(kin_mem->kin_stepmul, kin_mem->kin_pp, kin_mem->kin_pp); + ratio *= kin_mem->kin_stepmul; + pnorm *= kin_mem->kin_stepmul; + rlmax = ONE; + kin_mem->kin_stepl = pnorm; + if (kin_mem->kin_printfl > 0) KINPrintInfo(kin_mem, PRNT_PNORM1, "KINSOL", "KINLineSearch", INFO_PNORM1, pnorm); + if (pnorm <= kin_mem->kin_scsteptol) { + N_VLinearSum(ONE, kin_mem->kin_uu, ONE, kin_mem->kin_pp, kin_mem->kin_unew); + 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++) { + + /* compute the iterate unew = uu + pp */ + N_VLinearSum(ONE, kin_mem->kin_uu, ONE, kin_mem->kin_pp, kin_mem->kin_unew); + + /* evaluate func(unew) and its norm, and return */ + retval = kin_mem->kin_func(kin_mem->kin_unew, kin_mem->kin_fval, kin_mem->kin_user_data); kin_mem->kin_nfe++; + + /* if func was successful, accept pp */ + if (retval == 0) {fOK = SUNTRUE; break;} + + /* if func failed unrecoverably, give up */ + else if (retval < 0) return(KIN_SYSFUNC_FAIL); + + /* func failed recoverably; cut step in half and try again */ + N_VScale(HALF, kin_mem->kin_pp, kin_mem->kin_pp); + ratio *= HALF; + pnorm *= HALF; + rlmax = ONE; + kin_mem->kin_stepl = pnorm; + + } + + /* If func() failed recoverably MAX_RECVR times, give up */ + + if (!fOK) return(KIN_REPTD_SYSFUNC_ERR); + + /* Evaluate function norms */ + + *fnormp = N_VWL2Norm(kin_mem->kin_fval, kin_mem->kin_fscale); + *f1normp = HALF * (*fnormp) * (*fnormp) ; + + /* Estimate the line search value rl (lambda) to satisfy both ALPHA and BETA conditions */ + + slpi = kin_mem->kin_sFdotJp * ratio; + rlength = KINScSNorm(kin_mem, kin_mem->kin_pp, kin_mem->kin_uu); + rlmin = (kin_mem->kin_scsteptol) / rlength; + rl = ONE; + + if (kin_mem->kin_printfl > 2) + KINPrintInfo(kin_mem, PRNT_LAM, "KINSOL", "KINLineSearch", INFO_LAM, rlmin, kin_mem->kin_f1norm, pnorm); + + /* 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", + INFO_ALPHA, *fnormp, *f1normp, alpha_cond, rl); + + /* If ALPHA condition is satisfied, break out from loop */ + + if ((*f1normp) <= alpha_cond) break; + + /* Backtracking. Use quadratic fit the first time and cubic fit afterwards. */ + + if (firstBacktrack) { + + rltmp = -slpi / (TWO * ((*f1normp) - kin_mem->kin_f1norm - slpi)); + firstBacktrack = SUNFALSE; + + } else { + + tmp1 = (*f1normp) - kin_mem->kin_f1norm - (rl * slpi); + tmp2 = f1nprv - kin_mem->kin_f1norm - (rlprev * slpi); + rl_a = ((ONE / (rl * rl)) * tmp1) - ((ONE / (rlprev * rlprev)) * tmp2); + rl_b = ((-rlprev / (rl * rl)) * tmp1) + ((rl / (rlprev * rlprev)) * tmp2); + tmp1 = ONE / (rl - rlprev); + rl_a *= tmp1; + rl_b *= tmp1; + disc = (rl_b * rl_b) - (THREE * rl_a * slpi); + + if (SUNRabs(rl_a) < kin_mem->kin_uround) { /* cubic is actually just a quadratic (rl_a ~ 0) */ + rltmp = -slpi / (TWO * rl_b); + } else { /* real cubic */ + rltmp = (-rl_b + SUNRsqrt(disc)) / (THREE * rl_a); + } + } + if (rltmp > (HALF * rl)) rltmp = HALF * rl; + + /* Set new rl (do not allow a reduction by a factor larger than 10) */ + + rlprev = rl; + f1nprv = (*f1normp); + pt1trl = POINT1 * rl; + rl = SUNMAX(pt1trl, rltmp); + nbktrk_l++; + + /* Update unew and re-evaluate function */ + + N_VLinearSum(ONE, kin_mem->kin_uu, rl, 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) ; + + /* Check if rl (lambda) is too small */ + + if (rl < rlmin) { + /* unew sufficiently distinct from uu cannot be found. + 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); + } + + } /* end ALPHA condition loop */ + + + /* ALPHA condition is satisfied. Now check the BETA condition */ + + beta_cond = kin_mem->kin_f1norm + (beta * slpi * rl); + + if ((*f1normp) < beta_cond) { + + /* BETA condition not satisfied */ + + if ((rl == ONE) && (pnorm < kin_mem->kin_mxnewtstep)) { + + do { + + rlprev = rl; + f1nprv = *f1normp; + rl = SUNMIN((TWO * rl), rlmax); + nbktrk_l++; + + N_VLinearSum(ONE, kin_mem->kin_uu, rl, 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); + + alpha_cond = kin_mem->kin_f1norm + (alpha * slpi * rl); + beta_cond = kin_mem->kin_f1norm + (beta * slpi * rl); + + if (kin_mem->kin_printfl > 2) + KINPrintInfo(kin_mem, PRNT_BETA, "KINSOL", "KINLineSearch", + INFO_BETA, *f1normp, beta_cond, rl); + + } while (((*f1normp) <= alpha_cond) && + ((*f1normp) < beta_cond) && (rl < rlmax)); + + } /* end if (rl == ONE) block */ + + if ((rl < ONE) || ((rl > ONE) && (*f1normp > alpha_cond))) { + + rllo = SUNMIN(rl, rlprev); + rldiff = SUNRabs(rlprev - rl); + + do { + + rlinc = HALF * rldiff; + rl = rllo + rlinc; + nbktrk_l++; + + N_VLinearSum(ONE, kin_mem->kin_uu, rl, 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); + + alpha_cond = kin_mem->kin_f1norm + (alpha * slpi * rl); + beta_cond = kin_mem->kin_f1norm + (beta * slpi * rl); + + if (kin_mem->kin_printfl > 2) + KINPrintInfo(kin_mem, PRNT_ALPHABETA, "KINSOL", "KINLineSearch", + INFO_ALPHABETA, *f1normp, alpha_cond, beta_cond, rl); + + if ((*f1normp) > alpha_cond) rldiff = rlinc; + else if (*f1normp < beta_cond) { + rllo = rl; + rldiff = rldiff - rlinc; + } + + } while ((*f1normp > alpha_cond) || + ((*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 */ + + 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); + + /* increment beta-condition failures counter */ + + kin_mem->kin_nbcf++; + + } + + } /* end of if (rl < ONE) block */ + + } /* end of if (f1normp < beta_cond) block */ + + /* Update number of backtracking operations */ + + kin_mem->kin_nbktrk += nbktrk_l; + + if (kin_mem->kin_printfl > 1) + KINPrintInfo(kin_mem, PRNT_ADJ, "KINSOL", "KINLineSearch", INFO_ADJ, nbktrk_l); + + /* scale sFdotJp and sJpnorm by rl * ratio for later use in KINForcingTerm */ + + kin_mem->kin_sFdotJp = kin_mem->kin_sFdotJp * rl * ratio; + kin_mem->kin_sJpnorm = kin_mem->kin_sJpnorm * rl * ratio; + + if ((rl * pnorm) > (POINT99 * kin_mem->kin_mxnewtstep)) *maxStepTaken = SUNTRUE; + + return(KIN_SUCCESS); +} + +/* + * Function : KINConstraint + * + * This routine checks if the proposed solution vector uu + pp + * violates any constraints. If a constraint is violated, then the + * scalar stepmul is determined such that uu + stepmul * pp does + * not violate any constraints. + * + * Note: This routine is called by the functions + * KINLineSearch and KINFullNewton. + */ + +static int KINConstraint(KINMem kin_mem) +{ + N_VLinearSum(ONE, kin_mem->kin_uu, ONE, kin_mem->kin_pp, kin_mem->kin_vtemp1); + + /* if vtemp1[i] violates constraint[i] then vtemp2[i] = 1 + else vtemp2[i] = 0 (vtemp2 is the mask vector) */ + + if(N_VConstrMask(kin_mem->kin_constraints, kin_mem->kin_vtemp1, kin_mem->kin_vtemp2)) return(KIN_SUCCESS); + + /* vtemp1[i] = SUNRabs(pp[i]) */ + + N_VAbs(kin_mem->kin_pp, kin_mem->kin_vtemp1); + + /* consider vtemp1[i] only if vtemp2[i] = 1 (constraint violated) */ + + N_VProd(kin_mem->kin_vtemp2, kin_mem->kin_vtemp1, kin_mem->kin_vtemp1); + + N_VAbs(kin_mem->kin_uu, kin_mem->kin_vtemp2); + kin_mem->kin_stepmul = POINT9 * N_VMinQuotient(kin_mem->kin_vtemp2, kin_mem->kin_vtemp1); + + return(CONSTR_VIOLATED); +} + +/* + * ----------------------------------------------------------------- + * Stopping tests + * ----------------------------------------------------------------- + */ + +/* + * KINStop + * + * This routine checks the current iterate unew to see if the + * system func(unew) = 0 is satisfied by a variety of tests. + * + * strategy is one of KIN_NONE or KIN_LINESEARCH + * sflag is one of KIN_SUCCESS, STEP_TOO_SMALL + */ + +static int KINStop(KINMem kin_mem, booleantype maxStepTaken, int sflag) +{ + realtype fmax, rlength, omexp; + N_Vector delta; + + /* Check for too small a step */ + + if (sflag == STEP_TOO_SMALL) { + + 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; + return(RETRY_ITERATION); + } else { + /* Give up */ + if (kin_mem->kin_globalstrategy == KIN_NONE) return(KIN_STEP_LT_STPTOL); + else return(KIN_LINESEARCH_NONCONV); + } + + } + + /* Check tolerance on scaled function norm at the current iterate */ + + fmax = KINScFNorm(kin_mem, kin_mem->kin_fval, kin_mem->kin_fscale); + + 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); + + /* Check if the scaled distance between the last two steps is too small */ + /* NOTE: pp used as work space to store this distance */ + + delta = kin_mem->kin_pp; + N_VLinearSum(ONE, kin_mem->kin_unew, -ONE, kin_mem->kin_uu, delta); + rlength = KINScSNorm(kin_mem, delta, kin_mem->kin_unew); + + if (rlength <= kin_mem->kin_scsteptol) { + + 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; + return(CONTINUE_ITERATIONS); + } else { + /* give up */ + return(KIN_STEP_LT_STPTOL); + } + + } + + /* Check if the maximum number of iterations is reached */ + + if (kin_mem->kin_nni >= kin_mem->kin_mxiter) return(KIN_MAXITER_REACHED); + + /* 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 */ + + if (kin_mem->kin_inexact_ls) { + + /* We're doing inexact Newton. + Load threshold for reevaluating the Jacobian. */ + + kin_mem->kin_sthrsh = rlength; + + } else if (!(kin_mem->kin_noResMon)) { + + /* We're doing modified Newton and the user did not disable residual monitoring. + Check if it is time to monitor residual. */ + + if ((kin_mem->kin_nni - kin_mem->kin_nnilset_sub) >= kin_mem->kin_msbset_sub) { + + /* Residual monitoring needed */ + + kin_mem->kin_nnilset_sub = kin_mem->kin_nni; + + /* If indicated, estimate new OMEGA value */ + 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 the Jacobian is out of date, update it and retry */ + kin_mem->kin_sthrsh = TWO; + return(CONTINUE_ITERATIONS); + } 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; + } + + } else { + + /* Residual monitoring not needed */ + + /* Reset sthrsh */ + if (kin_mem->kin_retry_nni || kin_mem->kin_update_fnorm_sub) kin_mem->kin_fnorm_sub = kin_mem->kin_fnorm; + if (kin_mem->kin_update_fnorm_sub) kin_mem->kin_update_fnorm_sub = SUNFALSE; + kin_mem->kin_sthrsh = ONE; + + } + + } + + /* if made it to here, then the iteration process is not finished + so return CONTINUE_ITERATIONS flag */ + + return(CONTINUE_ITERATIONS); +} + +/* + * KINForcingTerm + * + * This routine computes eta, the scaling factor in the linear + * convergence stopping tolerance eps when choice #1 or choice #2 + * forcing terms are used. Eta is computed here for all but the + * first iterative step, which is set to the default in routine + * KINSolInit. + * + * This routine was written by Homer Walker of Utah State + * University with subsequent modifications by Allan Taylor @ LLNL. + * + * It is based on the concepts of the paper 'Choosing the forcing + * terms in an inexact Newton method', SIAM J Sci Comput, 17 + * (1996), pp 16 - 32, or Utah State University Research Report + * 6/94/75 of the same title. + */ + +static void KINForcingTerm(KINMem kin_mem, realtype fnormp) +{ + realtype eta_max, eta_min, eta_safe, linmodel_norm; + + eta_max = POINT9; + eta_min = POINT0001; + eta_safe = HALF; + + /* choice #1 forcing term */ + + if (kin_mem->kin_etaflag == KIN_ETACHOICE1) { + + /* 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)); + + /* form the safeguarded for choice #1 */ + + 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); + } + + /* 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; +} + + +/* + * ----------------------------------------------------------------- + * Norm functions + * ----------------------------------------------------------------- + */ + +/* + * Function : KINScFNorm + * + * This routine computes the max norm for scaled vectors. The + * scaling vector is scale, and the vector of which the norm is to + * be determined is vv. The returned value, fnormval, is the + * resulting scaled vector norm. This routine uses N_Vector + * functions from the vector module. + */ + +static realtype KINScFNorm(KINMem kin_mem, N_Vector v, N_Vector scale) +{ + N_VProd(scale, v, kin_mem->kin_vtemp1); + return(N_VMaxNorm(kin_mem->kin_vtemp1)); +} + +/* + * Function : KINScSNorm + * + * This routine computes the max norm of the scaled steplength, ss. + * Here ucur is the current step and usc is the u scale factor. + */ + +static realtype KINScSNorm(KINMem kin_mem, N_Vector v, N_Vector u) +{ + realtype length; + + N_VInv(kin_mem->kin_uscale, kin_mem->kin_vtemp1); + N_VAbs(u, kin_mem->kin_vtemp2); + N_VLinearSum(ONE, kin_mem->kin_vtemp1, ONE, kin_mem->kin_vtemp2, kin_mem->kin_vtemp1); + N_VDiv(v, kin_mem->kin_vtemp1, kin_mem->kin_vtemp1); + + length = N_VMaxNorm(kin_mem->kin_vtemp1); + + return(length); +} + +/* + * ================================================================= + * KINSOL Verbose output functions + * ================================================================= + */ + +/* + * KINPrintInfo + * + * KINPrintInfo is a high level error handling function + * Based on the value info_code, it composes the info message and + * 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, + const char *msgfmt, ...) +{ + va_list ap; + char msg[256], msg1[40]; + char retstr[30]; + int ret; + + /* Initialize argument processing + (msgfrmt is the last required argument) */ + + va_start(ap, msgfmt); + + if (info_code == PRNT_RETVAL) { + + /* If info_code = PRNT_RETVAL, decode the numeric value */ + + ret = va_arg(ap, int); + + switch(ret) { + case KIN_SUCCESS: + sprintf(retstr, "KIN_SUCCESS"); + break; + case KIN_SYSFUNC_FAIL: + sprintf(retstr, "KIN_SYSFUNC_FAIL"); + break; + case KIN_REPTD_SYSFUNC_ERR: + sprintf(retstr, "KIN_REPTD_SYSFUNC_ERR"); + break; + case KIN_STEP_LT_STPTOL: + sprintf(retstr, "KIN_STEP_LT_STPTOL"); + break; + case KIN_LINESEARCH_NONCONV: + sprintf(retstr, "KIN_LINESEARCH_NONCONV"); + break; + case KIN_LINESEARCH_BCFAIL: + sprintf(retstr, "KIN_LINESEARCH_BCFAIL"); + break; + case KIN_MAXITER_REACHED: + sprintf(retstr, "KIN_MAXITER_REACHED"); + break; + case KIN_MXNEWT_5X_EXCEEDED: + sprintf(retstr, "KIN_MXNEWT_5X_EXCEEDED"); + break; + case KIN_LINSOLV_NO_RECOVERY: + sprintf(retstr, "KIN_LINSOLV_NO_RECOVERY"); + break; + case KIN_LSETUP_FAIL: + sprintf(retstr, "KIN_PRECONDSET_FAILURE"); + break; + case KIN_LSOLVE_FAIL: + sprintf(retstr, "KIN_PRECONDSOLVE_FAILURE"); + break; + } + + /* Compose the message */ + + sprintf(msg1, msgfmt, ret); + sprintf(msg,"%s (%s)",msg1,retstr); + + + } else { + + /* Compose the message */ + + vsprintf(msg, msgfmt, ap); + + } + + /* call the info message handler */ + + ihfun(module, fname, msg, ih_data); + + /* finalize argument processing */ + + va_end(ap); + + return; +} + + +/* + * KINInfoHandler + * + * This is the default KINSOL info handling function. + * 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, + char *msg, void *data) +{ + KINMem kin_mem; + + /* 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); + } +#endif + +} + +/* + * ================================================================= + * KINSOL Error Handling functions + * ================================================================= + */ + +/* + * 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 + * 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, + const char *msgfmt, ...) +{ + va_list ap; + char msg[256]; + + /* Initialize the argument pointer variable + (msgfmt is the last required argument to KINProcessError) */ + + va_start(ap, msgfmt); + + /* Compose the message */ + + vsprintf(msg, msgfmt, ap); + + if (kin_mem == NULL) { /* We write to stderr */ +#ifndef NO_FPRINTF_OUTPUT + fprintf(stderr, "\n[%s ERROR] %s\n ", module, fname); + fprintf(stderr, "%s\n\n", msg); +#endif + + } else { /* We can call ehfun */ + ehfun(error_code, module, fname, msg, eh_data); + } + + /* Finalize argument processing */ + va_end(ap); + + return; +} + +/* + * KINErrHandler + * + * This is the default error handling function. + * It sends the error message to the stream pointed to by kin_errfp + */ + +void KINErrHandler(int error_code, const char *module, + const char *function, char *msg, void *data) +{ + KINMem kin_mem; + char err_type[10]; + + /* data points to kin_mem here */ + + kin_mem = (KINMem) data; + + if (error_code == KIN_WARNING) + sprintf(err_type,"WARNING"); + else + sprintf(err_type,"ERROR"); + +#ifndef NO_FPRINTF_OUTPUT + if (kin_mem->kin_errfp != NULL) { + fprintf(kin_mem->kin_errfp,"\n[%s %s] %s\n",module,err_type,function); + fprintf(kin_mem->kin_errfp," %s\n\n",msg); + } +#endif + + return; +} + + +/* + * ======================================================================= + * Picard and fixed point solvers + * ======================================================================= + */ + +/* + * KINPicardAA + * + * 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, + realtype *gamma, realtype *fmaxptr) +{ + 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; + fmax = kin_mem->kin_fnormtol + ONE; + iter = 0; + epsmin = ZERO; + fnormp = -ONE; + + N_VConst(ZERO, gval); + + /* 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; + + while (ret == CONTINUE_ITERATIONS) { + + iter++; + + /* Update the forcing term for the inexact linear solves */ + if (kin_mem->kin_inexact_ls) { + kin_mem->kin_eps = (kin_mem->kin_eta + kin_mem->kin_uround) * kin_mem->kin_fnorm; + 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 + with an eval of the nonlinear residual prior to this call. */ + retval = KINPicardFcnEval(kin_mem, gval, kin_mem->kin_uu, kin_mem->kin_fval); + + if (retval < 0) { + ret = KIN_SYSFUNC_FAIL; + break; + } + + 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); + } + + /* 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; + } + + /* Evaluate function norms */ + fnormp = N_VWL2Norm(kin_mem->kin_fval, kin_mem->kin_fscale); + 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) + KINPrintInfo(kin_mem, PRNT_FMAX, "KINSOL", "KINPicardAA", INFO_FMAX, fmax); + + /* print the current iter, fnorm, and nfe values if printfl > 0 */ + if (kin_mem->kin_printfl > 0) + KINPrintInfo(kin_mem, PRNT_NNI, "KINSOL", "KINPicardAA", INFO_NNI, iter, kin_mem->kin_nfe, kin_mem->kin_fnorm); + + /* Check if the maximum number of iterations is reached */ + if (iter >= kin_mem->kin_mxiter) { + ret = KIN_MAXITER_REACHED; + } + 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) { + /* 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; + + if (kin_mem->kin_printfl > 0) + KINPrintInfo(kin_mem, PRNT_RETVAL, "KINSOL", "KINPicardAA", INFO_RETVAL, ret); + + return(ret); +} + +/* + * KINPicardFcnEval + * + * This routine evaluates the Picard fixed point function + * using the linear solver, gval = u - L^{-1}F(u). + * The function assumes the user has defined L either through + * a user-supplied matvec if using a SPILS solver or through + * a supplied matrix if using a dense solver. This assumption is + * tested by a check on the strategy and the requisite functionality + * 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) +{ + int retval; + + if ((kin_mem->kin_nni - kin_mem->kin_nnilset) >= kin_mem->kin_msbset) { + kin_mem->kin_sthrsh = TWO; + kin_mem->kin_update_fnorm_sub = SUNTRUE; + } + + for(;;){ + + kin_mem->kin_jacCurrent = SUNFALSE; + + if ((kin_mem->kin_sthrsh > ONEPT5) && (kin_mem->kin_lsetup != NULL)) { + retval = kin_mem->kin_lsetup(kin_mem); + kin_mem->kin_jacCurrent = SUNTRUE; + kin_mem->kin_nnilset = kin_mem->kin_nni; + kin_mem->kin_nnilset_sub = kin_mem->kin_nni; + if (retval != 0) return(KIN_LSETUP_FAIL); + } + + /* 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)); + + if (retval == 0) { + /* Update gval = uval + gval since gval = -L^{-1}F(uu) */ + N_VLinearSum(ONE, uval, ONE, gval, gval); + 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 + and matrix information is not current */ + + kin_mem->kin_sthrsh = TWO; + } + +} + + +/* + * KINFP + * + * This routine is the main driver for the fixed point iteration with + * Anderson Acceleration. + */ + +static int KINFP(KINMem kin_mem, long int *iterp, + realtype *R, realtype *gamma, + realtype *fmaxptr) +{ + int retval, ret; + long int iter; + realtype fmax; + N_Vector delta; + + delta = kin_mem->kin_vtemp1; + ret = CONTINUE_ITERATIONS; + fmax = kin_mem->kin_fnormtol + ONE; + iter = 0; + + while (ret == CONTINUE_ITERATIONS) { + + iter++; + + /* 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++; + + if (retval < 0) { + ret = KIN_SYSFUNC_FAIL; + break; + } + + if (kin_mem->kin_m_aa == 0) { + 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); + } + + 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) + 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); + + /* Check if the maximum number of iterations is reached */ + if (iter >= kin_mem->kin_mxiter) { + ret = KIN_MAXITER_REACHED; + } + if (fmax <= kin_mem->kin_fnormtol) { + ret = KIN_SUCCESS; + } + + 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 */ + N_VScale(ONE, kin_mem->kin_unew, kin_mem->kin_uu); + } + + fflush(kin_mem->kin_errfp); + + } /* end of loop; return */ + + *iterp = iter; + + if (kin_mem->kin_printfl > 0) + KINPrintInfo(kin_mem, PRNT_RETVAL, "KINSOL", "KINFP", INFO_RETVAL, ret); + + return(ret); +} + + + /* ----------------------------------------------------------------- + * Stopping tests + * ----------------------------------------------------------------- + */ + + +/* + * ======================================================================== + * Anderson Acceleration + * ======================================================================== + */ + +static int AndersonAcc(KINMem kin_mem, N_Vector gval, N_Vector fv, + N_Vector x, N_Vector xold, + int iter, realtype *R, realtype *gamma) +{ + int i_pt, i, j, lAA, retval; + int *ipt_map; + realtype alfa; + realtype a, b, temp, c, s; + + /* local shortcuts for fused vector operation */ + int nvec=0; + realtype* cv=kin_mem->kin_cv; + 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); + 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 df_new = fval - fval_old */ + N_VLinearSum(ONE, fv, -1.0, 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); + + if (iter == 0) { + N_VScale(ONE, gval, x); + } + 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; + } + 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]); + } + + /* 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]; + } + } + + /* 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] = 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; + + retval = N_VDotProdMulti(lAA, fv, kin_mem->kin_q_aa, gamma); + if (retval != KIN_SUCCESS) return(KIN_VECTOROP_ERR); + + /* set arrays for fused vector operation */ + cv[0] = ONE; + Xv[0] = gval; + 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]; + + cv[nvec] = -gamma[i]; + Xv[nvec] = kin_mem->kin_dg_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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_bbdpre.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_bbdpre.c new file mode 100644 index 0000000..9c6d532 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_bbdpre.c @@ -0,0 +1,582 @@ +/* ----------------------------------------------------------------- + * Programmer(s): David J. Gardner @ LLNL + * Allan Taylor, Alan Hindmarsh, Radu Serban, 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 file contains implementations of routines for a + * band-block-diagonal preconditioner, i.e. a block-diagonal + * matrix with banded blocks, for use with KINSol and the + * KINLS linear solver interface. + * + * Note: With only one process, a banded matrix results + * rather than a b-b-d matrix with banded blocks. Diagonal + * blocking occurs at the process level. + * -----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "kinsol_impl.h" +#include "kinsol_ls_impl.h" +#include "kinsol_bbdpre_impl.h" + +#include <sundials/sundials_math.h> +#include <nvector/nvector_serial.h> + +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + +/* Prototypes of functions KINBBDPrecSetup and KINBBDPrecSolve */ +static int KINBBDPrecSetup(N_Vector uu, N_Vector uscale, + N_Vector fval, N_Vector fscale, + void *pdata); + +static int KINBBDPrecSolve(N_Vector uu, N_Vector uscale, + N_Vector fval, N_Vector fscale, + N_Vector vv, void *pdata); + +/* Prototype for KINBBDPrecFree */ +static int KINBBDPrecFree(KINMem kin_mem); + +/* Prototype for difference quotient jacobian calculation routine */ +static int KBBDDQJac(KBBDPrecData pdata, + N_Vector uu, N_Vector uscale, + N_Vector gu, N_Vector gtemp, N_Vector utemp); + +/*------------------------------------------------------------------ + user-callable functions + ------------------------------------------------------------------*/ + +/*------------------------------------------------------------------ + KINBBDPrecInit + ------------------------------------------------------------------*/ +int KINBBDPrecInit(void *kinmem, sunindextype Nlocal, + sunindextype mudq, sunindextype mldq, + sunindextype mukeep, sunindextype mlkeep, + realtype dq_rel_uu, + KINBBDLocalFn gloc, KINBBDCommFn gcomm) +{ + KINMem kin_mem; + KINLsMem kinls_mem; + KBBDPrecData pdata; + sunindextype muk, mlk, storage_mu, lrw1, liw1; + long int lrw, liw; + int flag; + + if (kinmem == NULL) { + KINProcessError(NULL, KINLS_MEM_NULL, "KINBBDPRE", + "KINBBDPrecInit", MSGBBD_MEM_NULL); + return(KINLS_MEM_NULL); + } + kin_mem = (KINMem) kinmem; + + /* Test if the LS linear solver interface has been created */ + if (kin_mem->kin_lmem == NULL) { + KINProcessError(kin_mem, KINLS_LMEM_NULL, "KINBBDPRE", + "KINBBDPrecInit", MSGBBD_LMEM_NULL); + return(KINLS_LMEM_NULL); + } + kinls_mem = (KINLsMem) kin_mem->kin_lmem; + + /* Test compatibility of NVECTOR package with the BBD preconditioner */ + /* Note: Do NOT need to check for N_VScale since has already been checked for in KINSOL */ + if (kin_mem->kin_vtemp1->ops->nvgetarraypointer == NULL) { + KINProcessError(kin_mem, KINLS_ILL_INPUT, "KINBBDPRE", + "KINBBDPrecInit", MSGBBD_BAD_NVECTOR); + return(KINLS_ILL_INPUT); + } + + /* Allocate data memory */ + pdata = NULL; + pdata = (KBBDPrecData) malloc(sizeof *pdata); + if (pdata == NULL) { + KINProcessError(kin_mem, KINLS_MEM_FAIL, + "KINBBDPRE", "KINBBDPrecInit", MSGBBD_MEM_FAIL); + return(KINLS_MEM_FAIL); + } + + /* Set pointers to gloc and gcomm; load half-bandwidths */ + pdata->kin_mem = kinmem; + pdata->gloc = gloc; + pdata->gcomm = gcomm; + pdata->mudq = SUNMIN(Nlocal-1, SUNMAX(0, mudq)); + pdata->mldq = SUNMIN(Nlocal-1, SUNMAX(0, mldq)); + muk = SUNMIN(Nlocal-1, SUNMAX(0, mukeep)); + mlk = SUNMIN(Nlocal-1, SUNMAX(0, mlkeep)); + pdata->mukeep = muk; + pdata->mlkeep = mlk; + + /* Set extended upper half-bandwidth for PP (required for pivoting) */ + storage_mu = SUNMIN(Nlocal-1, muk+mlk); + + /* Allocate memory for preconditioner matrix */ + pdata->PP = NULL; + pdata->PP = SUNBandMatrixStorage(Nlocal, muk, mlk, storage_mu); + if (pdata->PP == NULL) { + free(pdata); pdata = NULL; + KINProcessError(kin_mem, KINLS_MEM_FAIL, "KINBBDPRE", + "KINBBDPrecInit", MSGBBD_MEM_FAIL); + return(KINLS_MEM_FAIL); + } + + /* Allocate memory for temporary N_Vectors */ + pdata->zlocal = NULL; + pdata->zlocal = N_VNew_Serial(Nlocal); + if (pdata->zlocal == NULL) { + SUNMatDestroy(pdata->PP); + free(pdata); pdata = NULL; + KINProcessError(kin_mem, KINLS_MEM_FAIL, "KINBBDPRE", + "KINBBDPrecInit", MSGBBD_MEM_FAIL); + return(KINLS_MEM_FAIL); + } + + pdata->rlocal = NULL; + pdata->rlocal = N_VNewEmpty_Serial(Nlocal); /* empty vector */ + if (pdata->rlocal == NULL) { + N_VDestroy(pdata->zlocal); + SUNMatDestroy(pdata->PP); + free(pdata); pdata = NULL; + KINProcessError(kin_mem, KINLS_MEM_FAIL, "KINBBDPRE", + "KINBBDPrecInit", MSGBBD_MEM_FAIL); + return(KINLS_MEM_FAIL); + } + + pdata->tempv1 = NULL; + pdata->tempv1 = N_VClone(kin_mem->kin_vtemp1); + if (pdata->tempv1 == NULL) { + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + SUNMatDestroy(pdata->PP); + free(pdata); pdata = NULL; + KINProcessError(kin_mem, KINLS_MEM_FAIL, "KINBBDPRE", + "KINBBDPrecInit", MSGBBD_MEM_FAIL); + return(KINLS_MEM_FAIL); + } + + pdata->tempv2 = NULL; + pdata->tempv2 = N_VClone(kin_mem->kin_vtemp1); + if (pdata->tempv2 == NULL) { + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + N_VDestroy(pdata->tempv1); + SUNMatDestroy(pdata->PP); + free(pdata); pdata = NULL; + KINProcessError(kin_mem, KINLS_MEM_FAIL, "KINBBDPRE", + "KINBBDPrecInit", MSGBBD_MEM_FAIL); + return(KINLS_MEM_FAIL); + } + + pdata->tempv3 = NULL; + pdata->tempv3 = N_VClone(kin_mem->kin_vtemp1); + if (pdata->tempv3 == NULL) { + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + N_VDestroy(pdata->tempv1); + N_VDestroy(pdata->tempv2); + SUNMatDestroy(pdata->PP); + free(pdata); pdata = NULL; + KINProcessError(kin_mem, KINLS_MEM_FAIL, "KINBBDPRE", + "KINBBDPrecInit", MSGBBD_MEM_FAIL); + return(KINLS_MEM_FAIL); + } + + /* Allocate memory for banded linear solver */ + pdata->LS = NULL; + pdata->LS = SUNLinSol_Band(pdata->zlocal, pdata->PP); + if (pdata->LS == NULL) { + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + N_VDestroy(pdata->tempv1); + N_VDestroy(pdata->tempv2); + N_VDestroy(pdata->tempv3); + SUNMatDestroy(pdata->PP); + free(pdata); pdata = NULL; + KINProcessError(kin_mem, KINLS_MEM_FAIL, "KINBBDPRE", + "KINBBDPrecInit", MSGBBD_MEM_FAIL); + return(KINLS_MEM_FAIL); + } + + /* initialize band linear solver object */ + flag = SUNLinSolInitialize(pdata->LS); + if (flag != SUNLS_SUCCESS) { + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + N_VDestroy(pdata->tempv1); + N_VDestroy(pdata->tempv2); + N_VDestroy(pdata->tempv3); + SUNMatDestroy(pdata->PP); + SUNLinSolFree(pdata->LS); + free(pdata); pdata = NULL; + KINProcessError(kin_mem, KINLS_SUNLS_FAIL, "KINBBDPRE", + "KINBBDPrecInit", MSGBBD_SUNLS_FAIL); + return(KINLS_SUNLS_FAIL); + } + + /* Set rel_uu based on input value dq_rel_uu (0 implies default) */ + pdata->rel_uu = (dq_rel_uu > ZERO) ? dq_rel_uu : SUNRsqrt(kin_mem->kin_uround); + + /* Store Nlocal to be used in KINBBDPrecSetup */ + pdata->n_local = Nlocal; + + /* Set work space sizes and initialize nge */ + pdata->rpwsize = 0; + pdata->ipwsize = 0; + if (kin_mem->kin_vtemp1->ops->nvspace) { + N_VSpace(kin_mem->kin_vtemp1, &lrw1, &liw1); + pdata->rpwsize += 3*lrw1; + pdata->ipwsize += 3*liw1; + } + if (pdata->zlocal->ops->nvspace) { + N_VSpace(pdata->zlocal, &lrw1, &liw1); + pdata->rpwsize += lrw1; + pdata->ipwsize += liw1; + } + if (pdata->rlocal->ops->nvspace) { + N_VSpace(pdata->rlocal, &lrw1, &liw1); + pdata->rpwsize += lrw1; + pdata->ipwsize += liw1; + } + if (pdata->PP->ops->space) { + flag = SUNMatSpace(pdata->PP, &lrw, &liw); + pdata->rpwsize += lrw; + pdata->ipwsize += liw; + } + if (pdata->LS->ops->space) { + flag = SUNLinSolSpace(pdata->LS, &lrw, &liw); + pdata->rpwsize += lrw; + pdata->ipwsize += liw; + } + pdata->nge = 0; + + /* make sure pdata is free from any previous allocations */ + if (kinls_mem->pfree != NULL) + kinls_mem->pfree(kin_mem); + + /* Point to the new pdata field in the LS memory */ + kinls_mem->pdata = pdata; + + /* Attach the pfree function */ + kinls_mem->pfree = KINBBDPrecFree; + + /* Attach preconditioner solve and setup functions */ + flag = KINSetPreconditioner(kinmem, KINBBDPrecSetup, + KINBBDPrecSolve); + + return(flag); +} + + +/*------------------------------------------------------------------ + KINBBDPrecGetWorkSpace + ------------------------------------------------------------------*/ +int KINBBDPrecGetWorkSpace(void *kinmem, + long int *lenrwBBDP, + long int *leniwBBDP) +{ + KINMem kin_mem; + KINLsMem kinls_mem; + KBBDPrecData pdata; + + if (kinmem == NULL) { + KINProcessError(NULL, KINLS_MEM_NULL, "KINBBDPRE", + "KINBBDPrecGetWorkSpace", MSGBBD_MEM_NULL); + return(KINLS_MEM_NULL); + } + kin_mem = (KINMem) kinmem; + + if (kin_mem->kin_lmem == NULL) { + KINProcessError(kin_mem, KINLS_LMEM_NULL, "KINBBDPRE", + "KINBBDPrecGetWorkSpace", MSGBBD_LMEM_NULL); + return(KINLS_LMEM_NULL); + } + kinls_mem = (KINLsMem) kin_mem->kin_lmem; + + if (kinls_mem->pdata == NULL) { + KINProcessError(kin_mem, KINLS_PMEM_NULL, "KINBBDPRE", + "KINBBDPrecGetWorkSpace", MSGBBD_PMEM_NULL); + return(KINLS_PMEM_NULL); + } + pdata = (KBBDPrecData) kinls_mem->pdata; + + *lenrwBBDP = pdata->rpwsize; + *leniwBBDP = pdata->ipwsize; + + return(KINLS_SUCCESS); +} + +/*------------------------------------------------------------------ + KINBBDPrecGetNumGfnEvals + -------------------------------------------------------------------*/ +int KINBBDPrecGetNumGfnEvals(void *kinmem, + long int *ngevalsBBDP) +{ + KINMem kin_mem; + KINLsMem kinls_mem; + KBBDPrecData pdata; + + if (kinmem == NULL) { + KINProcessError(NULL, KINLS_MEM_NULL, "KINBBDPRE", + "KINBBDPrecGetNumGfnEvals", MSGBBD_MEM_NULL); + return(KINLS_MEM_NULL); + } + kin_mem = (KINMem) kinmem; + + if (kin_mem->kin_lmem == NULL) { + KINProcessError(kin_mem, KINLS_LMEM_NULL, "KINBBDPRE", + "KINBBDPrecGetNumGfnEvals", MSGBBD_LMEM_NULL); + return(KINLS_LMEM_NULL); + } + kinls_mem = (KINLsMem) kin_mem->kin_lmem; + + if (kinls_mem->pdata == NULL) { + KINProcessError(kin_mem, KINLS_PMEM_NULL, "KINBBDPRE", + "KINBBDPrecGetNumGfnEvals", MSGBBD_PMEM_NULL); + return(KINLS_PMEM_NULL); + } + pdata = (KBBDPrecData) kinls_mem->pdata; + + *ngevalsBBDP = pdata->nge; + + return(KINLS_SUCCESS); +} + + +/*------------------------------------------------------------------ + KINBBDPrecSetup + + KINBBDPrecSetup generates and factors a banded block of the + preconditioner matrix on each processor, via calls to the + user-supplied gloc and gcomm functions. It uses difference + quotient approximations to the Jacobian elements. + + KINBBDPrecSetup calculates a new Jacobian, stored in banded + matrix PP and does an LU factorization of P in place in PP. + + The parameters of KINBBDPrecSetup are as follows: + + uu is the current value of the dependent variable vector, + namely the solutin to func(uu)=0 + + uscale is the dependent variable scaling vector (i.e. uu) + + fval is the vector f(u) + + fscale is the function scaling vector + + bbd_data is the pointer to BBD data set by KINBBDInit. + + Note: The value to be returned by the KINBBDPrecSetup function + is a flag indicating whether it was successful. This value is: + 0 if successful, + > 0 for a recoverable error - step will be retried. + ------------------------------------------------------------------*/ +static int KINBBDPrecSetup(N_Vector uu, N_Vector uscale, + N_Vector fval, N_Vector fscale, + void *bbd_data) +{ + KBBDPrecData pdata; + KINMem kin_mem; + int retval; + + pdata = (KBBDPrecData) bbd_data; + + kin_mem = (KINMem) pdata->kin_mem; + + /* Call KBBDDQJac for a new Jacobian calculation and store in PP */ + retval = SUNMatZero(pdata->PP); + if (retval != 0) { + KINProcessError(kin_mem, -1, "KINBBDPRE", "KINBBDPrecSetup", + MSGBBD_SUNMAT_FAIL); + return(-1); + } + + retval = KBBDDQJac(pdata, uu, uscale, + pdata->tempv1, pdata->tempv2, pdata->tempv3); + if (retval != 0) { + KINProcessError(kin_mem, -1, "KINBBDPRE", "KINBBDPrecSetup", + MSGBBD_FUNC_FAILED); + return(-1); + } + + /* Do LU factorization of P and return error flag */ + retval = SUNLinSolSetup_Band(pdata->LS, pdata->PP); + return(retval); +} + +/*------------------------------------------------------------------ + INBBDPrecSolve + + KINBBDPrecSolve solves a linear system P z = r, with the + banded blocked preconditioner matrix P generated and factored + by KINBBDPrecSetup. Here, r comes in as vv and z is + returned in vv as well. + + The parameters for KINBBDPrecSolve are as follows: + + uu an N_Vector giving the current iterate for the system + + uscale an N_Vector giving the diagonal entries of the + uu scaling matrix + + fval an N_Vector giving the current function value + + fscale an N_Vector giving the diagonal entries of the + function scaling matrix + + vv vector initially set to the right-hand side vector r, but + which upon return contains a solution of the linear system + P*z = r + + bbd_data is the pointer to BBD data set by KINBBDInit. + + Note: The value returned by the KINBBDPrecSolve function is a + flag returned from the lienar solver object. + ------------------------------------------------------------------*/ + +static int KINBBDPrecSolve(N_Vector uu, N_Vector uscale, + N_Vector fval, N_Vector fscale, + N_Vector vv, void *bbd_data) +{ + KBBDPrecData pdata; + realtype *vd; + realtype *zd; + int i, retval; + + pdata = (KBBDPrecData) bbd_data; + + /* Get data pointers */ + vd = N_VGetArrayPointer(vv); + zd = N_VGetArrayPointer(pdata->zlocal); + + /* Attach local data array for vv to rlocal */ + N_VSetArrayPointer(vd, pdata->rlocal); + + /* Call banded solver object to do the work */ + retval = SUNLinSolSolve(pdata->LS, pdata->PP, pdata->zlocal, + pdata->rlocal, ZERO); + + /* Copy result into vv */ + for (i=0; i<pdata->n_local; i++) + vd[i] = zd[i]; + + return(retval); +} + + +/*------------------------------------------------------------------ + KINBBDPrecFree + ------------------------------------------------------------------*/ +static int KINBBDPrecFree(KINMem kin_mem) +{ + KINLsMem kinls_mem; + KBBDPrecData pdata; + + if (kin_mem->kin_lmem == NULL) return(0); + kinls_mem = (KINLsMem) kin_mem->kin_lmem; + + if (kinls_mem->pdata == NULL) return(0); + pdata = (KBBDPrecData) kinls_mem->pdata; + + SUNLinSolFree(pdata->LS); + N_VDestroy(pdata->zlocal); + N_VDestroy(pdata->rlocal); + N_VDestroy(pdata->tempv1); + N_VDestroy(pdata->tempv2); + N_VDestroy(pdata->tempv3); + SUNMatDestroy(pdata->PP); + + free(pdata); + pdata = NULL; + + return(0); +} + + +/*------------------------------------------------------------------ + KBBDDQJac + + This routine generates a banded difference quotient + approximation to the Jacobian of f(u). 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 gloc. By virtue of the band structure, the number of + these calls is bandwidth + 1, where bandwidth = ml + mu + 1. + This routine also assumes that the local elements of a vector + are stored contiguously. + ------------------------------------------------------------------*/ +static int KBBDDQJac(KBBDPrecData pdata, + N_Vector uu, N_Vector uscale, + N_Vector gu, N_Vector gtemp, N_Vector utemp) +{ + KINMem kin_mem; + realtype inc, inc_inv; + int retval; + sunindextype group, i, j, width, ngroups, i1, i2; + realtype *udata, *uscdata, *gudata, *gtempdata, *utempdata, *col_j; + + kin_mem = (KINMem) pdata->kin_mem; + + /* load utemp with uu = predicted solution vector */ + N_VScale(ONE, uu, utemp); + + /* set pointers to the data for all vectors */ + udata = N_VGetArrayPointer(uu); + uscdata = N_VGetArrayPointer(uscale); + gudata = N_VGetArrayPointer(gu); + gtempdata = N_VGetArrayPointer(gtemp); + utempdata = N_VGetArrayPointer(utemp); + + /* Call gcomm and gloc to get base value of g(uu) */ + if (pdata->gcomm != NULL) { + retval = pdata->gcomm(pdata->n_local, uu, kin_mem->kin_user_data); + if (retval != 0) return(retval); + } + + retval = pdata->gloc(pdata->n_local, uu, gu, kin_mem->kin_user_data); + pdata->nge++; + if (retval != 0) return(retval); + + /* Set bandwidth and number of column groups for band differencing */ + width = pdata->mldq + pdata->mudq + 1; + ngroups = SUNMIN(width, pdata->n_local); + + /* Loop over groups */ + for(group = 1; group <= ngroups; group++) { + + /* increment all u_j in group */ + for(j = group - 1; j < pdata->n_local; j += width) { + inc = pdata->rel_uu * SUNMAX(SUNRabs(udata[j]), (ONE / uscdata[j])); + utempdata[j] += inc; + } + + /* Evaluate g with incremented u */ + retval = pdata->gloc(pdata->n_local, utemp, gtemp, kin_mem->kin_user_data); + pdata->nge++; + if (retval != 0) return(retval); + + /* restore utemp, then form and load difference quotients */ + for (j = group - 1; j < pdata->n_local; j += width) { + utempdata[j] = udata[j]; + col_j = SUNBandMatrix_Column(pdata->PP,j); + inc = pdata->rel_uu * SUNMAX(SUNRabs(udata[j]) , (ONE / uscdata[j])); + inc_inv = ONE / inc; + i1 = SUNMAX(0, (j - pdata->mukeep)); + i2 = SUNMIN((j + pdata->mlkeep), (pdata->n_local - 1)); + for (i = i1; i <= i2; i++) + SM_COLUMN_ELEMENT_B(col_j, i, j) = inc_inv * (gtempdata[i] - gudata[i]); + } + } + + return(0); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_bbdpre_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_bbdpre_impl.h new file mode 100644 index 0000000..5e4a3e9 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_bbdpre_impl.h @@ -0,0 +1,82 @@ +/* ----------------------------------------------------------------- + * Programmer(s): David J. Gardner @ LLNL + * Allan Taylor, Alan Hindmarsh, Radu Serban, 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 + * ----------------------------------------------------------------- + * KINBBDPRE module header file (private version) + * -----------------------------------------------------------------*/ + +#ifndef _KINBBDPRE_IMPL_H +#define _KINBBDPRE_IMPL_H + +#include <kinsol/kinsol_bbdpre.h> +#include <sunmatrix/sunmatrix_band.h> +#include <sunlinsol/sunlinsol_band.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*------------------------------------------------------------------ + Definition of KBBDData + ------------------------------------------------------------------*/ + +typedef struct KBBDPrecDataRec { + + /* passed by user to KINBBDPrecAlloc, used by pset/psolve functions */ + sunindextype mudq, mldq, mukeep, mlkeep; + realtype rel_uu; /* relative error for the Jacobian DQ routine */ + KINBBDLocalFn gloc; + KINBBDCommFn gcomm; + + /* set by KINBBDPrecSetup and used by KINBBDPrecSetup and + KINBBDPrecSolve functions */ + sunindextype n_local; + SUNMatrix PP; + SUNLinearSolver LS; + N_Vector rlocal; + N_Vector zlocal; + N_Vector tempv1; + N_Vector tempv2; + N_Vector tempv3; + + /* available for optional output */ + long int rpwsize; + long int ipwsize; + long int nge; + + /* pointer to KINSol memory */ + void *kin_mem; + +} *KBBDPrecData; + +/* + *----------------------------------------------------------------- + * KINBBDPRE error messages + *----------------------------------------------------------------- + */ + +#define MSGBBD_MEM_NULL "KINSOL Memory is NULL." +#define MSGBBD_LMEM_NULL "Linear solver memory is NULL. One of the SPILS linear solvers must be attached." +#define MSGBBD_MEM_FAIL "A memory request failed." +#define MSGBBD_BAD_NVECTOR "A required vector operation is not implemented." +#define MSGBBD_SUNMAT_FAIL "An error arose from a SUNBandMatrix routine." +#define MSGBBD_SUNLS_FAIL "An error arose from a SUNBandLinearSolver routine." +#define MSGBBD_PMEM_NULL "BBD peconditioner memory is NULL. IDABBDPrecInit must be called." +#define MSGBBD_FUNC_FAILED "The gloc or gcomm routine failed in an unrecoverable manner." + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_direct.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_direct.c new file mode 100644 index 0000000..2d04fa6 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_direct.c @@ -0,0 +1,55 @@ +/*----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * 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 + *----------------------------------------------------------------- + * Implementation file for the deprecated direct linear solver interface in + * KINSOL; these routines now just wrap the updated KINSOL generic + * linear solver interface in kinsol_ls.h. + *-----------------------------------------------------------------*/ + +#include <kinsol/kinsol_ls.h> +#include <kinsol/kinsol_direct.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*================================================================= + Exported Functions (wrappers for equivalent routines in kinsol_ls.h) + =================================================================*/ + +int KINDlsSetLinearSolver(void *kinmem, SUNLinearSolver LS, SUNMatrix A) +{ return(KINSetLinearSolver(kinmem, LS, A)); } + +int KINDlsSetJacFn(void *kinmem, KINDlsJacFn jac) +{ return(KINSetJacFn(kinmem, jac)); } + +int KINDlsGetWorkSpace(void *kinmem, long int *lenrw, long int *leniw) +{ return(KINGetLinWorkSpace(kinmem, lenrw, leniw)); } + +int KINDlsGetNumJacEvals(void *kinmem, long int *njevals) +{ return(KINGetNumJacEvals(kinmem, njevals)); } + +int KINDlsGetNumFuncEvals(void *kinmem, long int *nfevals) +{ return(KINGetNumLinFuncEvals(kinmem, nfevals)); } + +int KINDlsGetLastFlag(void *kinmem, long int *flag) +{ return(KINGetLastLinFlag(kinmem, flag)); } + +char *KINDlsGetReturnFlagName(long int flag) +{ return(KINGetLinReturnFlagName(flag)); } + +#ifdef __cplusplus +} +#endif + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_impl.h new file mode 100644 index 0000000..ff4b883 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_impl.h @@ -0,0 +1,487 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Allan Taylor, Alan Hindmarsh, Radu Serban, 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 + * ----------------------------------------------------------------- + * KINSOL solver module header file (private version) + * ----------------------------------------------------------------- + */ + +#ifndef _KINSOL_IMPL_H +#define _KINSOL_IMPL_H + +#include <stdarg.h> + +#include <kinsol/kinsol.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/* + * ================================================================= + * M A I N S O L V E R M E M O R Y B L O C K + * ================================================================= + */ + +/* KINSOL default constants */ + +#define PRINTFL_DEFAULT 0 +#define MXITER_DEFAULT 200 +#define MXNBCF_DEFAULT 10 +#define MSBSET_DEFAULT 10 +#define MSBSET_SUB_DEFAULT 5 + +#define OMEGA_MIN RCONST(0.00001) +#define OMEGA_MAX RCONST(0.9) + +/* + * ----------------------------------------------------------------- + * Types : struct KINMemRec and struct *KINMem + * ----------------------------------------------------------------- + * A variable declaration of type struct *KINMem denotes a + * pointer to a data structure of type struct KINMemRec. The + * KINMemRec structure contains numerous fields that must be + * accessible by KINSOL solver module routines. + * ----------------------------------------------------------------- + */ + +typedef struct KINMemRec { + + 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 */ + realtype kin_scsteptol; /* scaled step length tolerance */ + int kin_globalstrategy; /* choices are KIN_NONE, KIN_LINESEARCH + 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) */ + 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 */ + booleantype kin_noMinEps; /* flag controlling whether or not the value + 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 */ + booleantype kin_callForcingTerm; /* flag set if using either KIN_ETACHOICE1 + or KIN_ETACHOICE2 */ + booleantype kin_noResMon; /* flag indicating if the nonlinear + residual monitoring scheme should be + used */ + booleantype kin_retry_nni; /* flag indicating if nonlinear iteration + 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) */ + + realtype kin_mxnewtstep; /* maximum allowable scaled step length */ + realtype kin_mxnstepin; /* input (or preset) value for mxnewtstep */ + realtype kin_sqrt_relfunc; /* relative error bound for func(u) */ + realtype kin_stepl; /* scaled length of current step */ + realtype kin_stepmul; /* step scaling factor */ + 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) */ + realtype kin_eta_alpha; /* alpha value used in eta calculation + (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 */ + + /* 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 */ + 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 */ + long int kin_nbktrk; /* number of backtracks performed by + KINLineSearch */ + long int kin_ncscmx; /* number of consecutive steps of size + 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) */ + 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)) */ + 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_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 */ + 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 */ + booleantype kin_aamem_aa; /* sets additional memory needed for Anderson Acc */ + booleantype kin_setstop_aa; /* determines whether user will set stopping criterion */ + realtype *kin_cv; /* scalar array for fused vector operations */ + N_Vector *kin_Xv; /* vector array for fused vector operations */ + + /* space requirements for vector storage */ + + sunindextype kin_lrw1; /* number of realtype-sized memory blocks needed + for a single N_Vector */ + sunindextype kin_liw1; /* number of int-sized memory blocks needed for + a single N_Vecotr */ + long int kin_lrw; /* total number of realtype-sized memory blocks + needed for all KINSOL work vectors */ + long int kin_liw; /* total number of int-sized memory blocks needed + 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_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) */ + + void *kin_lmem; /* pointer to linear solver memory block */ + + realtype kin_fnorm; /* value of L2-norm of fscale*fval */ + realtype kin_f1norm; /* f1norm = 0.5*(fnorm)^2 */ + realtype kin_sFdotJp; /* value of scaled F(u) vector (fscale*fval) + dotted with scaled J(u)*pp vector (set by lsolve) */ + realtype kin_sJpnorm; /* value of L2-norm of fscale*(J(u)*pp) + (set by lsolve) */ + + 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 + 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 + * variables sFdotJp and sJpnorm by a factor rl (lambda) that is + * chosen by the line search algorithm such that the sclaed Newton + * step satisfies the following conditions: + * + * F(u_k+1) <= F(u_k) + alpha*(F(u_k)^T * J(u_k))*p*rl + * + * F(u_k+1) >= F(u_k) + beta*(F(u_k)^T * J(u_k))*p*rl + * + * where alpha = 1.0e-4, beta = 0.9, u_k+1 = u_k + rl*p, + * 0 < rl <= 1, J denotes the system Jacobian, and F represents + * the nonliner system function. + * ----------------------------------------------------------------- + */ + + booleantype kin_MallocDone; /* flag indicating if KINMalloc has been + called yet */ + + /* message files */ + /*------------------------------------------- + Error handler function and error ouput file + -------------------------------------------*/ + + KINErrHandlerFn kin_ehfun; /* Error messages are handled by ehfun */ + void *kin_eh_data; /* dats pointer passed to ehfun */ + FILE *kin_errfp; /* KINSOL error messages are sent to errfp */ + + KINInfoHandlerFn kin_ihfun; /* Info messages are handled by ihfun */ + void *kin_ih_data; /* dats pointer passed to ihfun */ + FILE *kin_infofp; /* where KINSol info messages are sent */ + +} *KINMem; + +/* + * ================================================================= + * I N T E R F A C E T O L I N E A R S O L V E R + * ================================================================= + */ + +/* + * ----------------------------------------------------------------- + * Function : int (*kin_linit)(KINMem kin_mem) + * ----------------------------------------------------------------- + * kin_linit initializes solver-specific data structures (including + * variables used as counters or for storing statistical information), + * but system memory allocation should be done by the subroutine + * that actually initializes the environment for liner solver + * package. If the linear system is to be preconditioned, then the + * variable setupNonNull (type booleantype) should be set to SUNTRUE + * (predefined constant) and the kin_lsetup routine should be + * appropriately defined. + * + * kinmem pointer to an internal memory block allocated during + * prior calls to KINCreate and KINMalloc + * + * If the necessary variables have been successfully initialized, + * then the kin_linit function should return 0 (zero). Otherwise, + * the subroutine should indicate a failure has occurred by + * returning a non-zero integer value. + * ----------------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------- + * Function : int (*kin_lsetup)(KINMem kin_mem) + * ----------------------------------------------------------------- + * kin_lsetup interfaces with the user-supplied pset subroutine (the + * preconditioner setup routine), and updates relevant variable + * values (see KINSpgmrSetup/KINSpbcgSetup). Simply stated, the + * kin_lsetup routine prepares the linear solver for a subsequent + * call to the user-supplied kin_lsolve function. + * + * kinmem pointer to an internal memory block allocated during + * prior calls to KINCreate and KINMalloc + * + * If successful, the kin_lsetup routine should return 0 (zero). + * Otherwise it should return a non-zero value. + * ----------------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------- + * Function : int (*kin_lsolve)(KINMem kin_mem, N_Vector xx, + * N_Vector bb, realtype *sJpnorm, realtype *sFdotJp) + * ----------------------------------------------------------------- + * kin_lsolve interfaces with the subroutine implementing the + * numerical method to be used to solve the linear system J*xx = bb, + * and must increment the relevant counter variable values in + * addition to computing certain values used by the global strategy + * and forcing term routines (see KINInexactNewton, KINLineSearch, + * KINForcingTerm, and KINSpgmrSolve/KINSpbcgSolve). + * + * kinmem pointer to an internal memory block allocated during + * prior calls to KINCreate and KINMalloc + * + * xx vector (type N_Vector) set to initial guess by kin_lsolve + * routine prior to calling the linear solver, but which upon + * return contains an approximate solution of the linear + * system J*xx = bb, where J denotes the system Jacobian + * + * bb vector (type N_Vector) set to -func(u) (negative of the + * value of the system function evaluated at the current + * iterate) by KINLinSolDrv before kin_lsolve is called + * + * sJpnorm holds the value of the L2-norm (Euclidean norm) of + * fscale*(J(u)*pp) upon return + * + * sFdotJp holds the value of the scaled F(u) (fscale*F) dotted + * with the scaled J(u)*pp vector upon return + * + * If successful, the kin_lsolve routine should return 0 (zero). + * Otherwise it should return a positive value if a re-evaluation + * of the lsetup function could recover, or a negative value if + * no such recovery is possible. + * ----------------------------------------------------------------- + */ + +/* + * ----------------------------------------------------------------- + * Function : int (*kin_lfree)(KINMem kin_mem) + * ----------------------------------------------------------------- + * 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 + * success, nonzero on failure. + * + * kinmem pointer to an internal memory block allocated during + * prior calls to KINCreate and KINMalloc + * ----------------------------------------------------------------- + */ + +/* + * ================================================================= + * K I N S O L I N T E R N A L F U N C T I O N S + * ================================================================= + */ + + +/* High level error handler */ + +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); + + +/* High level info handler */ + +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); + +/* + * ================================================================= + * K I N S O L E R R O R M E S S A G E S + * ================================================================= + */ + +#define MSG_MEM_FAIL "A memory request failed." +#define MSG_NO_MEM "kinsol_mem = NULL illegal." +#define MSG_BAD_NVECTOR "A required vector operation is not implemented." +#define MSG_FUNC_NULL "func = NULL illegal." +#define MSG_NO_MALLOC "Attempt to call before KINMalloc illegal." + +#define MSG_BAD_PRINTFL "Illegal value for printfl." +#define MSG_BAD_MXITER "Illegal value for mxiter." +#define MSG_BAD_MSBSET "Illegal msbset < 0." +#define MSG_BAD_MSBSETSUB "Illegal msbsetsub < 0." +#define MSG_BAD_ETACHOICE "Illegal value for etachoice." +#define MSG_BAD_ETACONST "eta out of range." +#define MSG_BAD_GAMMA "gamma out of range." +#define MSG_BAD_ALPHA "alpha out of range." +#define MSG_BAD_MXNEWTSTEP "Illegal mxnewtstep < 0." +#define MSG_BAD_RELFUNC "relfunc < 0 illegal." +#define MSG_BAD_FNORMTOL "fnormtol < 0 illegal." +#define MSG_BAD_SCSTEPTOL "scsteptol < 0 illegal." +#define MSG_BAD_MXNBCF "mxbcf < 0 illegal." +#define MSG_BAD_CONSTRAINTS "Illegal values in constraints vector." +#define MSG_BAD_OMEGA "scalars < 0 illegal." +#define MSG_BAD_MAA "maa < 0 illegal." +#define MSG_ZERO_MAA "maa = 0 illegal." + +#define MSG_LSOLV_NO_MEM "The linear solver memory pointer is NULL." +#define MSG_UU_NULL "uu = NULL illegal." +#define MSG_BAD_GLSTRAT "Illegal value for global strategy." +#define MSG_BAD_USCALE "uscale = NULL illegal." +#define MSG_USCALE_NONPOSITIVE "uscale has nonpositive elements." +#define MSG_BAD_FSCALE "fscale = NULL illegal." +#define MSG_FSCALE_NONPOSITIVE "fscale has nonpositive elements." +#define MSG_CONSTRAINTS_NOTOK "Constraints not allowed with fixed point or Picard iterations" +#define MSG_INITIAL_CNSTRNT "Initial guess does NOT meet constraints." +#define MSG_LINIT_FAIL "The linear solver's init routine failed." + +#define MSG_SYSFUNC_FAILED "The system function failed in an unrecoverable manner." +#define MSG_SYSFUNC_FIRST "The system function failed at the first call." +#define MSG_LSETUP_FAILED "The linear solver's setup function failed in an unrecoverable manner." +#define MSG_LSOLVE_FAILED "The linear solver's solve function failed in an unrecoverable manner." +#define MSG_LINSOLV_NO_RECOVERY "The linear solver's solve function failed recoverably, but the Jacobian data is already current." +#define MSG_LINESEARCH_NONCONV "The line search algorithm was unable to find an iterate sufficiently distinct from the current iterate." +#define MSG_LINESEARCH_BCFAIL "The line search algorithm was unable to satisfy the beta-condition for nbcfails iterations." +#define MSG_MAXITER_REACHED "The maximum number of iterations was reached before convergence." +#define MSG_MXNEWT_5X_EXCEEDED "Five consecutive steps have been taken that satisfy a scaled step length test." +#define MSG_SYSFUNC_REPTD "Unable to correct repeated recoverable system function errors." +#define MSG_NOL_FAIL "Unable to find user's Linear Jacobian, which is required for the KIN_PICARD Strategy" + +/* + * ================================================================= + * K I N S O L I N F O M E S S A G E S + * ================================================================= + */ + +#define INFO_RETVAL "Return value: %d" +#define INFO_ADJ "no. of lambda adjustments = %ld" + +#if defined(SUNDIALS_EXTENDED_PRECISION) + +#define INFO_NNI "nni = %4ld nfe = %6ld fnorm = %26.16Lg" +#define INFO_TOL "scsteptol = %12.3Lg fnormtol = %12.3Lg" +#define INFO_FMAX "scaled f norm (for stopping) = %12.3Lg" +#define INFO_PNORM "pnorm = %12.4Le" +#define INFO_PNORM1 "(ivio=1) pnorm = %12.4Le" +#define INFO_FNORM "fnorm(L2) = %20.8Le" +#define INFO_LAM "min_lam = %11.4Le f1norm = %11.4Le pnorm = %11.4Le" +#define INFO_ALPHA "fnorm = %15.8Le f1norm = %15.8Le alpha_cond = %15.8Le lam = %15.8Le" +#define INFO_BETA "f1norm = %15.8Le beta_cond = %15.8Le lam = %15.8Le" +#define INFO_ALPHABETA "f1norm = %15.8Le alpha_cond = %15.8Le beta_cond = %15.8Le lam = %15.8Le" + +#elif defined(SUNDIALS_DOUBLE_PRECISION) + +#define INFO_NNI "nni = %4ld nfe = %6ld fnorm = %26.16lg" +#define INFO_TOL "scsteptol = %12.3lg fnormtol = %12.3lg" +#define INFO_FMAX "scaled f norm (for stopping) = %12.3lg" +#define INFO_PNORM "pnorm = %12.4le" +#define INFO_PNORM1 "(ivio=1) pnorm = %12.4le" +#define INFO_FNORM "fnorm(L2) = %20.8le" +#define INFO_LAM "min_lam = %11.4le f1norm = %11.4le pnorm = %11.4le" +#define INFO_ALPHA "fnorm = %15.8le f1norm = %15.8le alpha_cond = %15.8le lam = %15.8le" +#define INFO_BETA "f1norm = %15.8le beta_cond = %15.8le lam = %15.8le" +#define INFO_ALPHABETA "f1norm = %15.8le alpha_cond = %15.8le beta_cond = %15.8le lam = %15.8le" + +#else + +#define INFO_NNI "nni = %4ld nfe = %6ld fnorm = %26.16g" +#define INFO_TOL "scsteptol = %12.3g fnormtol = %12.3g" +#define INFO_FMAX "scaled f norm (for stopping) = %12.3g" +#define INFO_PNORM "pnorm = %12.4e" +#define INFO_PNORM1 "(ivio=1) pnorm = %12.4e" +#define INFO_FNORM "fnorm(L2) = %20.8e" +#define INFO_LAM "min_lam = %11.4e f1norm = %11.4e pnorm = %11.4e" +#define INFO_ALPHA "fnorm = %15.8e f1norm = %15.8e alpha_cond = %15.8e lam = %15.8e" +#define INFO_BETA "f1norm = %15.8e beta_cond = %15.8e lam = %15.8e" +#define INFO_ALPHABETA "f1norm = %15.8e alpha_cond = %15.8e beta_cond = %15.8e lam = %15.8e" + +#endif + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_io.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_io.c new file mode 100644 index 0000000..5a5138f --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_io.c @@ -0,0 +1,1060 @@ +/* + * ----------------------------------------------------------------- + * $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 + * 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 optional input and output + * functions for the KINSOL solver. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "kinsol_impl.h" +#include <sundials/sundials_types.h> +#include <sundials/sundials_math.h> + +#define ZERO RCONST(0.0) +#define POINT1 RCONST(0.1) +#define ONETHIRD RCONST(0.3333333333333333) +#define HALF RCONST(0.5) +#define TWOTHIRDS RCONST(0.6666666666666667) +#define POINT9 RCONST(0.9) +#define ONE RCONST(1.0) +#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 + * ----------------------------------------------------------------- + */ + +int KINSetErrHandlerFn(void *kinmem, KINErrHandlerFn ehfun, void *eh_data) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetErrHandlerFn", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + + kin_mem->kin_ehfun = ehfun; + kin_mem->kin_eh_data = eh_data; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINSetErrFile + * ----------------------------------------------------------------- + */ + +int KINSetErrFile(void *kinmem, FILE *errfp) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetErrFile", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + kin_mem->kin_errfp = errfp; + + return(KIN_SUCCESS); +} + +#define errfp (kin_mem->kin_errfp) + +/* + * ----------------------------------------------------------------- + * Function : KINSetPrintLevel + * ----------------------------------------------------------------- + */ + +int KINSetPrintLevel(void *kinmem, int printfl) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetPrintLevel", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + + if ((printfl < 0) || (printfl > 3)) { + KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetPrintLevel", MSG_BAD_PRINTFL); + return(KIN_ILL_INPUT); + } + + kin_mem->kin_printfl = printfl; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * KINSetInfoHandlerFn + * ----------------------------------------------------------------- + */ + +int KINSetInfoHandlerFn(void *kinmem, KINInfoHandlerFn ihfun, void *ih_data) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetInfoHandlerFn", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + + kin_mem->kin_ihfun = ihfun; + kin_mem->kin_ih_data = ih_data; + + return(KIN_SUCCESS); +} + + +/* + * ----------------------------------------------------------------- + * Function : KINSetInfoFile + * ----------------------------------------------------------------- + */ + +int KINSetInfoFile(void *kinmem, FILE *infofp) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetInfoFile", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + kin_mem->kin_infofp = infofp; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINSetUserData + * ----------------------------------------------------------------- + */ + +int KINSetUserData(void *kinmem, void *user_data) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetUserData", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + kin_mem->kin_user_data = user_data; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINSetMAA + * ----------------------------------------------------------------- + */ + +int KINSetMAA(void *kinmem, long int maa) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetMAA", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + + if (maa < 0) { + KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetMAA", MSG_BAD_MAA); + return(KIN_ILL_INPUT); + } + + 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 : KINSetAAStopCrit + * ----------------------------------------------------------------- + */ + +/* CSW: This function is currently not supported. + +int KINSetAAStopCrit(void *kinmem, booleantype setstop) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetAAStopCrit", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + kin_mem->kin_setstop_aa = setstop; + + return(KIN_SUCCESS); +} +*/ + +/* + * ----------------------------------------------------------------- + * Function : KINSetNumMaxIters + * ----------------------------------------------------------------- + */ + +int KINSetNumMaxIters(void *kinmem, long int mxiter) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetNumMaxIters", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + + if (mxiter < 0) { + KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetNumMaxIters", MSG_BAD_MXITER); + return(KIN_ILL_INPUT); + } + + if (mxiter == 0) + kin_mem->kin_mxiter = MXITER_DEFAULT; + else + kin_mem->kin_mxiter = mxiter; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINSetNoInitSetup + * ----------------------------------------------------------------- + */ + +int KINSetNoInitSetup(void *kinmem, booleantype noInitSetup) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetNoInitSetup", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + kin_mem->kin_noInitSetup = noInitSetup; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINSetNoResMon + * ----------------------------------------------------------------- + */ + +int KINSetNoResMon(void *kinmem, booleantype noResMon) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetNoResMon", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + kin_mem->kin_noResMon = noResMon; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINSetMaxSetupCalls + * ----------------------------------------------------------------- + */ + +int KINSetMaxSetupCalls(void *kinmem, long int msbset) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetMaxSetupCalls", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + + if (msbset < 0) { + KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetMaxSetupCalls", MSG_BAD_MSBSET); + return(KIN_ILL_INPUT); + } + + if (msbset == 0) + kin_mem->kin_msbset = MSBSET_DEFAULT; + else + kin_mem->kin_msbset = msbset; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINSetMaxSubSetupCalls + * ----------------------------------------------------------------- + */ + +int KINSetMaxSubSetupCalls(void *kinmem, long int msbsetsub) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetMaxSubSetupCalls", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + + if (msbsetsub < 0) { + 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 + kin_mem->kin_msbset_sub = msbsetsub; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINSetEtaForm + * ----------------------------------------------------------------- + */ + +int KINSetEtaForm(void *kinmem, int etachoice) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetEtaForm", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + + if ((etachoice != KIN_ETACONSTANT) && + (etachoice != KIN_ETACHOICE1) && + (etachoice != KIN_ETACHOICE2)) { + KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetEtaForm", MSG_BAD_ETACHOICE); + return(KIN_ILL_INPUT); + } + + kin_mem->kin_etaflag = etachoice; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINSetEtaConstValue + * ----------------------------------------------------------------- + */ + +int KINSetEtaConstValue(void *kinmem, realtype eta) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetEtaConstValue", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + + if ((eta < ZERO) || (eta > ONE)) { + KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetEtaConstValue", MSG_BAD_ETACONST); + return(KIN_ILL_INPUT); + } + + if (eta == ZERO) + kin_mem->kin_eta = POINT1; + else + kin_mem->kin_eta = eta; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINSetEtaParams + * ----------------------------------------------------------------- + */ + +int KINSetEtaParams(void *kinmem, realtype egamma, realtype ealpha) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetEtaParams", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + + if ((ealpha <= ONE) || (ealpha > TWO)) + if (ealpha != ZERO) { + KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetEtaParams", MSG_BAD_ALPHA); + return(KIN_ILL_INPUT); + } + + if (ealpha == ZERO) + kin_mem->kin_eta_alpha = TWO; + else + kin_mem->kin_eta_alpha = ealpha; + + if ((egamma <= ZERO) || (egamma > ONE)) + if (egamma != ZERO) { + KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetEtaParams", MSG_BAD_GAMMA); + return(KIN_ILL_INPUT); + } + + if (egamma == ZERO) + kin_mem->kin_eta_gamma = POINT9; + else + kin_mem->kin_eta_gamma = egamma; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINSetResMonParams + * ----------------------------------------------------------------- + */ + +int KINSetResMonParams(void *kinmem, realtype omegamin, realtype omegamax) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetResMonParams", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + + /* check omegamin */ + + if (omegamin < ZERO) { + KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetResMonParams", MSG_BAD_OMEGA); + return(KIN_ILL_INPUT); + } + + if (omegamin == ZERO) + kin_mem->kin_omega_min = OMEGA_MIN; + else + kin_mem->kin_omega_min = omegamin; + + /* check omegamax */ + + if (omegamax < ZERO) { + KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetResMonParams", MSG_BAD_OMEGA); + return(KIN_ILL_INPUT); + } + + if (omegamax == ZERO) { + + if (kin_mem->kin_omega_min > OMEGA_MAX) { + KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetResMonParams", MSG_BAD_OMEGA); + return(KIN_ILL_INPUT); + } + else kin_mem->kin_omega_max = OMEGA_MAX; + + } else { + + if (kin_mem->kin_omega_min > omegamax) { + KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetResMonParams", MSG_BAD_OMEGA); + return(KIN_ILL_INPUT); + } + else kin_mem->kin_omega_max = omegamax; + + } + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINSetResMonConstValue + * ----------------------------------------------------------------- + */ + +int KINSetResMonConstValue(void *kinmem, realtype omegaconst) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetResMonConstValue", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + + /* check omegaconst */ + + if (omegaconst < ZERO) { + KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetResMonConstValue", MSG_BAD_OMEGA); + return(KIN_ILL_INPUT); + } + + /* Load omega value. A value of 0 will force using omega_min and omega_max */ + kin_mem->kin_omega = omegaconst; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINSetNoMinEps + * ----------------------------------------------------------------- + */ + +int KINSetNoMinEps(void *kinmem, booleantype noMinEps) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetNoMinEps", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + kin_mem->kin_noMinEps = noMinEps; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINSetMaxNewtonStep + * ----------------------------------------------------------------- + */ + +int KINSetMaxNewtonStep(void *kinmem, realtype mxnewtstep) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetMaxNewtonStep", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + + if (mxnewtstep < ZERO) { + KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetMaxNewtonStep", MSG_BAD_MXNEWTSTEP); + return(KIN_ILL_INPUT); + } + + /* Note: passing a value of 0.0 will use the default + value (computed in KINSolInit) */ + + kin_mem->kin_mxnstepin = mxnewtstep; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINSetMaxBetaFails + * ----------------------------------------------------------------- + */ + +int KINSetMaxBetaFails(void *kinmem, long int mxnbcf) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetMaxBetaFails", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + + if (mxnbcf < 0) { + KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetMaxBetaFails", MSG_BAD_MXNBCF); + return(KIN_ILL_INPUT); + } + + if (mxnbcf == 0) + kin_mem->kin_mxnbcf = MXNBCF_DEFAULT; + else + kin_mem->kin_mxnbcf = mxnbcf; + + return(KIN_SUCCESS); + +} + +/* + * ----------------------------------------------------------------- + * Function : KINSetRelErrFunc + * ----------------------------------------------------------------- + */ + +int KINSetRelErrFunc(void *kinmem, realtype relfunc) +{ + KINMem kin_mem; + realtype uround; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetRelErrFunc", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + + if (relfunc < ZERO) { + KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetRelErrFunc", MSG_BAD_RELFUNC); + return(KIN_ILL_INPUT); + } + + if (relfunc == ZERO) { + uround = kin_mem->kin_uround; + kin_mem->kin_sqrt_relfunc = SUNRsqrt(uround); + } else { + kin_mem->kin_sqrt_relfunc = SUNRsqrt(relfunc); + } + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINSetFuncNormTol + * ----------------------------------------------------------------- + */ + +int KINSetFuncNormTol(void *kinmem, realtype fnormtol) +{ + KINMem kin_mem; + realtype uround; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetFuncNormTol", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + + if (fnormtol < ZERO) { + KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetFuncNormTol", MSG_BAD_FNORMTOL); + return(KIN_ILL_INPUT); + } + + if (fnormtol == ZERO) { + uround = kin_mem->kin_uround; + kin_mem->kin_fnormtol = SUNRpowerR(uround,ONETHIRD); + } else { + kin_mem->kin_fnormtol = fnormtol; + } + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINSetScaledStepTol + * ----------------------------------------------------------------- + */ + +int KINSetScaledStepTol(void *kinmem, realtype scsteptol) +{ + KINMem kin_mem; + realtype uround; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetScaledStepTol", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + + if (scsteptol < ZERO) { + KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetScaledStepTol", MSG_BAD_SCSTEPTOL); + return(KIN_ILL_INPUT); + } + + if (scsteptol == ZERO) { + uround = kin_mem->kin_uround; + kin_mem->kin_scsteptol = SUNRpowerR(uround,TWOTHIRDS); + } else { + kin_mem->kin_scsteptol = scsteptol; + } + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINSetConstraints + * ----------------------------------------------------------------- + */ + +int KINSetConstraints(void *kinmem, N_Vector constraints) +{ + KINMem kin_mem; + realtype temptest; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetConstraints", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + + if (constraints == NULL) { + if (kin_mem->kin_constraintsSet) { + N_VDestroy(kin_mem->kin_constraints); + lrw -= lrw1; + liw -= liw1; + } + kin_mem->kin_constraintsSet = SUNFALSE; + return(KIN_SUCCESS); + } + + /* Check the constraints vector */ + + temptest = N_VMaxNorm(constraints); + if (temptest > TWOPT5){ + KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetConstraints", MSG_BAD_CONSTRAINTS); + return(KIN_ILL_INPUT); + } + + if (!kin_mem->kin_constraintsSet) { + kin_mem->kin_constraints = N_VClone(constraints); + lrw += lrw1; + liw += liw1; + kin_mem->kin_constraintsSet = SUNTRUE; + } + + /* Load the constraint vector */ + + N_VScale(ONE, constraints, kin_mem->kin_constraints); + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINSetSysFunc + * ----------------------------------------------------------------- + */ + +int KINSetSysFunc(void *kinmem, KINSysFn func) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINSetSysFunc", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + + if (func == NULL) { + KINProcessError(NULL, KIN_ILL_INPUT, "KINSOL", "KINSetSysFunc", MSG_FUNC_NULL); + return(KIN_ILL_INPUT); + } + + kin_mem->kin_func = 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 + * ================================================================= + */ + +/* + * ----------------------------------------------------------------- + * Function : KINGetWorkSpace + * ----------------------------------------------------------------- + */ + +int KINGetWorkSpace(void *kinmem, long int *lenrw, long int *leniw) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINGetWorkSpace", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + + *lenrw = lrw; + *leniw = liw; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINGetNumNonlinSolvIters + * ----------------------------------------------------------------- + */ + +int KINGetNumNonlinSolvIters(void *kinmem, long int *nniters) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINGetNumNonlinSolvIters", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + *nniters = nni; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINGetNumFuncEvals + * ----------------------------------------------------------------- + */ + +int KINGetNumFuncEvals(void *kinmem, long int *nfevals) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINGetNumFuncEvals", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + *nfevals = nfe; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINGetNumBetaCondFails + * ----------------------------------------------------------------- + */ + +int KINGetNumBetaCondFails(void *kinmem, long int *nbcfails) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINGetNumBetaCondFails", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + *nbcfails = nbcf; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINGetNumBacktrackOps + * ----------------------------------------------------------------- + */ + +int KINGetNumBacktrackOps(void *kinmem, long int *nbacktr) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINGetNumBacktrackOps", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + *nbacktr = nbktrk; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINGetFuncNorm + * ----------------------------------------------------------------- + */ + +int KINGetFuncNorm(void *kinmem, realtype *funcnorm) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINGetFuncNorm", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + *funcnorm = kin_mem->kin_fnorm; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINGetStepLength + * ----------------------------------------------------------------- + */ + +int KINGetStepLength(void *kinmem, realtype *steplength) +{ + KINMem kin_mem; + + if (kinmem == NULL) { + KINProcessError(NULL, KIN_MEM_NULL, "KINSOL", "KINGetStepLength", MSG_NO_MEM); + return(KIN_MEM_NULL); + } + + kin_mem = (KINMem) kinmem; + *steplength = stepl; + + return(KIN_SUCCESS); +} + +/* + * ----------------------------------------------------------------- + * Function : KINGetReturnFlagName + * ----------------------------------------------------------------- + */ + +char *KINGetReturnFlagName(long int flag) +{ + char *name; + + name = (char *)malloc(24*sizeof(char)); + + switch(flag) { + case KIN_SUCCESS: + sprintf(name, "KIN_SUCCESS"); + break; + case KIN_INITIAL_GUESS_OK: + sprintf(name, "KIN_INITIAL_GUESS_OK"); + break; + case KIN_STEP_LT_STPTOL: + sprintf(name, "KIN_STEP_LT_STPTOL"); + break; + case KIN_WARNING: + sprintf(name, "KIN_WARNING"); + break; + case KIN_MEM_NULL: + sprintf(name, "KIN_MEM_NULL"); + break; + case KIN_ILL_INPUT: + sprintf(name, "KIN_ILL_INPUT"); + break; + case KIN_NO_MALLOC: + sprintf(name, "KIN_NO_MALLOC"); + break; + case KIN_MEM_FAIL: + sprintf(name, "KIN_MEM_FAIL"); + break; + case KIN_LINESEARCH_NONCONV: + sprintf(name, "KIN_LINESEARCH_NONCONV"); + break; + case KIN_MAXITER_REACHED: + sprintf(name, "KIN_MAXITER_REACHED"); + break; + case KIN_MXNEWT_5X_EXCEEDED: + sprintf(name, "KIN_MXNEWT_5X_EXCEEDED"); + break; + case KIN_LINESEARCH_BCFAIL: + sprintf(name, "KIN_LINESEARCH_BCFAIL"); + break; + case KIN_LINSOLV_NO_RECOVERY: + sprintf(name, "KIN_LINSOLV_NO_RECOVERY"); + break; + case KIN_LINIT_FAIL: + sprintf(name, "KIN_LINIT_FAIL"); + break; + case KIN_LSETUP_FAIL: + sprintf(name, "KIN_LSETUP_FAIL"); + break; + case KIN_LSOLVE_FAIL: + sprintf(name, "KIN_LSOLVE_FAIL"); + break; + default: + sprintf(name, "NONE"); + } + + return(name); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_ls.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_ls.c new file mode 100644 index 0000000..8f5f611 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_ls.c @@ -0,0 +1,1335 @@ +/*----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * David J. Gardner, Radu Serban 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 + *----------------------------------------------------------------- + * Implementation file for KINSOL's linear solver interface. + *-----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> + +#include "kinsol_impl.h" +#include "kinsol_ls_impl.h" + +#include <sundials/sundials_math.h> +#include <sunmatrix/sunmatrix_band.h> +#include <sunmatrix/sunmatrix_dense.h> +#include <sunmatrix/sunmatrix_sparse.h> + +/* constants */ +#define MIN_INC_MULT RCONST(1000.0) +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) +#define TWO RCONST(2.0) + + +/*================================================================== + KINLS Exported functions -- Required + ==================================================================*/ + +/*--------------------------------------------------------------- + KINSetLinearSolver specifies the linear solver + ---------------------------------------------------------------*/ +int KINSetLinearSolver(void *kinmem, SUNLinearSolver LS, SUNMatrix A) +{ + KINMem kin_mem; + KINLsMem kinls_mem; + int retval, LSType; + + /* Return immediately if either kinmem or LS inputs are NULL */ + if (kinmem == NULL) { + KINProcessError(NULL, KINLS_MEM_NULL, "KINLS", + "KINSetLinearSolver", MSG_LS_KINMEM_NULL); + return(KINLS_MEM_NULL); + } + if (LS == NULL) { + KINProcessError(NULL, KINLS_ILL_INPUT, "KINLS", + "KINSetLinearSolver", + "LS must be non-NULL"); + return(KINLS_ILL_INPUT); + } + 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) ) { + KINProcessError(kin_mem, KINLS_ILL_INPUT, "KINLS", + "KINSetLinearSolver", + "LS object is missing a required operation"); + return(KINLS_ILL_INPUT); + } + + /* check for required vector operations for KINLS interface */ + if ( (kin_mem->kin_vtemp1->ops->nvconst == NULL) || + (kin_mem->kin_vtemp1->ops->nvdotprod == NULL) ) { + KINProcessError(kin_mem, KINLS_ILL_INPUT, "KINLS", + "KINSetLinearSolver", MSG_LS_BAD_NVECTOR); + 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)) { + 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) ); + + /* Set four main system linear solver function fields in kin_mem */ + kin_mem->kin_linit = kinLsInitialize; + kin_mem->kin_lsetup = kinLsSetup; + kin_mem->kin_lsolve = kinLsSolve; + kin_mem->kin_lfree = kinLsFree; + + /* Get memory for KINLsMemRec */ + kinls_mem = NULL; + kinls_mem = (KINLsMem) malloc(sizeof(struct KINLsMemRec)); + if (kinls_mem == NULL) { + KINProcessError(kin_mem, KINLS_MEM_FAIL, "KINLS", + "KINSetLinearSolver", MSG_LS_MEM_FAIL); + return(KINLS_MEM_FAIL); + } + memset(kinls_mem, 0, sizeof(struct KINLsMemRec)); + + /* set SUNLinearSolver pointer */ + kinls_mem->LS = LS; + + /* Set defaults for Jacobian-related fields */ + if (A != NULL) { + kinls_mem->jacDQ = SUNTRUE; + kinls_mem->jac = kinLsDQJac; + kinls_mem->J_data = kin_mem; + } else { + kinls_mem->jacDQ = SUNFALSE; + kinls_mem->jac = NULL; + kinls_mem->J_data = NULL; + } + kinls_mem->jtimesDQ = SUNTRUE; + kinls_mem->jtimes = kinLsDQJtimes; + kinls_mem->jt_data = kin_mem; + + /* Set defaults for preconditioner-related fields */ + kinls_mem->pset = NULL; + kinls_mem->psolve = NULL; + kinls_mem->pfree = NULL; + kinls_mem->pdata = kin_mem->kin_user_data; + + /* Initialize counters */ + kinLsInitializeCounters(kinls_mem); + + /* Set default values for the rest of the LS parameters */ + kinls_mem->last_flag = KINLS_SUCCESS; + + /* If LS supports ATimes, attach KINLs routine */ + if (LS->ops->setatimes) { + retval = SUNLinSolSetATimes(LS, kin_mem, kinLsATimes); + if (retval != SUNLS_SUCCESS) { + KINProcessError(kin_mem, KINLS_SUNLS_FAIL, "KINLS", + "KINSetLinearSolver", + "Error in calling SUNLinSolSetATimes"); + free(kinls_mem); kinls_mem = NULL; + return(KINLS_SUNLS_FAIL); + } + } + + /* If LS supports preconditioning, initialize pset/psol to NULL */ + if (LS->ops->setpreconditioner) { + retval = SUNLinSolSetPreconditioner(LS, kin_mem, NULL, NULL); + if (retval != SUNLS_SUCCESS) { + KINProcessError(kin_mem, KINLS_SUNLS_FAIL, "KINLS", + "KINSetLinearSolver", + "Error in calling SUNLinSolSetPreconditioner"); + free(kinls_mem); kinls_mem = NULL; + return(KINLS_SUNLS_FAIL); + } + } + + /* initialize tolerance scaling factor */ + kinls_mem->tol_fac = -ONE; + + /* set SUNMatrix pointer (can be NULL) */ + kinls_mem->J = A; + + /* Attach linear solver memory to integrator memory */ + kin_mem->kin_lmem = kinls_mem; + + return(KINLS_SUCCESS); +} + + +/*================================================================== + Optional input/output routines + ==================================================================*/ + +/*------------------------------------------------------------------ + KINSetJacFn specifies the Jacobian function + ------------------------------------------------------------------*/ +int KINSetJacFn(void *kinmem, KINLsJacFn jac) +{ + KINMem kin_mem; + KINLsMem kinls_mem; + int retval; + + /* access KINLsMem structure */ + retval = kinLs_AccessLMem(kinmem, "KINSetJacFn", + &kin_mem, &kinls_mem); + if (retval != KIN_SUCCESS) return(retval); + + /* return with failure if jac cannot be used */ + if ((jac != NULL) && (kinls_mem->J == NULL)) { + KINProcessError(kin_mem, KINLS_ILL_INPUT, "KINLS", "KINSetJacFn", + "Jacobian routine cannot be supplied for NULL SUNMatrix"); + return(KINLS_ILL_INPUT); + } + + if (jac != NULL) { + kinls_mem->jacDQ = SUNFALSE; + kinls_mem->jac = jac; + kinls_mem->J_data = kin_mem->kin_user_data; + } else { + kinls_mem->jacDQ = SUNTRUE; + kinls_mem->jac = kinLsDQJac; + kinls_mem->J_data = kin_mem; + } + + return(KINLS_SUCCESS); +} + + +/*------------------------------------------------------------------ + KINSetPreconditioner sets the preconditioner setup and solve + functions + ------------------------------------------------------------------*/ +int KINSetPreconditioner(void *kinmem, + KINLsPrecSetupFn psetup, + KINLsPrecSolveFn psolve) +{ + KINMem kin_mem; + KINLsMem kinls_mem; + PSetupFn kinls_psetup; + PSolveFn kinls_psolve; + int retval; + + /* access KINLsMem structure */ + retval = kinLs_AccessLMem(kinmem, "KINSetPreconditioner", + &kin_mem, &kinls_mem); + if (retval != KIN_SUCCESS) return(retval); + + /* store function pointers for user-supplied routines in KINLS interface */ + kinls_mem->pset = psetup; + kinls_mem->psolve = psolve; + + /* issue error if LS object does not support user-supplied preconditioning */ + if (kinls_mem->LS->ops->setpreconditioner == NULL) { + KINProcessError(kin_mem, KINLS_ILL_INPUT, "KINLS", "KINSetPreconditioner", + "SUNLinearSolver object does not support user-supplied preconditioning"); + return(KINLS_ILL_INPUT); + } + + /* notify iterative linear solver to call KINLs interface routines */ + kinls_psetup = (psetup == NULL) ? NULL : kinLsPSetup; + kinls_psolve = (psolve == NULL) ? NULL : kinLsPSolve; + retval = SUNLinSolSetPreconditioner(kinls_mem->LS, kin_mem, + kinls_psetup, kinls_psolve); + if (retval != SUNLS_SUCCESS) { + KINProcessError(kin_mem, KINLS_SUNLS_FAIL, "KINLS", "KINSetPreconditioner", + "Error in calling SUNLinSolSetPreconditioner"); + return(KINLS_SUNLS_FAIL); + } + + return(KINLS_SUCCESS); +} + +/*------------------------------------------------------------------ + KINSetJacTimesVecFn sets the matrix-vector product function + ------------------------------------------------------------------*/ +int KINSetJacTimesVecFn(void *kinmem, KINLsJacTimesVecFn jtv) +{ + int retval; + KINMem kin_mem; + KINLsMem kinls_mem; + + /* access KINLsMem structure */ + retval = kinLs_AccessLMem(kinmem, "KINSetJacTimesVecFn", + &kin_mem, &kinls_mem); + if (retval != KIN_SUCCESS) return(retval); + + /* issue error if LS object does not support user-supplied ATimes */ + if (kinls_mem->LS->ops->setatimes == NULL) { + KINProcessError(kin_mem, KINLS_ILL_INPUT, "KINLS", "KINSetJacTimesVecFn", + "SUNLinearSolver object does not support user-supplied ATimes routine"); + return(KINLS_ILL_INPUT); + } + + /* store function pointers for user-supplied routine in KINLs + interface (NULL jtimes implies use of DQ default) */ + if (jtv != NULL) { + kinls_mem->jtimesDQ = SUNFALSE; + kinls_mem->jtimes = jtv; + kinls_mem->jt_data = kin_mem->kin_user_data; + } else { + kinls_mem->jtimesDQ = SUNTRUE; + kinls_mem->jtimes = kinLsDQJtimes; + kinls_mem->jt_data = kin_mem; + } + + return(KINLS_SUCCESS); +} + +/*------------------------------------------------------------------ + KINGetLinWorkSpace returns the integer and real workspace size + ------------------------------------------------------------------*/ +int KINGetLinWorkSpace(void *kinmem, long int *lenrwLS, long int *leniwLS) +{ + KINMem kin_mem; + KINLsMem kinls_mem; + sunindextype lrw1, liw1; + long int lrw, liw; + int retval; + + /* access KINLsMem structure */ + retval = kinLs_AccessLMem(kinmem, "KINGetLinWorkSpace", + &kin_mem, &kinls_mem); + if (retval != KIN_SUCCESS) return(retval); + + /* start with fixed sizes plus vector/matrix pointers */ + *lenrwLS = 1; + *leniwLS = 21; + + /* add N_Vector sizes */ + if (kin_mem->kin_vtemp1->ops->nvspace) { + N_VSpace(kin_mem->kin_vtemp1, &lrw1, &liw1); + *lenrwLS += lrw1; + *leniwLS += liw1; + } + + /* add LS sizes */ + if (kinls_mem->LS->ops->space) { + retval = SUNLinSolSpace(kinls_mem->LS, &lrw, &liw); + if (retval == 0) { + *lenrwLS += lrw; + *leniwLS += liw; + } + } + + return(KINLS_SUCCESS); +} + +/*------------------------------------------------------------------ + KINGetNumJacEvals returns the number of Jacobian evaluations + ------------------------------------------------------------------*/ +int KINGetNumJacEvals(void *kinmem, long int *njevals) +{ + KINMem kin_mem; + KINLsMem kinls_mem; + int retval; + + /* access KINLsMem structure; set output value and return */ + retval = kinLs_AccessLMem(kinmem, "KINGetNumJacEvals", + &kin_mem, &kinls_mem); + if (retval != KIN_SUCCESS) return(retval); + *njevals = kinls_mem->nje; + return(KINLS_SUCCESS); +} + +/*------------------------------------------------------------------ + KINGetNumPrecEvals returns the total number of preconditioner + evaluations + ------------------------------------------------------------------*/ +int KINGetNumPrecEvals(void *kinmem, long int *npevals) +{ + KINMem kin_mem; + KINLsMem kinls_mem; + int retval; + + /* access KINLsMem structure; set output value and return */ + retval = kinLs_AccessLMem(kinmem, "KINGetNumPrecEvals", + &kin_mem, &kinls_mem); + if (retval != KIN_SUCCESS) return(retval); + *npevals = kinls_mem->npe; + return(KINLS_SUCCESS); +} + +/*------------------------------------------------------------------ + KINGetNumPrecSolves returns the total number of times the + preconditioner was applied + ------------------------------------------------------------------*/ +int KINGetNumPrecSolves(void *kinmem, long int *npsolves) +{ + KINMem kin_mem; + KINLsMem kinls_mem; + int retval; + + /* access KINLsMem structure; set output value and return */ + retval = kinLs_AccessLMem(kinmem, "KINGetNumPrecSolves", + &kin_mem, &kinls_mem); + if (retval != KIN_SUCCESS) return(retval); + *npsolves = kinls_mem->nps; + return(KINLS_SUCCESS); +} + +/*------------------------------------------------------------------ + KINGetNumLinIters returns the total number of linear + iterations + ------------------------------------------------------------------*/ +int KINGetNumLinIters(void *kinmem, long int *nliters) +{ + KINMem kin_mem; + KINLsMem kinls_mem; + int retval; + + /* access KINLsMem structure; set output value and return */ + retval = kinLs_AccessLMem(kinmem, "KINGetNumLinIters", + &kin_mem, &kinls_mem); + if (retval != KIN_SUCCESS) return(retval); + *nliters = kinls_mem->nli; + return(KINLS_SUCCESS); +} + +/*------------------------------------------------------------------ + KINGetNumLinConvFails returns the total numbe of convergence + failures + ------------------------------------------------------------------*/ +int KINGetNumLinConvFails(void *kinmem, long int *nlcfails) +{ + KINMem kin_mem; + KINLsMem kinls_mem; + int retval; + + /* access KINLsMem structure; set output value and return */ + retval = kinLs_AccessLMem(kinmem, "KINGetNumLinConvFails", + &kin_mem, &kinls_mem); + if (retval != KIN_SUCCESS) return(retval); + *nlcfails = kinls_mem->ncfl; + return(KINLS_SUCCESS); +} + +/*------------------------------------------------------------------ + KINGetNumJtimesEvals returns the number of times the matrix + vector product was computed + ------------------------------------------------------------------*/ +int KINGetNumJtimesEvals(void *kinmem, long int *njvevals) +{ + KINMem kin_mem; + KINLsMem kinls_mem; + int retval; + + /* access KINLsMem structure; set output value and return */ + retval = kinLs_AccessLMem(kinmem, "KINGetNumJtimesEvals", + &kin_mem, &kinls_mem); + if (retval != KIN_SUCCESS) return(retval); + *njvevals = kinls_mem->njtimes; + return(KINLS_SUCCESS); +} + +/*------------------------------------------------------------------ + KINGetNumLinFuncEvals returns the number of calls to the user's + F routine by the linear solver module + ------------------------------------------------------------------*/ +int KINGetNumLinFuncEvals(void *kinmem, long int *nfevals) +{ + KINMem kin_mem; + KINLsMem kinls_mem; + int retval; + + /* access KINLsMem structure; set output value and return */ + retval = kinLs_AccessLMem(kinmem, "KINGetNumLinFuncEvals", + &kin_mem, &kinls_mem); + if (retval != KIN_SUCCESS) return(retval); + *nfevals = kinls_mem->nfeDQ; + return(KINLS_SUCCESS); +} + +/*------------------------------------------------------------------ + KINGetLastLinFlag returns the last flag set in the KINLS + function + ------------------------------------------------------------------*/ +int KINGetLastLinFlag(void *kinmem, long int *flag) +{ + KINMem kin_mem; + KINLsMem kinls_mem; + int retval; + + /* access KINLsMem structure; set output value and return */ + retval = kinLs_AccessLMem(kinmem, "KINGetLastLinFlag", + &kin_mem, &kinls_mem); + if (retval != KIN_SUCCESS) return(retval); + *flag = kinls_mem->last_flag; + return(KINLS_SUCCESS); +} + +/*------------------------------------------------------------------ + KINGetLinReturnFlagName + ------------------------------------------------------------------*/ +char *KINGetLinReturnFlagName(long int flag) +{ + char *name; + + name = (char *)malloc(30*sizeof(char)); + + switch(flag) { + case KINLS_SUCCESS: + sprintf(name, "KINLS_SUCCESS"); + break; + case KINLS_MEM_NULL: + sprintf(name, "KINLS_MEM_NULL"); + break; + case KINLS_LMEM_NULL: + sprintf(name, "KINLS_LMEM_NULL"); + break; + case KINLS_ILL_INPUT: + sprintf(name, "KINLS_ILL_INPUT"); + break; + case KINLS_MEM_FAIL: + sprintf(name, "KINLS_MEM_FAIL"); + break; + case KINLS_PMEM_NULL: + sprintf(name, "KINLS_PMEM_NULL"); + break; + case KINLS_JACFUNC_ERR: + sprintf(name,"KINLS_JACFUNC_ERR"); + break; + case KINLS_SUNMAT_FAIL: + sprintf(name,"KINLS_SUNMAT_FAIL"); + break; + case KINLS_SUNLS_FAIL: + sprintf(name,"KINLS_SUNLS_FAIL"); + break; + default: + sprintf(name, "NONE"); + } + + return(name); +} + + +/*================================================================== + KINLS Private functions + ==================================================================*/ + +/*------------------------------------------------------------------ + kinLsATimes + + This routine coordinates the generation of the matrix-vector + product z = J*v by calling either kinLsDQJtimes, which uses + a difference quotient approximation for J*v, or by calling the + user-supplied routine KINLsJacTimesVecFn if it is non-null. + ------------------------------------------------------------------*/ +int kinLsATimes(void *kinmem, N_Vector v, N_Vector z) +{ + KINMem kin_mem; + KINLsMem kinls_mem; + int retval; + + /* access KINLsMem structure */ + retval = kinLs_AccessLMem(kinmem, "kinLsATimes", + &kin_mem, &kinls_mem); + if (retval != KIN_SUCCESS) return(retval); + + /* call Jacobian-times-vector product routine + (either user-supplied or internal DQ) */ + retval = kinls_mem->jtimes(v, z, kin_mem->kin_uu, + &(kinls_mem->new_uu), + kinls_mem->jt_data); + kinls_mem->njtimes++; + return(retval); +} + + +/*--------------------------------------------------------------- + kinLsPSetup: + + This routine interfaces between the generic iterative linear + solvers and the user's psetup routine. It passes to psetup all + required state information from kin_mem. Its return value + is the same as that returned by psetup. Note that the generic + iterative linear solvers guarantee that kinLsPSetup will only + be called in the case that the user's psetup routine is non-NULL. + ---------------------------------------------------------------*/ +int kinLsPSetup(void *kinmem) +{ + KINMem kin_mem; + KINLsMem kinls_mem; + int retval; + + /* access KINLsMem structure */ + retval = kinLs_AccessLMem(kinmem, "kinLsPSetup", + &kin_mem, &kinls_mem); + if (retval != KIN_SUCCESS) return(retval); + + /* Call user pset routine to update preconditioner */ + retval = kinls_mem->pset(kin_mem->kin_uu, kin_mem->kin_uscale, + kin_mem->kin_fval, kin_mem->kin_fscale, + kinls_mem->pdata); + kinls_mem->npe++; + return(retval); +} + + +/*------------------------------------------------------------------ + kinLsPSolve + + This routine interfaces between the generic iterative linear + solvers and the user's psolve routine. It passes to psolve all + required state information from kinsol_mem. Its return value is + the same as that returned by psolve. Note that the generic + SUNLinSol solver guarantees that kinLsPSolve will not be called + in the case in which preconditioning is not done. This is the only + case in which the user's psolve routine is allowed to be NULL. + ------------------------------------------------------------------*/ +int kinLsPSolve(void *kinmem, N_Vector r, N_Vector z, realtype tol, int lr) +{ + KINMem kin_mem; + KINLsMem kinls_mem; + int retval; + + /* access KINLsMem structure */ + retval = kinLs_AccessLMem(kinmem, "kinLsPSolve", + &kin_mem, &kinls_mem); + if (retval != KIN_SUCCESS) return(retval); + + /* copy the rhs into z before the psolve call */ + /* Note: z returns with the solution */ + N_VScale(ONE, r, z); + + /* note: user-supplied preconditioning with KINSOL does not + support either the 'tol' or 'lr' inputs */ + retval = kinls_mem->psolve(kin_mem->kin_uu, kin_mem->kin_uscale, + kin_mem->kin_fval, kin_mem->kin_fscale, + z, kinls_mem->pdata); + kinls_mem->nps++; + return(retval); +} + + +/*------------------------------------------------------------------ + kinLsDQJac + + This routine is a wrapper for the Dense and Band implementations + of the difference quotient Jacobian approximation routines. + ------------------------------------------------------------------*/ +int kinLsDQJac(N_Vector u, N_Vector fu, SUNMatrix Jac, + void *kinmem, N_Vector tmp1, N_Vector tmp2) +{ + KINMem kin_mem; + int retval; + + /* access KINMem structure */ + if (kinmem == NULL) { + KINProcessError(NULL, KINLS_MEM_NULL, "KINLS", + "kinLsDQJac", MSG_LS_KINMEM_NULL); + return(KINLS_MEM_NULL); + } + kin_mem = (KINMem) kinmem; + + /* verify that Jac is non-NULL */ + if (Jac == NULL) { + KINProcessError(kin_mem, KINLS_LMEM_NULL, "KINLS", + "kinLsDQJac", MSG_LS_LMEM_NULL); + return(KINLS_LMEM_NULL); + } + + /* Call the matrix-structure-specific DQ approximation routine */ + if (SUNMatGetID(Jac) == SUNMATRIX_DENSE) { + retval = kinLsDenseDQJac(u, fu, Jac, kin_mem, tmp1, tmp2); + } else if (SUNMatGetID(Jac) == SUNMATRIX_BAND) { + retval = kinLsBandDQJac(u, fu, Jac, kin_mem, tmp1, tmp2); + } else { + KINProcessError(kin_mem, KIN_ILL_INPUT, "KINLS", "kinLsDQJac", + "unrecognized matrix type for kinLsDQJac"); + retval = KIN_ILL_INPUT; + } + return(retval); +} + + +/*------------------------------------------------------------------ + kinLsDenseDQJac + + This routine generates a dense difference quotient approximation + to the Jacobian of F(u). It assumes a dense SUNMatrix input + stored column-wise, and that elements within each column are + contiguous. The address of the jth column of J is obtained via + the function SUNDenseMatrix_Column() and this pointer is + associated with an N_Vector using the N_VGetArrayPointer and + N_VSetArrayPointer functions. Finally, the actual computation of + the jth column of the Jacobian is done with a call to N_VLinearSum. + + The increment used in the finite-difference approximation + J_ij = ( F_i(u+sigma_j * e_j) - F_i(u) ) / sigma_j + is + sigma_j = max{|u_j|, |1/uscale_j|} * sqrt(uround) + + Note: uscale_j = 1/typ(u_j) + + NOTE: Any type of failure of the system function here leads to an + unrecoverable failure of the Jacobian function and thus of + the linear solver setup function, stopping KINSOL. + ------------------------------------------------------------------*/ +int kinLsDenseDQJac(N_Vector u, N_Vector fu, SUNMatrix Jac, + KINMem kin_mem, N_Vector tmp1, N_Vector tmp2) +{ + realtype inc, inc_inv, ujsaved, ujscale, sign; + realtype *tmp2_data, *u_data, *uscale_data; + N_Vector ftemp, jthCol; + sunindextype j, N; + KINLsMem kinls_mem; + int retval = 0; + + /* access LsMem interface structure */ + kinls_mem = (KINLsMem) kin_mem->kin_lmem; + + /* access matrix dimension */ + N = SUNDenseMatrix_Rows(Jac); + + /* Save pointer to the array in tmp2 */ + tmp2_data = N_VGetArrayPointer(tmp2); + + /* Rename work vectors for readibility */ + ftemp = tmp1; + jthCol = tmp2; + + /* Obtain pointers to the data for u and uscale */ + u_data = N_VGetArrayPointer(u); + uscale_data = N_VGetArrayPointer(kin_mem->kin_uscale); + + /* This is the only for loop for 0..N-1 in KINSOL */ + + for (j = 0; j < N; j++) { + + /* Generate the jth col of J(u) */ + + /* Set data address of jthCol, and save u_j values and scaling */ + N_VSetArrayPointer(SUNDenseMatrix_Column(Jac,j), jthCol); + ujsaved = u_data[j]; + ujscale = ONE/uscale_data[j]; + + /* Compute increment */ + sign = (ujsaved >= ZERO) ? ONE : -ONE; + inc = kin_mem->kin_sqrt_relfunc*SUNMAX(SUNRabs(ujsaved), ujscale)*sign; + + /* Increment u_j, call F(u), and return if error occurs */ + u_data[j] += inc; + + retval = kin_mem->kin_func(u, ftemp, kin_mem->kin_user_data); + kinls_mem->nfeDQ++; + if (retval != 0) break; + + /* reset u_j */ + u_data[j] = ujsaved; + + /* Construct difference quotient in jthCol */ + inc_inv = ONE/inc; + N_VLinearSum(inc_inv, ftemp, -inc_inv, fu, jthCol); + } + + /* Restore original array pointer in tmp2 */ + N_VSetArrayPointer(tmp2_data, tmp2); + + return(retval); +} + + +/*------------------------------------------------------------------ + kinLsBandDQJac + + This routine generates a banded difference quotient approximation + to the Jacobian of F(u). It assumes a SUNBandMatrix input 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 + function SUNBandMatrix_Column() and to write a simple for loop to + set each of the elements of a column in succession. + + NOTE: Any type of failure of the system function her leads to an + unrecoverable failure of the Jacobian function and thus of + the linear solver setup function, stopping KINSOL. + ------------------------------------------------------------------*/ +int kinLsBandDQJac(N_Vector u, N_Vector fu, SUNMatrix Jac, + KINMem kin_mem, N_Vector tmp1, N_Vector tmp2) +{ + realtype inc, inc_inv; + N_Vector futemp, utemp; + sunindextype group, i, j, width, ngroups, i1, i2; + sunindextype N, mupper, mlower; + realtype *col_j, *fu_data, *futemp_data, *u_data, *utemp_data, *uscale_data; + KINLsMem kinls_mem; + int retval = 0; + + /* access LsMem interface structure */ + kinls_mem = (KINLsMem) kin_mem->kin_lmem; + + /* access matrix dimensions */ + N = SUNBandMatrix_Columns(Jac); + mupper = SUNBandMatrix_UpperBandwidth(Jac); + mlower = SUNBandMatrix_LowerBandwidth(Jac); + + /* Rename work vectors for use as temporary values of u and fu */ + futemp = tmp1; + utemp = tmp2; + + /* Obtain pointers to the data for ewt, fy, futemp, y, ytemp */ + fu_data = N_VGetArrayPointer(fu); + futemp_data = N_VGetArrayPointer(futemp); + u_data = N_VGetArrayPointer(u); + uscale_data = N_VGetArrayPointer(kin_mem->kin_uscale); + utemp_data = N_VGetArrayPointer(utemp); + + /* Load utemp with u */ + N_VScale(ONE, u, utemp); + + /* Set bandwidth and number of column groups for band differencing */ + width = mlower + mupper + 1; + ngroups = SUNMIN(width, N); + + for (group=1; group <= ngroups; group++) { + + /* Increment all utemp components in group */ + for(j=group-1; j < N; j+=width) { + inc = kin_mem->kin_sqrt_relfunc*SUNMAX(SUNRabs(u_data[j]), + ONE/SUNRabs(uscale_data[j])); + utemp_data[j] += inc; + } + + /* Evaluate f with incremented u */ + retval = kin_mem->kin_func(utemp, futemp, kin_mem->kin_user_data); + if (retval != 0) return(retval); + + /* Restore utemp components, then form and load difference quotients */ + for (j=group-1; j < N; j+=width) { + utemp_data[j] = u_data[j]; + col_j = SUNBandMatrix_Column(Jac, j); + inc = kin_mem->kin_sqrt_relfunc*SUNMAX(SUNRabs(u_data[j]), + ONE/SUNRabs(uscale_data[j])); + inc_inv = ONE/inc; + i1 = SUNMAX(0, j-mupper); + i2 = SUNMIN(j+mlower, N-1); + for (i=i1; i <= i2; i++) + SM_COLUMN_ELEMENT_B(col_j,i,j) = inc_inv * (futemp_data[i] - fu_data[i]); + } + } + + /* Increment counter nfeDQ */ + kinls_mem->nfeDQ += ngroups; + + return(0); +} + + +/*------------------------------------------------------------------ + kinLsDQJtimes + + This routine generates the matrix-vector product z = J*v using a + difference quotient approximation. The approximation is + J*v = [func(uu + sigma*v) - func(uu)]/sigma. Here sigma is based + on the dot products (uscale*uu, uscale*v) and + (uscale*v, uscale*v), the L1Norm(uscale*v), and on sqrt_relfunc + (the square root of the relative error in the function). Note + that v in the argument list has already been both preconditioned + and unscaled. + + NOTE: Unlike the DQ Jacobian functions for direct linear solvers + (which are called from within the lsetup function), this + function is called from within the lsolve function and thus + a recovery may still be possible even if the system function + fails (recoverably). + ------------------------------------------------------------------*/ +int kinLsDQJtimes(N_Vector v, N_Vector Jv, N_Vector u, + booleantype *new_u, void *kinmem) +{ + realtype sigma, sigma_inv, sutsv, sq1norm, sign, vtv; + KINMem kin_mem; + KINLsMem kinls_mem; + int retval; + + /* access KINLsMem structure */ + retval = kinLs_AccessLMem(kinmem, "kinLsDQJtimes", + &kin_mem, &kinls_mem); + if (retval != KIN_SUCCESS) return(retval); + + /* ensure that NVector supplies requisite routines */ + if ( (v->ops->nvprod == NULL) || (v->ops->nvdotprod == NULL) || + (v->ops->nvl1norm == NULL) || (v->ops->nvlinearsum == NULL) ){ + KINProcessError(kin_mem, KINLS_ILL_INPUT, "KINLS", + "kinLsDQJtimes", MSG_LS_BAD_NVECTOR); + return(KINLS_ILL_INPUT); + } + + /* scale the vector v and put Du*v into vtemp1 */ + N_VProd(v, kin_mem->kin_uscale, kin_mem->kin_vtemp1); + + /* scale u and put into Jv (used as a temporary storage) */ + N_VProd(u, kin_mem->kin_uscale, Jv); + + /* compute dot product (Du*u).(Du*v) */ + sutsv = N_VDotProd(Jv, kin_mem->kin_vtemp1); + + /* compute dot product (Du*v).(Du*v) */ + vtv = N_VDotProd(kin_mem->kin_vtemp1, kin_mem->kin_vtemp1); + + /* compute differencing factor -- this is from p. 469, Brown and Saad paper */ + sq1norm = N_VL1Norm(kin_mem->kin_vtemp1); + sign = (sutsv >= ZERO) ? ONE : -ONE ; + sigma = sign*(kin_mem->kin_sqrt_relfunc)*SUNMAX(SUNRabs(sutsv),sq1norm)/vtv; + sigma_inv = ONE/sigma; + + /* compute the u-prime at which to evaluate the function func */ + N_VLinearSum(ONE, u, sigma, v, kin_mem->kin_vtemp1); + + /* call the system function to calculate func(u+sigma*v) */ + retval = kin_mem->kin_func(kin_mem->kin_vtemp1, kin_mem->kin_vtemp2, + kin_mem->kin_user_data); + kinls_mem->nfeDQ++; + if (retval != 0) return(retval); + + /* finish the computation of the difference quotient */ + N_VLinearSum(sigma_inv, kin_mem->kin_vtemp2, -sigma_inv, kin_mem->kin_fval, Jv); + + return(0); +} + + +/*------------------------------------------------------------------ + kinLsInitialize performs remaining initializations specific + to the iterative linear solver interface (and solver itself) + ------------------------------------------------------------------*/ +int kinLsInitialize(KINMem kin_mem) +{ + KINLsMem kinls_mem; + int retval, LSType; + + /* Access KINLsMem structure */ + if (kin_mem->kin_lmem == NULL) { + KINProcessError(kin_mem, KINLS_LMEM_NULL, "KINLS", + "kinLsInitialize", MSG_LS_LMEM_NULL); + return(KINLS_LMEM_NULL); + } + 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) { + + /* If SUNMatrix A is NULL: ensure 'jac' function pointer is NULL */ + kinls_mem->jacDQ = SUNFALSE; + kinls_mem->jac = NULL; + kinls_mem->J_data = NULL; + + } else if (kinls_mem->jacDQ) { + + /* If J 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 (kinls_mem->J->ops->getid) { + + if ( (SUNMatGetID(kinls_mem->J) == SUNMATRIX_DENSE) || + (SUNMatGetID(kinls_mem->J) == SUNMATRIX_BAND) ) { + kinls_mem->jac = kinLsDQJac; + kinls_mem->J_data = kin_mem; + } else { + retval++; + } + + } else { + retval++; + } + if (retval) { + KINProcessError(kin_mem, KINLS_ILL_INPUT, "KINLS", "kinLsInitialize", + "No Jacobian constructor available for SUNMatrix type"); + kinls_mem->last_flag = KINLS_ILL_INPUT; + return(KINLS_ILL_INPUT); + } + + /* check for required vector operations for kinLsDQJac routine */ + if ( (kin_mem->kin_vtemp1->ops->nvlinearsum == NULL) || + (kin_mem->kin_vtemp1->ops->nvscale == NULL) || + (kin_mem->kin_vtemp1->ops->nvgetarraypointer == NULL) || + (kin_mem->kin_vtemp1->ops->nvsetarraypointer == NULL) ) { + KINProcessError(kin_mem, KINLS_ILL_INPUT, "KINLS", + "kinLsInitialize", MSG_LS_BAD_NVECTOR); + return(KINLS_ILL_INPUT); + } + + } else { + + /* If J is non-NULL, and 'jac' is user-supplied, + reset J_data pointer (just in case) */ + kinls_mem->J_data = kin_mem->kin_user_data; + } + + /* Prohibit Picard iteration with DQ Jacobian approximation or difference-quotient J*v */ + if ( (kin_mem->kin_globalstrategy == KIN_PICARD) && + kinls_mem->jacDQ && kinls_mem->jtimesDQ ) { + KINProcessError(kin_mem, KINLS_ILL_INPUT, "KINLS", + "kinLsInitialize", MSG_NOL_FAIL); + return(KINLS_ILL_INPUT); + } + + + /** error-checking is complete, begin initializtions **/ + + /* Initialize counters */ + kinLsInitializeCounters(kinls_mem); + + /* Set Jacobian-related fields, based on jtimesDQ */ + if (kinls_mem->jtimesDQ) { + kinls_mem->jtimes = kinLsDQJtimes; + kinls_mem->jt_data = kin_mem; + } else { + kinls_mem->jt_data = kin_mem->kin_user_data; + } + + /* if J is NULL and: NOT preconditioning or do NOT need to setup the + preconditioner, then set the lsetup function to NULL */ + if (kinls_mem->J == NULL) + if ((kinls_mem->psolve == NULL) || (kinls_mem->pset == NULL)) + kin_mem->kin_lsetup = NULL; + + /* Set scaling vectors assuming RIGHT preconditioning */ + /* NOTE: retval is non-zero only if LS == NULL */ + if (kinls_mem->LS->ops->setscalingvectors) { + retval = SUNLinSolSetScalingVectors(kinls_mem->LS, + kin_mem->kin_fscale, + kin_mem->kin_fscale); + if (retval != SUNLS_SUCCESS) { + KINProcessError(kin_mem, KINLS_SUNLS_FAIL, "KINLS", "kinLsInitialize", + "Error in calling SUNLinSolSetScalingVectors"); + return(KINLS_SUNLS_FAIL); + } + } + + /* If the linear solver is iterative or matrix-iterative, and if left/right + scaling are not supported, we must update linear solver tolerances in an + attempt to account for the fscale vector. We make the following assumptions: + 1. fscale_i = fs_mean, for i=0,...,n-1 (i.e. the weights are homogeneous) + 2. the linear solver uses a basic 2-norm to measure convergence + Hence (using the notation from sunlinsol_spgmr.h, with S = diag(fscale)), + || bbar - Abar xbar ||_2 < tol + <=> || S b - S A x ||_2 < tol + <=> || S (b - A x) ||_2 < tol + <=> \sum_{i=0}^{n-1} (fscale_i (b - A x)_i)^2 < tol^2 + <=> fs_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 / 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 */ + 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) ); + } else { + kinls_mem->tol_fac = ONE; + } + + /* Call LS initialize routine, and return result */ + kinls_mem->last_flag = SUNLinSolInitialize(kinls_mem->LS); + return(kinls_mem->last_flag); +} + + +/*------------------------------------------------------------------ + kinLsSetup call the LS setup routine + ------------------------------------------------------------------*/ +int kinLsSetup(KINMem kin_mem) +{ + KINLsMem kinls_mem; + int retval; + + /* Access KINLsMem structure */ + if (kin_mem->kin_lmem == NULL) { + KINProcessError(kin_mem, KINLS_LMEM_NULL, "KINLS", + "kinLsSetup", MSG_LS_LMEM_NULL); + return(KINLS_LMEM_NULL); + } + 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); + } + + /* Call Jacobian routine */ + retval = kinls_mem->jac(kin_mem->kin_uu, kin_mem->kin_fval, + kinls_mem->J, kinls_mem->J_data, + kin_mem->kin_vtemp1, kin_mem->kin_vtemp2); + if (retval != 0) { + KINProcessError(kin_mem, KINLS_JACFUNC_ERR, "KINLS", + "kinLsSetup", MSG_LS_JACFUNC_FAILED); + kinls_mem->last_flag = KINLS_JACFUNC_ERR; + return(kinls_mem->last_flag); + } + + } + + /* Call LS setup routine -- the LS will call kinLsPSetup (if applicable) */ + kinls_mem->last_flag = SUNLinSolSetup(kinls_mem->LS, kinls_mem->J); + + /* save nni value from most recent lsetup call */ + kin_mem->kin_nnilset = kin_mem->kin_nni; + + return(kinls_mem->last_flag); +} + + +/*------------------------------------------------------------------ + kinLsSolve interfaces between KINSOL and the generic + SUNLinearSolver object + ------------------------------------------------------------------*/ +int kinLsSolve(KINMem kin_mem, N_Vector xx, N_Vector bb, + realtype *sJpnorm, realtype *sFdotJp) +{ + KINLsMem kinls_mem; + int nli_inc, retval; + realtype res_norm, tol, LSType; + + /* Access KINLsMem structure */ + if (kin_mem->kin_lmem == NULL) { + KINProcessError(kin_mem, KINLS_LMEM_NULL, "KINLS", + "kinLsSolve", MSG_LS_LMEM_NULL); + return(KINLS_LMEM_NULL); + } + 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) */ + tol = kin_mem->kin_eps * kinls_mem->tol_fac; + + /* Set initial guess x = 0 to LS */ + N_VConst(ZERO, xx); + + /* set flag required for user-supplied J*v routine */ + kinls_mem->new_uu = SUNTRUE; + + /* Call solver */ + retval = SUNLinSolSolve(kinls_mem->LS, kinls_mem->J, xx, bb, tol); + + /* Retrieve solver statistics */ + res_norm = ZERO; + if (kinls_mem->LS->ops->resnorm) + res_norm = SUNLinSolResNorm(kinls_mem->LS); + nli_inc = 0; + 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) ) + KINPrintInfo(kin_mem, PRNT_NLI, "KINLS", "kinLsSolve", + INFO_NLI, nli_inc); + + /* Increment counters nli and ncfl */ + kinls_mem->nli += nli_inc; + if (retval != SUNLS_SUCCESS) kinls_mem->ncfl++; + + /* Interpret solver return value */ + kinls_mem->last_flag = retval; + + if ( (retval != 0) && (retval != SUNLS_RES_REDUCED) ) { + + switch(retval) { + case SUNLS_ATIMES_FAIL_REC: + case SUNLS_PSOLVE_FAIL_REC: + return(1); + break; + case SUNLS_MEM_NULL: + case SUNLS_ILL_INPUT: + case SUNLS_MEM_FAIL: + case SUNLS_GS_FAIL: + case SUNLS_CONV_FAIL: + case SUNLS_QRFACT_FAIL: + case SUNLS_LUFACT_FAIL: + case SUNLS_QRSOL_FAIL: + break; + case SUNLS_PACKAGE_FAIL_REC: + KINProcessError(kin_mem, SUNLS_PACKAGE_FAIL_REC, "KINLS", + "kinLsSolve", + "Failure in SUNLinSol external package"); + break; + case SUNLS_PACKAGE_FAIL_UNREC: + KINProcessError(kin_mem, SUNLS_PACKAGE_FAIL_UNREC, "KINLS", + "kinLsSolve", + "Failure in SUNLinSol external package"); + break; + case SUNLS_ATIMES_FAIL_UNREC: + KINProcessError(kin_mem, SUNLS_ATIMES_FAIL_UNREC, "KINLS", + "kinLsSolve", MSG_LS_JTIMES_FAILED); + break; + case SUNLS_PSOLVE_FAIL_UNREC: + KINProcessError(kin_mem, SUNLS_PSOLVE_FAIL_UNREC, "KINLS", + "kinLsSolve", MSG_LS_PSOLVE_FAILED); + break; + } + return(retval); + } + + /* SUNLinSolSolve returned SUNLS_SUCCESS or SUNLS_RES_REDUCED + + 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); + } + *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 */ + 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) ) + KINPrintInfo(kin_mem, PRNT_EPS, "KINLS", "kinLsSolve", + INFO_EPS, res_norm, kin_mem->kin_eps); + + return(0); +} + + +/*------------------------------------------------------------------ + kinLsFree frees memory associated with the KINLs system + solver interface + ------------------------------------------------------------------*/ +int kinLsFree(KINMem kin_mem) +{ + KINLsMem kinls_mem; + + /* Return immediately if kin_mem or kin_mem->kin_lmem are NULL */ + if (kin_mem == NULL) return (KINLS_SUCCESS); + if (kin_mem->kin_lmem == NULL) return(KINLS_SUCCESS); + kinls_mem = (KINLsMem) kin_mem->kin_lmem; + + /* Nullify SUNMatrix pointer */ + kinls_mem->J = NULL; + + /* Free preconditioner memory (if applicable) */ + if (kinls_mem->pfree) kinls_mem->pfree(kin_mem); + + /* free KINLs interface structure */ + free(kin_mem->kin_lmem); + + return(KINLS_SUCCESS); +} + + +/*------------------------------------------------------------------ + kinLsInitializeCounters resets counters for the LS interface + ------------------------------------------------------------------*/ +int kinLsInitializeCounters(KINLsMem kinls_mem) +{ + kinls_mem->nje = 0; + kinls_mem->nfeDQ = 0; + kinls_mem->npe = 0; + kinls_mem->nli = 0; + kinls_mem->nps = 0; + kinls_mem->ncfl = 0; + kinls_mem->njtimes = 0; + return(0); +} + + +/*--------------------------------------------------------------- + kinLs_AccessLMem + + This routine unpacks the kin_mem and ls_mem structures from + void* pointer. If either is missing it returns KINLS_MEM_NULL + or KINLS_LMEM_NULL. + ---------------------------------------------------------------*/ +int kinLs_AccessLMem(void* kinmem, const char *fname, + KINMem *kin_mem, KINLsMem *kinls_mem) +{ + if (kinmem==NULL) { + KINProcessError(NULL, KINLS_MEM_NULL, "KINLS", + fname, MSG_LS_KINMEM_NULL); + return(KINLS_MEM_NULL); + } + *kin_mem = (KINMem) kinmem; + if ((*kin_mem)->kin_lmem==NULL) { + KINProcessError(*kin_mem, KINLS_LMEM_NULL, "KINLS", + fname, MSG_LS_LMEM_NULL); + return(KINLS_LMEM_NULL); + } + *kinls_mem = (KINLsMem) (*kin_mem)->kin_lmem; + return(KINLS_SUCCESS); +} + + +/*--------------------------------------------------------------- + EOF + ---------------------------------------------------------------*/ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_ls_impl.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_ls_impl.h new file mode 100644 index 0000000..bbf540d --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_ls_impl.h @@ -0,0 +1,180 @@ +/*----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * David J. Gardner, Radu Serban 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 + *----------------------------------------------------------------- + * Implementation header file for KINSOL's linear solver interface. + *-----------------------------------------------------------------*/ + +#ifndef _KINLS_IMPL_H +#define _KINLS_IMPL_H + +#include <kinsol/kinsol_ls.h> +#include "kinsol_impl.h" + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + + +/*------------------------------------------------------------------ + keys for KINPrintInfo (do not use 1 -> conflict with PRNT_RETVAL) + ------------------------------------------------------------------*/ +#define PRNT_NLI 101 +#define PRNT_EPS 102 + + +/*------------------------------------------------------------------ + Types : struct KINLsMemRec, struct *KINLsMem + + The type KINLsMem is a pointer to a KINLsMemRec, which is a + structure containing fields that must be accessible by LS module + routines. + ------------------------------------------------------------------*/ +typedef struct KINLsMemRec { + + /* Jacobian construction & storage */ + booleantype jacDQ; /* SUNTRUE if using internal DQ Jacobian approx. */ + KINLsJacFn jac; /* Jacobian routine to be called */ + void *J_data; /* J_data is passed to jac */ + + /* Linear solver, matrix and vector objects/pointers */ + SUNLinearSolver LS; /* generic iterative linear solver object */ + SUNMatrix J; /* problem Jacobian */ + + /* Solver tolerance adjustment factor (if needed, see kinLsSolve) */ + realtype tol_fac; + + /* Statistics and associated parameters */ + long int nje; /* no. of calls to jac */ + long int nfeDQ; /* no. of calls to F due to DQ Jacobian or J*v + approximations */ + long int npe; /* npe = total number of precond calls */ + long int nli; /* nli = total number of linear iterations */ + long int nps; /* nps = total number of psolve calls */ + long int ncfl; /* ncfl = total number of convergence failures */ + long int njtimes; /* njtimes = total number of calls to jtimes */ + + booleantype new_uu; /* flag indicating if the iterate has been + updated - the Jacobian must be updated or + reevaluated (meant to be used by a + user-supplied jtimes function */ + + long int last_flag; /* last error return flag */ + + /* Preconditioner computation + (a) user-provided: + - pdata == user_data + - pfree == NULL (the user dealocates memory) + (b) internal preconditioner module + - pdata == kin_mem + - pfree == set by the prec. module and called in kinLsFree */ + KINLsPrecSetupFn pset; + KINLsPrecSolveFn psolve; + int (*pfree)(KINMem kin_mem); + void *pdata; + + /* Jacobian times vector compuation + (a) jtimes function provided by the user: + - jt_data == user_data + - jtimesDQ == SUNFALSE + (b) internal jtimes + - jt_data == kin_mem + - jtimesDQ == SUNTRUE */ + booleantype jtimesDQ; + KINLsJacTimesVecFn jtimes; + void *jt_data; + +} *KINLsMem; + + +/*------------------------------------------------------------------ + Prototypes of internal functions + ------------------------------------------------------------------*/ + +/* Interface routines called by system SUNLinearSolvers */ +int kinLsATimes(void *kinmem, N_Vector v, N_Vector z); +int kinLsPSetup(void *kinmem); +int kinLsPSolve(void *kinmem, N_Vector r, N_Vector z, + realtype tol, int lr); + +/* Difference quotient approximation for Jacobian times vector */ +int kinLsDQJtimes(N_Vector v, N_Vector Jv, N_Vector u, + booleantype *new_u, void *data); + +/* Difference-quotient Jacobian approximation routines */ +int kinLsDQJac(N_Vector u, N_Vector fu, SUNMatrix Jac, + void *data, N_Vector tmp1, N_Vector tmp2); + +int kinLsDenseDQJac(N_Vector u, N_Vector fu, SUNMatrix Jac, + KINMem kin_mem, N_Vector tmp1, N_Vector tmp2); + +int kinLsBandDQJac(N_Vector u, N_Vector fu, SUNMatrix Jac, + KINMem kin_mem, N_Vector tmp1, N_Vector tmp2); + +/* Generic linit/lsetup/lsolve/lfree interface routines for KINSOL to call */ +int kinLsInitialize(KINMem kin_mem); +int kinLsSetup(KINMem kin_mem); +int kinLsSolve(KINMem kin_mem, N_Vector x, N_Vector b, + realtype *sJpnorm, realtype *sFdotJp); +int kinLsFree(KINMem kin_mem); + +/* Auxilliary functions */ +int kinLsInitializeCounters(KINLsMem kinls_mem); +int kinLs_AccessLMem(void* kinmem, const char *fname, + KINMem* kin_mem, KINLsMem *kinls_mem); + + +/*------------------------------------------------------------------ + Error messages + ------------------------------------------------------------------*/ + +#define MSG_LS_KINMEM_NULL "KINSOL 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_LMEM_NULL "Linear solver memory is NULL." +#define MSG_LS_NEG_MAXRS "maxrs < 0 illegal." +#define MSG_LS_BAD_SIZES "Illegal bandwidth parameter(s). Must have 0 <= ml, mu <= N-1." + +#define MSG_LS_JACFUNC_FAILED "The Jacobian routine failed in an unrecoverable manner." +#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." +#define MSG_LS_JTIMES_FAILED "The Jacobian x vector routine failed in an unrecoverable manner." +#define MSG_LS_MATZERO_FAILED "The SUNMatZero routine failed in an unrecoverable manner." + + +/*------------------------------------------------------------------ + Info messages + ------------------------------------------------------------------*/ + +#define INFO_NLI "nli_inc = %d" + +#if defined(SUNDIALS_EXTENDED_PRECISION) + +#define INFO_EPS "residual norm = %12.3Lg eps = %12.3Lg" + +#elif defined(SUNDIALS_DOUBLE_PRECISION) + +#define INFO_EPS "residual norm = %12.3lg eps = %12.3lg" + +#else + +#define INFO_EPS "residual norm = %12.3g eps = %12.3g" + +#endif + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_spils.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_spils.c new file mode 100644 index 0000000..9e3ce82 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/kinsol/kinsol_spils.c @@ -0,0 +1,73 @@ +/*----------------------------------------------------------------- + * Programmer(s): Daniel R. Reynolds @ SMU + * Scott Cohen, Alan Hindmarsh, Radu Serban, + * 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 + *----------------------------------------------------------------- + * Header file for the deprecated Scaled Preconditioned Iterative + * Linear Solver interface in KINSOL; these routines now just wrap + * the updated KINSOL generic linear solver interface in kinsol_ls.h. + *-----------------------------------------------------------------*/ + +#include <kinsol/kinsol_ls.h> +#include <kinsol/kinsol_spils.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +/*================================================================= + Exported Functions (wrappers for equivalent routines in kinsol_ls.h) + =================================================================*/ + +int KINSpilsSetLinearSolver(void *kinmem, SUNLinearSolver LS) +{ return(KINSetLinearSolver(kinmem, LS, NULL)); } + +int KINSpilsSetPreconditioner(void *kinmem, KINSpilsPrecSetupFn psetup, + KINSpilsPrecSolveFn psolve) +{ return(KINSetPreconditioner(kinmem, psetup, psolve)); } + +int KINSpilsSetJacTimesVecFn(void *kinmem, KINSpilsJacTimesVecFn jtv) +{ return(KINSetJacTimesVecFn(kinmem, jtv)); } + +int KINSpilsGetWorkSpace(void *kinmem, long int *lenrwLS, long int *leniwLS) +{ return(KINGetLinWorkSpace(kinmem, lenrwLS, leniwLS)); } + +int KINSpilsGetNumPrecEvals(void *kinmem, long int *npevals) +{ return(KINGetNumPrecEvals(kinmem, npevals)); } + +int KINSpilsGetNumPrecSolves(void *kinmem, long int *npsolves) +{ return(KINGetNumPrecSolves(kinmem, npsolves)); } + +int KINSpilsGetNumLinIters(void *kinmem, long int *nliters) +{ return(KINGetNumLinIters(kinmem, nliters)); } + +int KINSpilsGetNumConvFails(void *kinmem, long int *nlcfails) +{ return(KINGetNumLinConvFails(kinmem, nlcfails)); } + +int KINSpilsGetNumJtimesEvals(void *kinmem, long int *njvevals) +{ return(KINGetNumJtimesEvals(kinmem, njvevals)); } + +int KINSpilsGetNumFuncEvals(void *kinmem, long int *nfevals) +{ return(KINGetNumLinFuncEvals(kinmem, nfevals)); } + +int KINSpilsGetLastFlag(void *kinmem, long int *flag) +{ return(KINGetLastLinFlag(kinmem, flag)); } + +char *KINSpilsGetReturnFlagName(long int flag) +{ return(KINGetLinReturnFlagName(flag)); } + + +#ifdef __cplusplus +} +#endif + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/openmp/fnvector_openmp.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/openmp/fnvector_openmp.c new file mode 100644 index 0000000..b54f6cb --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/openmp/fnvector_openmp.c @@ -0,0 +1,154 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Steven Smith @ 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 (companion of nvector_openmp.h) contains the + * implementation needed for the Fortran initialization of openmp + * vector operations. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fnvector_openmp.h" + +/* Define global vector variables */ + +N_Vector F2C_CVODE_vec; +N_Vector F2C_CVODE_vecQ; +N_Vector *F2C_CVODE_vecS; +N_Vector F2C_CVODE_vecB; +N_Vector F2C_CVODE_vecQB; + +N_Vector F2C_IDA_vec; +N_Vector F2C_IDA_vecQ; +N_Vector *F2C_IDA_vecS; +N_Vector F2C_IDA_vecB; +N_Vector F2C_IDA_vecQB; + +N_Vector F2C_KINSOL_vec; + +N_Vector F2C_ARKODE_vec; + +/* Fortran callable interfaces */ + +void FNV_INITOMP(int *code, long int *N, int *num_threads, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + F2C_CVODE_vec = NULL; + F2C_CVODE_vec = N_VNewEmpty_OpenMP(*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); + if (F2C_IDA_vec == NULL) *ier = -1; + break; + case FCMIX_KINSOL: + F2C_KINSOL_vec = NULL; + F2C_KINSOL_vec = N_VNewEmpty_OpenMP(*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); + if (F2C_ARKODE_vec == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + +void FNV_INITOMP_Q(int *code, long int *Nq, int *num_threads, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + F2C_CVODE_vecQ = NULL; + F2C_CVODE_vecQ = N_VNewEmpty_OpenMP(*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); + if (F2C_IDA_vecQ == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + +void FNV_INITOMP_B(int *code, long int *NB, int *num_threads, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + F2C_CVODE_vecB = NULL; + F2C_CVODE_vecB = N_VNewEmpty_OpenMP(*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); + if (F2C_IDA_vecB == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + +void FNV_INITOMP_QB(int *code, long int *NqB, int *num_threads, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + F2C_CVODE_vecQB = NULL; + F2C_CVODE_vecQB = N_VNewEmpty_OpenMP(*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); + if (F2C_IDA_vecQB == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + +void FNV_INITOMP_S(int *code, int *Ns, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + F2C_CVODE_vecS = NULL; + F2C_CVODE_vecS = (N_Vector *) N_VCloneVectorArrayEmpty_OpenMP(*Ns, F2C_CVODE_vec); + if (F2C_CVODE_vecS == NULL) *ier = -1; + break; + case FCMIX_IDA: + F2C_IDA_vecS = NULL; + F2C_IDA_vecS = (N_Vector *) N_VCloneVectorArrayEmpty_OpenMP(*Ns, F2C_IDA_vec); + if (F2C_IDA_vecS == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/openmp/fnvector_openmp.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/openmp/fnvector_openmp.h new file mode 100644 index 0000000..aa354de --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/openmp/fnvector_openmp.h @@ -0,0 +1,92 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Steven Smith @ 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 (companion of nvector_openmp.h) contains the + * definitions needed for the initialization of openmp + * vector operations in Fortran. + * ----------------------------------------------------------------- + */ + +#ifndef _FNVECTOR_OPENMP_H +#define _FNVECTOR_OPENMP_H + +#include <nvector/nvector_openmp.h> +#include <sundials/sundials_fnvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +#if defined(SUNDIALS_F77_FUNC) +#define FNV_INITOMP SUNDIALS_F77_FUNC(fnvinitomp, FNVINITOMP) +#else +#define FNV_INITOMP fnvinitomp_ +#endif + +#if defined(SUNDIALS_F77_FUNC_) + +#define FNV_INITOMP_Q SUNDIALS_F77_FUNC_(fnvinitomp_q, FNVINITOMP_Q) +#define FNV_INITOMP_S SUNDIALS_F77_FUNC_(fnvinitomp_s, FNVINITOMP_S) +#define FNV_INITOMP_B SUNDIALS_F77_FUNC_(fnvinitomp_b, FNVINITOMP_B) +#define FNV_INITOMP_QB SUNDIALS_F77_FUNC_(fnvinitomp_qb, FNVINITOMP_QB) + +#else + +#define FNV_INITOMP_Q fnvinitomp_q_ +#define FNV_INITOMP_S fnvinitomp_s_ +#define FNV_INITOMP_B fnvinitomp_b_ +#define FNV_INITOMP_QB fnvinitomp_qb_ + +#endif + +/* Declarations of global variables */ + +extern N_Vector F2C_CVODE_vec; +extern N_Vector F2C_CVODE_vecQ; +extern N_Vector *F2C_CVODE_vecS; +extern N_Vector F2C_CVODE_vecB; +extern N_Vector F2C_CVODE_vecQB; + +extern N_Vector F2C_IDA_vec; +extern N_Vector F2C_IDA_vecQ; +extern N_Vector *F2C_IDA_vecS; +extern N_Vector F2C_IDA_vecB; +extern N_Vector F2C_IDA_vecQB; + +extern N_Vector F2C_KINSOL_vec; + +extern N_Vector F2C_ARKODE_vec; + +/* + * Prototypes of exported functions + * + * FNV_INITOMP - initializes openmp vector operations for main problem + * FNV_INITOMP_Q - initializes openmp vector operations for quadratures + * FNV_INITOMP_S - initializes openmp vector operations for sensitivities + * FNV_INITOMP_B - initializes openmp vector operations for adjoint problem + * FNV_INITOMP_QB - initializes openmp vector operations for adjoint quadratures + * + */ + +void FNV_INITOMP(int *code, long int *neq, int *num_threads, int *ier); +void FNV_INITOMP_Q(int *code, long int *Nq, int *num_threads, int *ier); +void FNV_INITOMP_S(int *code, int *Ns, int *ier); +void FNV_INITOMP_B(int *code, long int *NB, int *num_threads, int *ier); +void FNV_INITOMP_QB(int *code, long int *NqB, int *num_threads, int *ier); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/openmp/nvector_openmp.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/openmp/nvector_openmp.c new file mode 100644 index 0000000..e278029 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/openmp/nvector_openmp.c @@ -0,0 +1,2586 @@ +/* ----------------------------------------------------------------- + * 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 + * @ 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 an OpenMP implementation + * of the NVECTOR module. + * -----------------------------------------------------------------*/ + +#include <omp.h> + +#include <stdio.h> +#include <stdlib.h> + +#include <nvector/nvector_openmp.h> +#include <sundials/sundials_math.h> + +#define ZERO RCONST(0.0) +#define HALF RCONST(0.5) +#define ONE RCONST(1.0) +#define ONEPT5 RCONST(1.5) + +/* Private functions for special cases of vector operations */ +static void VCopy_OpenMP(N_Vector x, N_Vector z); /* z=x */ +static void VSum_OpenMP(N_Vector x, N_Vector y, N_Vector z); /* z=x+y */ +static void VDiff_OpenMP(N_Vector x, N_Vector y, N_Vector z); /* z=x-y */ +static void VNeg_OpenMP(N_Vector x, N_Vector z); /* z=-x */ +static void VScaleSum_OpenMP(realtype c, N_Vector x, N_Vector y, N_Vector z); /* z=c(x+y) */ +static void VScaleDiff_OpenMP(realtype c, N_Vector x, N_Vector y, N_Vector z); /* z=c(x-y) */ +static void VLin1_OpenMP(realtype a, N_Vector x, N_Vector y, N_Vector z); /* z=ax+y */ +static void VLin2_OpenMP(realtype a, N_Vector x, N_Vector y, N_Vector z); /* z=ax-y */ +static void Vaxpy_OpenMP(realtype a, N_Vector x, N_Vector y); /* y <- ax+y */ +static void VScaleBy_OpenMP(realtype a, N_Vector x); /* x <- ax */ + +/* Private functions for special cases of vector array operations */ +static int VSumVectorArray_OpenMP(int nvec, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=X+Y */ +static int VDiffVectorArray_OpenMP(int nvec, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=X-Y */ +static int VScaleSumVectorArray_OpenMP(int nvec, realtype c, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=c(X+Y) */ +static int VScaleDiffVectorArray_OpenMP(int nvec, realtype c, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=c(X-Y) */ +static int VLin1VectorArray_OpenMP(int nvec, realtype a, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=aX+Y */ +static int VLin2VectorArray_OpenMP(int nvec, realtype a, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=aX-Y */ +static int VaxpyVectorArray_OpenMP(int nvec, realtype a, N_Vector* X, N_Vector* Y); /* Y <- aX+Y */ + +/* + * ----------------------------------------------------------------- + * exported functions + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------- + * Returns vector type ID. Used to identify vector implementation + * from abstract N_Vector interface. + */ +N_Vector_ID N_VGetVectorID_OpenMP(N_Vector v) +{ + return SUNDIALS_NVEC_OPENMP; +} + +/* ---------------------------------------------------------------------------- + * Function to create a new empty vector + */ + +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); + 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 = 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; + + /* 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; + + /* 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 = 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); +} + +/* ---------------------------------------------------------------------------- + * Function to create a new vector + */ + +N_Vector N_VNew_OpenMP(sunindextype length, int num_threads) +{ + N_Vector v; + realtype *data; + + v = NULL; + v = N_VNewEmpty_OpenMP(length, num_threads); + if (v == NULL) return(NULL); + + /* Create data */ + if (length > 0) { + + /* Allocate memory */ + data = NULL; + data = (realtype *) malloc(length * sizeof(realtype)); + if(data == NULL) { N_VDestroy_OpenMP(v); return(NULL); } + + /* Attach data */ + NV_OWN_DATA_OMP(v) = SUNTRUE; + NV_DATA_OMP(v) = data; + + } + + return(v); +} + +/* ---------------------------------------------------------------------------- + * Function to create a vector with user data component + */ + +N_Vector N_VMake_OpenMP(sunindextype length, realtype *v_data, int num_threads) +{ + N_Vector v; + + v = NULL; + v = N_VNewEmpty_OpenMP(length, num_threads); + if (v == NULL) return(NULL); + + if (length > 0) { + /* Attach data */ + NV_OWN_DATA_OMP(v) = SUNFALSE; + NV_DATA_OMP(v) = v_data; + } + + return(v); +} + +/* ---------------------------------------------------------------------------- + * Function to create an array of new vectors. + */ + +N_Vector *N_VCloneVectorArray_OpenMP(int count, N_Vector w) +{ + N_Vector *vs; + int j; + + if (count <= 0) return(NULL); + + vs = NULL; + vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + if(vs == NULL) return(NULL); + + for (j = 0; j < count; j++) { + vs[j] = NULL; + vs[j] = N_VClone_OpenMP(w); + if (vs[j] == NULL) { + N_VDestroyVectorArray_OpenMP(vs, j-1); + return(NULL); + } + } + + return(vs); +} + +/* ---------------------------------------------------------------------------- + * Function to create an array of new vectors with NULL data array. + */ + +N_Vector *N_VCloneVectorArrayEmpty_OpenMP(int count, N_Vector w) +{ + N_Vector *vs; + int j; + + if (count <= 0) return(NULL); + + vs = NULL; + vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + if(vs == NULL) return(NULL); + + for (j = 0; j < count; j++) { + vs[j] = NULL; + vs[j] = N_VCloneEmpty_OpenMP(w); + if (vs[j] == NULL) { + N_VDestroyVectorArray_OpenMP(vs, j-1); + return(NULL); + } + } + + return(vs); +} + +/* ---------------------------------------------------------------------------- + * Function to free an array created with N_VCloneVectorArray_OpenMP + */ + +void N_VDestroyVectorArray_OpenMP(N_Vector *vs, int count) +{ + int j; + + for (j = 0; j < count; j++) N_VDestroy_OpenMP(vs[j]); + + free(vs); vs = NULL; + + return; +} + +/* ---------------------------------------------------------------------------- + * Function to return number of vector elements + */ +sunindextype N_VGetLength_OpenMP(N_Vector v) +{ + return NV_LENGTH_OMP(v); +} + +/* ---------------------------------------------------------------------------- + * Function to print a vector to stdout + */ + +void N_VPrint_OpenMP(N_Vector x) +{ + N_VPrintFile_OpenMP(x, stdout); +} + +/* ---------------------------------------------------------------------------- + * Function to print a vector to outfile + */ + +void N_VPrintFile_OpenMP(N_Vector x, FILE *outfile) +{ + sunindextype i, N; + realtype *xd; + + xd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + + for (i = 0; i < N; i++) { +#if defined(SUNDIALS_EXTENDED_PRECISION) + fprintf(outfile, "%11.8Lg\n", xd[i]); +#elif defined(SUNDIALS_DOUBLE_PRECISION) + fprintf(outfile, "%11.8g\n", xd[i]); +#else + fprintf(outfile, "%11.8g\n", xd[i]); +#endif + } + fprintf(outfile, "\n"); + + return; +} + +/* + * ----------------------------------------------------------------- + * implementation of vector operations + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------------------- + * Create new vector from existing vector without attaching data + */ + +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); + 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 */ + 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; + + /* Attach content and ops */ + v->content = content; + v->ops = ops; + + return(v); +} + + +/* ---------------------------------------------------------------------------- + * Create new vector from existing vector and attach data + */ + +N_Vector N_VClone_OpenMP(N_Vector w) +{ + N_Vector v; + realtype *data; + sunindextype length; + + v = NULL; + v = N_VCloneEmpty_OpenMP(w); + if (v == NULL) return(NULL); + + length = NV_LENGTH_OMP(w); + + /* Create data */ + if (length > 0) { + + /* Allocate memory */ + data = NULL; + data = (realtype *) malloc(length * sizeof(realtype)); + if(data == NULL) { N_VDestroy_OpenMP(v); return(NULL); } + + /* Attach data */ + NV_OWN_DATA_OMP(v) = SUNTRUE; + NV_DATA_OMP(v) = data; + + } + + return(v); +} + + +/* ---------------------------------------------------------------------------- + * Destroy vector and free vector memory + */ + +void N_VDestroy_OpenMP(N_Vector v) +{ + if (NV_OWN_DATA_OMP(v) == SUNTRUE) { + free(NV_DATA_OMP(v)); + NV_DATA_OMP(v) = NULL; + } + free(v->content); v->content = NULL; + free(v->ops); v->ops = NULL; + free(v); v = NULL; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Get storage requirement for N_Vector + */ + +void N_VSpace_OpenMP(N_Vector v, sunindextype *lrw, sunindextype *liw) +{ + *lrw = NV_LENGTH_OMP(v); + *liw = 1; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Get vector data pointer + */ + +realtype *N_VGetArrayPointer_OpenMP(N_Vector v) +{ + return((realtype *) NV_DATA_OMP(v)); +} + + +/* ---------------------------------------------------------------------------- + * Set vector data pointer + */ + +void N_VSetArrayPointer_OpenMP(realtype *v_data, N_Vector v) +{ + if (NV_LENGTH_OMP(v) > 0) NV_DATA_OMP(v) = v_data; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute linear combination z[i] = a*x[i]+b*y[i] + */ + +void N_VLinearSum_OpenMP(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype c, *xd, *yd, *zd; + N_Vector v1, v2; + booleantype test; + + xd = yd = zd = NULL; + + if ((b == ONE) && (z == y)) { /* BLAS usage: axpy y <- ax+y */ + Vaxpy_OpenMP(a,x,y); + return; + } + + if ((a == ONE) && (z == x)) { /* BLAS usage: axpy x <- by+x */ + Vaxpy_OpenMP(b,y,x); + return; + } + + /* Case: a == b == 1.0 */ + + if ((a == ONE) && (b == ONE)) { + VSum_OpenMP(x, y, z); + return; + } + + /* Cases: (1) a == 1.0, b = -1.0, (2) a == -1.0, b == 1.0 */ + + if ((test = ((a == ONE) && (b == -ONE))) || ((a == -ONE) && (b == ONE))) { + v1 = test ? y : x; + v2 = test ? x : y; + VDiff_OpenMP(v2, v1, z); + return; + } + + /* Cases: (1) a == 1.0, b == other or 0.0, (2) a == other or 0.0, b == 1.0 */ + /* if a or b is 0.0, then user should have called N_VScale */ + + if ((test = (a == ONE)) || (b == ONE)) { + c = test ? b : a; + v1 = test ? y : x; + v2 = test ? x : y; + VLin1_OpenMP(c, v1, v2, z); + return; + } + + /* Cases: (1) a == -1.0, b != 1.0, (2) a != 1.0, b == -1.0 */ + + if ((test = (a == -ONE)) || (b == -ONE)) { + c = test ? b : a; + v1 = test ? y : x; + v2 = test ? x : y; + VLin2_OpenMP(c, v1, v2, z); + return; + } + + /* Case: a == b */ + /* catches case both a and b are 0.0 - user should have called N_VConst */ + + if (a == b) { + VScaleSum_OpenMP(a, x, y, z); + return; + } + + /* Case: a == -b */ + + if (a == -b) { + VScaleDiff_OpenMP(a, x, y, z); + return; + } + + /* Do all cases not handled above: + (1) a == other, b == 0.0 - user should have called N_VScale + (2) a == 0.0, b == other - user should have called N_VScale + (3) a,b == other, a !=b, a != -b */ + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + yd = NV_DATA_OMP(y); + zd = NV_DATA_OMP(z); + +#pragma omp parallel for default(none) private(i) shared(N,a,b,xd,yd,zd) schedule(static) \ + num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) + zd[i] = (a*xd[i])+(b*yd[i]); + + return; +} + + +/* ---------------------------------------------------------------------------- + * Assigns constant value to all vector elements, z[i] = c + */ + +void N_VConst_OpenMP(realtype c, N_Vector z) +{ + sunindextype i, N; + realtype *zd; + + zd = NULL; + + N = NV_LENGTH_OMP(z); + zd = NV_DATA_OMP(z); + +#pragma omp parallel for default(none) private(i) shared(N,c,zd) schedule(static) \ + num_threads(NV_NUM_THREADS_OMP(z)) + for (i = 0; i < N; i++) zd[i] = c; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute componentwise product z[i] = x[i]*y[i] + */ + +void N_VProd_OpenMP(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + yd = NV_DATA_OMP(y); + zd = NV_DATA_OMP(z); + +#pragma omp parallel for default(none) private(i) shared(N,xd,yd,zd) schedule(static) \ + num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) + zd[i] = xd[i]*yd[i]; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute componentwise division z[i] = x[i]/y[i] + */ + +void N_VDiv_OpenMP(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + yd = NV_DATA_OMP(y); + zd = NV_DATA_OMP(z); + +#pragma omp parallel for default(none) private(i) shared(N,xd,yd,zd) schedule(static) \ + num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) + zd[i] = xd[i]/yd[i]; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute scaler multiplication z[i] = c*x[i] + */ + +void N_VScale_OpenMP(realtype c, N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + if (z == x) { /* BLAS usage: scale x <- cx */ + VScaleBy_OpenMP(c, x); + return; + } + + if (c == ONE) { + VCopy_OpenMP(x, z); + } else if (c == -ONE) { + VNeg_OpenMP(x, z); + } else { + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + zd = NV_DATA_OMP(z); + +#pragma omp parallel for default(none) private(i) shared(N,c,xd,zd) schedule(static) \ + num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) + zd[i] = c*xd[i]; + } + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute absolute value of vector components z[i] = SUNRabs(x[i]) + */ + +void N_VAbs_OpenMP(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + zd = NV_DATA_OMP(z); + +#pragma omp parallel for schedule(static) num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) + zd[i] = SUNRabs(xd[i]); + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute componentwise inverse z[i] = 1 / x[i] + */ + +void N_VInv_OpenMP(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + zd = NV_DATA_OMP(z); + +#pragma omp parallel for default(none) private(i) shared(N,xd,zd) schedule(static) \ + num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) + zd[i] = ONE/xd[i]; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute componentwise addition of a scaler to a vector z[i] = x[i] + b + */ + +void N_VAddConst_OpenMP(N_Vector x, realtype b, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + zd = NV_DATA_OMP(z); + +#pragma omp parallel for default(none) private(i) shared(N,b,xd,zd) schedule(static) \ + num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) + zd[i] = xd[i]+b; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Computes the dot product of two vectors, a = sum(x[i]*y[i]) + */ + +realtype N_VDotProd_OpenMP(N_Vector x, N_Vector y) +{ + sunindextype i, N; + realtype sum, *xd, *yd; + + sum = ZERO; + xd = yd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + yd = NV_DATA_OMP(y); + +#pragma omp parallel for default(none) private(i) shared(N,xd,yd) \ + reduction(+:sum) schedule(static) num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) { + sum += xd[i]*yd[i]; + } + + return(sum); +} + + +/* ---------------------------------------------------------------------------- + * Computes max norm of a vector + */ + +realtype N_VMaxNorm_OpenMP(N_Vector x) +{ + sunindextype i, N; + realtype tmax, max, *xd; + + max = ZERO; + xd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + +#pragma omp parallel default(none) private(i,tmax) shared(N,max,xd) \ + num_threads(NV_NUM_THREADS_OMP(x)) + { + tmax = ZERO; +#pragma omp for schedule(static) + for (i = 0; i < N; i++) { + if (SUNRabs(xd[i]) > tmax) tmax = SUNRabs(xd[i]); + } +#pragma omp critical + { + if (tmax > max) + max = tmax; + } + } + return(max); +} + + +/* ---------------------------------------------------------------------------- + * Computes weighted root mean square norm of a vector + */ + +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)); +} + + +/* ---------------------------------------------------------------------------- + * Computes weighted root mean square norm of a masked vector + */ + +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)); +} + + +/* ---------------------------------------------------------------------------- + * Finds the minimun component of a vector + */ + +realtype N_VMin_OpenMP(N_Vector x) +{ + sunindextype i, N; + realtype min, *xd; + realtype tmin; + + xd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + + min = xd[0]; + +#pragma omp parallel default(none) private(i,tmin) shared(N,min,xd) \ + num_threads(NV_NUM_THREADS_OMP(x)) + { + tmin = xd[0]; +#pragma omp for schedule(static) + for (i = 1; i < N; i++) { + if (xd[i] < tmin) tmin = xd[i]; + } + if (tmin < min) { +#pragma omp critical + { + if (tmin < min) min = tmin; + } + } + } + + return(min); +} + + +/* ---------------------------------------------------------------------------- + * Computes weighted L2 norm of a vector + */ + +realtype N_VWL2Norm_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)); +} + + +/* ---------------------------------------------------------------------------- + * Computes L1 norm of a vector + */ + +realtype N_VL1Norm_OpenMP(N_Vector x) +{ + sunindextype i, N; + realtype sum, *xd; + + sum = ZERO; + xd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + +#pragma omp parallel for default(none) private(i) shared(N,xd) \ + reduction(+:sum) schedule(static) num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i<N; i++) + sum += SUNRabs(xd[i]); + + return(sum); +} + + +/* ---------------------------------------------------------------------------- + * Compare vector component values to a scaler + */ + +void N_VCompare_OpenMP(realtype c, N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + zd = NV_DATA_OMP(z); + +#pragma omp parallel for default(none) private(i) shared(N,c,xd,zd) schedule(static) \ + num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) { + zd[i] = (SUNRabs(xd[i]) >= c) ? ONE : ZERO; + } + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute componentwise inverse z[i] = ONE/x[i] and checks if x[i] == ZERO + */ + +booleantype N_VInvTest_OpenMP(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd, val; + + xd = zd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + zd = NV_DATA_OMP(z); + + val = ZERO; + +#pragma omp parallel for default(none) private(i) shared(N,val,xd,zd) schedule(static) \ + num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) { + if (xd[i] == ZERO) + val = ONE; + else + zd[i] = ONE/xd[i]; + } + + if (val > ZERO) + return (SUNFALSE); + else + return (SUNTRUE); +} + + +/* ---------------------------------------------------------------------------- + * Compute constraint mask of a vector + */ + +booleantype N_VConstrMask_OpenMP(N_Vector c, N_Vector x, N_Vector m) +{ + sunindextype i, N; + realtype temp; + realtype *cd, *xd, *md; + booleantype test; + + cd = xd = md = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + cd = NV_DATA_OMP(c); + md = NV_DATA_OMP(m); + + temp = ZERO; + +#pragma omp parallel for default(none) private(i,test) shared(N,xd,cd,md,temp) \ + schedule(static) num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) { + md[i] = ZERO; + + /* Continue if no constraints were set for the variable */ + if (cd[i] == ZERO) + continue; + + /* Check if a set constraint has been violated */ + test = (SUNRabs(cd[i]) > ONEPT5 && xd[i]*cd[i] <= ZERO) || + (SUNRabs(cd[i]) > HALF && xd[i]*cd[i] < ZERO); + if (test) { + temp = md[i] = ONE; /* Here is a race to write to temp */ + } + } + /* Return false if any constraint was violated */ + return (temp == ONE) ? SUNFALSE : SUNTRUE; +} + + +/* ---------------------------------------------------------------------------- + * Compute minimum componentwise quotient + */ + +realtype N_VMinQuotient_OpenMP(N_Vector num, N_Vector denom) +{ + sunindextype i, N; + realtype *nd, *dd, min, tmin, val; + + nd = dd = NULL; + + N = NV_LENGTH_OMP(num); + nd = NV_DATA_OMP(num); + dd = NV_DATA_OMP(denom); + + min = BIG_REAL; + +#pragma omp parallel default(none) private(i,tmin,val) shared(N,min,nd,dd) \ + num_threads(NV_NUM_THREADS_OMP(num)) + { + tmin = BIG_REAL; +#pragma omp for schedule(static) + for (i = 0; i < N; i++) { + if (dd[i] != ZERO) { + val = nd[i]/dd[i]; + if (val < tmin) tmin = val; + } + } + if (tmin < min) { +#pragma omp critical + { + if (tmin < min) min = tmin; + } + } + } + + return(min); +} + + +/* + * ----------------------------------------------------------------- + * fused vector operations + * ----------------------------------------------------------------- + */ + +int N_VLinearCombination_OpenMP(int nvec, realtype* c, N_Vector* X, N_Vector z) +{ + int i; + sunindextype j, N; + realtype* zd=NULL; + realtype* xd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VScale */ + if (nvec == 1) { + N_VScale_OpenMP(c[0], X[0], z); + return(0); + } + + /* should have called N_VLinearSum */ + if (nvec == 2) { + N_VLinearSum_OpenMP(c[0], X[0], c[1], X[1], z); + return(0); + } + + /* get vector length and data array */ + N = NV_LENGTH_OMP(z); + zd = NV_DATA_OMP(z); + + + /* + * X[0] += c[i]*X[i], i = 1,...,nvec-1 + */ + if ((X[0] == z) && (c[0] == ONE)) { +#pragma omp parallel default(none) private(i,j,xd) shared(nvec,X,N,c,zd) \ + num_threads(NV_NUM_THREADS_OMP(z)) + { + for (i=1; i<nvec; i++) { + xd = NV_DATA_OMP(X[i]); +#pragma omp for schedule(static) + for (j=0; j<N; j++) { + zd[j] += c[i] * xd[j]; + } + } + } + return(0); + } + + /* + * X[0] = c[0] * X[0] + sum{ c[i] * X[i] }, i = 1,...,nvec-1 + */ + if (X[0] == z) { +#pragma omp parallel default(none) private(i,j,xd) shared(nvec,X,N,c,zd) \ + num_threads(NV_NUM_THREADS_OMP(z)) + { +#pragma omp for schedule(static) + for (j=0; j<N; j++) { + zd[j] *= c[0]; + } + + for (i=1; i<nvec; i++) { + xd = NV_DATA_OMP(X[i]); +#pragma omp for schedule(static) + for (j=0; j<N; j++) { + zd[j] += c[i] * xd[j]; + } + } + } + return(0); + } + + /* + * z = sum{ c[i] * X[i] }, i = 0,...,nvec-1 + */ +#pragma omp parallel default(none) private(i,j,xd) shared(nvec,X,N,c,zd) \ + num_threads(NV_NUM_THREADS_OMP(z)) + { + xd = NV_DATA_OMP(X[0]); +#pragma omp for schedule(static) + for (j=0; j<N; j++) { + zd[j] = c[0] * xd[j]; + } + + for (i=1; i<nvec; i++) { + xd = NV_DATA_OMP(X[i]); +#pragma omp for schedule(static) + for (j=0; j<N; j++) { + zd[j] += c[i] * xd[j]; + } + } + } + return(0); +} + + +int N_VScaleAddMulti_OpenMP(int nvec, realtype* a, N_Vector x, N_Vector* Y, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VLinearSum */ + if (nvec == 1) { + N_VLinearSum_OpenMP(a[0], x, ONE, Y[0], Z[0]); + return(0); + } + + /* get vector length and data array */ + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + + /* + * Y[i][j] += a[i] * x[j] + */ + if (Y == Z) { +#pragma omp parallel default(none) private(i,j,yd) shared(nvec,Y,N,a,xd) \ + num_threads(NV_NUM_THREADS_OMP(x)) + { + for (i=0; i<nvec; i++) { + yd = NV_DATA_OMP(Y[i]); +#pragma omp for schedule(static) + for (j=0; j<N; j++) { + yd[j] += a[i] * xd[j]; + } + } + } + return(0); + } + + /* + * Z[i][j] = Y[i][j] + a[i] * x[j] + */ +#pragma omp parallel default(none) private(i,j,yd,zd) shared(nvec,Y,Z,N,a,xd) \ + num_threads(NV_NUM_THREADS_OMP(x)) + { + for (i=0; i<nvec; i++) { + yd = NV_DATA_OMP(Y[i]); + zd = NV_DATA_OMP(Z[i]); +#pragma omp for schedule(static) + for (j=0; j<N; j++) { + zd[j] = a[i] * xd[j] + yd[j]; + } + } + } + return(0); +} + + +int N_VDotProdMulti_OpenMP(int nvec, N_Vector x, N_Vector* Y, realtype* dotprods) +{ + int i; + sunindextype j, N; + realtype sum; + realtype* xd=NULL; + realtype* yd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VDotProd */ + if (nvec == 1) { + dotprods[0] = N_VDotProd_OpenMP(x, Y[0]); + return(0); + } + + /* get vector length and data array */ + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + + /* initialize dot products */ + for (i=0; i<nvec; i++) { + dotprods[i] = ZERO; + } + + /* compute multiple dot products */ +#pragma omp parallel default(none) private(i,j,yd,sum) shared(nvec,Y,N,xd,dotprods) \ + num_threads(NV_NUM_THREADS_OMP(x)) + { + for (i=0; i<nvec; i++) { + yd = NV_DATA_OMP(Y[i]); + sum = ZERO; +#pragma omp for schedule(static) + for (j=0; j<N; j++) { + sum += xd[j] * yd[j]; + } +#pragma omp critical + { + dotprods[i] += sum; + } + } + } + + return(0); +} + + +/* + * ----------------------------------------------------------------- + * vector array operations + * ----------------------------------------------------------------- + */ + +int N_VLinearSumVectorArray_OpenMP(int nvec, + realtype a, N_Vector* X, + realtype b, N_Vector* Y, + N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + realtype c; + N_Vector* V1; + N_Vector* V2; + booleantype test; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VLinearSum */ + if (nvec == 1) { + N_VLinearSum_OpenMP(a, X[0], b, Y[0], Z[0]); + return(0); + } + + /* BLAS usage: axpy y <- ax+y */ + if ((b == ONE) && (Z == Y)) + return(VaxpyVectorArray_OpenMP(nvec, a, X, Y)); + + /* BLAS usage: axpy x <- by+x */ + if ((a == ONE) && (Z == X)) + return(VaxpyVectorArray_OpenMP(nvec, b, Y, X)); + + /* Case: a == b == 1.0 */ + if ((a == ONE) && (b == ONE)) + return(VSumVectorArray_OpenMP(nvec, X, Y, Z)); + + /* Cases: */ + /* (1) a == 1.0, b = -1.0, */ + /* (2) a == -1.0, b == 1.0 */ + if ((test = ((a == ONE) && (b == -ONE))) || ((a == -ONE) && (b == ONE))) { + V1 = test ? Y : X; + V2 = test ? X : Y; + return(VDiffVectorArray_OpenMP(nvec, V2, V1, Z)); + } + + /* Cases: */ + /* (1) a == 1.0, b == other or 0.0, */ + /* (2) a == other or 0.0, b == 1.0 */ + /* if a or b is 0.0, then user should have called N_VScale */ + if ((test = (a == ONE)) || (b == ONE)) { + c = test ? b : a; + V1 = test ? Y : X; + V2 = test ? X : Y; + return(VLin1VectorArray_OpenMP(nvec, c, V1, V2, Z)); + } + + /* Cases: */ + /* (1) a == -1.0, b != 1.0, */ + /* (2) a != 1.0, b == -1.0 */ + if ((test = (a == -ONE)) || (b == -ONE)) { + c = test ? b : a; + V1 = test ? Y : X; + V2 = test ? X : Y; + return(VLin2VectorArray_OpenMP(nvec, c, V1, V2, Z)); + } + + /* Case: a == b */ + /* catches case both a and b are 0.0 - user should have called N_VConst */ + if (a == b) + return(VScaleSumVectorArray_OpenMP(nvec, a, X, Y, Z)); + + /* Case: a == -b */ + if (a == -b) + return(VScaleDiffVectorArray_OpenMP(nvec, a, X, Y, Z)); + + /* Do all cases not handled above: */ + /* (1) a == other, b == 0.0 - user should have called N_VScale */ + /* (2) a == 0.0, b == other - user should have called N_VScale */ + /* (3) a,b == other, a !=b, a != -b */ + + /* get vector length */ + N = NV_LENGTH_OMP(Z[0]); + + /* compute linear sum for each vector pair in vector arrays */ +#pragma omp parallel default(none) private(i,j,xd,yd,zd) shared(nvec,X,Y,Z,N,a,b) \ + num_threads(NV_NUM_THREADS_OMP(Z[0])) + { + for (i=0; i<nvec; i++) { + xd = NV_DATA_OMP(X[i]); + yd = NV_DATA_OMP(Y[i]); + zd = NV_DATA_OMP(Z[i]); +#pragma omp for schedule(static) + for (j=0; j<N; j++) { + zd[j] = a * xd[j] + b * yd[j]; + } + } + } + + return(0); +} + + +int N_VScaleVectorArray_OpenMP(int nvec, realtype* c, N_Vector* X, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* zd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VScale */ + if (nvec == 1) { + N_VScale_OpenMP(c[0], X[0], Z[0]); + return(0); + } + + /* get vector length */ + N = NV_LENGTH_OMP(Z[0]); + + /* + * X[i] *= c[i] + */ + if (X == Z) { +#pragma omp parallel default(none) private(i,j,xd) shared(nvec,X,N,c) \ + num_threads(NV_NUM_THREADS_OMP(Z[0])) + { + for (i=0; i<nvec; i++) { + xd = NV_DATA_OMP(X[i]); +#pragma omp for schedule(static) + for (j=0; j<N; j++) { + xd[j] *= c[i]; + } + } + } + return(0); + } + + /* + * Z[i] = c[i] * X[i] + */ +#pragma omp parallel default(none) private(i,j,xd,zd) shared(nvec,X,Z,N,c) \ + num_threads(NV_NUM_THREADS_OMP(Z[0])) + { + for (i=0; i<nvec; i++) { + xd = NV_DATA_OMP(X[i]); + zd = NV_DATA_OMP(Z[i]); +#pragma omp for schedule(static) + for (j=0; j<N; j++) { + zd[j] = c[i] * xd[j]; + } + } + } + return(0); +} + + +int N_VConstVectorArray_OpenMP(int nvec, realtype c, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* zd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VConst */ + if (nvec == 1) { + N_VConst_OpenMP(c, Z[0]); + return(0); + } + + /* get vector length */ + N = NV_LENGTH_OMP(Z[0]); + + /* set each vector in the vector array to a constant */ +#pragma omp parallel default(none) private(i,j,zd) shared(nvec,Z,N,c) \ + num_threads(NV_NUM_THREADS_OMP(Z[0])) + { + for (i=0; i<nvec; i++) { + zd = NV_DATA_OMP(Z[i]); +#pragma omp for schedule(static) + for (j=0; j<N; j++) { + zd[j] = c; + } + } + } + + return(0); +} + + +int N_VWrmsNormVectorArray_OpenMP(int nvec, N_Vector* X, N_Vector* W, realtype* nrm) +{ + int i; + sunindextype j, N; + realtype sum; + realtype* wd=NULL; + realtype* xd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VWrmsNorm */ + if (nvec == 1) { + nrm[0] = N_VWrmsNorm_OpenMP(X[0], W[0]); + return(0); + } + + /* get vector length */ + N = NV_LENGTH_OMP(X[0]); + + /* initialize norms */ + for (i=0; i<nvec; i++) { + nrm[i] = ZERO; + } + + /* compute the WRMS norm for each vector in the vector array */ +#pragma omp parallel default(none) private(i,j,xd,wd,sum) shared(nvec,X,W,N,nrm) \ + num_threads(NV_NUM_THREADS_OMP(X[0])) + { + for (i=0; i<nvec; i++) { + xd = NV_DATA_OMP(X[i]); + wd = NV_DATA_OMP(W[i]); + sum = ZERO; +#pragma omp for schedule(static) + for (j=0; j<N; j++) { + sum += SUNSQR(xd[j] * wd[j]); + } +#pragma omp critical + { + nrm[i] += sum; + } + } + } + + for (i=0; i<nvec; i++) { + nrm[i] = SUNRsqrt(nrm[i]/N); + } + + return(0); +} + + +int N_VWrmsNormMaskVectorArray_OpenMP(int nvec, N_Vector* X, N_Vector* W, + N_Vector id, realtype* nrm) +{ + int i; + sunindextype j, N; + realtype sum; + realtype* wd=NULL; + realtype* xd=NULL; + realtype* idd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VWrmsNorm */ + if (nvec == 1) { + nrm[0] = N_VWrmsNormMask_OpenMP(X[0], W[0], id); + return(0); + } + + /* get vector length and mask data array */ + N = NV_LENGTH_OMP(X[0]); + idd = NV_DATA_OMP(id); + + /* initialize norms */ + for (i=0; i<nvec; i++) { + nrm[i] = ZERO; + } + + /* compute the WRMS norm for each vector in the vector array */ +#pragma omp parallel default(none) private(i,j,xd,wd,sum) shared(nvec,X,W,N,idd,nrm) \ + num_threads(NV_NUM_THREADS_OMP(X[0])) + { + for (i=0; i<nvec; i++) { + xd = NV_DATA_OMP(X[i]); + wd = NV_DATA_OMP(W[i]); + sum = ZERO; +#pragma omp for schedule(static) + for (j=0; j<N; j++) { + if (idd[j] > ZERO) + sum += SUNSQR(xd[j] * wd[j]); + } +#pragma omp critical + { + nrm[i] += sum; + } + } + } + + for (i=0; i<nvec; i++) { + nrm[i] = SUNRsqrt(nrm[i]/N); + } + + return(0); +} + + +int N_VScaleAddMultiVectorArray_OpenMP(int nvec, int nsum, realtype* a, + N_Vector* X, N_Vector** Y, N_Vector** Z) +{ + int i, j; + sunindextype k, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + int retval; + N_Vector* YY; + N_Vector* ZZ; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + if (nsum < 1) return(-1); + + /* --------------------------- + * Special cases for nvec == 1 + * --------------------------- */ + + if (nvec == 1) { + + /* should have called N_VLinearSum */ + if (nsum == 1) { + N_VLinearSum_OpenMP(a[0], X[0], ONE, Y[0][0], Z[0][0]); + return(0); + } + + /* should have called N_VScaleAddMulti */ + YY = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + ZZ = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + + for (j=0; j<nsum; j++) { + YY[j] = Y[j][0]; + ZZ[j] = Z[j][0]; + } + + retval = N_VScaleAddMulti_OpenMP(nsum, a, X[0], YY, ZZ); + + free(YY); + free(ZZ); + return(retval); + } + + /* -------------------------- + * Special cases for nvec > 1 + * -------------------------- */ + + /* should have called N_VLinearSumVectorArray */ + if (nsum == 1) { + retval = N_VLinearSumVectorArray_OpenMP(nvec, a[0], X, ONE, Y[0], Z[0]); + return(retval); + } + + /* ---------------------------- + * Compute multiple linear sums + * ---------------------------- */ + + /* get vector length */ + N = NV_LENGTH_OMP(X[0]); + + /* + * Y[i][j] += a[i] * x[j] + */ + if (Y == Z) { +#pragma omp parallel default(none) private(i,j,k,xd,yd) shared(nvec,nsum,X,Y,N,a) \ + num_threads(NV_NUM_THREADS_OMP(X[0])) + { + for (i=0; i<nvec; i++) { + xd = NV_DATA_OMP(X[i]); + for (j=0; j<nsum; j++) { + yd = NV_DATA_OMP(Y[j][i]); +#pragma omp for schedule(static) + for (k=0; k<N; k++) { + yd[k] += a[j] * xd[k]; + } + } + } + } + return(0); + } + + /* + * Z[i][j] = Y[i][j] + a[i] * x[j] + */ +#pragma omp parallel default(none) private(i,j,k,xd,yd,zd) shared(nvec,nsum,X,Y,Z,N,a) \ + num_threads(NV_NUM_THREADS_OMP(X[0])) + { + for (i=0; i<nvec; i++) { + xd = NV_DATA_OMP(X[i]); + for (j=0; j<nsum; j++) { + yd = NV_DATA_OMP(Y[j][i]); + zd = NV_DATA_OMP(Z[j][i]); +#pragma omp for schedule(static) + for (k=0; k<N; k++) { + zd[k] = a[j] * xd[k] + yd[k]; + } + } + } + } + return(0); +} + + +int N_VLinearCombinationVectorArray_OpenMP(int nvec, int nsum, + realtype* c, + N_Vector** X, + N_Vector* Z) +{ + int i; /* vector arrays index in summation [0,nsum) */ + int j; /* vector index in vector array [0,nvec) */ + sunindextype k; /* element index in vector [0,N) */ + sunindextype N; + realtype* zd=NULL; + realtype* xd=NULL; + + realtype* ctmp; + N_Vector* Y; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + if (nsum < 1) return(-1); + + /* --------------------------- + * Special cases for nvec == 1 + * --------------------------- */ + + if (nvec == 1) { + + /* should have called N_VScale */ + if (nsum == 1) { + N_VScale_OpenMP(c[0], X[0][0], Z[0]); + return(0); + } + + /* should have called N_VLinearSum */ + if (nsum == 2) { + N_VLinearSum_OpenMP(c[0], X[0][0], c[1], X[1][0], Z[0]); + return(0); + } + + /* should have called N_VLinearCombination */ + Y = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + + for (i=0; i<nsum; i++) { + Y[i] = X[i][0]; + } + + N_VLinearCombination_OpenMP(nsum, c, Y, Z[0]); + + free(Y); + return(0); + } + + /* -------------------------- + * Special cases for nvec > 1 + * -------------------------- */ + + /* should have called N_VScaleVectorArray */ + if (nsum == 1) { + + ctmp = (realtype*) malloc(nvec * sizeof(realtype)); + + for (j=0; j<nvec; j++) { + ctmp[j] = c[0]; + } + + N_VScaleVectorArray_OpenMP(nvec, ctmp, X[0], Z); + + free(ctmp); + return(0); + } + + /* should have called N_VLinearSumVectorArray */ + if (nsum == 2) { + N_VLinearSumVectorArray_OpenMP(nvec, c[0], X[0], c[1], X[1], Z); + return(0); + } + + /* -------------------------- + * Compute linear combination + * -------------------------- */ + + /* get vector length */ + N = NV_LENGTH_OMP(Z[0]); + + /* + * X[0][j] += c[i]*X[i][j], i = 1,...,nvec-1 + */ + if ((X[0] == Z) && (c[0] == ONE)) { +#pragma omp parallel default(none) private(i,j,k,xd,zd) shared(nvec,nsum,X,Z,N,c) \ + num_threads(NV_NUM_THREADS_OMP(Z[0])) + { + for (j=0; j<nvec; j++) { + zd = NV_DATA_OMP(Z[j]); + for (i=1; i<nsum; i++) { + xd = NV_DATA_OMP(X[i][j]); +#pragma omp for schedule(static) + for (k=0; k<N; k++) { + zd[k] += c[i] * xd[k]; + } + } + } + } + return(0); + } + + /* + * X[0][j] = c[0] * X[0][j] + sum{ c[i] * X[i][j] }, i = 1,...,nvec-1 + */ + if (X[0] == Z) { +#pragma omp parallel default(none) private(i,j,k,xd,zd) shared(nvec,nsum,X,Z,N,c) \ + num_threads(NV_NUM_THREADS_OMP(Z[0])) + { + for (j=0; j<nvec; j++) { + zd = NV_DATA_OMP(Z[j]); +#pragma omp for schedule(static) + for (k=0; k<N; k++) { + zd[k] *= c[0]; + } + for (i=1; i<nsum; i++) { + xd = NV_DATA_OMP(X[i][j]); +#pragma omp for schedule(static) + for (k=0; k<N; k++) { + zd[k] += c[i] * xd[k]; + } + } + } + } + return(0); + } + + /* + * Z[j] = sum{ c[i] * X[i][j] }, i = 0,...,nvec-1 + */ +#pragma omp parallel default(none) private(i,j,k,xd,zd) shared(nvec,nsum,X,Z,N,c) \ + num_threads(NV_NUM_THREADS_OMP(Z[0])) + { + for (j=0; j<nvec; j++) { + /* scale first vector in the sum into the output vector */ + xd = NV_DATA_OMP(X[0][j]); + zd = NV_DATA_OMP(Z[j]); +#pragma omp for schedule(static) + for (k=0; k<N; k++) { + zd[k] = c[0] * xd[k]; + } + /* scale and sum remaining vectors into the output vector */ + for (i=1; i<nsum; i++) { + xd = NV_DATA_OMP(X[i][j]); +#pragma omp for schedule(static) + for (k=0; k<N; k++) { + zd[k] += c[i] * xd[k]; + } + } + } + } + return(0); +} + + +/* + * ----------------------------------------------------------------- + * private functions for special cases of vector operations + * ----------------------------------------------------------------- + */ + + +/* ---------------------------------------------------------------------------- + * Copy vector components into a second vector + */ + +static void VCopy_OpenMP(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + zd = NV_DATA_OMP(z); + +#pragma omp parallel for default(none) private(i) shared(N,xd,zd) schedule(static) \ + num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) + zd[i] = xd[i]; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute vector sum + */ + +static void VSum_OpenMP(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + yd = NV_DATA_OMP(y); + zd = NV_DATA_OMP(z); + +#pragma omp parallel for default(none) private(i) shared(N,xd,yd,zd) schedule(static) \ + num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) + zd[i] = xd[i]+yd[i]; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute vector difference + */ + +static void VDiff_OpenMP(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + yd = NV_DATA_OMP(y); + zd = NV_DATA_OMP(z); + +#pragma omp parallel for default(none) private(i) shared(N,xd,yd,zd) schedule(static) \ + num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) + zd[i] = xd[i]-yd[i]; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute the negative of a vector + */ + +static void VNeg_OpenMP(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + zd = NV_DATA_OMP(z); + +#pragma omp parallel for default(none) private(i) shared(N,xd,zd) schedule(static) \ + num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) + zd[i] = -xd[i]; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute scaled vector sum + */ + +static void VScaleSum_OpenMP(realtype c, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + yd = NV_DATA_OMP(y); + zd = NV_DATA_OMP(z); + +#pragma omp parallel for default(none) private(i) shared(N,c,xd,yd,zd) schedule(static) \ + num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) + zd[i] = c*(xd[i]+yd[i]); + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute scaled vector difference + */ + +static void VScaleDiff_OpenMP(realtype c, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + yd = NV_DATA_OMP(y); + zd = NV_DATA_OMP(z); + +#pragma omp parallel for default(none) private(i) shared(N,c,xd,yd,zd) schedule(static) \ + num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) + zd[i] = c*(xd[i]-yd[i]); + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute vector sum z[i] = a*x[i]+y[i] + */ + +static void VLin1_OpenMP(realtype a, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + yd = NV_DATA_OMP(y); + zd = NV_DATA_OMP(z); + +#pragma omp parallel for default(none) private(i) shared(N,a,xd,yd,zd) schedule(static) \ + num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) + zd[i] = (a*xd[i])+yd[i]; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute vector difference z[i] = a*x[i]-y[i] + */ + +static void VLin2_OpenMP(realtype a, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + yd = NV_DATA_OMP(y); + zd = NV_DATA_OMP(z); + +#pragma omp parallel for default(none) private(i) shared(N,a,xd,yd,zd) schedule(static) \ + num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) + zd[i] = (a*xd[i])-yd[i]; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute special cases of linear sum + */ + +static void Vaxpy_OpenMP(realtype a, N_Vector x, N_Vector y) +{ + sunindextype i, N; + realtype *xd, *yd; + + xd = yd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + yd = NV_DATA_OMP(y); + + if (a == ONE) { +#pragma omp parallel for default(none) private(i) shared(N,xd,yd) schedule(static) \ + num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) + yd[i] += xd[i]; + return; + } + + if (a == -ONE) { +#pragma omp parallel for default(none) private(i) shared(N,xd,yd) schedule(static) \ + num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) + yd[i] -= xd[i]; + return; + } + +#pragma omp parallel for default(none) private(i) shared(N,a,xd,yd) schedule(static) \ + num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) + yd[i] += a*xd[i]; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute scaled vector x[i] = a*x[i] + */ + +static void VScaleBy_OpenMP(realtype a, N_Vector x) +{ + sunindextype i, N; + realtype *xd; + + xd = NULL; + + N = NV_LENGTH_OMP(x); + xd = NV_DATA_OMP(x); + +#pragma omp parallel for default(none) private(i) shared(N,a,xd) schedule(static) \ + num_threads(NV_NUM_THREADS_OMP(x)) + for (i = 0; i < N; i++) + xd[i] *= a; + + return; +} + + +/* + * ----------------------------------------------------------------- + * private functions for special cases of vector array operations + * ----------------------------------------------------------------- + */ + +static int VSumVectorArray_OpenMP(int nvec, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + N = NV_LENGTH_OMP(X[0]); + +#pragma omp parallel default(none) private(i,j,xd,yd,zd) shared(nvec,X,Y,Z,N) \ + num_threads(NV_NUM_THREADS_OMP(X[0])) + { + for (i=0; i<nvec; i++) { + xd = NV_DATA_OMP(X[i]); + yd = NV_DATA_OMP(Y[i]); + zd = NV_DATA_OMP(Z[i]); +#pragma omp for schedule(static) + for (j=0; j<N; j++) + zd[j] = xd[j] + yd[j]; + } + } + + return(0); +} + +static int VDiffVectorArray_OpenMP(int nvec, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + N = NV_LENGTH_OMP(X[0]); + +#pragma omp parallel default(none) private(i,j,xd,yd,zd) shared(nvec,X,Y,Z,N) \ + num_threads(NV_NUM_THREADS_OMP(X[0])) + { + for (i=0; i<nvec; i++) { + xd = NV_DATA_OMP(X[i]); + yd = NV_DATA_OMP(Y[i]); + zd = NV_DATA_OMP(Z[i]); +#pragma omp for schedule(static) + for (j=0; j<N; j++) + zd[j] = xd[j] - yd[j]; + } + } + + return(0); +} + +static int VScaleSumVectorArray_OpenMP(int nvec, realtype c, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + N = NV_LENGTH_OMP(X[0]); + +#pragma omp parallel default(none) private(i,j,xd,yd,zd) shared(nvec,X,Y,Z,N,c) \ + num_threads(NV_NUM_THREADS_OMP(X[0])) + { + for (i=0; i<nvec; i++) { + xd = NV_DATA_OMP(X[i]); + yd = NV_DATA_OMP(Y[i]); + zd = NV_DATA_OMP(Z[i]); +#pragma omp for schedule(static) + for (j=0; j<N; j++) + zd[j] = c * (xd[j] + yd[j]); + } + } + + return(0); +} + +static int VScaleDiffVectorArray_OpenMP(int nvec, realtype c, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + N = NV_LENGTH_OMP(X[0]); + +#pragma omp parallel default(none) private(i,j,xd,yd,zd) shared(nvec,X,Y,Z,N,c) \ + num_threads(NV_NUM_THREADS_OMP(X[0])) + { + for (i=0; i<nvec; i++) { + xd = NV_DATA_OMP(X[i]); + yd = NV_DATA_OMP(Y[i]); + zd = NV_DATA_OMP(Z[i]); +#pragma omp for schedule(static) + for (j=0; j<N; j++) + zd[j] = c * (xd[j] - yd[j]); + } + } + + return(0); +} + +static int VLin1VectorArray_OpenMP(int nvec, realtype a, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + N = NV_LENGTH_OMP(X[0]); + +#pragma omp parallel default(none) private(i,j,xd,yd,zd) shared(nvec,X,Y,Z,N,a) \ + num_threads(NV_NUM_THREADS_OMP(X[0])) + { + for (i=0; i<nvec; i++) { + xd = NV_DATA_OMP(X[i]); + yd = NV_DATA_OMP(Y[i]); + zd = NV_DATA_OMP(Z[i]); +#pragma omp for schedule(static) + for (j=0; j<N; j++) + zd[j] = (a * xd[j]) + yd[j]; + } + } + + return(0); +} + +static int VLin2VectorArray_OpenMP(int nvec, realtype a, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + N = NV_LENGTH_OMP(X[0]); + +#pragma omp parallel default(none) private(i,j,xd,yd,zd) shared(nvec,X,Y,Z,N,a) \ + num_threads(NV_NUM_THREADS_OMP(X[0])) + { + for (i=0; i<nvec; i++) { + xd = NV_DATA_OMP(X[i]); + yd = NV_DATA_OMP(Y[i]); + zd = NV_DATA_OMP(Z[i]); +#pragma omp for schedule(static) + for (j=0; j<N; j++) + zd[j] = (a * xd[j]) - yd[j]; + } + } + + return(0); +} + +static int VaxpyVectorArray_OpenMP(int nvec, realtype a, N_Vector* X, N_Vector* Y) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + + N = NV_LENGTH_OMP(X[0]); + + if (a == ONE) { +#pragma omp parallel default(none) private(i,j,xd,yd) shared(nvec,X,Y,N,a) \ + num_threads(NV_NUM_THREADS_OMP(X[0])) + { + for (i=0; i<nvec; i++) { + xd = NV_DATA_OMP(X[i]); + yd = NV_DATA_OMP(Y[i]); +#pragma omp for schedule(static) + for (j=0; j<N; j++) + yd[j] += xd[j]; + } + } + return(0); + } + + if (a == -ONE) { +#pragma omp parallel default(none) private(i,j,xd,yd) shared(nvec,X,Y,N,a) \ + num_threads(NV_NUM_THREADS_OMP(X[0])) + { + for (i=0; i<nvec; i++) { + xd = NV_DATA_OMP(X[i]); + yd = NV_DATA_OMP(Y[i]); +#pragma omp for schedule(static) + for (j=0; j<N; j++) + yd[j] -= xd[j]; + } + } + return(0); + } + +#pragma omp parallel default(none) private(i,j,xd,yd) shared(nvec,X,Y,N,a) \ + num_threads(NV_NUM_THREADS_OMP(X[0])) + { + for (i=0; i<nvec; i++) { + xd = NV_DATA_OMP(X[i]); + yd = NV_DATA_OMP(Y[i]); +#pragma omp for schedule(static) + for (j=0; j<N; j++) + yd[j] += a * xd[j]; + } + } + return(0); +} + + +/* + * ----------------------------------------------------------------- + * Enable / Disable fused and vector array operations + * ----------------------------------------------------------------- + */ + +int N_VEnableFusedOps_OpenMP(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); + + if (tf) { + /* enable all fused vector operations */ + v->ops->nvlinearcombination = N_VLinearCombination_OpenMP; + v->ops->nvscaleaddmulti = N_VScaleAddMulti_OpenMP; + v->ops->nvdotprodmulti = N_VDotProdMulti_OpenMP; + /* enable all vector array operations */ + v->ops->nvlinearsumvectorarray = N_VLinearSumVectorArray_OpenMP; + v->ops->nvscalevectorarray = N_VScaleVectorArray_OpenMP; + v->ops->nvconstvectorarray = N_VConstVectorArray_OpenMP; + v->ops->nvwrmsnormvectorarray = N_VWrmsNormVectorArray_OpenMP; + v->ops->nvwrmsnormmaskvectorarray = N_VWrmsNormMaskVectorArray_OpenMP; + v->ops->nvscaleaddmultivectorarray = N_VScaleAddMultiVectorArray_OpenMP; + v->ops->nvlinearcombinationvectorarray = N_VLinearCombinationVectorArray_OpenMP; + } 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 N_VEnableLinearCombination_OpenMP(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 = N_VLinearCombination_OpenMP; + else + v->ops->nvlinearcombination = NULL; + + /* return success */ + return(0); +} + +int N_VEnableScaleAddMulti_OpenMP(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 = N_VScaleAddMulti_OpenMP; + else + v->ops->nvscaleaddmulti = NULL; + + /* return success */ + return(0); +} + +int N_VEnableDotProdMulti_OpenMP(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 = N_VDotProdMulti_OpenMP; + else + v->ops->nvdotprodmulti = NULL; + + /* return success */ + return(0); +} + +int N_VEnableLinearSumVectorArray_OpenMP(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 = N_VLinearSumVectorArray_OpenMP; + else + v->ops->nvlinearsumvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableScaleVectorArray_OpenMP(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 = N_VScaleVectorArray_OpenMP; + else + v->ops->nvscalevectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableConstVectorArray_OpenMP(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 = N_VConstVectorArray_OpenMP; + else + v->ops->nvconstvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableWrmsNormVectorArray_OpenMP(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 = N_VWrmsNormVectorArray_OpenMP; + else + v->ops->nvwrmsnormvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableWrmsNormMaskVectorArray_OpenMP(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 = N_VWrmsNormMaskVectorArray_OpenMP; + else + v->ops->nvwrmsnormmaskvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableScaleAddMultiVectorArray_OpenMP(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->nvscaleaddmultivectorarray = N_VScaleAddMultiVectorArray_OpenMP; + else + v->ops->nvscaleaddmultivectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableLinearCombinationVectorArray_OpenMP(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->nvlinearcombinationvectorarray = N_VLinearCombinationVectorArray_OpenMP; + else + v->ops->nvlinearcombinationvectorarray = NULL; + + /* return success */ + return(0); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/openmpdev/nvector_openmpdev.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/openmpdev/nvector_openmpdev.c new file mode 100644 index 0000000..9e04447 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/openmpdev/nvector_openmpdev.c @@ -0,0 +1,3057 @@ +/* ----------------------------------------------------------------- + * Programmer(s): David J. Gardner and Shelby Lockhart @ LLNL + * ----------------------------------------------------------------- + * 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 + * 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 an OpenMP DEV implementation + * of the NVECTOR module. + * -----------------------------------------------------------------*/ + +#include <omp.h> + +#include <stdio.h> +#include <stdlib.h> + +#include <nvector/nvector_openmpdev.h> +#include <sundials/sundials_math.h> + +#define ZERO RCONST(0.0) +#define HALF RCONST(0.5) +#define ONE RCONST(1.0) +#define ONEPT5 RCONST(1.5) + +/* Private functions for special cases of vector operations */ +static void VCopy_OpenMPDEV(N_Vector x, N_Vector z); /* z=x */ +static void VSum_OpenMPDEV(N_Vector x, N_Vector y, N_Vector z); /* z=x+y */ +static void VDiff_OpenMPDEV(N_Vector x, N_Vector y, N_Vector z); /* z=x-y */ +static void VNeg_OpenMPDEV(N_Vector x, N_Vector z); /* z=-x */ +static void VScaleSum_OpenMPDEV(realtype c, N_Vector x, N_Vector y, N_Vector z); /* z=c(x+y) */ +static void VScaleDiff_OpenMPDEV(realtype c, N_Vector x, N_Vector y, N_Vector z); /* z=c(x-y) */ +static void VLin1_OpenMPDEV(realtype a, N_Vector x, N_Vector y, N_Vector z); /* z=ax+y */ +static void VLin2_OpenMPDEV(realtype a, N_Vector x, N_Vector y, N_Vector z); /* z=ax-y */ +static void Vaxpy_OpenMPDEV(realtype a, N_Vector x, N_Vector y); /* y <- ax+y */ +static void VScaleBy_OpenMPDEV(realtype a, N_Vector x); /* x <- ax */ + +/* Private functions for special cases of vector array operations */ +static int VSumVectorArray_OpenMPDEV(int nvec, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=X+Y */ +static int VDiffVectorArray_OpenMPDEV(int nvec, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=X-Y */ +static int VScaleSumVectorArray_OpenMPDEV(int nvec, realtype c, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=c(X+Y) */ +static int VScaleDiffVectorArray_OpenMPDEV(int nvec, realtype c, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=c(X-Y) */ +static int VLin1VectorArray_OpenMPDEV(int nvec, realtype a, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=aX+Y */ +static int VLin2VectorArray_OpenMPDEV(int nvec, realtype a, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=aX-Y */ +static int VaxpyVectorArray_OpenMPDEV(int nvec, realtype a, N_Vector* X, N_Vector* Y); /* Y <- aX+Y */ + +/* + * ----------------------------------------------------------------- + * exported functions + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------- + * Returns vector type ID. Used to identify vector implementation + * from abstract N_Vector interface. + */ +N_Vector_ID N_VGetVectorID_OpenMPDEV(N_Vector v) +{ + return SUNDIALS_NVEC_OPENMPDEV; +} + +/* ---------------------------------------------------------------------------- + * Function to create a new empty vector + */ + +N_Vector N_VNewEmpty_OpenMPDEV(sunindextype length) +{ + N_Vector v; + N_Vector_Ops ops; + N_VectorContent_OpenMPDEV content; + + /* Create vector */ + v = NULL; + v = (N_Vector) malloc(sizeof *v); + 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 = 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; + + /* 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; + + /* Create content */ + content = NULL; + content = (N_VectorContent_OpenMPDEV) malloc(sizeof(struct _N_VectorContent_OpenMPDEV)); + if (content == NULL) { free(ops); free(v); return(NULL); } + + 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); +} + +/* ---------------------------------------------------------------------------- + * Function to create a new vector + */ + +N_Vector N_VNew_OpenMPDEV(sunindextype length) +{ + N_Vector v; + realtype *data; + realtype *dev_data; + int dev; + + v = NULL; + v = N_VNewEmpty_OpenMPDEV(length); + if (v == NULL) return(NULL); + + /* Create data */ + if (length > 0) { + + /* Allocate memory on host */ + data = NULL; + data = (realtype *) malloc(length * sizeof(realtype)); + + /* 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); } + + /* Attach data */ + NV_OWN_DATA_OMPDEV(v) = SUNTRUE; + NV_DATA_HOST_OMPDEV(v) = data; + NV_DATA_DEV_OMPDEV(v) = dev_data; + + } + + return(v); +} + +/* ---------------------------------------------------------------------------- + * Function to create a vector with user data component + */ + +N_Vector N_VMake_OpenMPDEV(sunindextype length, realtype *h_vdata, realtype *d_vdata) +{ + N_Vector v; + int dev, host; + + if (h_vdata == NULL || d_vdata == NULL) return(NULL); + + v = NULL; + v = N_VNewEmpty_OpenMPDEV(length); + if (v == NULL) return(NULL); + + if (length > 0) { + /* Get device and host identifiers */ + dev = omp_get_default_device(); + host = omp_get_initial_device(); + + /* Attach data */ + NV_OWN_DATA_OMPDEV(v) = SUNFALSE; + NV_DATA_HOST_OMPDEV(v) = h_vdata; + NV_DATA_DEV_OMPDEV(v) = d_vdata; + } + + return(v); +} + +/* ---------------------------------------------------------------------------- + * Function to create an array of new vectors. + */ + +N_Vector *N_VCloneVectorArray_OpenMPDEV(int count, N_Vector w) +{ + N_Vector *vs; + int j; + + if (count <= 0) return(NULL); + + vs = NULL; + vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + if(vs == NULL) return(NULL); + + for (j = 0; j < count; j++) { + vs[j] = NULL; + vs[j] = N_VClone_OpenMPDEV(w); + if (vs[j] == NULL) { + N_VDestroyVectorArray_OpenMPDEV(vs, j-1); + return(NULL); + } + } + + return(vs); +} + +/* ---------------------------------------------------------------------------- + * Function to create an array of new vectors with NULL data array. + */ + +N_Vector *N_VCloneVectorArrayEmpty_OpenMPDEV(int count, N_Vector w) +{ + N_Vector *vs; + int j; + + if (count <= 0) return(NULL); + + vs = NULL; + vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + if(vs == NULL) return(NULL); + + for (j = 0; j < count; j++) { + vs[j] = NULL; + vs[j] = N_VCloneEmpty_OpenMPDEV(w); + if (vs[j] == NULL) { + N_VDestroyVectorArray_OpenMPDEV(vs, j-1); + return(NULL); + } + } + + return(vs); +} + +/* ---------------------------------------------------------------------------- + * Function to free an array created with N_VCloneVectorArray_OpenMPDEV + */ + +void N_VDestroyVectorArray_OpenMPDEV(N_Vector *vs, int count) +{ + int j; + + for (j = 0; j < count; j++) N_VDestroy_OpenMPDEV(vs[j]); + + free(vs); vs = NULL; + + return; +} + +/* ---------------------------------------------------------------------------- + * Function to return number of vector elements + */ +sunindextype N_VGetLength_OpenMPDEV(N_Vector v) +{ + return NV_LENGTH_OMPDEV(v); +} + +/* ---------------------------------------------------------------------------- + * Function to return a pointer to the data array on the host. + */ +realtype *N_VGetHostArrayPointer_OpenMPDEV(N_Vector v) +{ + return((realtype *) NV_DATA_HOST_OMPDEV(v)); +} + +/* ---------------------------------------------------------------------------- + * Function to return a pointer to the data array on the device. + */ +realtype *N_VGetDeviceArrayPointer_OpenMPDEV(N_Vector v) +{ + return((realtype *) NV_DATA_DEV_OMPDEV(v)); +} + +/* ---------------------------------------------------------------------------- + * Function to print a vector to stdout + */ + +void N_VPrint_OpenMPDEV(N_Vector x) +{ + N_VPrintFile_OpenMPDEV(x, stdout); +} + +/* ---------------------------------------------------------------------------- + * Function to print a vector to outfile + */ + +void N_VPrintFile_OpenMPDEV(N_Vector x, FILE *outfile) +{ + sunindextype i, N; + realtype *xd; + + xd = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd = NV_DATA_HOST_OMPDEV(x); + + for (i = 0; i < N; i++) { +#if defined(SUNDIALS_EXTENDED_PRECISION) + fprintf(outfile, "%11.8Lg\n", xd[i]); +#elif defined(SUNDIALS_DOUBLE_PRECISION) + fprintf(outfile, "%11.8g\n", xd[i]); +#else + fprintf(outfile, "%11.8g\n", xd[i]); +#endif + } + fprintf(outfile, "\n"); + + return; +} + +/* ---------------------------------------------------------------------------- + * Function to copy host array into device array + */ + +void N_VCopyToDevice_OpenMPDEV(N_Vector x) +{ + int dev, host; + sunindextype length; + realtype *host_ptr; + realtype *dev_ptr; + + /* Get array information */ + length = NV_LENGTH_OMPDEV(x); + host_ptr = NV_DATA_HOST_OMPDEV(x); + dev_ptr = NV_DATA_DEV_OMPDEV(x); + + /* Get device and host identifiers */ + dev = omp_get_default_device(); + host = omp_get_initial_device(); + + /* Copy array from host to device */ + omp_target_memcpy(dev_ptr, host_ptr, sizeof(realtype) * length, 0, 0, dev, host); + + return; +} + +/* ---------------------------------------------------------------------------- + * Function to copy device array into host array + */ + +void N_VCopyFromDevice_OpenMPDEV(N_Vector x) +{ + int dev, host; + sunindextype length; + realtype *host_ptr; + realtype *dev_ptr; + + /* Get array information */ + length = NV_LENGTH_OMPDEV(x); + host_ptr = NV_DATA_HOST_OMPDEV(x); + dev_ptr = NV_DATA_DEV_OMPDEV(x); + + /* Get device and host identifiers */ + dev = omp_get_default_device(); + host = omp_get_initial_device(); + + /* Copy array from device to host */ + omp_target_memcpy(host_ptr, dev_ptr, sizeof(realtype) * length, 0, 0, host, dev); + + return; +} + +/* + * ----------------------------------------------------------------- + * implementation of vector operations + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------------------- + * Create new vector from existing vector without attaching data + */ + +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); + 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 */ + content = NULL; + content = (N_VectorContent_OpenMPDEV) malloc(sizeof(struct _N_VectorContent_OpenMPDEV)); + if (content == NULL) { free(ops); free(v); return(NULL); } + + 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); +} + + +/* ---------------------------------------------------------------------------- + * Create new vector from existing vector and attach data + */ + +N_Vector N_VClone_OpenMPDEV(N_Vector w) +{ + N_Vector v; + realtype *data; + realtype *dev_data; + sunindextype length; + int dev; + + v = NULL; + v = N_VCloneEmpty_OpenMPDEV(w); + if (v == NULL) return(NULL); + + length = NV_LENGTH_OMPDEV(w); + + /* Create data */ + if (length > 0) { + + /* Allocate memory on host */ + data = NULL; + data = (realtype *) malloc(length * sizeof(realtype)); + + /* 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); } + + /* Attach data */ + NV_OWN_DATA_OMPDEV(v) = SUNTRUE; + NV_DATA_HOST_OMPDEV(v)= data; + NV_DATA_DEV_OMPDEV(v) = dev_data; + + } + + return(v); +} + + +/* ---------------------------------------------------------------------------- + * Destroy vector and free vector memory + */ + +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; + } + + free(v->content); v->content = NULL; + free(v->ops); v->ops = NULL; + free(v); v = NULL; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Get storage requirement for N_Vector + */ + +void N_VSpace_OpenMPDEV(N_Vector v, sunindextype *lrw, sunindextype *liw) +{ + *lrw = NV_LENGTH_OMPDEV(v); + *liw = 1; + + return; +} + +/* ---------------------------------------------------------------------------- + * Compute linear combination z[i] = a*x[i]+b*y[i] + */ + +void N_VLinearSum_OpenMPDEV(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype c, *xd_dev, *yd_dev, *zd_dev; + N_Vector v1, v2; + booleantype test; + int dev; + + xd_dev = yd_dev = zd_dev = NULL; + + if ((b == ONE) && (z == y)) { /* BLAS usage: axpy y <- ax+y */ + Vaxpy_OpenMPDEV(a,x,y); + return; + } + + if ((a == ONE) && (z == x)) { /* BLAS usage: axpy x <- by+x */ + Vaxpy_OpenMPDEV(b,y,x); + return; + } + + /* Case: a == b == 1.0 */ + + if ((a == ONE) && (b == ONE)) { + VSum_OpenMPDEV(x, y, z); + return; + } + + /* Cases: (1) a == 1.0, b = -1.0, (2) a == -1.0, b == 1.0 */ + + if ((test = ((a == ONE) && (b == -ONE))) || ((a == -ONE) && (b == ONE))) { + v1 = test ? y : x; + v2 = test ? x : y; + VDiff_OpenMPDEV(v2, v1, z); + return; + } + + /* Cases: (1) a == 1.0, b == other or 0.0, (2) a == other or 0.0, b == 1.0 */ + /* if a or b is 0.0, then user should have called N_VScale */ + + if ((test = (a == ONE)) || (b == ONE)) { + c = test ? b : a; + v1 = test ? y : x; + v2 = test ? x : y; + VLin1_OpenMPDEV(c, v1, v2, z); + return; + } + + /* Cases: (1) a == -1.0, b != 1.0, (2) a != 1.0, b == -1.0 */ + + if ((test = (a == -ONE)) || (b == -ONE)) { + c = test ? b : a; + v1 = test ? y : x; + v2 = test ? x : y; + VLin2_OpenMPDEV(c, v1, v2, z); + return; + } + + /* Case: a == b */ + /* catches case both a and b are 0.0 - user should have called N_VConst */ + + if (a == b) { + VScaleSum_OpenMPDEV(a, x, y, z); + return; + } + + /* Case: a == -b */ + + if (a == -b) { + VScaleDiff_OpenMPDEV(a, x, y, z); + return; + } + + /* Do all cases not handled above: + (1) a == other, b == 0.0 - user should have called N_VScale + (2) a == 0.0, b == other - user should have called N_VScale + (3) a,b == other, a !=b, a != -b */ + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + yd_dev = NV_DATA_DEV_OMPDEV(y); + zd_dev = NV_DATA_DEV_OMPDEV(z); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N,a,b) is_device_ptr(xd_dev, yd_dev, zd_dev) device(dev) +#pragma omp teams distribute parallel for schedule(static, 1) + for (i = 0; i < N; i++) + zd_dev[i] = (a*xd_dev[i])+(b*yd_dev[i]); + + return; +} + + +/* ---------------------------------------------------------------------------- + * Assigns constant value to all vector elements, z[i] = c + */ + +void N_VConst_OpenMPDEV(realtype c, N_Vector z) +{ + sunindextype i, N; + realtype *zd_dev; + int dev; + + zd_dev = NULL; + + N = NV_LENGTH_OMPDEV(z); + zd_dev = NV_DATA_DEV_OMPDEV(z); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N,c) is_device_ptr(zd_dev) device(dev) +#pragma omp teams distribute parallel for schedule(static, 1) + for (i = 0; i < N; i++) zd_dev[i] = c; + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute componentwise product z[i] = x[i]*y[i] + */ + +void N_VProd_OpenMPDEV(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd_dev, *yd_dev, *zd_dev; + int dev; + + xd_dev = yd_dev = zd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + yd_dev = NV_DATA_DEV_OMPDEV(y); + zd_dev = NV_DATA_DEV_OMPDEV(z); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N) is_device_ptr(xd_dev, yd_dev, zd_dev) device(dev) +#pragma omp teams distribute parallel for schedule(static, 1) + for (i = 0; i < N; i++) + zd_dev[i] = xd_dev[i]*yd_dev[i]; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute componentwise division z[i] = x[i]/y[i] + */ + +void N_VDiv_OpenMPDEV(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd_dev, *yd_dev, *zd_dev; + int dev; + + xd_dev = yd_dev = zd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + yd_dev = NV_DATA_DEV_OMPDEV(y); + zd_dev = NV_DATA_DEV_OMPDEV(z); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N) is_device_ptr(xd_dev, yd_dev, zd_dev) device(dev) +#pragma omp teams distribute parallel for schedule(static, 1) + for (i = 0; i < N; i++) + zd_dev[i] = xd_dev[i]/yd_dev[i]; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute scaler multiplication z[i] = c*x[i] + */ + +void N_VScale_OpenMPDEV(realtype c, N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd_dev, *zd_dev; + int dev; + + xd_dev = zd_dev = NULL; + + if (z == x) { /* BLAS usage: scale x <- cx */ + VScaleBy_OpenMPDEV(c, x); + return; + } + + if (c == ONE) { + VCopy_OpenMPDEV(x, z); + } else if (c == -ONE) { + VNeg_OpenMPDEV(x, z); + } else { + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + zd_dev = NV_DATA_DEV_OMPDEV(z); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N,c) is_device_ptr(xd_dev, zd_dev) device(dev) +#pragma omp teams distribute parallel for schedule(static, 1) + for (i = 0; i < N; i++) + zd_dev[i] = c*xd_dev[i]; + } + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute absolute value of vector components z[i] = SUNRabs(x[i]) + */ + +void N_VAbs_OpenMPDEV(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd_dev, *zd_dev; + int dev; + + xd_dev = zd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + zd_dev = NV_DATA_DEV_OMPDEV(z); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N) is_device_ptr(xd_dev, zd_dev) device(dev) +#pragma omp teams distribute parallel for schedule(static, 1) + for (i = 0; i < N; i++) + zd_dev[i] = SUNRabs(xd_dev[i]); + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute componentwise inverse z[i] = 1 / x[i] + */ + +void N_VInv_OpenMPDEV(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd_dev, *zd_dev; + int dev; + + xd_dev = zd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + zd_dev = NV_DATA_DEV_OMPDEV(z); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N) is_device_ptr(xd_dev, zd_dev) device(dev) +#pragma omp teams distribute parallel for schedule(static, 1) + for (i = 0; i < N; i++) + zd_dev[i] = ONE/xd_dev[i]; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute componentwise addition of a scaler to a vector z[i] = x[i] + b + */ + +void N_VAddConst_OpenMPDEV(N_Vector x, realtype b, N_Vector z) +{ + sunindextype i, N; + realtype *xd_dev, *zd_dev; + int dev; + + xd_dev = zd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + zd_dev = NV_DATA_DEV_OMPDEV(z); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N,b) is_device_ptr(xd_dev, zd_dev) device(dev) +#pragma omp teams distribute parallel for schedule(static, 1) + for (i = 0; i < N; i++) + zd_dev[i] = xd_dev[i]+b; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Computes the dot product of two vectors, a = sum(x[i]*y[i]) + */ + +realtype N_VDotProd_OpenMPDEV(N_Vector x, N_Vector y) +{ + sunindextype i, N; + realtype sum, *xd_dev, *yd_dev; + int dev; + + xd_dev = yd_dev = NULL; + + sum = ZERO; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + yd_dev = NV_DATA_DEV_OMPDEV(y); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N) map(tofrom:sum) is_device_ptr(xd_dev, yd_dev) device(dev) +#pragma omp teams distribute parallel for reduction(+:sum) schedule(static, 1) + for (i = 0; i < N; i++) { + sum += xd_dev[i]*yd_dev[i]; + } + + return(sum); +} + + +/* ---------------------------------------------------------------------------- + * Computes max norm of a vector + */ + +realtype N_VMaxNorm_OpenMPDEV(N_Vector x) +{ + sunindextype i, N; + realtype max, *xd_dev; + int dev; + + max = ZERO; + xd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N) map(tofrom:max) is_device_ptr(xd_dev) device(dev) +#pragma omp teams distribute parallel for reduction(max:max) schedule(static, 1) + for (i = 0; i < N; i++) { + max = SUNMAX(SUNRabs(xd_dev[i]), max); + } + + return(max); +} + + +/* ---------------------------------------------------------------------------- + * Computes weighted root mean square norm of a vector + */ + +realtype N_VWrmsNorm_OpenMPDEV(N_Vector x, N_Vector w) +{ + sunindextype i, N; + realtype sum, *xd_dev, *wd_dev; + int dev; + + sum = ZERO; + xd_dev = wd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + wd_dev = NV_DATA_DEV_OMPDEV(w); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N) map(tofrom:sum) is_device_ptr(xd_dev, wd_dev) device(dev) +#pragma omp teams distribute parallel for reduction(+:sum) schedule(static, 1) + for (i = 0; i < N; i++) { + sum += SUNSQR(xd_dev[i]*wd_dev[i]); + } + + return(SUNRsqrt(sum/N)); +} + + +/* ---------------------------------------------------------------------------- + * Computes weighted root mean square norm of a masked vector + */ + +realtype N_VWrmsNormMask_OpenMPDEV(N_Vector x, N_Vector w, N_Vector id) +{ + sunindextype i, N; + realtype sum, *xd_dev, *wd_dev, *idd_dev; + int dev; + + sum = ZERO; + xd_dev = wd_dev = idd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + wd_dev = NV_DATA_DEV_OMPDEV(w); + idd_dev = NV_DATA_DEV_OMPDEV(id); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N) map(tofrom:sum) is_device_ptr(xd_dev, wd_dev, idd_dev) device(dev) +#pragma omp teams distribute parallel for reduction(+:sum) schedule(static, 1) + for (i = 0; i < N; i++) { + if (idd_dev[i] > ZERO) { + sum += SUNSQR(xd_dev[i]*wd_dev[i]); + } + } + + return(SUNRsqrt(sum / N)); +} + + +/* ---------------------------------------------------------------------------- + * Finds the minimun component of a vector + */ + +realtype N_VMin_OpenMPDEV(N_Vector x) +{ + sunindextype i, N; + realtype min, *xd_dev; + int dev; + + xd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N) map(from:min) is_device_ptr(xd_dev) device(dev) +#pragma omp teams num_teams(1) + { + min = xd_dev[0]; +#pragma omp distribute parallel for reduction(min:min) schedule(static, 1) + for (i = 1; i < N; i++) { + min = SUNMIN(xd_dev[i], min); + } + } + + return(min); +} + + +/* ---------------------------------------------------------------------------- + * Computes weighted L2 norm of a vector + */ + +realtype N_VWL2Norm_OpenMPDEV(N_Vector x, N_Vector w) +{ + sunindextype i, N; + realtype sum, *xd_dev, *wd_dev; + int dev; + + sum = ZERO; + xd_dev = wd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + wd_dev = NV_DATA_DEV_OMPDEV(w); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N) map(tofrom:sum) is_device_ptr(xd_dev, wd_dev) device(dev) +#pragma omp teams distribute parallel for reduction(+:sum) schedule(static, 1) + for (i = 0; i < N; i++) { + sum += SUNSQR(xd_dev[i]*wd_dev[i]); + } + + return(SUNRsqrt(sum)); +} + + +/* ---------------------------------------------------------------------------- + * Computes L1 norm of a vector + */ + +realtype N_VL1Norm_OpenMPDEV(N_Vector x) +{ + sunindextype i, N; + realtype sum, *xd_dev; + int dev; + + sum = ZERO; + xd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N) map(tofrom:sum) is_device_ptr(xd_dev) device(dev) +#pragma omp teams distribute parallel for reduction(+:sum) schedule(static, 1) + for (i = 0; i<N; i++) + sum += SUNRabs(xd_dev[i]); + + return(sum); +} + + +/* ---------------------------------------------------------------------------- + * Compare vector component values to a scaler + */ + +void N_VCompare_OpenMPDEV(realtype c, N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd_dev, *zd_dev; + int dev; + + xd_dev = zd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + zd_dev = NV_DATA_DEV_OMPDEV(z); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N,c) is_device_ptr(xd_dev, zd_dev) device(dev) +#pragma omp teams distribute parallel for schedule(static, 1) + for (i = 0; i < N; i++) + zd_dev[i] = (SUNRabs(xd_dev[i]) >= c) ? ONE : ZERO; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute componentwise inverse z[i] = ONE/x[i] and checks if x[i] == ZERO + */ + +booleantype N_VInvTest_OpenMPDEV(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd_dev, *zd_dev, val; + int dev; + + xd_dev = zd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + zd_dev = NV_DATA_DEV_OMPDEV(z); + + /* get default device identifier */ + dev = omp_get_default_device(); + + val = ZERO; + +#pragma omp target map(to:N) map(tofrom:val) is_device_ptr(xd_dev, zd_dev) device(dev) +#pragma omp teams distribute parallel for reduction(max:val) schedule(static, 1) + for (i = 0; i < N; i++) { + if (xd_dev[i] == ZERO) + val = ONE; + else + zd_dev[i] = ONE/xd_dev[i]; + } + + if (val > ZERO) + return (SUNFALSE); + else + return (SUNTRUE); +} + + +/* ---------------------------------------------------------------------------- + * Compute constraint mask of a vector + */ + +booleantype N_VConstrMask_OpenMPDEV(N_Vector c, N_Vector x, N_Vector m) +{ + sunindextype i, N; + realtype temp; + realtype *cd_dev, *xd_dev, *md_dev; + int dev; + + cd_dev = xd_dev = md_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + cd_dev = NV_DATA_DEV_OMPDEV(c); + md_dev = NV_DATA_DEV_OMPDEV(m); + + /* get default device identifier */ + dev = omp_get_default_device(); + + temp = ONE; + +#pragma omp target map(to:N) map(tofrom:temp) is_device_ptr(xd_dev, cd_dev, md_dev) device(dev) +#pragma omp teams distribute parallel for reduction(min:temp) schedule(static, 1) + for (i = 0; i < N; i++) { + md_dev[i] = ZERO; + if (cd_dev[i] == ZERO) continue; + if (cd_dev[i] > ONEPT5 || cd_dev[i] < -ONEPT5) { + if ( xd_dev[i]*cd_dev[i] <= ZERO) { temp = ZERO; md_dev[i] = ONE; } + continue; + } + if ( cd_dev[i] > HALF || cd_dev[i] < -HALF) { + if (xd_dev[i]*cd_dev[i] < ZERO ) { temp = ZERO; md_dev[i] = ONE; } + } + } + + if (temp == ONE) return (SUNTRUE); + else return(SUNFALSE); +} + + +/* ---------------------------------------------------------------------------- + * Compute minimum componentwise quotient + */ + +realtype N_VMinQuotient_OpenMPDEV(N_Vector num, N_Vector denom) +{ + sunindextype i, N; + realtype *nd_dev, *dd_dev, min; + int dev; + + nd_dev = dd_dev = NULL; + + N = NV_LENGTH_OMPDEV(num); + nd_dev = NV_DATA_DEV_OMPDEV(num); + dd_dev = NV_DATA_DEV_OMPDEV(denom); + + /* get default device identifier */ + dev = omp_get_default_device(); + + min = BIG_REAL; + +#pragma omp target map(to:N) map(tofrom:min) is_device_ptr(nd_dev, dd_dev) device(dev) +#pragma omp teams distribute parallel for reduction(min:min) schedule(static, 1) + for (i = 0; i < N; i++) + if (dd_dev[i] != ZERO) min = SUNMIN(nd_dev[i]/dd_dev[i], min); + + return(min); +} + + +/* + * ----------------------------------------------------------------- + * fused vector operations + * ----------------------------------------------------------------- + */ + +int N_VLinearCombination_OpenMPDEV(int nvec, realtype* c, N_Vector* X, N_Vector z) +{ + int i, dev; + realtype to_add; /* temporary variable to hold sum being added in atomic operation */ + sunindextype j, N; + realtype* zd_dev=NULL; + realtype* xd_dev=NULL; + realtype** xd_dev_ptrs=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VScale */ + if (nvec == 1) { + N_VScale_OpenMPDEV(c[0], X[0], z); + return(0); + } + + /* should have called N_VLinearSum */ + if (nvec == 2) { + N_VLinearSum_OpenMPDEV(c[0], X[0], c[1], X[1], z); + return(0); + } + + /* get vector length and data array */ + N = NV_LENGTH_OMPDEV(z); + zd_dev = NV_DATA_DEV_OMPDEV(z); + + /* get default device identifier */ + dev = omp_get_default_device(); + + /* Allocate and store X dev pointers to copy to device */ + xd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + for (i=0; i<nvec; i++) + xd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(X[i]); + + /* + * X[0] += c[i]*X[i], i = 1,...,nvec-1 + */ + if ((X[0] == z) && (c[0] == ONE)) { +#pragma omp target map(to:N,nvec,c[:nvec],xd_dev_ptrs[:nvec]) \ + is_device_ptr(xd_dev,zd_dev) device(dev) +#pragma omp teams distribute + { + for (i=1; i<nvec; i++) { + xd_dev = xd_dev_ptrs[i]; +#pragma omp parallel for schedule(static, 1) + for (j=0; j<N; j++) { + to_add = c[i] * xd_dev[j]; +#pragma omp atomic + zd_dev[j] += to_add; + } + } + } + free(xd_dev_ptrs); + return(0); + } + + /* + * X[0] = c[0] * X[0] + sum{ c[i] * X[i] }, i = 1,...,nvec-1 + */ + if (X[0] == z) { +#pragma omp target map(to:N,nvec,c[:nvec],xd_dev_ptrs[:nvec]) \ + is_device_ptr(xd_dev,zd_dev) + { +#pragma omp teams distribute parallel for schedule(static,1) + for (j=0; j<N; j++) + zd_dev[j] *= c[0]; + } + +#pragma omp target map(to:N,nvec,c[:nvec],xd_dev_ptrs[:nvec]) \ + is_device_ptr(xd_dev,zd_dev) +#pragma omp teams distribute + { + for (i=1; i<nvec; i++) { + xd_dev = xd_dev_ptrs[i]; +#pragma omp parallel for schedule(static, 1) + for (j=0; j<N; j++) { + to_add = c[i] * xd_dev[j]; +#pragma omp atomic + zd_dev[j] += to_add; + } + } + } + free(xd_dev_ptrs); + return(0); + } + + /* + * z = sum{ c[i] * X[i] }, i = 0,...,nvec-1 + */ + xd_dev = NV_DATA_DEV_OMPDEV(X[0]); +#pragma omp target map(to:N,c[:nvec]) \ + is_device_ptr(xd_dev, zd_dev) device(dev) + { +#pragma omp teams distribute parallel for schedule(static, 1) + for (j=0; j<N; j++) { + zd_dev[j] = c[0] * xd_dev[j]; + } + } + +#pragma omp target map(to:N,nvec,c[:nvec],xd_dev_ptrs[:nvec]) \ + is_device_ptr(xd_dev, zd_dev) device(dev) +#pragma omp teams distribute + { + for (i=1; i<nvec; i++) { + xd_dev = xd_dev_ptrs[i]; +#pragma omp parallel for schedule(static, 1) + for (j=0; j<N; j++) { + to_add = c[i] * xd_dev[j]; +#pragma omp atomic + zd_dev[j] += to_add; + } + } + } + free(xd_dev_ptrs); + return(0); +} + +int N_VScaleAddMulti_OpenMPDEV(int nvec, realtype* a, N_Vector x, N_Vector* Y, N_Vector* Z) +{ + int i, dev; + sunindextype j, N; + realtype* xd_dev=NULL; + realtype* yd_dev=NULL; + realtype* zd_dev=NULL; + realtype** yd_dev_ptrs=NULL; + realtype** zd_dev_ptrs=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VLinearSum */ + if (nvec == 1) { + N_VLinearSum_OpenMPDEV(a[0], x, ONE, Y[0], Z[0]); + return(0); + } + + /* get vector length and data array */ + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + + /* get default device identifier */ + dev = omp_get_default_device(); + + /* Allocate and store dev pointers to copy to device */ + yd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + for (i=0; i<nvec; i++) + yd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(Y[i]); + + /* + * Y[i][j] += a[i] * x[j] + */ + if (Y == Z) { +#pragma omp target map(to:N,nvec,a[:nvec],yd_dev_ptrs[:nvec]) \ + is_device_ptr(xd_dev, yd_dev) device(dev) +#pragma omp teams distribute + { + for (i=0; i<nvec; i++) { + yd_dev = yd_dev_ptrs[i]; +#pragma omp parallel for schedule(static, 1) + for (j=0; j<N; j++) + yd_dev[j] += a[i] * xd_dev[j]; + } + } + free(yd_dev_ptrs); + return(0); + } + + /* Allocate and store dev pointers to copy to device */ + zd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + for (i=0; i<nvec; i++) + zd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(Z[i]); + + /* + * Z[i][j] = Y[i][j] + a[i] * x[j] + */ +#pragma omp target map(to:N,nvec,a[:nvec],yd_dev_ptrs[:nvec],zd_dev_ptrs[:nvec]) \ + is_device_ptr(xd_dev, yd_dev, zd_dev) device(dev) +#pragma omp teams distribute + { + for (i=0; i<nvec; i++) { + yd_dev = yd_dev_ptrs[i]; + zd_dev = zd_dev_ptrs[i]; +#pragma omp parallel for schedule(static, 1) + for (j=0; j<N; j++) + zd_dev[j] = a[i] * xd_dev[j] + yd_dev[j]; + } + } + free(yd_dev_ptrs); + free(zd_dev_ptrs); + return(0); +} + +int N_VDotProdMulti_OpenMPDEV(int nvec, N_Vector x, N_Vector* Y, realtype* dotprods) +{ + int i, dev; + sunindextype j, N; + realtype sum; + realtype* xd_dev=NULL; + realtype* yd_dev=NULL; + realtype** yd_dev_ptrs=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VDotProd */ + if (nvec == 1) { + dotprods[0] = N_VDotProd_OpenMPDEV(x, Y[0]); + return(0); + } + + /* get vector length and data array */ + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + + /* get default device identifier */ + dev = omp_get_default_device(); + + /* initialize dot products */ + for (i=0; i<nvec; i++) { + dotprods[i] = ZERO; + } + + /* Allocate and store dev pointers to copy to device */ + yd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + for (i=0; i<nvec; i++) + yd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(Y[i]); + + /* compute multiple dot products */ +#pragma omp target map(to:N,nvec,yd_dev_ptrs[:nvec]) map(tofrom:dotprods[:nvec]) \ + is_device_ptr(xd_dev,yd_dev) device(dev) +#pragma omp teams distribute + for (i=0; i<nvec; i++) { + yd_dev = yd_dev_ptrs[i]; + sum = ZERO; +#pragma omp parallel for reduction(+:sum) schedule(static, 1) + for (j=0; j<N; j++) + sum += xd_dev[j] * yd_dev[j]; + dotprods[i] += sum; + } + + free(yd_dev_ptrs); + return(0); +} + + +/* + * ----------------------------------------------------------------- + * vector array operations + * ----------------------------------------------------------------- + */ + +int N_VLinearSumVectorArray_OpenMPDEV(int nvec, + realtype a, N_Vector* X, + realtype b, N_Vector* Y, + N_Vector* Z) +{ + int i, dev; + sunindextype j, N; + N_Vector* V1; + N_Vector* V2; + booleantype test; + realtype c; + realtype* xd_dev=NULL; + realtype* yd_dev=NULL; + realtype* zd_dev=NULL; + realtype** xd_dev_ptrs=NULL; + realtype** yd_dev_ptrs=NULL; + realtype** zd_dev_ptrs=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VLinearSum */ + if (nvec == 1) { + N_VLinearSum_OpenMPDEV(a, X[0], b, Y[0], Z[0]); + return(0); + } + + /* BLAS usage: axpy y <- ax+y */ + if ((b == ONE) && (Z == Y)) + return(VaxpyVectorArray_OpenMPDEV(nvec, a, X, Y)); + + /* BLAS usage: axpy x <- by+x */ + if ((a == ONE) && (Z == X)) + return(VaxpyVectorArray_OpenMPDEV(nvec, b, Y, X)); + + /* Case: a == b == 1.0 */ + if ((a == ONE) && (b == ONE)) + return(VSumVectorArray_OpenMPDEV(nvec, X, Y, Z)); + + /* Cases: */ + /* (1) a == 1.0, b = -1.0, */ + /* (2) a == -1.0, b == 1.0 */ + if ((test = ((a == ONE) && (b == -ONE))) || ((a == -ONE) && (b == ONE))) { + V1 = test ? Y : X; + V2 = test ? X : Y; + return(VDiffVectorArray_OpenMPDEV(nvec, V2, V1, Z)); + } + + /* Cases: */ + /* (1) a == 1.0, b == other or 0.0, */ + /* (2) a == other or 0.0, b == 1.0 */ + /* if a or b is 0.0, then user should have called N_VScale */ + if ((test = (a == ONE)) || (b == ONE)) { + c = test ? b : a; + V1 = test ? Y : X; + V2 = test ? X : Y; + return(VLin1VectorArray_OpenMPDEV(nvec, c, V1, V2, Z)); + } + + /* Cases: */ + /* (1) a == -1.0, b != 1.0, */ + /* (2) a != 1.0, b == -1.0 */ + if ((test = (a == -ONE)) || (b == -ONE)) { + c = test ? b : a; + V1 = test ? Y : X; + V2 = test ? X : Y; + return(VLin2VectorArray_OpenMPDEV(nvec, c, V1, V2, Z)); + } + + /* Case: a == b */ + /* catches case both a and b are 0.0 - user should have called N_VConst */ + if (a == b) + return(VScaleSumVectorArray_OpenMPDEV(nvec, a, X, Y, Z)); + + /* Case: a == -b */ + if (a == -b) + return(VScaleDiffVectorArray_OpenMPDEV(nvec, a, X, Y, Z)); + + /* Do all cases not handled above: */ + /* (1) a == other, b == 0.0 - user should have called N_VScale */ + /* (2) a == 0.0, b == other - user should have called N_VScale */ + /* (3) a,b == other, a !=b, a != -b */ + + /* get vector length */ + N = NV_LENGTH_OMPDEV(Z[0]); + + /* get default device identifier */ + dev = omp_get_default_device(); + + /* Allocate and store dev pointers to copy to device */ + xd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + yd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + zd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + for (i=0; i<nvec; i++) + xd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(X[i]); + for (i=0; i<nvec; i++) + yd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(Y[i]); + for (i=0; i<nvec; i++) + zd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(Z[i]); + + /* compute linear sum for each vector pair in vector arrays */ +#pragma omp target map(to:N,nvec,a,b,xd_dev_ptrs[:nvec], yd_dev_ptrs[:nvec],zd_dev_ptrs[:nvec]) \ + is_device_ptr(xd_dev, yd_dev, zd_dev) device(dev) +#pragma omp teams distribute + { + for (i=0; i<nvec; i++) { + xd_dev = xd_dev_ptrs[i]; + yd_dev = yd_dev_ptrs[i]; + zd_dev = zd_dev_ptrs[i]; +#pragma omp parallel for schedule(static, 1) + for (j=0; j<N; j++) + zd_dev[j] = a * xd_dev[j] + b * yd_dev[j]; + } + } + + free(xd_dev_ptrs); + free(yd_dev_ptrs); + free(zd_dev_ptrs); + return(0); +} + +int N_VScaleVectorArray_OpenMPDEV(int nvec, realtype* c, N_Vector* X, N_Vector* Z) +{ + int i, dev; + sunindextype j, N; + realtype* xd_dev=NULL; + realtype* zd_dev=NULL; + realtype** xd_dev_ptrs=NULL; + realtype** zd_dev_ptrs=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VScale */ + if (nvec == 1) { + N_VScale_OpenMPDEV(c[0], X[0], Z[0]); + return(0); + } + + /* get vector length */ + N = NV_LENGTH_OMPDEV(Z[0]); + + /* get default device identifier */ + dev = omp_get_default_device(); + + /* Allocate and store dev pointers to copy to device */ + xd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + for (i=0; i<nvec; i++) { + xd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(X[i]); + } + + /* + * X[i] *= c[i] + */ + if (X == Z) { +#pragma omp target map(to:N,nvec,c[:nvec],xd_dev_ptrs[:nvec]) \ + is_device_ptr(xd_dev) device(dev) +#pragma omp teams distribute + { + for (i=0; i<nvec; i++) { + xd_dev = xd_dev_ptrs[i]; +#pragma omp parallel for schedule(static, 1) + for (j=0; j<N; j++) + xd_dev[j] *= c[i]; + } + } + free(xd_dev_ptrs); + return(0); + } + + /* Allocate and store dev pointers to copy to device */ + zd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + for (i=0; i<nvec; i++) + zd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(Z[i]); + + /* + * Z[i] = c[i] * X[i] + */ +#pragma omp target map(to:N,nvec,c[:nvec],xd_dev_ptrs[:nvec],zd_dev_ptrs[:nvec]) \ + is_device_ptr(xd_dev, zd_dev) device(dev) +#pragma omp teams distribute + { + for (i=0; i<nvec; i++) { + xd_dev = xd_dev_ptrs[i]; + zd_dev = zd_dev_ptrs[i]; +#pragma omp parallel for schedule(static, 1) + for (j=0; j<N; j++) + zd_dev[j] = c[i] * xd_dev[j]; + } + } + free(xd_dev_ptrs); + free(zd_dev_ptrs); + return(0); +} + +int N_VConstVectorArray_OpenMPDEV(int nvec, realtype c, N_Vector* Z) +{ + int i, dev; + sunindextype j, N; + realtype* zd_dev=NULL; + realtype** zd_dev_ptrs=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VConst */ + if (nvec == 1) { + N_VConst_OpenMPDEV(c, Z[0]); + return(0); + } + + /* get vector length */ + N = NV_LENGTH_OMPDEV(Z[0]); + + /* get device */ + dev = omp_get_default_device(); + + /* Allocate and store dev pointers to copy to device */ + zd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + for (i=0; i<nvec; i++) + zd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(Z[i]); + + /* set each vector in the vector array to a constant */ +#pragma omp target map(to:N,nvec,zd_dev_ptrs[:nvec]) \ + is_device_ptr(zd_dev) device(dev) +#pragma omp teams distribute + { + for (i=0; i<nvec; i++) { + zd_dev = zd_dev_ptrs[i]; +#pragma omp parallel for schedule(static, 1) + for (j=0; j<N; j++) + zd_dev[j] = c; + } + } + + free(zd_dev_ptrs); + return(0); +} + +int N_VWrmsNormVectorArray_OpenMPDEV(int nvec, N_Vector* X, N_Vector* W, realtype* nrm) +{ + int i, dev; + sunindextype j, N; + realtype sum; + realtype* wd_dev=NULL; + realtype* xd_dev=NULL; + realtype** wd_dev_ptrs=NULL; + realtype** xd_dev_ptrs=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VWrmsNorm */ + if (nvec == 1) { + nrm[0] = N_VWrmsNorm_OpenMPDEV(X[0], W[0]); + return(0); + } + + /* get vector length */ + N = NV_LENGTH_OMPDEV(X[0]); + + /* get default device identifier */ + dev = omp_get_default_device(); + + /* initialize norms */ + for (i=0; i<nvec; i++) + nrm[i] = ZERO; + + /* Allocate and store dev pointers to copy to device */ + wd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + xd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + for (i=0; i<nvec; i++) + wd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(W[i]); + for (i=0; i<nvec; i++) + xd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(X[i]); + + /* compute the WRMS norm for each vector in the vector array */ +#pragma omp target map(to:N,nvec,xd_dev_ptrs[:nvec],wd_dev_ptrs[:nvec]) map(tofrom:nrm[:nvec]) \ + is_device_ptr(xd_dev, wd_dev) device(dev) +#pragma omp teams distribute + { + for (i=0; i<nvec; i++) { + xd_dev = xd_dev_ptrs[i]; + wd_dev = wd_dev_ptrs[i]; + sum = ZERO; +#pragma omp parallel for reduction(+:sum) schedule(static, 1) + { + for (j=0; j<N; j++) + sum += SUNSQR(xd_dev[j] * wd_dev[j]); + } + nrm[i] = SUNRsqrt(sum/N); + } + } + + free(wd_dev_ptrs); + free(xd_dev_ptrs); + return(0); +} + + +int N_VWrmsNormMaskVectorArray_OpenMPDEV(int nvec, N_Vector* X, N_Vector* W, + N_Vector id, realtype* nrm) +{ + int i, dev; + sunindextype j, N; + realtype sum; + realtype* wd_dev=NULL; + realtype* xd_dev=NULL; + realtype* idd_dev=NULL; + realtype** wd_dev_ptrs=NULL; + realtype** xd_dev_ptrs=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VWrmsNorm */ + if (nvec == 1) { + nrm[0] = N_VWrmsNormMask_OpenMPDEV(X[0], W[0], id); + return(0); + } + + /* get vector length and mask data array */ + N = NV_LENGTH_OMPDEV(X[0]); + idd_dev = NV_DATA_DEV_OMPDEV(id); + + /* get default device identifier */ + dev = omp_get_default_device(); + + /* initialize norms */ + for (i=0; i<nvec; i++) + nrm[i] = ZERO; + + /* Allocate and store dev pointers to copy to device */ + xd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + wd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + for (i=0; i<nvec; i++) + xd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(X[i]); + for (i=0; i<nvec; i++) + wd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(W[i]); + + /* compute the WRMS norm for each vector in the vector array */ +#pragma omp target map(to:N,nvec,xd_dev_ptrs[:nvec],wd_dev_ptrs[:nvec]) map(tofrom:nrm[:nvec]) \ + is_device_ptr(idd_dev,xd_dev,wd_dev) device(dev) +#pragma omp teams distribute + { + for (i=0; i<nvec; i++) { + xd_dev = xd_dev_ptrs[i]; + wd_dev = wd_dev_ptrs[i]; + sum = ZERO; +#pragma omp parallel for reduction(+:sum) schedule(static, 1) + { + for (j=0; j<N; j++) { + if (idd_dev[j] > ZERO) + sum += SUNSQR(xd_dev[j] * wd_dev[j]); + } + } + nrm[i] = SUNRsqrt(sum/N); + } + } + + free(xd_dev_ptrs); + free(wd_dev_ptrs); + return(0); +} + +int N_VScaleAddMultiVectorArray_OpenMPDEV(int nvec, int nsum, realtype* a, + N_Vector* X, N_Vector** Y, N_Vector** Z) +{ + int i, j, dev; + sunindextype k, N; + realtype* xd_dev=NULL; + realtype* yd_dev=NULL; + realtype* zd_dev=NULL; + realtype** xd_dev_ptrs=NULL; + realtype** yd_dev_ptrs=NULL; + realtype** zd_dev_ptrs=NULL; + + int retval; + N_Vector* YY; + N_Vector* ZZ; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + if (nsum < 1) return(-1); + + /* --------------------------- + * Special cases for nvec == 1 + * --------------------------- */ + + if (nvec == 1) { + + /* should have called N_VLinearSum */ + if (nsum == 1) { + N_VLinearSum_OpenMPDEV(a[0], X[0], ONE, Y[0][0], Z[0][0]); + return(0); + } + + /* should have called N_VScaleAddMulti */ + YY = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + ZZ = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + + for (j=0; j<nsum; j++) { + YY[j] = Y[j][0]; + ZZ[j] = Z[j][0]; + } + + retval = N_VScaleAddMulti_OpenMPDEV(nsum, a, X[0], YY, ZZ); + + free(YY); + free(ZZ); + return(retval); + } + + /* -------------------------- + * Special cases for nvec > 1 + * -------------------------- */ + + /* should have called N_VLinearSumVectorArray */ + if (nsum == 1) { + retval = N_VLinearSumVectorArray_OpenMPDEV(nvec, a[0], X, ONE, Y[0], Z[0]); + return(retval); + } + + /* ---------------------------- + * Compute multiple linear sums + * ---------------------------- */ + + /* get vector length */ + N = NV_LENGTH_OMPDEV(X[0]); + + /* get default device identifier */ + dev = omp_get_default_device(); + + /* Allocate and store dev pointers to copy to device */ + xd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + yd_dev_ptrs = (realtype**) malloc(nvec * nsum * sizeof(realtype*)); + for (i=0; i<nvec; i++) + xd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(X[i]); + for (i=0; i<nvec; i++) { + for (j=0; j<nsum; j++) + yd_dev_ptrs[i * nsum + j] = NV_DATA_DEV_OMPDEV(Y[j][i]); + } + + /* + * Y[i][j] += a[i] * x[j] + */ + if (Y == Z) { +#pragma omp target map(to:N,nvec,nsum,a[:nsum],xd_dev_ptrs[:nvec],yd_dev_ptrs[:nvec*nsum]) \ + is_device_ptr(xd_dev, yd_dev) device(dev) +#pragma omp teams distribute + { + for (i=0; i<nvec; i++) { + xd_dev = xd_dev_ptrs[i]; + for (j=0; j<nsum; j++) { + yd_dev = yd_dev_ptrs[i*nsum+j]; +#pragma omp parallel for schedule(static, 1) + for (k=0; k<N; k++) + yd_dev[k] += a[j] * xd_dev[k]; + } + } + } + free(xd_dev_ptrs); + free(yd_dev_ptrs); + return(0); + } + + /* Allocate and store dev pointers to copy to device */ + zd_dev_ptrs = (realtype**) malloc(nvec * nsum * sizeof(realtype*)); + for (i=0; i<nvec; i++) { + for (j=0; j<nsum; j++) + zd_dev_ptrs[i * nsum + j] = NV_DATA_DEV_OMPDEV(Z[j][i]); + } + + /* + * Z[i][j] = Y[i][j] + a[i] * x[j] + */ +#pragma omp target map(to:N,nvec,nsum,a[:nsum],xd_dev_ptrs[:nvec],yd_dev_ptrs[:nvec*nsum],zd_dev_ptrs[:nvec*nsum]) \ + is_device_ptr(xd_dev, yd_dev, zd_dev) device(dev) +#pragma omp teams distribute + { + for (i=0; i<nvec; i++) { + xd_dev = xd_dev_ptrs[i]; + for (j=0; j<nsum; j++) { + yd_dev = yd_dev_ptrs[i*nsum+j]; + zd_dev = zd_dev_ptrs[i*nsum+j]; +#pragma omp parallel for schedule(static, 1) + for (k=0; k<N; k++) + zd_dev[k] = a[j] * xd_dev[k] + yd_dev[k]; + } + } + } + + free(xd_dev_ptrs); + free(yd_dev_ptrs); + free(zd_dev_ptrs); + return(0); +} + +int N_VLinearCombinationVectorArray_OpenMPDEV(int nvec, int nsum, + realtype* c, + N_Vector** X, + N_Vector* Z) +{ + int i; /* vector arrays index in summation [0,nsum) */ + int j; /* vector index in vector array [0,nvec) */ + sunindextype k; /* element index in vector [0,N) */ + sunindextype N; + realtype* zd_dev=NULL; + realtype* xd_dev=NULL; + realtype** zd_dev_ptrs=NULL; + realtype** xd_dev_ptrs=NULL; + int dev; + + realtype* ctmp; + N_Vector* Y; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + if (nsum < 1) return(-1); + + /* --------------------------- + * Special cases for nvec == 1 + * --------------------------- */ + + if (nvec == 1) { + + /* should have called N_VScale */ + if (nsum == 1) { + N_VScale_OpenMPDEV(c[0], X[0][0], Z[0]); + return(0); + } + + /* should have called N_VLinearSum */ + if (nsum == 2) { + N_VLinearSum_OpenMPDEV(c[0], X[0][0], c[1], X[1][0], Z[0]); + return(0); + } + + /* should have called N_VLinearCombination */ + Y = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + + for (i=0; i<nsum; i++) { + Y[i] = X[i][0]; + } + + N_VLinearCombination_OpenMPDEV(nsum, c, Y, Z[0]); + + free(Y); + return(0); + } + + /* -------------------------- + * Special cases for nvec > 1 + * -------------------------- */ + + /* should have called N_VScaleVectorArray */ + if (nsum == 1) { + + ctmp = (realtype*) malloc(nvec * sizeof(realtype)); + + for (j=0; j<nvec; j++) { + ctmp[j] = c[0]; + } + + N_VScaleVectorArray_OpenMPDEV(nvec, ctmp, X[0], Z); + + free(ctmp); + return(0); + } + + /* should have called N_VLinearSumVectorArray */ + if (nsum == 2) { + N_VLinearSumVectorArray_OpenMPDEV(nvec, c[0], X[0], c[1], X[1], Z); + return(0); + } + + /* -------------------------- + * Compute linear combination + * -------------------------- */ + + /* get vector length */ + N = NV_LENGTH_OMPDEV(Z[0]); + + /* get default device identifier */ + dev = omp_get_default_device(); + + /* Allocate and store dev pointers to copy to device */ + zd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + xd_dev_ptrs = (realtype**) malloc(nvec * nsum * sizeof(realtype*)); + for (j=0; j<nvec; j++) + zd_dev_ptrs[j] = NV_DATA_DEV_OMPDEV(Z[j]); + for (j=0; j<nvec; j++) { + for (i=0; i<nsum; i++) + xd_dev_ptrs[j * nsum + i] = NV_DATA_DEV_OMPDEV(X[i][j]); + } + + /* + * X[0][j] += c[i]*X[i][j], i = 1,...,nvec-1 + */ + if ((X[0] == Z) && (c[0] == ONE)) { +#pragma omp target map(to:N,nvec,c[:nsum],xd_dev_ptrs[:nvec*nsum],zd_dev_ptrs[:nvec]) \ + is_device_ptr(xd_dev, zd_dev) device(dev) +#pragma omp teams distribute + { + for (j=0; j<nvec; j++) { + zd_dev = zd_dev_ptrs[j]; + for (i=1; i<nsum; i++) { + xd_dev = xd_dev_ptrs[j*nsum+i]; +#pragma omp parallel for schedule(static, 1) + for (k=0; k<N; k++) + zd_dev[k] += c[i] * xd_dev[k]; + } + } + } + free(xd_dev_ptrs); + free(zd_dev_ptrs); + return(0); + } + + /* + * X[0][j] = c[0] * X[0][j] + sum{ c[i] * X[i][j] }, i = 1,...,nvec-1 + */ + if (X[0] == Z) { +#pragma omp target map(to:N,nvec,c[:nsum],xd_dev_ptrs[:nvec*nsum],zd_dev_ptrs[:nvec]) \ + is_device_ptr(zd_dev) device(dev) +#pragma omp teams distribute + { + for (j=0; j<nvec; j++) { + zd_dev = zd_dev_ptrs[j]; +#pragma omp parallel for schedule(static, 1) + for (k=0; k<N; k++) + zd_dev[k] *= c[0]; + + for (i=1; i<nsum; i++) { + xd_dev = xd_dev_ptrs[j*nsum+i]; +#pragma omp parallel for schedule(static, 1) + for (k=0; k<N; k++) + zd_dev[k] += c[i] * xd_dev[k]; + } + } + } + free(xd_dev_ptrs); + free(zd_dev_ptrs); + return(0); + } + + /* + * Z[j] = sum{ c[i] * X[i][j] }, i = 0,...,nvec-1 + */ +#pragma omp target map(to:N,nvec,c[:nsum],xd_dev_ptrs[:nvec*nsum],zd_dev_ptrs[:nvec]) \ + is_device_ptr(zd_dev) device(dev) +#pragma omp teams distribute + { + for (j=0; j<nvec; j++) { + /* scale first vector in the sum into the output vector */ + xd_dev = xd_dev_ptrs[j*nsum]; + zd_dev = zd_dev_ptrs[j]; +#pragma omp parallel for schedule(static, 1) + for (k=0; k<N; k++) + zd_dev[k] = c[0] * xd_dev[k]; + + /* scale and sum remaining vectors into the output vector */ + for (i=1; i<nsum; i++) { + xd_dev = xd_dev_ptrs[j*nsum+i]; +#pragma omp parallel for schedule(static, 1) + for (k=0; k<N; k++) + zd_dev[k] += c[i] * xd_dev[k]; + } + } + } + free(xd_dev_ptrs); + free(zd_dev_ptrs); + return(0); +} + + +/* + * ----------------------------------------------------------------- + * private functions + * ----------------------------------------------------------------- + */ + + +/* ---------------------------------------------------------------------------- + * Copy vector components into a second vector + */ + +static void VCopy_OpenMPDEV(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd_dev, *zd_dev; + int dev; + + xd_dev = zd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + zd_dev = NV_DATA_DEV_OMPDEV(z); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N) is_device_ptr(xd_dev, zd_dev) device(dev) +#pragma omp teams distribute parallel for schedule(static, 1) + for (i = 0; i < N; i++) + zd_dev[i] = xd_dev[i]; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute vector sum + */ + +static void VSum_OpenMPDEV(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd_dev, *yd_dev, *zd_dev; + int dev; + + xd_dev = yd_dev = zd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + yd_dev = NV_DATA_DEV_OMPDEV(y); + zd_dev = NV_DATA_DEV_OMPDEV(z); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N) is_device_ptr(xd_dev, yd_dev, zd_dev) device(dev) +#pragma omp teams distribute parallel for schedule(static, 1) + for (i = 0; i < N; i++) + zd_dev[i] = xd_dev[i]+yd_dev[i]; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute vector difference + */ + +static void VDiff_OpenMPDEV(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd_dev, *yd_dev, *zd_dev; + int dev; + + xd_dev = yd_dev = zd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + yd_dev = NV_DATA_DEV_OMPDEV(y); + zd_dev = NV_DATA_DEV_OMPDEV(z); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N) is_device_ptr(xd_dev, yd_dev, zd_dev) device(dev) +#pragma omp teams distribute parallel for schedule(static, 1) + for (i = 0; i < N; i++) + zd_dev[i] = xd_dev[i]-yd_dev[i]; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute the negative of a vector + */ + +static void VNeg_OpenMPDEV(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd_dev, *zd_dev; + int dev; + + xd_dev = zd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + zd_dev = NV_DATA_DEV_OMPDEV(z); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N) is_device_ptr(xd_dev, zd_dev) device(dev) +#pragma omp teams distribute parallel for schedule(static, 1) + for (i = 0; i < N; i++) + zd_dev[i] = -xd_dev[i]; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute scaled vector sum + */ + +static void VScaleSum_OpenMPDEV(realtype c, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd_dev, *yd_dev, *zd_dev; + int dev; + + xd_dev = yd_dev = zd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + yd_dev = NV_DATA_DEV_OMPDEV(y); + zd_dev = NV_DATA_DEV_OMPDEV(z); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N,c) is_device_ptr(xd_dev, yd_dev, zd_dev) device(dev) +#pragma omp teams distribute parallel for schedule(static, 1) + for (i = 0; i < N; i++) + zd_dev[i] = c*(xd_dev[i]+yd_dev[i]); + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute scaled vector difference + */ + +static void VScaleDiff_OpenMPDEV(realtype c, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd_dev, *yd_dev, *zd_dev; + int dev; + + xd_dev = yd_dev = zd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + yd_dev = NV_DATA_DEV_OMPDEV(y); + zd_dev = NV_DATA_DEV_OMPDEV(z); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N,c) is_device_ptr(xd_dev, yd_dev, zd_dev) device(dev) +#pragma omp teams distribute parallel for schedule(static, 1) + for (i = 0; i < N; i++) + zd_dev[i] = c*(xd_dev[i]-yd_dev[i]); + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute vector sum z[i] = a*x[i]+y[i] + */ + +static void VLin1_OpenMPDEV(realtype a, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd_dev, *yd_dev, *zd_dev; + int dev; + + xd_dev = yd_dev = zd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + yd_dev = NV_DATA_DEV_OMPDEV(y); + zd_dev = NV_DATA_DEV_OMPDEV(z); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N,a) is_device_ptr(xd_dev, yd_dev, zd_dev) device(dev) +#pragma omp teams distribute parallel for schedule(static, 1) + for (i = 0; i < N; i++) + zd_dev[i] = (a*xd_dev[i])+yd_dev[i]; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute vector difference z[i] = a*x[i]-y[i] + */ + +static void VLin2_OpenMPDEV(realtype a, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd_dev, *yd_dev, *zd_dev; + int dev; + + xd_dev = yd_dev = zd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + yd_dev = NV_DATA_DEV_OMPDEV(y); + zd_dev = NV_DATA_DEV_OMPDEV(z); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N,a) is_device_ptr(xd_dev, yd_dev, zd_dev) device(dev) +#pragma omp teams distribute parallel for schedule(static, 1) + for (i = 0; i < N; i++) + zd_dev[i] = (a*xd_dev[i])-yd_dev[i]; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute special cases of linear sum + */ + +static void Vaxpy_OpenMPDEV(realtype a, N_Vector x, N_Vector y) +{ + sunindextype i, N; + realtype *xd_dev, *yd_dev; + int dev; + + xd_dev = yd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + yd_dev = NV_DATA_DEV_OMPDEV(y); + + /* get default device identifier */ + dev = omp_get_default_device(); + + if (a == ONE) { +#pragma omp target map(to:N) is_device_ptr(xd_dev, yd_dev) device(dev) +#pragma omp teams distribute parallel for schedule(static, 1) + for (i = 0; i < N; i++) + yd_dev[i] += xd_dev[i]; + return; + } + + if (a == -ONE) { +#pragma omp target map(to:N) is_device_ptr(xd_dev, yd_dev) device(dev) +#pragma omp teams distribute parallel for schedule(static, 1) + for (i = 0; i < N; i++) + yd_dev[i] -= xd_dev[i]; + return; + } + +#pragma omp target map(to:N,a) is_device_ptr(xd_dev, yd_dev) device(dev) +#pragma omp teams distribute parallel for schedule(static, 1) + for (i = 0; i < N; i++) + yd_dev[i] += a*xd_dev[i]; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute scaled vector x[i] = a*x[i] + */ + +static void VScaleBy_OpenMPDEV(realtype a, N_Vector x) +{ + sunindextype i, N; + realtype *xd_dev; + int dev; + + xd_dev = NULL; + + N = NV_LENGTH_OMPDEV(x); + xd_dev = NV_DATA_DEV_OMPDEV(x); + + /* get default device identifier */ + dev = omp_get_default_device(); + +#pragma omp target map(to:N,a) is_device_ptr(xd_dev) device(dev) +#pragma omp teams distribute parallel for schedule(static, 1) + for (i = 0; i < N; i++) + xd_dev[i] *= a; + + return; +} + + +/* + * ----------------------------------------------------------------- + * private functions for special cases of vector array operations + * ----------------------------------------------------------------- + */ + +static int VSumVectorArray_OpenMPDEV(int nvec, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i, dev; + sunindextype j, N; + realtype* xd_dev=NULL; + realtype* yd_dev=NULL; + realtype* zd_dev=NULL; + realtype** xd_dev_ptrs=NULL; + realtype** yd_dev_ptrs=NULL; + realtype** zd_dev_ptrs=NULL; + + N = NV_LENGTH_OMPDEV(X[0]); + + /* get default device identifier */ + dev = omp_get_default_device(); + + /* Allocate and store dev pointers to copy to device */ + xd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + yd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + zd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + for (i=0; i<nvec; i++) + xd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(X[i]); + for (i=0; i<nvec; i++) + yd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(Y[i]); + for (i=0; i<nvec; i++) + zd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(Z[i]); + +#pragma omp target map(to:N,xd_dev_ptrs[:nvec],yd_dev_ptrs[:nvec],zd_dev_ptrs[:nvec]) \ + is_device_ptr(xd_dev, yd_dev, zd_dev) device(dev) +#pragma omp teams distribute + { + for (i=0; i<nvec; i++) { + xd_dev = xd_dev_ptrs[i]; + yd_dev = yd_dev_ptrs[i]; + zd_dev = zd_dev_ptrs[i]; +#pragma omp parallel for schedule(static, 1) + for (j=0; j<N; j++) + zd_dev[j] = xd_dev[j] + yd_dev[j]; + } + } + + free(xd_dev_ptrs); + free(yd_dev_ptrs); + free(zd_dev_ptrs); + return(0); +} + +static int VDiffVectorArray_OpenMPDEV(int nvec, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i, dev; + sunindextype j, N; + realtype* xd_dev=NULL; + realtype* yd_dev=NULL; + realtype* zd_dev=NULL; + realtype** xd_dev_ptrs=NULL; + realtype** yd_dev_ptrs=NULL; + realtype** zd_dev_ptrs=NULL; + + N = NV_LENGTH_OMPDEV(X[0]); + + /* get default device identifier */ + dev = omp_get_default_device(); + + /* Allocate and store dev pointers to copy to device */ + xd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + yd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + zd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + for (i=0; i<nvec; i++) + xd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(X[i]); + for (i=0; i<nvec; i++) + yd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(Y[i]); + for (i=0; i<nvec; i++) + zd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(Z[i]); + +#pragma omp target map(to:N,xd_dev_ptrs[:nvec],yd_dev_ptrs[:nvec],zd_dev_ptrs[:nvec]) \ + is_device_ptr(xd_dev,yd_dev,zd_dev) device(dev) +#pragma omp teams distribute + { + for (i=0; i<nvec; i++) { + xd_dev = xd_dev_ptrs[i]; + yd_dev = yd_dev_ptrs[i]; + zd_dev = zd_dev_ptrs[i]; +#pragma omp parallel for schedule(static, 1) + for (j=0; j<N; j++) + zd_dev[j] = xd_dev[j] - yd_dev[j]; + } + } + + free(xd_dev_ptrs); + free(yd_dev_ptrs); + free(zd_dev_ptrs); + return(0); +} + +static int VScaleSumVectorArray_OpenMPDEV(int nvec, realtype c, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i, dev; + sunindextype j, N; + realtype* xd_dev=NULL; + realtype* yd_dev=NULL; + realtype* zd_dev=NULL; + realtype** xd_dev_ptrs=NULL; + realtype** yd_dev_ptrs=NULL; + realtype** zd_dev_ptrs=NULL; + + N = NV_LENGTH_OMPDEV(X[0]); + + /* get default device identifier */ + dev = omp_get_default_device(); + + /* Allocate and store dev pointers to copy to device */ + xd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + yd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + zd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + for (i=0; i<nvec; i++) + xd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(X[i]); + for (i=0; i<nvec; i++) + yd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(Y[i]); + for (i=0; i<nvec; i++) + zd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(Z[i]); + +#pragma omp target map(to:N,xd_dev_ptrs[:nvec],yd_dev_ptrs[:nvec],zd_dev_ptrs[:nvec]) \ + is_device_ptr(xd_dev,yd_dev,zd_dev) device(dev) +#pragma omp teams distribute + { + for (i=0; i<nvec; i++) { + xd_dev = xd_dev_ptrs[i]; + yd_dev = yd_dev_ptrs[i]; + zd_dev = zd_dev_ptrs[i]; +#pragma omp parallel for schedule(static, 1) + for (j=0; j<N; j++) + zd_dev[j] = c * (xd_dev[j] + yd_dev[j]); + } + } + + free(xd_dev_ptrs); + free(yd_dev_ptrs); + free(zd_dev_ptrs); + return(0); +} + +static int VScaleDiffVectorArray_OpenMPDEV(int nvec, realtype c, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i, dev; + sunindextype j, N; + realtype* xd_dev=NULL; + realtype* yd_dev=NULL; + realtype* zd_dev=NULL; + realtype** xd_dev_ptrs=NULL; + realtype** yd_dev_ptrs=NULL; + realtype** zd_dev_ptrs=NULL; + + N = NV_LENGTH_OMPDEV(X[0]); + + /* get default device identifier */ + dev = omp_get_default_device(); + + /* Allocate and store dev ointer to copy to device */ + xd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + yd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + zd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + for (i=0; i<nvec; i++) + xd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(X[i]); + for (i=0; i<nvec; i++) + yd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(Y[i]); + for (i=0; i<nvec; i++) + zd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(Z[i]); + +#pragma omp target map(to:N,xd_dev_ptrs[:nvec],yd_dev_ptrs[:nvec],zd_dev_ptrs[:nvec]) \ + is_device_ptr(xd_dev,yd_dev,zd_dev) device(dev) +#pragma omp teams distribute + { + for (i=0; i<nvec; i++) { + xd_dev = xd_dev_ptrs[i]; + yd_dev = yd_dev_ptrs[i]; + zd_dev = zd_dev_ptrs[i]; +#pragma omp parallel for schedule(static, 1) + for (j=0; j<N; j++) + zd_dev[j] = c * (xd_dev[j] - yd_dev[j]); + } + } + + free(xd_dev_ptrs); + free(yd_dev_ptrs); + free(zd_dev_ptrs); + return(0); +} + +static int VLin1VectorArray_OpenMPDEV(int nvec, realtype a, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i, dev; + sunindextype j, N; + realtype* xd_dev=NULL; + realtype* yd_dev=NULL; + realtype* zd_dev=NULL; + realtype** xd_dev_ptrs=NULL; + realtype** yd_dev_ptrs=NULL; + realtype** zd_dev_ptrs=NULL; + + N = NV_LENGTH_OMPDEV(X[0]); + + /* get default device identifier */ + dev = omp_get_default_device(); + + /* Allocate and store dev pointers to copy to device */ + xd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + yd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + zd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + for (i=0; i<nvec; i++) + xd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(X[i]); + for (i=0; i<nvec; i++) + yd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(Y[i]); + for (i=0; i<nvec; i++) + zd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(Z[i]); + +#pragma omp target map(to:N,xd_dev_ptrs[:nvec],yd_dev_ptrs[:nvec],zd_dev_ptrs[:nvec]) \ + is_device_ptr(xd_dev,yd_dev,zd_dev) device(dev) +#pragma omp teams distribute + { + for (i=0; i<nvec; i++) { + xd_dev = xd_dev_ptrs[i]; + yd_dev = yd_dev_ptrs[i]; + zd_dev = zd_dev_ptrs[i]; +#pragma omp parallel for schedule(static, 1) + for (j=0; j<N; j++) + zd_dev[j] = (a * xd_dev[j]) + yd_dev[j]; + } + } + + free(xd_dev_ptrs); + free(yd_dev_ptrs); + free(zd_dev_ptrs); + return(0); +} + +static int VLin2VectorArray_OpenMPDEV(int nvec, realtype a, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i, dev; + sunindextype j, N; + realtype* xd_dev=NULL; + realtype* yd_dev=NULL; + realtype* zd_dev=NULL; + realtype** xd_dev_ptrs=NULL; + realtype** yd_dev_ptrs=NULL; + realtype** zd_dev_ptrs=NULL; + + N = NV_LENGTH_OMPDEV(X[0]); + + /* get default device identifier */ + dev = omp_get_default_device(); + + /* Allocate and store dev pointers to copy to device */ + xd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + yd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + zd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + for (i=0; i<nvec; i++) + xd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(X[i]); + for (i=0; i<nvec; i++) + yd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(Y[i]); + for (i=0; i<nvec; i++) + zd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(Z[i]); + +#pragma omp target map(to:N,xd_dev_ptrs[:nvec],yd_dev_ptrs[:nvec],zd_dev_ptrs[:nvec]) \ + is_device_ptr(xd_dev,yd_dev,zd_dev) device(dev) +#pragma omp teams distribute + { + for (i=0; i<nvec; i++) { + xd_dev = xd_dev_ptrs[i]; + yd_dev = yd_dev_ptrs[i]; + zd_dev = zd_dev_ptrs[i]; +#pragma omp parallel for schedule(static, 1) + for (j=0; j<N; j++) + zd_dev[j] = (a * xd_dev[j]) - yd_dev[j]; + } + } + + free(xd_dev_ptrs); + free(yd_dev_ptrs); + free(zd_dev_ptrs); + return(0); +} + +static int VaxpyVectorArray_OpenMPDEV(int nvec, realtype a, N_Vector* X, N_Vector* Y) +{ + int i, dev; + sunindextype j, N; + realtype* xd_dev=NULL; + realtype* yd_dev=NULL; + realtype** xd_dev_ptrs=NULL; + realtype** yd_dev_ptrs=NULL; + + N = NV_LENGTH_OMPDEV(X[0]); + + /* get default device identifier */ + dev = omp_get_default_device(); + + /* Allocate and store dev pointers to copy to device */ + xd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + yd_dev_ptrs = (realtype**) malloc(nvec * sizeof(realtype*)); + for (i=0; i<nvec; i++) + xd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(X[i]); + for (i=0; i<nvec; i++) + yd_dev_ptrs[i] = NV_DATA_DEV_OMPDEV(Y[i]); + + if (a == ONE) { +#pragma omp target map(to:N,xd_dev_ptrs[:nvec],yd_dev_ptrs[:nvec]) \ + is_device_ptr(xd_dev,yd_dev) device(dev) +#pragma omp teams distribute + { + for (i=0; i<nvec; i++) { + xd_dev = xd_dev_ptrs[i]; + yd_dev = yd_dev_ptrs[i]; +#pragma omp parallel for schedule(static, 1) + for (j=0; j<N; j++) + yd_dev[j] += xd_dev[j]; + } + } + free(xd_dev_ptrs); + free(yd_dev_ptrs); + return(0); + } + + if (a == -ONE) { +#pragma omp target map(to:N,xd_dev_ptrs[:nvec],yd_dev_ptrs[:nvec]) \ + is_device_ptr(xd_dev,yd_dev) device(dev) +#pragma omp teams distribute + { + for (i=0; i<nvec; i++) { + xd_dev = xd_dev_ptrs[i]; + yd_dev = yd_dev_ptrs[i]; +#pragma omp parallel for schedule(static, 1) + for (j=0; j<N; j++) + yd_dev[j] -= xd_dev[j]; + } + } + free(xd_dev_ptrs); + free(yd_dev_ptrs); + return(0); + } + +#pragma omp target map(to:N,xd_dev_ptrs[:nvec],yd_dev_ptrs[:nvec]) \ + is_device_ptr(xd_dev,yd_dev) device(dev) +#pragma omp teams distribute + { + for (i=0; i<nvec; i++) { + xd_dev = xd_dev_ptrs[i]; + yd_dev = yd_dev_ptrs[i]; +#pragma omp parallel for schedule(static, 1) + for (j=0; j<N; j++) + yd_dev[j] += a * xd_dev[j]; + } + } + free(xd_dev_ptrs); + free(yd_dev_ptrs); + return(0); +} + + +/* + * ----------------------------------------------------------------- + * Enable / Disable fused and vector array operations + * ----------------------------------------------------------------- + */ + +int N_VEnableFusedOps_OpenMPDEV(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); + + if (tf) { + /* enable all fused vector operations */ + v->ops->nvlinearcombination = N_VLinearCombination_OpenMPDEV; + v->ops->nvscaleaddmulti = N_VScaleAddMulti_OpenMPDEV; + v->ops->nvdotprodmulti = N_VDotProdMulti_OpenMPDEV; + /* enable all vector array operations */ + v->ops->nvlinearsumvectorarray = N_VLinearSumVectorArray_OpenMPDEV; + v->ops->nvscalevectorarray = N_VScaleVectorArray_OpenMPDEV; + v->ops->nvconstvectorarray = N_VConstVectorArray_OpenMPDEV; + v->ops->nvwrmsnormvectorarray = N_VWrmsNormVectorArray_OpenMPDEV; + v->ops->nvwrmsnormmaskvectorarray = N_VWrmsNormMaskVectorArray_OpenMPDEV; + v->ops->nvscaleaddmultivectorarray = N_VScaleAddMultiVectorArray_OpenMPDEV; + v->ops->nvlinearcombinationvectorarray = N_VLinearCombinationVectorArray_OpenMPDEV; + } 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 N_VEnableLinearCombination_OpenMPDEV(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 = N_VLinearCombination_OpenMPDEV; + else + v->ops->nvlinearcombination = NULL; + + /* return success */ + return(0); +} + +int N_VEnableScaleAddMulti_OpenMPDEV(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 = N_VScaleAddMulti_OpenMPDEV; + else + v->ops->nvscaleaddmulti = NULL; + + /* return success */ + return(0); +} + +int N_VEnableDotProdMulti_OpenMPDEV(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 = N_VDotProdMulti_OpenMPDEV; + else + v->ops->nvdotprodmulti = NULL; + + /* return success */ + return(0); +} + +int N_VEnableLinearSumVectorArray_OpenMPDEV(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 = N_VLinearSumVectorArray_OpenMPDEV; + else + v->ops->nvlinearsumvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableScaleVectorArray_OpenMPDEV(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 = N_VScaleVectorArray_OpenMPDEV; + else + v->ops->nvscalevectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableConstVectorArray_OpenMPDEV(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 = N_VConstVectorArray_OpenMPDEV; + else + v->ops->nvconstvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableWrmsNormVectorArray_OpenMPDEV(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 = N_VWrmsNormVectorArray_OpenMPDEV; + else + v->ops->nvwrmsnormvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableWrmsNormMaskVectorArray_OpenMPDEV(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 = N_VWrmsNormMaskVectorArray_OpenMPDEV; + else + v->ops->nvwrmsnormmaskvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableScaleAddMultiVectorArray_OpenMPDEV(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->nvscaleaddmultivectorarray = N_VScaleAddMultiVectorArray_OpenMPDEV; + else + v->ops->nvscaleaddmultivectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableLinearCombinationVectorArray_OpenMPDEV(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->nvlinearcombinationvectorarray = N_VLinearCombinationVectorArray_OpenMPDEV; + else + v->ops->nvlinearcombinationvectorarray = NULL; + + /* return success */ + return(0); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/parallel/fnvector_parallel.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/parallel/fnvector_parallel.c new file mode 100644 index 0000000..b8812f5 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/parallel/fnvector_parallel.c @@ -0,0 +1,191 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): 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 file (companion of nvector_parallel.h) contains the + * implementation needed for the Fortran initialization of parallel + * vector operations. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fnvector_parallel.h" + +/* Define global vector variables */ + +N_Vector F2C_CVODE_vec; +N_Vector F2C_CVODE_vecQ; +N_Vector *F2C_CVODE_vecS; +N_Vector F2C_CVODE_vecB; +N_Vector F2C_CVODE_vecQB; + +N_Vector F2C_IDA_vec; +N_Vector F2C_IDA_vecQ; +N_Vector *F2C_IDA_vecS; +N_Vector F2C_IDA_vecB; +N_Vector F2C_IDA_vecQB; + +N_Vector F2C_KINSOL_vec; + +N_Vector F2C_ARKODE_vec; + +#ifndef SUNDIALS_MPI_COMM_F2C +#define MPI_Fint int +#endif + +/* Fortran callable interfaces */ + +void FNV_INITP(MPI_Fint *comm, int *code, long int *L, long int *N, int *ier) +{ + MPI_Comm F2C_comm; + +#ifdef SUNDIALS_MPI_COMM_F2C + F2C_comm = MPI_Comm_f2c(*comm); +#else + F2C_comm = MPI_COMM_WORLD; +#endif + + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + F2C_CVODE_vec = NULL; + F2C_CVODE_vec = N_VNewEmpty_Parallel(F2C_comm, *L, *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); + 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); + 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); + if (F2C_ARKODE_vec == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + +void FNV_INITP_Q(MPI_Fint *comm, int *code, long int *Lq, long int *Nq, int *ier) +{ + MPI_Comm F2C_comm; + +#ifdef SUNDIALS_MPI_COMM_F2C + F2C_comm = MPI_Comm_f2c(*comm); +#else + F2C_comm = MPI_COMM_WORLD; +#endif + + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + F2C_CVODE_vecQ = NULL; + F2C_CVODE_vecQ = N_VNewEmpty_Parallel(F2C_comm, *Lq, *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); + if (F2C_IDA_vecQ == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + +void FNV_INITP_B(MPI_Fint *comm, int *code, long int *LB, long int *NB, int *ier) +{ + MPI_Comm F2C_comm; + +#ifdef SUNDIALS_MPI_COMM_F2C + F2C_comm = MPI_Comm_f2c(*comm); +#else + F2C_comm = MPI_COMM_WORLD; +#endif + + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + F2C_CVODE_vecB = NULL; + F2C_CVODE_vecB = N_VNewEmpty_Parallel(F2C_comm, *LB, *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); + if (F2C_IDA_vecB == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + +void FNV_INITP_QB(MPI_Fint *comm, int *code, long int *LqB, long int *NqB, int *ier) +{ + MPI_Comm F2C_comm; + +#ifdef SUNDIALS_MPI_COMM_F2C + F2C_comm = MPI_Comm_f2c(*comm); +#else + F2C_comm = MPI_COMM_WORLD; +#endif + + + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + F2C_CVODE_vecQB = NULL; + F2C_CVODE_vecQB = N_VNewEmpty_Parallel(F2C_comm, *LqB, *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); + if (F2C_IDA_vecQB == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + +void FNV_INITP_S(int *code, int *Ns, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + F2C_CVODE_vecS = NULL; + F2C_CVODE_vecS = (N_Vector *) N_VCloneVectorArrayEmpty_Parallel(*Ns, F2C_CVODE_vec); + if (F2C_CVODE_vecS == NULL) *ier = -1; + break; + case FCMIX_IDA: + F2C_IDA_vecS = NULL; + F2C_IDA_vecS = (N_Vector *) N_VCloneVectorArrayEmpty_Parallel(*Ns, F2C_IDA_vec); + if (F2C_IDA_vecS == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/parallel/fnvector_parallel.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/parallel/fnvector_parallel.h new file mode 100644 index 0000000..3e3db9d --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/parallel/fnvector_parallel.h @@ -0,0 +1,96 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Radu Serban 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 file (companion of nvector_parallel.c) contains the + * definitions needed for the initialization of parallel + * vector operations in Fortran. + * ----------------------------------------------------------------- + */ + +#ifndef _FNVECTOR_PARALLEL_H +#define _FNVECTOR_PARALLEL_H + +#include <nvector/nvector_parallel.h> +#include <sundials/sundials_fnvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +#if defined(SUNDIALS_F77_FUNC) +#define FNV_INITP SUNDIALS_F77_FUNC(fnvinitp, FNVINITP) +#else +#define FNV_INITP fnvinitp_ +#endif + +#if defined(SUNDIALS_F77_FUNC_) + +#define FNV_INITP_Q SUNDIALS_F77_FUNC_(fnvinitp_q, FNVINITP_Q) +#define FNV_INITP_S SUNDIALS_F77_FUNC_(fnvinitp_s, FNVINITP_S) +#define FNV_INITP_B SUNDIALS_F77_FUNC_(fnvinitp_b, FNVINITP_B) +#define FNV_INITP_QB SUNDIALS_F77_FUNC_(fnvinitp_qb, FNVINITP_QB) + +#else + +#define FNV_INITP_Q fnvinitp_q_ +#define FNV_INITP_S fnvinitp_s_ +#define FNV_INITP_B fnvinitp_b_ +#define FNV_INITP_QB fnvinitp_qb_ + +#endif + +/* Declarations of global variables */ + +extern N_Vector F2C_CVODE_vec; +extern N_Vector F2C_CVODE_vecQ; +extern N_Vector *F2C_CVODE_vecS; +extern N_Vector F2C_CVODE_vecB; +extern N_Vector F2C_CVODE_vecQB; + +extern N_Vector F2C_IDA_vec; +extern N_Vector F2C_IDA_vecQ; +extern N_Vector *F2C_IDA_vecS; +extern N_Vector F2C_IDA_vecB; +extern N_Vector F2C_IDA_vecQB; + +extern N_Vector F2C_KINSOL_vec; + +extern N_Vector F2C_ARKODE_vec; + +/* + * Prototypes of exported functions + * + * FNV_INITP - initializes parallel vector operations for main problem + * FNV_INITP_Q - initializes parallel vector operations for quadratures + * FNV_INITP_S - initializes parallel vector operations for sensitivities + * FNV_INITP_B - initializes parallel vector operations for adjoint problem + * FNV_INITP_QB - initializes parallel vector operations for adjoint quadratures + * + */ + +#ifndef SUNDIALS_MPI_COMM_F2C +#define MPI_Fint int +#endif + +void FNV_INITP(MPI_Fint *comm, int *code, long int *L, long int *N, int *ier); +void FNV_INITP_Q(MPI_Fint *comm, int *code, long int *Lq, long int *Nq, int *ier); +void FNV_INITP_B(MPI_Fint *comm, int *code, long int *LB, long int *NB, int *ier); +void FNV_INITP_QB(MPI_Fint *comm, int *code, long int *LqB, long int *NqB, int *ier); +void FNV_INITP_S(int *code, int *Ns, int *ier); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/parallel/nvector_parallel.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/parallel/nvector_parallel.c new file mode 100644 index 0000000..441b08e --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/parallel/nvector_parallel.c @@ -0,0 +1,2256 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Scott D. Cohen, Alan C. Hindmarsh, Radu Serban, + * 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 implementation file for a parallel MPI implementation + * of the NVECTOR package. + * -----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include <nvector/nvector_parallel.h> +#include <sundials/sundials_math.h> +#include <sundials/sundials_mpi.h> + +#define ZERO RCONST(0.0) +#define HALF RCONST(0.5) +#define ONE RCONST(1.0) +#define ONEPT5 RCONST(1.5) + +/* Private functions for special cases of vector operations */ +static void VCopy_Parallel(N_Vector x, N_Vector z); /* z=x */ +static void VSum_Parallel(N_Vector x, N_Vector y, N_Vector z); /* z=x+y */ +static void VDiff_Parallel(N_Vector x, N_Vector y, N_Vector z); /* z=x-y */ +static void VNeg_Parallel(N_Vector x, N_Vector z); /* z=-x */ +static void VScaleSum_Parallel(realtype c, N_Vector x, N_Vector y, N_Vector z); /* z=c(x+y) */ +static void VScaleDiff_Parallel(realtype c, N_Vector x, N_Vector y, N_Vector z); /* z=c(x-y) */ +static void VLin1_Parallel(realtype a, N_Vector x, N_Vector y, N_Vector z); /* z=ax+y */ +static void VLin2_Parallel(realtype a, N_Vector x, N_Vector y, N_Vector z); /* z=ax-y */ +static void Vaxpy_Parallel(realtype a, N_Vector x, N_Vector y); /* y <- ax+y */ +static void VScaleBy_Parallel(realtype a, N_Vector x); /* x <- ax */ + +/* Private functions for special cases of vector array operations */ +static int VSumVectorArray_Parallel(int nvec, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=X+Y */ +static int VDiffVectorArray_Parallel(int nvec, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=X-Y */ +static int VScaleSumVectorArray_Parallel(int nvec, realtype c, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=c(X+Y) */ +static int VScaleDiffVectorArray_Parallel(int nvec, realtype c, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=c(X-Y) */ +static int VLin1VectorArray_Parallel(int nvec, realtype a, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=aX+Y */ +static int VLin2VectorArray_Parallel(int nvec, realtype a, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=aX-Y */ +static int VaxpyVectorArray_Parallel(int nvec, realtype a, N_Vector* X, N_Vector* Y); /* Y <- aX+Y */ + +/* Error Message */ +#define BAD_N1 "N_VNew_Parallel -- Sum of local vector lengths differs from " +#define BAD_N2 "input global length. \n\n" +#define BAD_N BAD_N1 BAD_N2 + +/* + * ----------------------------------------------------------------- + * exported functions + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------- + * Returns vector type ID. Used to identify vector implementation + * from abstract N_Vector interface. + */ + +N_Vector_ID N_VGetVectorID_Parallel(N_Vector v) +{ + return SUNDIALS_NVEC_PARALLEL; +} + +/* ---------------------------------------------------------------- + * Function to create a new parallel vector with empty data array + */ + +N_Vector N_VNewEmpty_Parallel(MPI_Comm comm, + sunindextype local_length, + 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); + if (Nsum != global_length) { + fprintf(stderr, BAD_N); + return(NULL); + } + + /* Create vector */ + v = NULL; + v = (N_Vector) malloc(sizeof *v); + 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 = 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; + + /* 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; + + /* Create content */ + content = NULL; + content = (N_VectorContent_Parallel) malloc(sizeof(struct _N_VectorContent_Parallel)); + if (content == NULL) { free(ops); free(v); return(NULL); } + + /* Attach lengths and communicator */ + 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); +} + +/* ---------------------------------------------------------------- + * Function to create a new parallel vector + */ + +N_Vector N_VNew_Parallel(MPI_Comm comm, + sunindextype local_length, + sunindextype global_length) +{ + N_Vector v; + realtype *data; + + v = NULL; + v = N_VNewEmpty_Parallel(comm, local_length, global_length); + if (v == NULL) return(NULL); + + /* Create data */ + if(local_length > 0) { + + /* Allocate memory */ + data = NULL; + data = (realtype *) malloc(local_length * sizeof(realtype)); + if(data == NULL) { N_VDestroy_Parallel(v); return(NULL); } + + /* Attach data */ + NV_OWN_DATA_P(v) = SUNTRUE; + NV_DATA_P(v) = data; + + } + + return(v); +} + +/* ---------------------------------------------------------------- + * Function to create a parallel N_Vector with user data component + */ + +N_Vector N_VMake_Parallel(MPI_Comm comm, + sunindextype local_length, + sunindextype global_length, + realtype *v_data) +{ + N_Vector v; + + v = NULL; + v = N_VNewEmpty_Parallel(comm, local_length, global_length); + if (v == NULL) return(NULL); + + if (local_length > 0) { + /* Attach data */ + NV_OWN_DATA_P(v) = SUNFALSE; + NV_DATA_P(v) = v_data; + } + + return(v); +} + +/* ---------------------------------------------------------------- + * Function to create an array of new parallel vectors. + */ + +N_Vector *N_VCloneVectorArray_Parallel(int count, N_Vector w) +{ + N_Vector *vs; + int j; + + if (count <= 0) return(NULL); + + vs = NULL; + vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + if(vs == NULL) return(NULL); + + for (j = 0; j < count; j++) { + vs[j] = NULL; + vs[j] = N_VClone_Parallel(w); + if (vs[j] == NULL) { + N_VDestroyVectorArray_Parallel(vs, j-1); + return(NULL); + } + } + + return(vs); +} + +/* ---------------------------------------------------------------- + * Function to create an array of new parallel vectors with empty + * (NULL) data array. + */ + +N_Vector *N_VCloneVectorArrayEmpty_Parallel(int count, N_Vector w) +{ + N_Vector *vs; + int j; + + if (count <= 0) return(NULL); + + vs = NULL; + vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + if(vs == NULL) return(NULL); + + for (j = 0; j < count; j++) { + vs[j] = NULL; + vs[j] = N_VCloneEmpty_Parallel(w); + if (vs[j] == NULL) { + N_VDestroyVectorArray_Parallel(vs, j-1); + return(NULL); + } + } + + return(vs); +} + +/* ---------------------------------------------------------------- + * Function to free an array created with N_VCloneVectorArray_Parallel + */ + +void N_VDestroyVectorArray_Parallel(N_Vector *vs, int count) +{ + int j; + + for (j = 0; j < count; j++) N_VDestroy_Parallel(vs[j]); + + free(vs); vs = NULL; + + return; +} + +/* ---------------------------------------------------------------- + * Function to return global vector length + */ + +sunindextype N_VGetLength_Parallel(N_Vector v) +{ + return NV_GLOBLENGTH_P(v); +} + +/* ---------------------------------------------------------------- + * Function to return local vector length + */ + +sunindextype N_VGetLocalLength_Parallel(N_Vector v) +{ + return NV_LOCLENGTH_P(v); +} + +/* ---------------------------------------------------------------- + * Function to print the local data in a parallel vector to stdout + */ + +void N_VPrint_Parallel(N_Vector x) +{ + N_VPrintFile_Parallel(x, stdout); +} + +/* ---------------------------------------------------------------- + * Function to print the local data in a parallel vector to outfile + */ + +void N_VPrintFile_Parallel(N_Vector x, FILE* outfile) +{ + sunindextype i, N; + realtype *xd; + + xd = NULL; + + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + + for (i = 0; i < N; i++) { +#if defined(SUNDIALS_EXTENDED_PRECISION) + fprintf(outfile, "%Lg\n", xd[i]); +#elif defined(SUNDIALS_DOUBLE_PRECISION) + fprintf(outfile, "%g\n", xd[i]); +#else + fprintf(outfile, "%g\n", xd[i]); +#endif + } + fprintf(outfile, "\n"); + + return; +} + +/* + * ----------------------------------------------------------------- + * implementation of vector operations + * ----------------------------------------------------------------- + */ + +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); + 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 */ + content = NULL; + content = (N_VectorContent_Parallel) malloc(sizeof(struct _N_VectorContent_Parallel)); + if (content == NULL) { free(ops); free(v); return(NULL); } + + /* Attach lengths and communicator */ + 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); +} + +N_Vector N_VClone_Parallel(N_Vector w) +{ + N_Vector v; + realtype *data; + sunindextype local_length; + + v = NULL; + v = N_VCloneEmpty_Parallel(w); + if (v == NULL) return(NULL); + + local_length = NV_LOCLENGTH_P(w); + + /* Create data */ + if(local_length > 0) { + + /* Allocate memory */ + data = NULL; + data = (realtype *) malloc(local_length * sizeof(realtype)); + if(data == NULL) { N_VDestroy_Parallel(v); return(NULL); } + + /* Attach data */ + NV_OWN_DATA_P(v) = SUNTRUE; + NV_DATA_P(v) = data; + } + + return(v); +} + +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; + } + free(v->content); v->content = NULL; + free(v->ops); v->ops = NULL; + free(v); v = NULL; + + return; +} + +void N_VSpace_Parallel(N_Vector v, sunindextype *lrw, sunindextype *liw) +{ + MPI_Comm comm; + int npes; + + comm = NV_COMM_P(v); + MPI_Comm_size(comm, &npes); + + *lrw = NV_GLOBLENGTH_P(v); + *liw = 2*npes; + + return; +} + +realtype *N_VGetArrayPointer_Parallel(N_Vector v) +{ + return((realtype *) NV_DATA_P(v)); +} + +void N_VSetArrayPointer_Parallel(realtype *v_data, N_Vector v) +{ + if (NV_LOCLENGTH_P(v) > 0) NV_DATA_P(v) = v_data; + + return; +} + +void N_VLinearSum_Parallel(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype c, *xd, *yd, *zd; + N_Vector v1, v2; + booleantype test; + + xd = yd = zd = NULL; + + if ((b == ONE) && (z == y)) { /* BLAS usage: axpy y <- ax+y */ + Vaxpy_Parallel(a, x, y); + return; + } + + if ((a == ONE) && (z == x)) { /* BLAS usage: axpy x <- by+x */ + Vaxpy_Parallel(b, y, x); + return; + } + + /* Case: a == b == 1.0 */ + + if ((a == ONE) && (b == ONE)) { + VSum_Parallel(x, y, z); + return; + } + + /* Cases: (1) a == 1.0, b = -1.0, (2) a == -1.0, b == 1.0 */ + + if ((test = ((a == ONE) && (b == -ONE))) || ((a == -ONE) && (b == ONE))) { + v1 = test ? y : x; + v2 = test ? x : y; + VDiff_Parallel(v2, v1, z); + return; + } + + /* Cases: (1) a == 1.0, b == other or 0.0, (2) a == other or 0.0, b == 1.0 */ + /* if a or b is 0.0, then user should have called N_VScale */ + + if ((test = (a == ONE)) || (b == ONE)) { + c = test ? b : a; + v1 = test ? y : x; + v2 = test ? x : y; + VLin1_Parallel(c, v1, v2, z); + return; + } + + /* Cases: (1) a == -1.0, b != 1.0, (2) a != 1.0, b == -1.0 */ + + if ((test = (a == -ONE)) || (b == -ONE)) { + c = test ? b : a; + v1 = test ? y : x; + v2 = test ? x : y; + VLin2_Parallel(c, v1, v2, z); + return; + } + + /* Case: a == b */ + /* catches case both a and b are 0.0 - user should have called N_VConst */ + + if (a == b) { + VScaleSum_Parallel(a, x, y, z); + return; + } + + /* Case: a == -b */ + + if (a == -b) { + VScaleDiff_Parallel(a, x, y, z); + return; + } + + /* Do all cases not handled above: + (1) a == other, b == 0.0 - user should have called N_VScale + (2) a == 0.0, b == other - user should have called N_VScale + (3) a,b == other, a !=b, a != -b */ + + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + yd = NV_DATA_P(y); + zd = NV_DATA_P(z); + + for (i = 0; i < N; i++) + zd[i] = (a*xd[i])+(b*yd[i]); + + return; +} + +void N_VConst_Parallel(realtype c, N_Vector z) +{ + sunindextype i, N; + realtype *zd; + + zd = NULL; + + N = NV_LOCLENGTH_P(z); + zd = NV_DATA_P(z); + + for (i = 0; i < N; i++) zd[i] = c; + + return; +} + +void N_VProd_Parallel(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + yd = NV_DATA_P(y); + zd = NV_DATA_P(z); + + for (i = 0; i < N; i++) + zd[i] = xd[i]*yd[i]; + + return; +} + +void N_VDiv_Parallel(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + yd = NV_DATA_P(y); + zd = NV_DATA_P(z); + + for (i = 0; i < N; i++) + zd[i] = xd[i]/yd[i]; + + return; +} + +void N_VScale_Parallel(realtype c, N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + if (z == x) { /* BLAS usage: scale x <- cx */ + VScaleBy_Parallel(c, x); + return; + } + + if (c == ONE) { + VCopy_Parallel(x, z); + } else if (c == -ONE) { + VNeg_Parallel(x, z); + } else { + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + zd = NV_DATA_P(z); + for (i = 0; i < N; i++) + zd[i] = c*xd[i]; + } + + return; +} + +void N_VAbs_Parallel(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + zd = NV_DATA_P(z); + + for (i = 0; i < N; i++) + zd[i] = SUNRabs(xd[i]); + + return; +} + +void N_VInv_Parallel(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + zd = NV_DATA_P(z); + + for (i = 0; i < N; i++) + zd[i] = ONE/xd[i]; + + return; +} + +void N_VAddConst_Parallel(N_Vector x, realtype b, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + zd = NV_DATA_P(z); + + for (i = 0; i < N; i++) zd[i] = xd[i]+b; + + return; +} + +realtype N_VDotProd_Parallel(N_Vector x, N_Vector y) +{ + sunindextype i, N; + realtype sum, *xd, *yd, gsum; + MPI_Comm comm; + + sum = ZERO; + xd = yd = NULL; + + 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]; + + gsum = SUNMPI_Allreduce_scalar(sum, 1, comm); + + return(gsum); +} + +realtype N_VMaxNorm_Parallel(N_Vector x) +{ + sunindextype i, N; + realtype max, *xd, gmax; + MPI_Comm comm; + + 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++) { + if (SUNRabs(xd[i]) > max) max = SUNRabs(xd[i]); + } + + gmax = SUNMPI_Allreduce_scalar(max, 2, comm); + + return(gmax); +} + +realtype N_VWrmsNorm_Parallel(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; + + 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); + + 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)); +} + +realtype N_VWrmsNormMask_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; + + 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); + + for (i = 0; i < N; i++) { + if (idd[i] > ZERO) { + prodi = xd[i]*wd[i]; + sum += SUNSQR(prodi); + } + } + + gsum = SUNMPI_Allreduce_scalar(sum, 1, comm); + + return(SUNRsqrt(gsum/N_global)); +} + +realtype N_VMin_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); + + min = BIG_REAL; + + if (N > 0) { + + xd = NV_DATA_P(x); + + min = xd[0]; + + for (i = 1; i < N; i++) { + if (xd[i] < min) min = xd[i]; + } + + } + + gmin = SUNMPI_Allreduce_scalar(min, 3, comm); + + 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); + + return(SUNRsqrt(gsum)); +} + +realtype N_VL1Norm_Parallel(N_Vector x) +{ + sunindextype i, N; + realtype sum, gsum, *xd; + MPI_Comm comm; + + sum = ZERO; + xd = NULL; + + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + comm = NV_COMM_P(x); + + for (i = 0; i<N; i++) + sum += SUNRabs(xd[i]); + + gsum = SUNMPI_Allreduce_scalar(sum, 1, comm); + + return(gsum); +} + +void N_VCompare_Parallel(realtype c, N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + zd = NV_DATA_P(z); + + for (i = 0; i < N; i++) { + zd[i] = (SUNRabs(xd[i]) >= c) ? ONE : ZERO; + } + + return; +} + +booleantype N_VInvTest_Parallel(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd, val, gval; + MPI_Comm comm; + + xd = zd = NULL; + + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + zd = NV_DATA_P(z); + comm = NV_COMM_P(x); + + val = ONE; + for (i = 0; i < N; i++) { + if (xd[i] == ZERO) + val = ZERO; + else + zd[i] = ONE/xd[i]; + } + + gval = SUNMPI_Allreduce_scalar(val, 3, comm); + + if (gval == ZERO) + return(SUNFALSE); + else + return(SUNTRUE); +} + +booleantype N_VConstrMask_Parallel(N_Vector c, N_Vector x, N_Vector m) +{ + sunindextype i, N; + realtype temp; + realtype *cd, *xd, *md; + booleantype test; + MPI_Comm comm; + + cd = xd = md = NULL; + + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + cd = NV_DATA_P(c); + md = NV_DATA_P(m); + comm = NV_COMM_P(x); + + temp = ZERO; + + for (i = 0; i < N; i++) { + md[i] = ZERO; + + /* Continue if no constraints were set for the variable */ + if (cd[i] == ZERO) + continue; + + /* Check if a set constraint has been violated */ + test = (SUNRabs(cd[i]) > ONEPT5 && xd[i]*cd[i] <= ZERO) || + (SUNRabs(cd[i]) > HALF && xd[i]*cd[i] < ZERO); + if (test) { + temp = md[i] = ONE; + } + } + + /* 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_Parallel(N_Vector num, N_Vector denom) +{ + booleantype notEvenOnce; + sunindextype i, N; + realtype *nd, *dd, min; + MPI_Comm comm; + + nd = dd = NULL; + + N = NV_LOCLENGTH_P(num); + nd = NV_DATA_P(num); + dd = NV_DATA_P(denom); + comm = NV_COMM_P(num); + + notEvenOnce = SUNTRUE; + min = BIG_REAL; + + for (i = 0; i < N; i++) { + if (dd[i] == ZERO) continue; + else { + if (!notEvenOnce) min = SUNMIN(min, nd[i]/dd[i]); + else { + min = nd[i]/dd[i]; + notEvenOnce = SUNFALSE; + } + } + } + + return(SUNMPI_Allreduce_scalar(min, 3, comm)); +} + + +/* + * ----------------------------------------------------------------- + * fused vector operations + * ----------------------------------------------------------------- + */ + +int N_VLinearCombination_Parallel(int nvec, realtype* c, N_Vector* X, N_Vector z) +{ + int i; + sunindextype j, N; + realtype* zd=NULL; + realtype* xd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VScale */ + if (nvec == 1) { + N_VScale_Parallel(c[0], X[0], z); + return(0); + } + + /* should have called N_VLinearSum */ + if (nvec == 2) { + N_VLinearSum_Parallel(c[0], X[0], c[1], X[1], z); + return(0); + } + + /* get vector length and data array */ + N = NV_LOCLENGTH_P(z); + zd = NV_DATA_P(z); + + /* + * X[0] += c[i]*X[i], i = 1,...,nvec-1 + */ + if ((X[0] == z) && (c[0] == ONE)) { + for (i=1; i<nvec; i++) { + xd = NV_DATA_P(X[i]); + for (j=0; j<N; j++) { + zd[j] += c[i] * xd[j]; + } + } + return(0); + } + + /* + * X[0] = c[0] * X[0] + sum{ c[i] * X[i] }, i = 1,...,nvec-1 + */ + if (X[0] == z) { + for (j=0; j<N; j++) { + zd[j] *= c[0]; + } + for (i=1; i<nvec; i++) { + xd = NV_DATA_P(X[i]); + for (j=0; j<N; j++) { + zd[j] += c[i] * xd[j]; + } + } + return(0); + } + + /* + * z = sum{ c[i] * X[i] }, i = 0,...,nvec-1 + */ + xd = NV_DATA_P(X[0]); + for (j=0; j<N; j++) { + zd[j] = c[0] * xd[j]; + } + for (i=1; i<nvec; i++) { + xd = NV_DATA_P(X[i]); + for (j=0; j<N; j++) { + zd[j] += c[i] * xd[j]; + } + } + return(0); +} + + +int N_VScaleAddMulti_Parallel(int nvec, realtype* a, N_Vector x, N_Vector* Y, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VLinearSum */ + if (nvec == 1) { + N_VLinearSum_Parallel(a[0], x, ONE, Y[0], Z[0]); + return(0); + } + + /* get vector length and data array */ + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + + /* + * Y[i][j] += a[i] * x[j] + */ + if (Y == Z) { + for (i=0; i<nvec; i++) { + yd = NV_DATA_P(Y[i]); + for (j=0; j<N; j++) { + yd[j] += a[i] * xd[j]; + } + } + return(0); + } + + /* + * Z[i][j] = Y[i][j] + a[i] * x[j] + */ + for (i=0; i<nvec; i++) { + yd = NV_DATA_P(Y[i]); + zd = NV_DATA_P(Z[i]); + for (j=0; j<N; j++) { + zd[j] = a[i] * xd[j] + yd[j]; + } + } + return(0); +} + + +int N_VDotProdMulti_Parallel(int nvec, N_Vector x, N_Vector* Y, realtype* dotprods) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + MPI_Comm comm; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VDotProd */ + if (nvec == 1) { + dotprods[0] = N_VDotProd_Parallel(x, Y[0]); + return(0); + } + + /* get vector length, data array, and communicator */ + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + comm = NV_COMM_P(x); + + /* compute multiple dot products */ + for (i=0; i<nvec; i++) { + yd = NV_DATA_P(Y[i]); + dotprods[i] = ZERO; + for (j=0; j<N; j++) { + dotprods[i] += xd[j] * yd[j]; + } + } + SUNMPI_Allreduce(dotprods, nvec, 1, comm); + + return(0); +} + + +/* + * ----------------------------------------------------------------- + * vector array operations + * ----------------------------------------------------------------- + */ + +int N_VLinearSumVectorArray_Parallel(int nvec, + realtype a, N_Vector* X, + realtype b, N_Vector* Y, + N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + realtype c; + N_Vector* V1; + N_Vector* V2; + booleantype test; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VLinearSum */ + if (nvec == 1) { + N_VLinearSum_Parallel(a, X[0], b, Y[0], Z[0]); + return(0); + } + + /* BLAS usage: axpy y <- ax+y */ + if ((b == ONE) && (Z == Y)) + return(VaxpyVectorArray_Parallel(nvec, a, X, Y)); + + /* BLAS usage: axpy x <- by+x */ + if ((a == ONE) && (Z == X)) + return(VaxpyVectorArray_Parallel(nvec, b, Y, X)); + + /* Case: a == b == 1.0 */ + if ((a == ONE) && (b == ONE)) + return(VSumVectorArray_Parallel(nvec, X, Y, Z)); + + /* Cases: */ + /* (1) a == 1.0, b = -1.0, */ + /* (2) a == -1.0, b == 1.0 */ + if ((test = ((a == ONE) && (b == -ONE))) || ((a == -ONE) && (b == ONE))) { + V1 = test ? Y : X; + V2 = test ? X : Y; + return(VDiffVectorArray_Parallel(nvec, V2, V1, Z)); + } + + /* Cases: */ + /* (1) a == 1.0, b == other or 0.0, */ + /* (2) a == other or 0.0, b == 1.0 */ + /* if a or b is 0.0, then user should have called N_VScale */ + if ((test = (a == ONE)) || (b == ONE)) { + c = test ? b : a; + V1 = test ? Y : X; + V2 = test ? X : Y; + return(VLin1VectorArray_Parallel(nvec, c, V1, V2, Z)); + } + + /* Cases: */ + /* (1) a == -1.0, b != 1.0, */ + /* (2) a != 1.0, b == -1.0 */ + if ((test = (a == -ONE)) || (b == -ONE)) { + c = test ? b : a; + V1 = test ? Y : X; + V2 = test ? X : Y; + return(VLin2VectorArray_Parallel(nvec, c, V1, V2, Z)); + } + + /* Case: a == b */ + /* catches case both a and b are 0.0 - user should have called N_VConst */ + if (a == b) + return(VScaleSumVectorArray_Parallel(nvec, a, X, Y, Z)); + + /* Case: a == -b */ + if (a == -b) + return(VScaleDiffVectorArray_Parallel(nvec, a, X, Y, Z)); + + /* Do all cases not handled above: */ + /* (1) a == other, b == 0.0 - user should have called N_VScale */ + /* (2) a == 0.0, b == other - user should have called N_VScale */ + /* (3) a,b == other, a !=b, a != -b */ + + /* get vector length */ + N = NV_LOCLENGTH_P(Z[0]); + + /* compute linear sum for each vector pair in vector arrays */ + for (i=0; i<nvec; i++) { + xd = NV_DATA_P(X[i]); + yd = NV_DATA_P(Y[i]); + zd = NV_DATA_P(Z[i]); + for (j=0; j<N; j++) { + zd[j] = a * xd[j] + b * yd[j]; + } + } + + return(0); +} + + +int N_VScaleVectorArray_Parallel(int nvec, realtype* c, N_Vector* X, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* zd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VScale */ + if (nvec == 1) { + N_VScale_Parallel(c[0], X[0], Z[0]); + return(0); + } + + /* get vector length */ + N = NV_LOCLENGTH_P(Z[0]); + + /* + * X[i] *= c[i] + */ + if (X == Z) { + for (i=0; i<nvec; i++) { + xd = NV_DATA_P(X[i]); + for (j=0; j<N; j++) { + xd[j] *= c[i]; + } + } + return(0); + } + + /* + * Z[i] = c[i] * X[i] + */ + for (i=0; i<nvec; i++) { + xd = NV_DATA_P(X[i]); + zd = NV_DATA_P(Z[i]); + for (j=0; j<N; j++) { + zd[j] = c[i] * xd[j]; + } + } + return(0); +} + + +int N_VConstVectorArray_Parallel(int nvec, realtype c, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* zd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VConst */ + if (nvec == 1) { + N_VConst_Parallel(c, Z[0]); + return(0); + } + + /* get vector length */ + N = NV_LOCLENGTH_P(Z[0]); + + /* set each vector in the vector array to a constant */ + for (i=0; i<nvec; i++) { + zd = NV_DATA_P(Z[i]); + for (j=0; j<N; j++) { + zd[j] = c; + } + } + + return(0); +} + + +int N_VWrmsNormVectorArray_Parallel(int nvec, N_Vector* X, N_Vector* W, realtype* nrm) +{ + int i; + sunindextype j, Nl, Ng; + realtype* wd=NULL; + realtype* xd=NULL; + MPI_Comm comm; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VWrmsNorm */ + if (nvec == 1) { + nrm[0] = N_VWrmsNorm_Parallel(X[0], W[0]); + return(0); + } + + /* get vector lengths and communicator */ + Nl = NV_LOCLENGTH_P(X[0]); + Ng = NV_GLOBLENGTH_P(X[0]); + comm = NV_COMM_P(X[0]); + + /* compute the WRMS norm for each vector in the vector array */ + for (i=0; i<nvec; i++) { + xd = NV_DATA_P(X[i]); + wd = NV_DATA_P(W[i]); + nrm[i] = ZERO; + for (j=0; j<Nl; j++) { + nrm[i] += SUNSQR(xd[j] * wd[j]); + } + } + SUNMPI_Allreduce(nrm, nvec, 1, comm); + + for (i=0; i<nvec; i++) + nrm[i] = SUNRsqrt(nrm[i]/Ng); + + return(0); +} + + +int N_VWrmsNormMaskVectorArray_Parallel(int nvec, N_Vector* X, N_Vector* W, + N_Vector id, realtype* nrm) +{ + int i; + sunindextype j, Nl, Ng; + realtype* wd=NULL; + realtype* xd=NULL; + realtype* idd=NULL; + MPI_Comm comm; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VWrmsNorm */ + if (nvec == 1) { + nrm[0] = N_VWrmsNormMask_Parallel(X[0], W[0], id); + return(0); + } + + /* get vector lengths, communicator, and mask data */ + Nl = NV_LOCLENGTH_P(X[0]); + Ng = NV_GLOBLENGTH_P(X[0]); + comm = NV_COMM_P(X[0]); + idd = NV_DATA_P(id); + + /* compute the WRMS norm for each vector in the vector array */ + for (i=0; i<nvec; i++) { + xd = NV_DATA_P(X[i]); + wd = NV_DATA_P(W[i]); + nrm[i] = ZERO; + for (j=0; j<Nl; j++) { + if (idd[j] > ZERO) + nrm[i] += SUNSQR(xd[j] * wd[j]); + } + } + SUNMPI_Allreduce(nrm, nvec, 1, comm); + + for (i=0; i<nvec; i++) + nrm[i] = SUNRsqrt(nrm[i]/Ng); + + return(0); +} + + +int N_VScaleAddMultiVectorArray_Parallel(int nvec, int nsum, realtype* a, + N_Vector* X, N_Vector** Y, N_Vector** Z) +{ + int i, j; + sunindextype k, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + int retval; + N_Vector* YY; + N_Vector* ZZ; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + if (nsum < 1) return(-1); + + /* --------------------------- + * Special cases for nvec == 1 + * --------------------------- */ + + if (nvec == 1) { + + /* should have called N_VLinearSum */ + if (nsum == 1) { + N_VLinearSum_Parallel(a[0], X[0], ONE, Y[0][0], Z[0][0]); + return(0); + } + + /* should have called N_VScaleAddMulti */ + YY = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + ZZ = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + + for (j=0; j<nsum; j++) { + YY[j] = Y[j][0]; + ZZ[j] = Z[j][0]; + } + + retval = N_VScaleAddMulti_Parallel(nsum, a, X[0], YY, ZZ); + + free(YY); + free(ZZ); + return(retval); + } + + /* -------------------------- + * Special cases for nvec > 1 + * -------------------------- */ + + /* should have called N_VLinearSumVectorArray */ + if (nsum == 1) { + retval = N_VLinearSumVectorArray_Parallel(nvec, a[0], X, ONE, Y[0], Z[0]); + return(retval); + } + + /* ---------------------------- + * Compute multiple linear sums + * ---------------------------- */ + + /* get vector length */ + N = NV_LOCLENGTH_P(X[0]); + + /* + * Y[i][j] += a[i] * x[j] + */ + if (Y == Z) { + for (i=0; i<nvec; i++) { + xd = NV_DATA_P(X[i]); + for (j=0; j<nsum; j++){ + yd = NV_DATA_P(Y[j][i]); + for (k=0; k<N; k++) { + yd[k] += a[j] * xd[k]; + } + } + } + return(0); + } + + /* + * Z[i][j] = Y[i][j] + a[i] * x[j] + */ + for (i=0; i<nvec; i++) { + xd = NV_DATA_P(X[i]); + for (j=0; j<nsum; j++) { + yd = NV_DATA_P(Y[j][i]); + zd = NV_DATA_P(Z[j][i]); + for (k=0; k<N; k++) { + zd[k] = a[j] * xd[k] + yd[k]; + } + } + } + return(0); +} + + +int N_VLinearCombinationVectorArray_Parallel(int nvec, int nsum, + realtype* c, + N_Vector** X, + N_Vector* Z) +{ + int i; /* vector arrays index in summation [0,nsum) */ + int j; /* vector index in vector array [0,nvec) */ + sunindextype k; /* element index in vector [0,N) */ + sunindextype N; + realtype* zd=NULL; + realtype* xd=NULL; + + realtype* ctmp; + N_Vector* Y; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + if (nsum < 1) return(-1); + + /* --------------------------- + * Special cases for nvec == 1 + * --------------------------- */ + + if (nvec == 1) { + + /* should have called N_VScale */ + if (nsum == 1) { + N_VScale_Parallel(c[0], X[0][0], Z[0]); + return(0); + } + + /* should have called N_VLinearSum */ + if (nsum == 2) { + N_VLinearSum_Parallel(c[0], X[0][0], c[1], X[1][0], Z[0]); + return(0); + } + + /* should have called N_VLinearCombination */ + Y = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + + for (i=0; i<nsum; i++) { + Y[i] = X[i][0]; + } + + N_VLinearCombination_Parallel(nsum, c, Y, Z[0]); + + free(Y); + return(0); + } + + /* -------------------------- + * Special cases for nvec > 1 + * -------------------------- */ + + /* should have called N_VScaleVectorArray */ + if (nsum == 1) { + + ctmp = (realtype*) malloc(nvec * sizeof(realtype)); + + for (j=0; j<nvec; j++) { + ctmp[j] = c[0]; + } + + N_VScaleVectorArray_Parallel(nvec, ctmp, X[0], Z); + + free(ctmp); + return(0); + } + + /* should have called N_VLinearSumVectorArray */ + if (nsum == 2) { + N_VLinearSumVectorArray_Parallel(nvec, c[0], X[0], c[1], X[1], Z); + return(0); + } + + /* -------------------------- + * Compute linear combination + * -------------------------- */ + + /* get vector length */ + N = NV_LOCLENGTH_P(Z[0]); + + /* + * X[0][j] += c[i]*X[i][j], i = 1,...,nvec-1 + */ + if ((X[0] == Z) && (c[0] == ONE)) { + for (j=0; j<nvec; j++) { + zd = NV_DATA_P(Z[j]); + for (i=1; i<nsum; i++) { + xd = NV_DATA_P(X[i][j]); + for (k=0; k<N; k++) { + zd[k] += c[i] * xd[k]; + } + } + } + return(0); + } + + /* + * X[0][j] = c[0] * X[0][j] + sum{ c[i] * X[i][j] }, i = 1,...,nvec-1 + */ + if (X[0] == Z) { + for (j=0; j<nvec; j++) { + zd = NV_DATA_P(Z[j]); + for (k=0; k<N; k++) { + zd[k] *= c[0]; + } + for (i=1; i<nsum; i++) { + xd = NV_DATA_P(X[i][j]); + for (k=0; k<N; k++) { + zd[k] += c[i] * xd[k]; + } + } + } + return(0); + } + + /* + * Z[j] = sum{ c[i] * X[i][j] }, i = 0,...,nvec-1 + */ + for (j=0; j<nvec; j++) { + xd = NV_DATA_P(X[0][j]); + zd = NV_DATA_P(Z[j]); + for (k=0; k<N; k++) { + zd[k] = c[0] * xd[k]; + } + for (i=1; i<nsum; i++) { + xd = NV_DATA_P(X[i][j]); + for (k=0; k<N; k++) { + zd[k] += c[i] * xd[k]; + } + } + } + return(0); +} + + +/* + * ----------------------------------------------------------------- + * private functions + * ----------------------------------------------------------------- + */ + +static void VCopy_Parallel(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + zd = NV_DATA_P(z); + + for (i = 0; i < N; i++) + zd[i] = xd[i]; + + return; +} + +static void VSum_Parallel(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + yd = NV_DATA_P(y); + zd = NV_DATA_P(z); + + for (i = 0; i < N; i++) + zd[i] = xd[i]+yd[i]; + + return; +} + +static void VDiff_Parallel(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + yd = NV_DATA_P(y); + zd = NV_DATA_P(z); + + for (i = 0; i < N; i++) + zd[i] = xd[i]-yd[i]; + + return; +} + +static void VNeg_Parallel(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + zd = NV_DATA_P(z); + + for (i = 0; i < N; i++) + zd[i] = -xd[i]; + + return; +} + +static void VScaleSum_Parallel(realtype c, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + yd = NV_DATA_P(y); + zd = NV_DATA_P(z); + + for (i = 0; i < N; i++) + zd[i] = c*(xd[i]+yd[i]); + + return; +} + +static void VScaleDiff_Parallel(realtype c, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + yd = NV_DATA_P(y); + zd = NV_DATA_P(z); + + for (i = 0; i < N; i++) + zd[i] = c*(xd[i]-yd[i]); + + return; +} + +static void VLin1_Parallel(realtype a, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + yd = NV_DATA_P(y); + zd = NV_DATA_P(z); + + for (i = 0; i < N; i++) + zd[i] = (a*xd[i])+yd[i]; + + return; +} + +static void VLin2_Parallel(realtype a, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + yd = NV_DATA_P(y); + zd = NV_DATA_P(z); + + for (i = 0; i < N; i++) + zd[i] = (a*xd[i])-yd[i]; + + return; +} + +static void Vaxpy_Parallel(realtype a, N_Vector x, N_Vector y) +{ + sunindextype i, N; + realtype *xd, *yd; + + xd = yd = NULL; + + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + yd = NV_DATA_P(y); + + if (a == ONE) { + for (i = 0; i < N; i++) + yd[i] += xd[i]; + return; + } + + if (a == -ONE) { + for (i = 0; i < N; i++) + yd[i] -= xd[i]; + return; + } + + for (i = 0; i < N; i++) + yd[i] += a*xd[i]; + + return; +} + +static void VScaleBy_Parallel(realtype a, N_Vector x) +{ + sunindextype i, N; + realtype *xd; + + xd = NULL; + + N = NV_LOCLENGTH_P(x); + xd = NV_DATA_P(x); + + for (i = 0; i < N; i++) + xd[i] *= a; + + return; +} + + +/* + * ----------------------------------------------------------------- + * private functions for special cases of vector array operations + * ----------------------------------------------------------------- + */ + +static int VSumVectorArray_Parallel(int nvec, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + N = NV_LOCLENGTH_P(X[0]); + + for (i=0; i<nvec; i++) { + xd = NV_DATA_P(X[i]); + yd = NV_DATA_P(Y[i]); + zd = NV_DATA_P(Z[i]); + for (j=0; j<N; j++) + zd[j] = xd[j] + yd[j]; + } + + return(0); +} + +static int VDiffVectorArray_Parallel(int nvec, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + N = NV_LOCLENGTH_P(X[0]); + + for (i=0; i<nvec; i++) { + xd = NV_DATA_P(X[i]); + yd = NV_DATA_P(Y[i]); + zd = NV_DATA_P(Z[i]); + for (j=0; j<N; j++) + zd[j] = xd[j] - yd[j]; + } + + return(0); +} + +static int VScaleSumVectorArray_Parallel(int nvec, realtype c, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + N = NV_LOCLENGTH_P(X[0]); + + for (i=0; i<nvec; i++) { + xd = NV_DATA_P(X[i]); + yd = NV_DATA_P(Y[i]); + zd = NV_DATA_P(Z[i]); + for (j=0; j<N; j++) + zd[j] = c * (xd[j] + yd[j]); + } + + return(0); +} + +static int VScaleDiffVectorArray_Parallel(int nvec, realtype c, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + N = NV_LOCLENGTH_P(X[0]); + + for (i=0; i<nvec; i++) { + xd = NV_DATA_P(X[i]); + yd = NV_DATA_P(Y[i]); + zd = NV_DATA_P(Z[i]); + for (j=0; j<N; j++) + zd[j] = c * (xd[j] - yd[j]); + } + + return(0); +} + +static int VLin1VectorArray_Parallel(int nvec, realtype a, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + N = NV_LOCLENGTH_P(X[0]); + + for (i=0; i<nvec; i++) { + xd = NV_DATA_P(X[i]); + yd = NV_DATA_P(Y[i]); + zd = NV_DATA_P(Z[i]); + for (j=0; j<N; j++) + zd[j] = (a * xd[j]) + yd[j]; + } + + return(0); +} + +static int VLin2VectorArray_Parallel(int nvec, realtype a, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + N = NV_LOCLENGTH_P(X[0]); + + for (i=0; i<nvec; i++) { + xd = NV_DATA_P(X[i]); + yd = NV_DATA_P(Y[i]); + zd = NV_DATA_P(Z[i]); + for (j=0; j<N; j++) + zd[j] = (a * xd[j]) - yd[j]; + } + + return(0); +} + +static int VaxpyVectorArray_Parallel(int nvec, realtype a, N_Vector* X, N_Vector* Y) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + + N = NV_LOCLENGTH_P(X[0]); + + if (a == ONE) { + for (i=0; i<nvec; i++) { + xd = NV_DATA_P(X[i]); + yd = NV_DATA_P(Y[i]); + for (j=0; j<N; j++) + yd[j] += xd[j]; + } + + return(0); + } + + if (a == -ONE) { + for (i=0; i<nvec; i++) { + xd = NV_DATA_P(X[i]); + yd = NV_DATA_P(Y[i]); + for (j=0; j<N; j++) + yd[j] -= xd[j]; + } + + return(0); + } + + for (i=0; i<nvec; i++) { + xd = NV_DATA_P(X[i]); + yd = NV_DATA_P(Y[i]); + for (j=0; j<N; j++) + yd[j] += a * xd[j]; + } + + return(0); +} + + +/* + * ----------------------------------------------------------------- + * Enable / Disable fused and vector array operations + * ----------------------------------------------------------------- + */ + +int N_VEnableFusedOps_Parallel(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); + + if (tf) { + /* enable all fused vector operations */ + v->ops->nvlinearcombination = N_VLinearCombination_Parallel; + v->ops->nvscaleaddmulti = N_VScaleAddMulti_Parallel; + v->ops->nvdotprodmulti = N_VDotProdMulti_Parallel; + /* enable all vector array operations */ + v->ops->nvlinearsumvectorarray = N_VLinearSumVectorArray_Parallel; + v->ops->nvscalevectorarray = N_VScaleVectorArray_Parallel; + v->ops->nvconstvectorarray = N_VConstVectorArray_Parallel; + v->ops->nvwrmsnormvectorarray = N_VWrmsNormVectorArray_Parallel; + v->ops->nvwrmsnormmaskvectorarray = N_VWrmsNormMaskVectorArray_Parallel; + v->ops->nvscaleaddmultivectorarray = N_VScaleAddMultiVectorArray_Parallel; + v->ops->nvlinearcombinationvectorarray = N_VLinearCombinationVectorArray_Parallel; + } 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 N_VEnableLinearCombination_Parallel(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 = N_VLinearCombination_Parallel; + else + v->ops->nvlinearcombination = NULL; + + /* return success */ + return(0); +} + +int N_VEnableScaleAddMulti_Parallel(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 = N_VScaleAddMulti_Parallel; + else + v->ops->nvscaleaddmulti = NULL; + + /* return success */ + return(0); +} + +int N_VEnableDotProdMulti_Parallel(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 = N_VDotProdMulti_Parallel; + else + v->ops->nvdotprodmulti = NULL; + + /* return success */ + return(0); +} + +int N_VEnableLinearSumVectorArray_Parallel(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 = N_VLinearSumVectorArray_Parallel; + else + v->ops->nvlinearsumvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableScaleVectorArray_Parallel(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 = N_VScaleVectorArray_Parallel; + else + v->ops->nvscalevectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableConstVectorArray_Parallel(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 = N_VConstVectorArray_Parallel; + else + v->ops->nvconstvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableWrmsNormVectorArray_Parallel(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 = N_VWrmsNormVectorArray_Parallel; + else + v->ops->nvwrmsnormvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableWrmsNormMaskVectorArray_Parallel(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 = N_VWrmsNormMaskVectorArray_Parallel; + else + v->ops->nvwrmsnormmaskvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableScaleAddMultiVectorArray_Parallel(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->nvscaleaddmultivectorarray = N_VScaleAddMultiVectorArray_Parallel; + else + v->ops->nvscaleaddmultivectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableLinearCombinationVectorArray_Parallel(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->nvlinearcombinationvectorarray = N_VLinearCombinationVectorArray_Parallel; + else + v->ops->nvlinearcombinationvectorarray = NULL; + + /* return success */ + return(0); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/parhyp/nvector_parhyp.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/parhyp/nvector_parhyp.c new file mode 100644 index 0000000..87b7585 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/parhyp/nvector_parhyp.c @@ -0,0 +1,1983 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Slaven Peles @ LLNL and Jean M. Sexton @ SMU + * ----------------------------------------------------------------- + * 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 + * 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 a HYPRE ParVector wrapper + * for the NVECTOR package. + * -----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include <nvector/nvector_parhyp.h> +#include <sundials/sundials_math.h> +#include <sundials/sundials_mpi.h> + +#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, + * NV_GLOBLENGTH_PH, and NV_COMM_PH + * ----------------------------------------------------------------- + * In the descriptions below, the following user declarations + * are assumed: + * + * N_Vector v; + * sunindextype v_len, s_len, i; + * + * (1) NV_CONTENT_PH + * + * This routines gives access to the contents of the HYPRE + * vector wrapper (the N_Vector). + * + * The assignment v_cont = NV_CONTENT_PH(v) sets v_cont to be + * a pointer to the N_Vector content structure. + * + * (2) NV_DATA_PH, NV_LOCLENGTH_PH, NV_GLOBLENGTH_PH, and NV_COMM_PH + * + * These routines give access to the individual parts of + * the content structure of a parhyp N_Vector. + * + * The assignment v_llen = NV_LOCLENGTH_PH(v) sets v_llen to + * be the length of the local part of the vector v. The call + * NV_LOCLENGTH_PH(v) = llen_v generally should NOT be used! It + * will change locally stored value with the HYPRE local vector + * length, but it will NOT change the length of the actual HYPRE + * local vector. + * + * The assignment v_glen = NV_GLOBLENGTH_PH(v) sets v_glen to + * be the global length of the vector v. The call + * NV_GLOBLENGTH_PH(v) = glen_v generally should NOT be used! It + * will change locally stored value with the HYPRE parallel vector + * length, but it will NOT change the length of the actual HYPRE + * parallel vector. + * + * The assignment v_comm = NV_COMM_PH(v) sets v_comm to be the + * MPI communicator of the vector v. The assignment + * NV_COMM_C(v) = comm_v sets the MPI communicator of v to be + * NV_COMM_PH(v) = comm_v generally should NOT be used! It + * will change locally stored value with the HYPRE parallel vector + * communicator, but it will NOT change the communicator of the + * actual HYPRE parallel vector. + * + * (3) NV_DATA_PH, NV_HYPRE_PARVEC_PH + * + * The assignment v_data = NV_DATA_PH(v) sets v_data to be + * a pointer to the first component of the data inside the + * local vector of the HYPRE_parhyp vector for the vector v. + * The assignment NV_DATA_PH(v) = data_v should NOT be used. + * Instead, use NV_HYPRE_PARVEC_PH to obtain pointer to HYPRE + * vector and then use HYPRE functions to manipulate vector data. + * + * The assignment v_parhyp = NV_HYPRE_PARVEC_PH(v) sets v_parhyp + * to be a pointer to HYPRE_ParVector of vector v. The assignment + * NV_HYPRE_PARVEC_PH(v) = parhyp_v sets pointer to + * HYPRE_ParVector of vector v to be parhyp_v. + * + * ----------------------------------------------------------------- + */ + +#define NV_CONTENT_PH(v) ( (N_VectorContent_ParHyp)(v->content) ) + +#define NV_LOCLENGTH_PH(v) ( NV_CONTENT_PH(v)->local_length ) + +#define NV_GLOBLENGTH_PH(v) ( NV_CONTENT_PH(v)->global_length ) + +#define NV_OWN_PARVEC_PH(v) ( NV_CONTENT_PH(v)->own_parvector ) + +#define NV_HYPRE_PARVEC_PH(v) ( NV_CONTENT_PH(v)->x ) + +#define NV_DATA_PH(v) ( NV_HYPRE_PARVEC_PH(v) == NULL ? NULL : hypre_VectorData(hypre_ParVectorLocalVector(NV_HYPRE_PARVEC_PH(v))) ) + +#define NV_COMM_PH(v) ( NV_CONTENT_PH(v)->comm ) + + +/* Private function prototypes */ + +/* z=x+y */ +static void VSum_ParHyp(N_Vector x, N_Vector y, N_Vector z); +/* z=x-y */ +static void VDiff_ParHyp(N_Vector x, N_Vector y, N_Vector z); +/* z=c(x+y) */ +static void VScaleSum_ParHyp(realtype c, N_Vector x, N_Vector y, N_Vector z); +/* z=c(x-y) */ +static void VScaleDiff_ParHyp(realtype c, N_Vector x, N_Vector y, N_Vector z); +/* z=ax+y */ +static void VLin1_ParHyp(realtype a, N_Vector x, N_Vector y, N_Vector z); +/* z=ax-y */ +static void VLin2_ParHyp(realtype a, N_Vector x, N_Vector y, N_Vector z); + +/* + * ----------------------------------------------------------------- + * exported functions + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------- + * Returns vector type ID. Used to identify vector implementation + * from abstract N_Vector interface. + */ +N_Vector_ID N_VGetVectorID_ParHyp(N_Vector v) +{ + return SUNDIALS_NVEC_PARHYP; +} + + +/* ---------------------------------------------------------------- + * Function to create a new parhyp vector without underlying + * HYPRE vector. + */ +N_Vector N_VNewEmpty_ParHyp(MPI_Comm comm, + sunindextype local_length, + sunindextype global_length) +{ + N_Vector v; + N_Vector_Ops ops; + N_VectorContent_ParHyp content; + + /* Create vector */ + v = NULL; + v = (N_Vector) malloc(sizeof *v); + 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 = 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; + + /* 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; + + /* Create content */ + content = NULL; + content = (N_VectorContent_ParHyp) malloc(sizeof(struct _N_VectorContent_ParHyp)); + if (content == NULL) { free(ops); free(v); return(NULL); } + + /* Attach lengths and communicator */ + content->local_length = local_length; + content->global_length = global_length; + content->comm = comm; + content->own_parvector = SUNFALSE; + content->x = NULL; + + /* Attach content and ops */ + v->content = content; + v->ops = ops; + + return(v); +} + + +/* ---------------------------------------------------------------- + * Function to create a parhyp N_Vector wrapper around user + * supplie HYPRE vector. + */ + +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; + + v = NULL; + v = N_VNewEmpty_ParHyp(comm, local_length, global_length); + if (v == NULL) + return(NULL); + + NV_OWN_PARVEC_PH(v) = SUNFALSE; + NV_HYPRE_PARVEC_PH(v) = x; + + return(v); +} + + +/* ---------------------------------------------------------------- + * Function to create an array of new parhyp vectors. + */ + +N_Vector *N_VCloneVectorArray_ParHyp(int count, N_Vector w) +{ + N_Vector *vs; + int j; + + if (count <= 0) return(NULL); + + vs = NULL; + vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + if(vs == NULL) return(NULL); + + for (j = 0; j < count; j++) { + vs[j] = NULL; + vs[j] = N_VClone_ParHyp(w); + if (vs[j] == NULL) { + N_VDestroyVectorArray_ParHyp(vs, j-1); + return(NULL); + } + } + + return(vs); +} + +/* ---------------------------------------------------------------- + * Function to create an array of new parhyp vector wrappers + * without uderlying HYPRE vectors. + */ + +N_Vector *N_VCloneVectorArrayEmpty_ParHyp(int count, N_Vector w) +{ + N_Vector *vs; + int j; + + if (count <= 0) return(NULL); + + vs = NULL; + vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + if(vs == NULL) return(NULL); + + for (j = 0; j < count; j++) { + vs[j] = NULL; + vs[j] = N_VCloneEmpty_ParHyp(w); + if (vs[j] == NULL) { + N_VDestroyVectorArray_ParHyp(vs, j-1); + return(NULL); + } + } + + return(vs); +} + +/* ---------------------------------------------------------------- + * Function to free an array created with N_VCloneVectorArray_ParHyp + */ + +void N_VDestroyVectorArray_ParHyp(N_Vector *vs, int count) +{ + int j; + + for (j = 0; j < count; j++) + N_VDestroy_ParHyp(vs[j]); + + free(vs); + vs = NULL; + + return; +} + + +/* ---------------------------------------------------------------- + * Extract HYPRE vector + */ + +HYPRE_ParVector N_VGetVector_ParHyp(N_Vector v) +{ + return NV_HYPRE_PARVEC_PH(v); +} + +/* ---------------------------------------------------------------- + * Function to print a parhyp vector. + * TODO: Consider using a HYPRE function for this. + */ + +void N_VPrint_ParHyp(N_Vector x) +{ + N_VPrintFile_ParHyp(x, stdout); +} + +/* ---------------------------------------------------------------- + * Function to print a parhyp vector. + * TODO: Consider using a HYPRE function for this. + */ + +void N_VPrintFile_ParHyp(N_Vector x, FILE *outfile) +{ + sunindextype i, N; + realtype *xd; + + xd = NULL; + + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + + for (i = 0; i < N; i++) { +#if defined(SUNDIALS_EXTENDED_PRECISION) + fprintf(outfile, "%Lg\n", xd[i]); +#elif defined(SUNDIALS_DOUBLE_PRECISION) + fprintf(outfile, "%g\n", xd[i]); +#else + fprintf(outfile, "%g\n", xd[i]); +#endif + } + fprintf(outfile, "\n"); + + return; +} + +/* + * ----------------------------------------------------------------- + * implementation of vector operations + * ----------------------------------------------------------------- + */ + +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); + 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; + + /* Create content */ + content = NULL; + content = (N_VectorContent_ParHyp) malloc(sizeof(struct _N_VectorContent_ParHyp)); + if (content == NULL) { free(ops); free(v); return(NULL); } + + /* Attach lengths and communicator */ + 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); +} + +/* + * Clone HYPRE vector wrapper. + * + */ +N_Vector N_VClone_ParHyp(N_Vector w) +{ + N_Vector v; + HYPRE_ParVector vx; + const HYPRE_ParVector wx = NV_HYPRE_PARVEC_PH(w); + + v = NULL; + v = N_VCloneEmpty_ParHyp(w); + if (v==NULL) + return(NULL); + + vx = hypre_ParVectorCreate(wx->comm, wx->global_size, wx->partitioning); + hypre_ParVectorInitialize(vx); + + hypre_ParVectorSetPartitioningOwner(vx, 0); + hypre_ParVectorSetDataOwner(vx, 1); + hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(vx), 1); + + NV_HYPRE_PARVEC_PH(v) = vx; + 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)); + } + + free(v->content); v->content = NULL; + free(v->ops); v->ops = NULL; + free(v); v = NULL; + + return; +} + + +void N_VSpace_ParHyp(N_Vector v, sunindextype *lrw, sunindextype *liw) +{ + MPI_Comm comm; + int npes; + + comm = NV_COMM_PH(v); + MPI_Comm_size(comm, &npes); + + *lrw = NV_GLOBLENGTH_PH(v); + *liw = 2*npes; + + return; +} + + +/* + * This function is disabled in ParHyp implementation and returns NULL. + * The user should extract HYPRE vector using N_VGetVector_ParHyp and + * then use HYPRE functions to get pointer to raw data of the local HYPRE + * vector. + */ +realtype *N_VGetArrayPointer_ParHyp(N_Vector v) +{ + return NULL; /* ((realtype *) NV_DATA_PH(v)); */ +} + + +/* + * This method is not implemented for HYPRE vector wrapper. + * TODO: Put error handler in the function body. + */ +void N_VSetArrayPointer_ParHyp(realtype *v_data, N_Vector v) +{ + /* Not implemented for Hypre vector */ +} + +/* + * Computes z[i] = a*x[i] + b*y[i] + * + */ +void N_VLinearSum_ParHyp(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype c, *xd, *yd, *zd; + N_Vector v1, v2; + booleantype test; + + xd = yd = zd = NULL; + + if ((b == ONE) && (z == y)) { /* BLAS usage: axpy y <- ax+y */ + HYPRE_Complex alpha=a; + HYPRE_ParVectorAxpy( alpha, (HYPRE_ParVector) NV_HYPRE_PARVEC_PH(x), + (HYPRE_ParVector) NV_HYPRE_PARVEC_PH(y)); + return; + } + + if ((a == ONE) && (z == x)) { /* BLAS usage: axpy x <- by+x */ + HYPRE_Complex beta=b; + HYPRE_ParVectorAxpy( beta, (HYPRE_ParVector) NV_HYPRE_PARVEC_PH(y), + (HYPRE_ParVector) NV_HYPRE_PARVEC_PH(x)); + return; + } + + /* Case: a == b == 1.0 */ + + if ((a == ONE) && (b == ONE)) { + VSum_ParHyp(x, y, z); + return; + } + + /* Cases: (1) a == 1.0, b = -1.0, (2) a == -1.0, b == 1.0 */ + + if ((test = ((a == ONE) && (b == -ONE))) || ((a == -ONE) && (b == ONE))) { + v1 = test ? y : x; + v2 = test ? x : y; + VDiff_ParHyp(v2, v1, z); + return; + } + + /* Cases: (1) a == 1.0, b == other or 0.0, (2) a == other or 0.0, b == 1.0 */ + /* if a or b is 0.0, then user should have called N_VScale */ + + if ((test = (a == ONE)) || (b == ONE)) { + c = test ? b : a; + v1 = test ? y : x; + v2 = test ? x : y; + VLin1_ParHyp(c, v1, v2, z); + return; + } + + /* Cases: (1) a == -1.0, b != 1.0, (2) a != 1.0, b == -1.0 */ + + if ((test = (a == -ONE)) || (b == -ONE)) { + c = test ? b : a; + v1 = test ? y : x; + v2 = test ? x : y; + VLin2_ParHyp(c, v1, v2, z); + return; + } + + /* Case: a == b */ + /* catches case both a and b are 0.0 - user should have called N_VConst */ + + if (a == b) { + VScaleSum_ParHyp(a, x, y, z); + return; + } + + /* Case: a == -b */ + + if (a == -b) { + VScaleDiff_ParHyp(a, x, y, z); + return; + } + + /* Do all cases not handled above: + (1) a == other, b == 0.0 - user should have called N_VScale + (2) a == 0.0, b == other - user should have called N_VScale + (3) a,b == other, a !=b, a != -b */ + + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + yd = NV_DATA_PH(y); + zd = NV_DATA_PH(z); + + for (i = 0; i < N; i++) + zd[i] = (a*xd[i])+(b*yd[i]); + + return; +} + +void N_VConst_ParHyp(realtype c, N_Vector z) +{ + HYPRE_Complex value = c; + HYPRE_ParVectorSetConstantValues( (HYPRE_ParVector) NV_HYPRE_PARVEC_PH(z), value); + return; +} + +/* ---------------------------------------------------------------------------- + * Compute componentwise product z[i] = x[i]*y[i] + */ + +void N_VProd_ParHyp(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + yd = NV_DATA_PH(y); + zd = NV_DATA_PH(z); + + for (i = 0; i < N; i++) + zd[i] = xd[i]*yd[i]; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute componentwise division z[i] = x[i]/y[i] + */ + +void N_VDiv_ParHyp(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + yd = NV_DATA_PH(y); + zd = NV_DATA_PH(z); + + for (i = 0; i < N; i++) + zd[i] = xd[i]/yd[i]; + + return; +} + + +void N_VScale_ParHyp(realtype c, N_Vector x, N_Vector z) +{ + HYPRE_Complex value = c; + + if (x != z) { + HYPRE_ParVectorCopy((HYPRE_ParVector) NV_HYPRE_PARVEC_PH(x), (HYPRE_ParVector) NV_HYPRE_PARVEC_PH(z)); + } + HYPRE_ParVectorScale(value, (HYPRE_ParVector) NV_HYPRE_PARVEC_PH(z)); + + return; +} + + +void N_VAbs_ParHyp(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + zd = NV_DATA_PH(z); + + for (i = 0; i < N; i++) + zd[i] = SUNRabs(xd[i]); + + return; +} + +void N_VInv_ParHyp(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + zd = NV_DATA_PH(z); + + for (i = 0; i < N; i++) + zd[i] = ONE/xd[i]; + + return; +} + +void N_VAddConst_ParHyp(N_Vector x, realtype b, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + zd = NV_DATA_PH(z); + + for (i = 0; i < N; i++) + zd[i] = xd[i] + b; + + return; +} + +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); + + return(gsum); +} + +realtype N_VMaxNorm_ParHyp(N_Vector x) +{ + sunindextype i, N; + realtype max, *xd, gmax; + MPI_Comm comm; + + xd = NULL; + + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + comm = NV_COMM_PH(x); + + max = ZERO; + + for (i = 0; i < N; i++) { + if (SUNRabs(xd[i]) > max) max = SUNRabs(xd[i]); + } + + gmax = SUNMPI_Allreduce_scalar(max, 2, comm); + + return(gmax); +} + +realtype N_VWrmsNorm_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; + + 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); + + 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)); +} + +realtype N_VWrmsNormMask_ParHyp(N_Vector x, N_Vector w, N_Vector id) +{ + sunindextype i, N, N_global; + realtype sum, prodi, *xd, *wd, *idd, gsum; + MPI_Comm comm; + + sum = ZERO; + xd = wd = idd = NULL; + + 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); + + for (i = 0; i < N; i++) { + if (idd[i] > ZERO) { + prodi = xd[i]*wd[i]; + sum += SUNSQR(prodi); + } + } + + gsum = SUNMPI_Allreduce_scalar(sum, 1, comm); + + return(SUNRsqrt(gsum/N_global)); +} + +realtype N_VMin_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); + + 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]; + } + + } + + gmin = SUNMPI_Allreduce_scalar(min, 3, comm); + + 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); + + return(SUNRsqrt(gsum)); +} + +realtype N_VL1Norm_ParHyp(N_Vector x) +{ + sunindextype i, N; + realtype sum, gsum, *xd; + MPI_Comm comm; + + sum = ZERO; + xd = NULL; + + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + comm = NV_COMM_PH(x); + + for (i = 0; i<N; i++) + sum += SUNRabs(xd[i]); + + gsum = SUNMPI_Allreduce_scalar(sum, 1, comm); + + return(gsum); +} + +void N_VCompare_ParHyp(realtype c, N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + zd = NV_DATA_PH(z); + + for (i = 0; i < N; i++) { + zd[i] = (SUNRabs(xd[i]) >= c) ? ONE : ZERO; + } + + return; +} + +booleantype N_VInvTest_ParHyp(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd, val, gval; + MPI_Comm comm; + + xd = zd = NULL; + + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + zd = NV_DATA_PH(z); + comm = NV_COMM_PH(x); + + val = ONE; + for (i = 0; i < N; i++) { + if (xd[i] == ZERO) + val = ZERO; + else + zd[i] = ONE/xd[i]; + } + + gval = SUNMPI_Allreduce_scalar(val, 3, comm); + + if (gval == ZERO) + return(SUNFALSE); + else + return(SUNTRUE); +} + +booleantype N_VConstrMask_ParHyp(N_Vector c, N_Vector x, N_Vector m) +{ + sunindextype i, N; + realtype temp; + realtype *cd, *xd, *md; + booleantype test; + MPI_Comm comm; + + cd = xd = md = NULL; + + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + cd = NV_DATA_PH(c); + md = NV_DATA_PH(m); + comm = NV_COMM_PH(x); + + temp = ZERO; + + for (i = 0; i < N; i++) { + md[i] = ZERO; + + /* Continue if no constraints were set for the variable */ + if (cd[i] == ZERO) + continue; + + /* Check if a set constraint has been violated */ + test = (SUNRabs(cd[i]) > ONEPT5 && xd[i]*cd[i] <= ZERO) || + (SUNRabs(cd[i]) > HALF && xd[i]*cd[i] < ZERO); + if (test) { + temp = md[i] = ONE; + } + } + + /* 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_ParHyp(N_Vector num, N_Vector denom) +{ + booleantype notEvenOnce; + sunindextype i, N; + realtype *nd, *dd, min; + MPI_Comm comm; + + nd = dd = NULL; + + N = NV_LOCLENGTH_PH(num); + nd = NV_DATA_PH(num); + dd = NV_DATA_PH(denom); + comm = NV_COMM_PH(num); + + notEvenOnce = SUNTRUE; + min = BIG_REAL; + + for (i = 0; i < N; i++) { + if (dd[i] == ZERO) continue; + else { + if (!notEvenOnce) min = SUNMIN(min, nd[i]/dd[i]); + else { + min = nd[i]/dd[i]; + notEvenOnce = SUNFALSE; + } + } + } + + return(SUNMPI_Allreduce_scalar(min, 3, comm)); +} + + +/* + * ----------------------------------------------------------------- + * fused vector operations + * ----------------------------------------------------------------- + */ + + +int N_VLinearCombination_ParHyp(int nvec, realtype* c, N_Vector* X, N_Vector z) +{ + int i; + sunindextype j, N; + realtype* zd=NULL; + realtype* xd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VScale */ + if (nvec == 1) { + N_VScale_ParHyp(c[0], X[0], z); + return(0); + } + + /* should have called N_VLinearSum */ + if (nvec == 2) { + N_VLinearSum_ParHyp(c[0], X[0], c[1], X[1], z); + return(0); + } + + /* get vector length and data array */ + N = NV_LOCLENGTH_PH(z); + zd = NV_DATA_PH(z); + + /* + * X[0] += c[i]*X[i], i = 1,...,nvec-1 + */ + if ((X[0] == z) && (c[0] == ONE)) { + for (i=1; i<nvec; i++) { + xd = NV_DATA_PH(X[i]); + for (j=0; j<N; j++) { + zd[j] += c[i] * xd[j]; + } + } + return(0); + } + + /* + * X[0] = c[0] * X[0] + sum{ c[i] * X[i] }, i = 1,...,nvec-1 + */ + if (X[0] == z) { + for (j=0; j<N; j++) { + zd[j] *= c[0]; + } + for (i=1; i<nvec; i++) { + xd = NV_DATA_PH(X[i]); + for (j=0; j<N; j++) { + zd[j] += c[i] * xd[j]; + } + } + return(0); + } + + /* + * z = sum{ c[i] * X[i] }, i = 0,...,nvec-1 + */ + xd = NV_DATA_PH(X[0]); + for (j=0; j<N; j++) { + zd[j] = c[0] * xd[j]; + } + for (i=1; i<nvec; i++) { + xd = NV_DATA_PH(X[i]); + for (j=0; j<N; j++) { + zd[j] += c[i] * xd[j]; + } + } + return(0); +} + + +int N_VScaleAddMulti_ParHyp(int nvec, realtype* a, N_Vector x, N_Vector* Y, + N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VLinearSum */ + if (nvec == 1) { + N_VLinearSum_ParHyp(a[0], x, ONE, Y[0], Z[0]); + return(0); + } + + /* get vector length and data array */ + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + + /* + * Y[i][j] += a[i] * x[j] + */ + if (Y == Z) { + for (i=0; i<nvec; i++) { + yd = NV_DATA_PH(Y[i]); + for (j=0; j<N; j++) { + yd[j] += a[i] * xd[j]; + } + } + return(0); + } + + /* + * Z[i][j] = Y[i][j] + a[i] * x[j] + */ + for (i=0; i<nvec; i++) { + yd = NV_DATA_PH(Y[i]); + zd = NV_DATA_PH(Z[i]); + for (j=0; j<N; j++) { + zd[j] = a[i] * xd[j] + yd[j]; + } + } + return(0); +} + + +int N_VDotProdMulti_ParHyp(int nvec, N_Vector x, N_Vector* Y, realtype* dotprods) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + MPI_Comm comm; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VDotProd */ + if (nvec == 1) { + dotprods[0] = N_VDotProd_ParHyp(x, Y[0]); + return(0); + } + + /* get vector length, data array, and communicator */ + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + comm = NV_COMM_PH(x); + + /* compute multiple dot products */ + for (i=0; i<nvec; i++) { + yd = NV_DATA_PH(Y[i]); + dotprods[i] = ZERO; + for (j=0; j<N; j++) { + dotprods[i] += xd[j] * yd[j]; + } + } + SUNMPI_Allreduce(dotprods, nvec, 1, comm); + + return(0); +} + + +/* + * ----------------------------------------------------------------- + * vector array operations + * ----------------------------------------------------------------- + */ + + +int N_VLinearSumVectorArray_ParHyp(int nvec, + realtype a, N_Vector* X, + realtype b, N_Vector* Y, + N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VLinearSum */ + if (nvec == 1) { + N_VLinearSum_ParHyp(a, X[0], b, Y[0], Z[0]); + return(0); + } + + /* get vector length */ + N = NV_LOCLENGTH_PH(Z[0]); + + /* compute linear sum for each vector pair in vector arrays */ + for (i=0; i<nvec; i++) { + xd = NV_DATA_PH(X[i]); + yd = NV_DATA_PH(Y[i]); + zd = NV_DATA_PH(Z[i]); + for (j=0; j<N; j++) { + zd[j] = a * xd[j] + b * yd[j]; + } + } + + return(0); +} + + +int N_VScaleVectorArray_ParHyp(int nvec, realtype* c, N_Vector* X, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* zd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VScale */ + if (nvec == 1) { + N_VScale_ParHyp(c[0], X[0], Z[0]); + return(0); + } + + /* get vector length */ + N = NV_LOCLENGTH_PH(Z[0]); + + /* + * X[i] *= c[i] + */ + if (X == Z) { + for (i=0; i<nvec; i++) { + xd = NV_DATA_PH(X[i]); + for (j=0; j<N; j++) { + xd[j] *= c[i]; + } + } + return(0); + } + + /* + * Z[i] = c[i] * X[i] + */ + for (i=0; i<nvec; i++) { + xd = NV_DATA_PH(X[i]); + zd = NV_DATA_PH(Z[i]); + for (j=0; j<N; j++) { + zd[j] = c[i] * xd[j]; + } + } + + return(0); +} + + +int N_VConstVectorArray_ParHyp(int nvec, realtype c, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* zd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VConst */ + if (nvec == 1) { + N_VConst_ParHyp(c, Z[0]); + return(0); + } + + /* get vector length */ + N = NV_LOCLENGTH_PH(Z[0]); + + /* set each vector in the vector array to a constant */ + for (i=0; i<nvec; i++) { + zd = NV_DATA_PH(Z[i]); + for (j=0; j<N; j++) { + zd[j] = c; + } + } + + return(0); +} + + +int N_VWrmsNormVectorArray_ParHyp(int nvec, N_Vector* X, N_Vector* W, realtype* nrm) +{ + int i; + sunindextype j, Nl, Ng; + realtype* wd=NULL; + realtype* xd=NULL; + MPI_Comm comm; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VWrmsNorm */ + if (nvec == 1) { + nrm[0] = N_VWrmsNorm_ParHyp(X[0], W[0]); + return(0); + } + + /* get vector lengths and communicator */ + Nl = NV_LOCLENGTH_PH(X[0]); + Ng = NV_GLOBLENGTH_PH(X[0]); + comm = NV_COMM_PH(X[0]); + + /* compute the WRMS norm for each vector in the vector array */ + for (i=0; i<nvec; i++) { + xd = NV_DATA_PH(X[i]); + wd = NV_DATA_PH(W[i]); + nrm[i] = ZERO; + for (j=0; j<Nl; j++) { + nrm[i] += SUNSQR(xd[j] * wd[j]); + } + } + SUNMPI_Allreduce(nrm, nvec, 1, comm); + + for (i=0; i<nvec; i++) + nrm[i] = SUNRsqrt(nrm[i]/Ng); + + return(0); +} + + +int N_VWrmsNormMaskVectorArray_ParHyp(int nvec, N_Vector* X, N_Vector* W, + N_Vector id, realtype* nrm) +{ + int i; + sunindextype j, Nl, Ng; + realtype* wd=NULL; + realtype* xd=NULL; + realtype* idd=NULL; + MPI_Comm comm; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VWrmsNorm */ + if (nvec == 1) { + nrm[0] = N_VWrmsNormMask_ParHyp(X[0], W[0], id); + return(0); + } + + /* get vector lengths, communicator, and mask data */ + Nl = NV_LOCLENGTH_PH(X[0]); + Ng = NV_GLOBLENGTH_PH(X[0]); + comm = NV_COMM_PH(X[0]); + idd = NV_DATA_PH(id); + + /* compute the WRMS norm for each vector in the vector array */ + for (i=0; i<nvec; i++) { + xd = NV_DATA_PH(X[i]); + wd = NV_DATA_PH(W[i]); + nrm[i] = ZERO; + for (j=0; j<Nl; j++) { + if (idd[j] > ZERO) + nrm[i] += SUNSQR(xd[j] * wd[j]); + } + } + SUNMPI_Allreduce(nrm, nvec, 1, comm); + + for (i=0; i<nvec; i++) + nrm[i] = SUNRsqrt(nrm[i]/Ng); + + return(0); +} + + +int N_VScaleAddMultiVectorArray_ParHyp(int nvec, int nsum, realtype* a, + N_Vector* X, N_Vector** Y, N_Vector** Z) +{ + int i, j; + sunindextype k, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + int retval; + N_Vector* YY; + N_Vector* ZZ; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + if (nsum < 1) return(-1); + + /* --------------------------- + * Special cases for nvec == 1 + * --------------------------- */ + + if (nvec == 1) { + + /* should have called N_VLinearSum */ + if (nsum == 1) { + N_VLinearSum_ParHyp(a[0], X[0], ONE, Y[0][0], Z[0][0]); + return(0); + } + + /* should have called N_VScaleAddMulti */ + YY = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + ZZ = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + + for (j=0; j<nsum; j++) { + YY[j] = Y[j][0]; + ZZ[j] = Z[j][0]; + } + + retval = N_VScaleAddMulti_ParHyp(nsum, a, X[0], YY, ZZ); + + free(YY); + free(ZZ); + return(retval); + } + + /* -------------------------- + * Special cases for nvec > 1 + * -------------------------- */ + + /* should have called N_VLinearSumVectorArray */ + if (nsum == 1) { + retval = N_VLinearSumVectorArray_ParHyp(nvec, a[0], X, ONE, Y[0], Z[0]); + return(retval); + } + + /* ---------------------------- + * Compute multiple linear sums + * ---------------------------- */ + + /* get vector length */ + N = NV_LOCLENGTH_PH(X[0]); + + /* + * Y[i][j] += a[i] * x[j] + */ + if (Y == Z) { + for (i=0; i<nvec; i++) { + xd = NV_DATA_PH(X[i]); + for (j=0; j<nsum; j++){ + yd = NV_DATA_PH(Y[j][i]); + for (k=0; k<N; k++) { + yd[k] += a[j] * xd[k]; + } + } + } + return(0); + } + + /* + * Z[i][j] = Y[i][j] + a[i] * x[j] + */ + for (i=0; i<nvec; i++) { + xd = NV_DATA_PH(X[i]); + for (j=0; j<nsum; j++) { + yd = NV_DATA_PH(Y[j][i]); + zd = NV_DATA_PH(Z[j][i]); + for (k=0; k<N; k++) { + zd[k] = a[j] * xd[k] + yd[k]; + } + } + } + return(0); +} + + +int N_VLinearCombinationVectorArray_ParHyp(int nvec, int nsum, + realtype* c, + N_Vector** X, + N_Vector* Z) +{ + int i; /* vector arrays index in summation [0,nsum) */ + int j; /* vector index in vector array [0,nvec) */ + sunindextype k; /* element index in vector [0,N) */ + sunindextype N; + realtype* zd=NULL; + realtype* xd=NULL; + + realtype* ctmp; + N_Vector* Y; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + if (nsum < 1) return(-1); + + /* --------------------------- + * Special cases for nvec == 1 + * --------------------------- */ + + if (nvec == 1) { + + /* should have called N_VScale */ + if (nsum == 1) { + N_VScale_ParHyp(c[0], X[0][0], Z[0]); + return(0); + } + + /* should have called N_VLinearSum */ + if (nsum == 2) { + N_VLinearSum_ParHyp(c[0], X[0][0], c[1], X[1][0], Z[0]); + return(0); + } + + /* should have called N_VLinearCombination */ + Y = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + + for (i=0; i<nsum; i++) { + Y[i] = X[i][0]; + } + + N_VLinearCombination_ParHyp(nsum, c, Y, Z[0]); + + free(Y); + return(0); + } + + /* -------------------------- + * Special cases for nvec > 1 + * -------------------------- */ + + /* should have called N_VScaleVectorArray */ + if (nsum == 1) { + + ctmp = (realtype*) malloc(nvec * sizeof(realtype)); + + for (j=0; j<nvec; j++) { + ctmp[j] = c[0]; + } + + N_VScaleVectorArray_ParHyp(nvec, ctmp, X[0], Z); + + free(ctmp); + return(0); + } + + /* should have called N_VLinearSumVectorArray */ + if (nsum == 2) { + N_VLinearSumVectorArray_ParHyp(nvec, c[0], X[0], c[1], X[1], Z); + return(0); + } + + /* -------------------------- + * Compute linear combination + * -------------------------- */ + + /* get vector length */ + N = NV_LOCLENGTH_PH(Z[0]); + + /* + * X[0][j] += c[i]*X[i][j], i = 1,...,nvec-1 + */ + if ((X[0] == Z) && (c[0] == ONE)) { + for (j=0; j<nvec; j++) { + zd = NV_DATA_PH(Z[j]); + for (i=1; i<nsum; i++) { + xd = NV_DATA_PH(X[i][j]); + for (k=0; k<N; k++) { + zd[k] += c[i] * xd[k]; + } + } + } + return(0); + } + + /* + * X[0][j] = c[0] * X[0][j] + sum{ c[i] * X[i][j] }, i = 1,...,nvec-1 + */ + if (X[0] == Z) { + for (j=0; j<nvec; j++) { + zd = NV_DATA_PH(Z[j]); + for (k=0; k<N; k++) { + zd[k] *= c[0]; + } + for (i=1; i<nsum; i++) { + xd = NV_DATA_PH(X[i][j]); + for (k=0; k<N; k++) { + zd[k] += c[i] * xd[k]; + } + } + } + return(0); + } + + /* + * Z[j] = sum{ c[i] * X[i][j] }, i = 0,...,nvec-1 + */ + for (j=0; j<nvec; j++) { + xd = NV_DATA_PH(X[0][j]); + zd = NV_DATA_PH(Z[j]); + for (k=0; k<N; k++) { + zd[k] = c[0] * xd[k]; + } + for (i=1; i<nsum; i++) { + xd = NV_DATA_PH(X[i][j]); + for (k=0; k<N; k++) { + zd[k] += c[i] * xd[k]; + } + } + } + return(0); +} + + +/* + * ----------------------------------------------------------------- + * private functions + * ----------------------------------------------------------------- + */ + +static void VSum_ParHyp(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + yd = NV_DATA_PH(y); + zd = NV_DATA_PH(z); + + for (i = 0; i < N; i++) + zd[i] = xd[i]+yd[i]; + + return; +} + +static void VDiff_ParHyp(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + yd = NV_DATA_PH(y); + zd = NV_DATA_PH(z); + + for (i = 0; i < N; i++) + zd[i] = xd[i]-yd[i]; + + return; +} + + +static void VScaleSum_ParHyp(realtype c, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + yd = NV_DATA_PH(y); + zd = NV_DATA_PH(z); + + for (i = 0; i < N; i++) + zd[i] = c*(xd[i]+yd[i]); + + return; +} + +static void VScaleDiff_ParHyp(realtype c, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + yd = NV_DATA_PH(y); + zd = NV_DATA_PH(z); + + for (i = 0; i < N; i++) + zd[i] = c*(xd[i]-yd[i]); + + return; +} + +static void VLin1_ParHyp(realtype a, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + yd = NV_DATA_PH(y); + zd = NV_DATA_PH(z); + + for (i = 0; i < N; i++) + zd[i] = (a*xd[i])+yd[i]; + + return; +} + +static void VLin2_ParHyp(realtype a, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LOCLENGTH_PH(x); + xd = NV_DATA_PH(x); + yd = NV_DATA_PH(y); + zd = NV_DATA_PH(z); + + for (i = 0; i < N; i++) + zd[i] = (a*xd[i])-yd[i]; + + return; +} + + +/* + * ----------------------------------------------------------------- + * Enable / Disable fused and vector array operations + * ----------------------------------------------------------------- + */ + +int N_VEnableFusedOps_ParHyp(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); + + if (tf) { + /* enable all fused vector operations */ + v->ops->nvlinearcombination = N_VLinearCombination_ParHyp; + v->ops->nvscaleaddmulti = N_VScaleAddMulti_ParHyp; + v->ops->nvdotprodmulti = N_VDotProdMulti_ParHyp; + /* enable all vector array operations */ + v->ops->nvlinearsumvectorarray = N_VLinearSumVectorArray_ParHyp; + v->ops->nvscalevectorarray = N_VScaleVectorArray_ParHyp; + v->ops->nvconstvectorarray = N_VConstVectorArray_ParHyp; + v->ops->nvwrmsnormvectorarray = N_VWrmsNormVectorArray_ParHyp; + v->ops->nvwrmsnormmaskvectorarray = N_VWrmsNormMaskVectorArray_ParHyp; + v->ops->nvscaleaddmultivectorarray = N_VScaleAddMultiVectorArray_ParHyp; + v->ops->nvlinearcombinationvectorarray = N_VLinearCombinationVectorArray_ParHyp; + } 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 N_VEnableLinearCombination_ParHyp(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 = N_VLinearCombination_ParHyp; + else + v->ops->nvlinearcombination = NULL; + + /* return success */ + return(0); +} + +int N_VEnableScaleAddMulti_ParHyp(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 = N_VScaleAddMulti_ParHyp; + else + v->ops->nvscaleaddmulti = NULL; + + /* return success */ + return(0); +} + +int N_VEnableDotProdMulti_ParHyp(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 = N_VDotProdMulti_ParHyp; + else + v->ops->nvdotprodmulti = NULL; + + /* return success */ + return(0); +} + +int N_VEnableLinearSumVectorArray_ParHyp(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 = N_VLinearSumVectorArray_ParHyp; + else + v->ops->nvlinearsumvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableScaleVectorArray_ParHyp(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 = N_VScaleVectorArray_ParHyp; + else + v->ops->nvscalevectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableConstVectorArray_ParHyp(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 = N_VConstVectorArray_ParHyp; + else + v->ops->nvconstvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableWrmsNormVectorArray_ParHyp(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 = N_VWrmsNormVectorArray_ParHyp; + else + v->ops->nvwrmsnormvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableWrmsNormMaskVectorArray_ParHyp(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 = N_VWrmsNormMaskVectorArray_ParHyp; + else + v->ops->nvwrmsnormmaskvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableScaleAddMultiVectorArray_ParHyp(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->nvscaleaddmultivectorarray = N_VScaleAddMultiVectorArray_ParHyp; + else + v->ops->nvscaleaddmultivectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableLinearCombinationVectorArray_ParHyp(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->nvlinearcombinationvectorarray = N_VLinearCombinationVectorArray_ParHyp; + else + v->ops->nvlinearcombinationvectorarray = NULL; + + /* return success */ + return(0); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/petsc/nvector_petsc.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/petsc/nvector_petsc.c new file mode 100644 index 0000000..9a2112b --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/petsc/nvector_petsc.c @@ -0,0 +1,1722 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Slaven Peles @ LLNL + * ----------------------------------------------------------------- + * Based on N_Vector_Parallel by Scott D. Cohen, Alan C. Hindmarsh, + * Radu Serban, 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 implementation file for a PETSc implementation + * of the NVECTOR package. + * -----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include <nvector/nvector_petsc.h> +#include <sundials/sundials_math.h> +#include <sundials/sundials_mpi.h> + +#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_VNewEmpty_Petsc -- 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_PTC, NV_OWN_DATA_PTC, + * NV_LOCLENGTH_PTC, NV_GLOBLENGTH_PTC, + * NV_COMM_PTC + * ----------------------------------------------------------------- + * In the descriptions below, the following user declarations + * are assumed: + * + * N_Vector v; + * sunindextype v_len, s_len, i; + * + * (1) NV_CONTENT_PTC + * + * This routines gives access to the contents of the PETSc + * vector wrapper N_Vector. + * + * The assignment v_cont = NV_CONTENT_PTC(v) sets v_cont to be + * a pointer to the N_Vector (PETSc wrapper) content structure. + * + * (2) NV_PVEC_PTC, NV_OWN_DATA_PTC, NV_LOCLENGTH_PTC, NV_GLOBLENGTH_PTC, + * and NV_COMM_PTC + * + * These routines give access to the individual parts of + * the content structure of a PETSc N_Vector wrapper. + * + * NV_PVEC_PTC(v) returns the PETSc vector (Vec) object. + * + * The assignment v_llen = NV_LOCLENGTH_PTC(v) sets v_llen to + * be the length of the local part of the vector v. The call + * NV_LOCLENGTH_PTC(v) = llen_v should NOT be used! It will + * change the value stored in the N_Vector content structure, + * but it will NOT change the length of the actual PETSc vector. + * + * The assignment v_glen = NV_GLOBLENGTH_PTC(v) sets v_glen to + * be the global length of the vector v. The call + * NV_GLOBLENGTH_PTC(v) = glen_v should NOT be used! It will + * change the value stored in the N_Vector content structure, + * but it will NOT change the length of the actual PETSc vector. + * + * The assignment v_comm = NV_COMM_PTC(v) sets v_comm to be the + * MPI communicator of the vector v. The assignment + * NV_COMM_PTC(v) = comm_v should NOT be used! It will change + * the value stored in the N_Vector content structure, but it + * will NOT change the MPI communicator of the actual PETSc + * vector. + * + * ----------------------------------------------------------------- + */ + +#define NV_CONTENT_PTC(v) ( (N_VectorContent_Petsc)(v->content) ) + +#define NV_LOCLENGTH_PTC(v) ( NV_CONTENT_PTC(v)->local_length ) + +#define NV_GLOBLENGTH_PTC(v) ( NV_CONTENT_PTC(v)->global_length ) + +#define NV_OWN_DATA_PTC(v) ( NV_CONTENT_PTC(v)->own_data ) + +#define NV_PVEC_PTC(v) ( NV_CONTENT_PTC(v)->pvec ) + +#define NV_COMM_PTC(v) ( NV_CONTENT_PTC(v)->comm ) + + + +/* ---------------------------------------------------------------- + * Returns vector type ID. Used to identify vector implementation + * from abstract N_Vector interface. + */ +N_Vector_ID N_VGetVectorID_Petsc(N_Vector v) +{ + return SUNDIALS_NVEC_PETSC; +} + + +/* ---------------------------------------------------------------- + * Function to create a new N_Vector wrapper with an empty (NULL) + * PETSc vector. + */ + +N_Vector N_VNewEmpty_Petsc(MPI_Comm comm, + sunindextype local_length, + 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); + CHKERRABORT(comm,ierr); + if (Nsum != global_length) { + fprintf(stderr, BAD_N); + return(NULL); + } + + /* Create vector */ + v = NULL; + v = (N_Vector) malloc(sizeof *v); + 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 = 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; + + /* 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; + + /* Create content */ + content = NULL; + content = (N_VectorContent_Petsc) malloc(sizeof(struct _N_VectorContent_Petsc)); + if (content == NULL) { + free(ops); + free(v); + return(NULL); + } + + /* Attach lengths and communicator */ + 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); +} + + + +/* ---------------------------------------------------------------- + * Function to create an N_Vector wrapper for a PETSc vector. + */ + +N_Vector N_VMake_Petsc(Vec pvec) +{ + N_Vector v = NULL; + MPI_Comm comm; + PetscInt local_length; + PetscInt global_length; + + VecGetLocalSize(pvec, &local_length); + VecGetSize(pvec, &global_length); + PetscObjectGetComm((PetscObject) pvec, &comm); + + v = N_VNewEmpty_Petsc(comm, local_length, global_length); + if (v == NULL) + return(NULL); + + /* Attach data */ + NV_OWN_DATA_PTC(v) = SUNFALSE; + NV_PVEC_PTC(v) = pvec; + + return(v); +} + +/* ---------------------------------------------------------------- + * Function to create an array of new PETSc vector wrappers. + */ + +N_Vector *N_VCloneVectorArray_Petsc(int count, N_Vector w) +{ + N_Vector *vs; + int j; + + if (count <= 0) return(NULL); + + vs = NULL; + vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + if(vs == NULL) return(NULL); + + for (j = 0; j < count; j++) { + vs[j] = NULL; + vs[j] = N_VClone_Petsc(w); + if (vs[j] == NULL) { + N_VDestroyVectorArray_Petsc(vs, j-1); + return(NULL); + } + } + + return(vs); +} + +/* ---------------------------------------------------------------- + * Function to create an array of new PETSc vector wrappers with + * empty (NULL) PETSc vectors. + */ + +N_Vector *N_VCloneVectorArrayEmpty_Petsc(int count, N_Vector w) +{ + N_Vector *vs; + int j; + + if (count <= 0) return(NULL); + + vs = NULL; + vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + if(vs == NULL) return(NULL); + + for (j = 0; j < count; j++) { + vs[j] = NULL; + vs[j] = N_VCloneEmpty_Petsc(w); + if (vs[j] == NULL) { + N_VDestroyVectorArray_Petsc(vs, j-1); + return(NULL); + } + } + + return(vs); +} + +/* ---------------------------------------------------------------- + * Function to free an array created with N_VCloneVectorArray_Petsc + */ + +void N_VDestroyVectorArray_Petsc(N_Vector *vs, int count) +{ + int j; + + for (j = 0; j < count; j++) N_VDestroy_Petsc(vs[j]); + + free(vs); + vs = NULL; + + return; +} + +/* ---------------------------------------------------------------- + * Function to extract PETSc vector + */ + +Vec N_VGetVector_Petsc(N_Vector v) +{ + return NV_PVEC_PTC(v); +} + +/* ---------------------------------------------------------------- + * Function to print the global data in a PETSc vector to stdout + */ + +void N_VPrint_Petsc(N_Vector x) +{ + Vec xv = NV_PVEC_PTC(x); + MPI_Comm comm = NV_COMM_PTC(x); + + VecView(xv, PETSC_VIEWER_STDOUT_(comm)); + + return; +} + +/* ---------------------------------------------------------------- + * Function to print the global data in a PETSc vector to fname + */ + +void N_VPrintFile_Petsc(N_Vector x, const char fname[]) +{ + Vec xv = NV_PVEC_PTC(x); + MPI_Comm comm = NV_COMM_PTC(x); + PetscViewer viewer; + + PetscViewerASCIIOpen(comm, fname, &viewer); + + VecView(xv, viewer); + + PetscViewerDestroy(&viewer); + + return; +} + +/* + * ----------------------------------------------------------------- + * implementation of vector operations + * ----------------------------------------------------------------- + */ + +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); + 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 */ + content = NULL; + content = (N_VectorContent_Petsc) malloc(sizeof(struct _N_VectorContent_Petsc)); + if (content == NULL) { + free(ops); + free(v); + return(NULL); + } + + /* Attach lengths and communicator */ + 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); +} + +N_Vector N_VClone_Petsc(N_Vector w) +{ + N_Vector v = NULL; + Vec pvec = NULL; + Vec wvec = NV_PVEC_PTC(w); + + /* PetscErrorCode ierr; */ + + v = N_VCloneEmpty_Petsc(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 = */ + VecDuplicate(wvec, &pvec); + if(pvec == NULL) { + N_VDestroy_Petsc(v); + return(NULL); + } + + /* Attach data */ + NV_OWN_DATA_PTC(v) = SUNTRUE; + NV_PVEC_PTC(v) = pvec; + + return(v); +} + +void N_VDestroy_Petsc(N_Vector v) +{ + if (NV_OWN_DATA_PTC(v) == SUNTRUE) { + VecDestroy(&(NV_PVEC_PTC(v))); + NV_PVEC_PTC(v) = NULL; + } + + free(v->content); + v->content = NULL; + free(v->ops); + v->ops = NULL; + free(v); + v = NULL; + + return; +} + +void N_VSpace_Petsc(N_Vector v, sunindextype *lrw, sunindextype *liw) +{ + MPI_Comm comm; + int npes; + + comm = NV_COMM_PTC(v); + MPI_Comm_size(comm, &npes); + + *lrw = NV_GLOBLENGTH_PTC(v); + *liw = 2*npes; + + return; +} + +/* + * Not implemented for PETSc wrapper. + */ +realtype *N_VGetArrayPointer_Petsc(N_Vector v) +{ + return NULL; +} + +/* + * Not implemented for PETSc wrapper. + */ +void N_VSetArrayPointer_Petsc(realtype *v_data, N_Vector v) +{ + return; +} + +void N_VLinearSum_Petsc(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z) +{ + Vec xv = NV_PVEC_PTC(x); + Vec yv = NV_PVEC_PTC(y); + Vec zv = NV_PVEC_PTC(z); + + if (x == y) { + N_VScale_Petsc(a + b, x, z); /* z <~ ax+bx */ + return; + } + + if (z == y) { + if (b == ONE) { + VecAXPY(yv, a, xv); /* BLAS usage: axpy y <- ax+y */ + return; + } + VecAXPBY(yv, a, b, xv); /* BLAS usage: axpby y <- ax+by */ + return; + } + + if (z == x) { + if (a == ONE) { + VecAXPY(xv, b, yv); /* BLAS usage: axpy x <- by+x */ + return; + } + VecAXPBY(xv, b, a, yv); /* BLAS usage: axpby x <- by+ax */ + return; + } + + + /* Do all cases not handled above: + (1) a == other, b == 0.0 - user should have called N_VScale + (2) a == 0.0, b == other - user should have called N_VScale + (3) a,b == other, a !=b, a != -b */ + + VecAXPBYPCZ(zv, a, b, 0.0, xv, yv); /* PETSc, probably not optimal */ + + return; +} + +void N_VConst_Petsc(realtype c, N_Vector z) +{ + Vec zv = NV_PVEC_PTC(z); + + VecSet(zv, c); + + return; +} + +void N_VProd_Petsc(N_Vector x, N_Vector y, N_Vector z) +{ + Vec xv = NV_PVEC_PTC(x); + Vec yv = NV_PVEC_PTC(y); + Vec zv = NV_PVEC_PTC(z); + + VecPointwiseMult(zv, xv, yv); + + return; +} + +void N_VDiv_Petsc(N_Vector x, N_Vector y, N_Vector z) +{ + Vec xv = NV_PVEC_PTC(x); + Vec yv = NV_PVEC_PTC(y); + Vec zv = NV_PVEC_PTC(z); + + VecPointwiseDivide(zv, xv, yv); /* z = x/y */ + + return; +} + +void N_VScale_Petsc(realtype c, N_Vector x, N_Vector z) +{ + Vec xv = NV_PVEC_PTC(x); + Vec zv = NV_PVEC_PTC(z); + + if (z == x) { /* BLAS usage: scale x <- cx */ + VecScale(xv, c); + return; + } + + VecAXPBY(zv, c, 0.0, xv); + + return; +} + +void N_VAbs_Petsc(N_Vector x, N_Vector z) +{ + Vec xv = NV_PVEC_PTC(x); + Vec zv = NV_PVEC_PTC(z); + + if(z != x) + VecCopy(xv, zv); /* copy x~>z */ + VecAbs(zv); + + return; +} + +void N_VInv_Petsc(N_Vector x, N_Vector z) +{ + Vec xv = NV_PVEC_PTC(x); + Vec zv = NV_PVEC_PTC(z); + + if(z != x) + VecCopy(xv, zv); /* copy x~>z */ + VecReciprocal(zv); + + return; +} + +void N_VAddConst_Petsc(N_Vector x, realtype b, N_Vector z) +{ + Vec xv = NV_PVEC_PTC(x); + Vec zv = NV_PVEC_PTC(z); + + if(z != x) + VecCopy(xv, zv); /* copy x~>z */ + VecShift(zv, b); + + return; +} + +realtype N_VDotProd_Petsc(N_Vector x, N_Vector y) +{ + Vec xv = NV_PVEC_PTC(x); + Vec yv = NV_PVEC_PTC(y); + PetscScalar dotprod; + + VecDot(xv, yv, &dotprod); + + return dotprod; +} + +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) +{ + sunindextype i; + sunindextype N = NV_LOCLENGTH_PTC(x); + sunindextype N_global = NV_GLOBLENGTH_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])); + } + VecRestoreArray(xv, &xd); + VecRestoreArray(wv, &wd); + + global_sum = SUNMPI_Allreduce_scalar(sum, 1, comm); + return (SUNRsqrt(global_sum/N_global)); +} + +realtype N_VWrmsNormMask_Petsc(N_Vector x, N_Vector w, N_Vector id) +{ + sunindextype i; + sunindextype N = NV_LOCLENGTH_PTC(x); + sunindextype N_global = NV_GLOBLENGTH_PTC(x); + MPI_Comm comm = NV_COMM_PTC(x); + + Vec xv = NV_PVEC_PTC(x); + Vec wv = NV_PVEC_PTC(w); + Vec idv = NV_PVEC_PTC(id); + PetscScalar *xd; + PetscScalar *wd; + PetscScalar *idd; + PetscReal sum = ZERO; + realtype global_sum; + + VecGetArray(xv, &xd); + VecGetArray(wv, &wd); + VecGetArray(idv, &idd); + for (i = 0; i < N; i++) { + PetscReal tag = (PetscReal) idd[i]; + if (tag > ZERO) { + sum += PetscSqr(PetscAbsScalar(xd[i] * wd[i])); + } + } + VecRestoreArray(xv, &xd); + VecRestoreArray(wv, &wd); + VecRestoreArray(idv, &idd); + + global_sum = SUNMPI_Allreduce_scalar(sum, 1, comm); + return (SUNRsqrt(global_sum/N_global)); +} + +realtype N_VMin_Petsc(N_Vector x) +{ + Vec xv = NV_PVEC_PTC(x); + PetscReal minval; + PetscInt i; + + VecMin(xv, &i, &minval); + + return minval; +} + +realtype N_VWL2Norm_Petsc(N_Vector x, N_Vector w) +{ + 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])); + } + VecRestoreArray(xv, &xd); + VecRestoreArray(wv, &wd); + + global_sum = SUNMPI_Allreduce_scalar(sum, 1, comm); + return (SUNRsqrt(global_sum)); +} + +realtype N_VL1Norm_Petsc(N_Vector x) +{ + Vec xv = NV_PVEC_PTC(x); + PetscReal norm; + + VecNorm(xv, NORM_1, &norm); + + return norm; +} + +void N_VCompare_Petsc(realtype c, N_Vector x, N_Vector z) +{ + sunindextype i; + sunindextype N = NV_LOCLENGTH_PTC(x); + Vec xv = NV_PVEC_PTC(x); + Vec zv = NV_PVEC_PTC(z); + PetscReal cpet = c; /* <~ realtype should typedef to PETScReal */ + PetscScalar *xdata; + PetscScalar *zdata; + + VecGetArray(xv, &xdata); + VecGetArray(zv, &zdata); + for (i = 0; i < N; i++) { + zdata[i] = PetscAbsScalar(xdata[i]) >= cpet ? ONE : ZERO; + } + VecRestoreArray(xv, &xdata); + VecRestoreArray(zv, &zdata); + + return; +} + +booleantype N_VInvTest_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; + PetscScalar *zd; + PetscReal val = ONE; + + VecGetArray(xv, &xd); + VecGetArray(zv, &zd); + for (i = 0; i < N; i++) { + if (xd[i] == ZERO) + val = ZERO; + else + zd[i] = ONE/xd[i]; + } + 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) +{ + 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); + Vec cv = NV_PVEC_PTC(c); + Vec mv = NV_PVEC_PTC(m); + PetscScalar *xd; + PetscScalar *cd; + PetscScalar *md; + + temp = ZERO; + + VecGetArray(xv, &xd); + VecGetArray(cv, &cd); + VecGetArray(mv, &md); + for (i = 0; i < N; i++) { + PetscReal cc = (PetscReal) cd[i]; /* <~ Drop imaginary parts if any. */ + PetscReal xx = (PetscReal) xd[i]; /* <~ Constraints defined on Re{x} */ + md[i] = ZERO; + + /* Continue if no constraints were set for the variable */ + if (cc == ZERO) + continue; + + /* Check if a set constraint has been violated */ + test = (SUNRabs(cc) > ONEPT5 && xx*cc <= ZERO) || + (SUNRabs(cc) > HALF && xx*cc < ZERO); + if (test) { + temp = md[i] = ONE; + } + } + VecRestoreArray(xv, &xd); + 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 notEvenOnce = SUNTRUE; + sunindextype i; + sunindextype N = NV_LOCLENGTH_PTC(num); + MPI_Comm comm = NV_COMM_PTC(num); + + Vec nv = NV_PVEC_PTC(num); + Vec dv = NV_PVEC_PTC(denom); + PetscScalar *nd; + PetscScalar *dd; + PetscReal minval = BIG_REAL; + + VecGetArray(nv, &nd); + VecGetArray(dv, &dd); + for (i = 0; i < N; i++) { + PetscReal nr = (PetscReal) nd[i]; + PetscReal dr = (PetscReal) dd[i]; + if (dr == ZERO) + continue; + else { + if (!notEvenOnce) + minval = SUNMIN(minval, nr/dr); + else { + minval = nr/dr; + notEvenOnce = SUNFALSE; + } + } + } + VecRestoreArray(nv, &nd); + VecRestoreArray(dv, &dd); + + return(SUNMPI_Allreduce_scalar(minval, 3, comm)); +} + + +/* + * ----------------------------------------------------------------- + * fused vector operations + * ----------------------------------------------------------------- + */ + + +int N_VLinearCombination_Petsc(int nvec, realtype* c, N_Vector* X, N_Vector z) +{ + int i; + Vec* xv; + Vec zv; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VScale */ + if (nvec == 1) { + N_VScale_Petsc(c[0], X[0], z); + return(0); + } + + /* should have called N_VLinearSum */ + if (nvec == 2) { + N_VLinearSum_Petsc(c[0], X[0], c[1], X[1], z); + return(0); + } + + /* get petsc vectors */ + xv = (Vec*) malloc(nvec * sizeof(Vec)); + for (i=0; i<nvec; i++) + xv[i] = NV_PVEC_PTC(X[i]); + + zv = NV_PVEC_PTC(z); + + /* + * X[0] += c[i]*X[i], i = 1,...,nvec-1 + */ + if ((X[0] == z) && (c[0] == ONE)) { + VecMAXPY(zv, nvec-1, c+1, xv+1); + return(0); + } + + /* + * X[0] = c[0] * X[0] + sum{ c[i] * X[i] }, i = 1,...,nvec-1 + */ + if (X[0] == z) { + VecScale(zv, c[0]); + VecMAXPY(zv, nvec-1, c+1, xv+1); + return(0); + } + + /* + * z = sum{ c[i] * X[i] }, i = 0,...,nvec-1 + */ + VecAXPBY(zv, c[0], 0.0, xv[0]); + VecMAXPY(zv, nvec-1, c+1, xv+1); + return(0); +} + + +int N_VScaleAddMulti_Petsc(int nvec, realtype* a, N_Vector x, N_Vector* Y, N_Vector* Z) +{ + int i; + sunindextype j, N; + PetscScalar *xd, *yd, *zd; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VLinearSum */ + if (nvec == 1) { + N_VLinearSum_Petsc(a[0], x, ONE, Y[0], Z[0]); + return(0); + } + + /* get vector length and data array */ + N = NV_LOCLENGTH_PTC(x); + VecGetArray(NV_PVEC_PTC(x), &xd); + + /* + * Y[i][j] += a[i] * x[j] + */ + if (Y == Z) { + for (i=0; i<nvec; i++) { + VecGetArray(NV_PVEC_PTC(Y[i]), &yd); + for (j=0; j<N; j++) { + yd[j] += a[i] * xd[j]; + } + VecRestoreArray(NV_PVEC_PTC(Y[i]), &yd); + } + return(0); + } + + /* + * Z[i][j] = Y[i][j] + a[i] * x[j] + */ + for (i=0; i<nvec; i++) { + VecGetArray(NV_PVEC_PTC(Y[i]), &yd); + VecGetArray(NV_PVEC_PTC(Z[i]), &zd); + for (j=0; j<N; j++) { + zd[j] = a[i] * xd[j] + yd[j]; + } + VecRestoreArray(NV_PVEC_PTC(Y[i]), &yd); + VecRestoreArray(NV_PVEC_PTC(Z[i]), &zd); + } + return(0); +} + + +int N_VDotProdMulti_Petsc(int nvec, N_Vector x, N_Vector* Y, realtype* dotprods) +{ + int i; + Vec* yv; + Vec xv; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VDotProd */ + if (nvec == 1) { + dotprods[0] = N_VDotProd_Petsc(x, Y[0]); + return(0); + } + + /* get petsc vectors */ + yv = (Vec*) malloc(nvec * sizeof(Vec)); + for (i=0; i<nvec; i++) + yv[i] = NV_PVEC_PTC(Y[i]); + + xv = NV_PVEC_PTC(x); + + VecMDot(xv, nvec, yv, dotprods); + return(0); +} + + +/* + * ----------------------------------------------------------------------------- + * vector array operations + * ----------------------------------------------------------------------------- + */ + +int N_VLinearSumVectorArray_Petsc(int nvec, + realtype a, N_Vector* X, + realtype b, N_Vector* Y, + N_Vector* Z) +{ + int i; + sunindextype j, N; + PetscScalar *xd, *yd, *zd; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VLinearSum */ + if (nvec == 1) { + N_VLinearSum_Petsc(a, X[0], b, Y[0], Z[0]); + return(0); + } + + /* get vector length */ + N = NV_LOCLENGTH_PTC(Z[0]); + + /* compute linear sum for each vector pair in vector arrays */ + for (i=0; i<nvec; i++) { + VecGetArray(NV_PVEC_PTC(X[i]), &xd); + VecGetArray(NV_PVEC_PTC(Y[i]), &yd); + VecGetArray(NV_PVEC_PTC(Z[i]), &zd); + for (j=0; j<N; j++) { + zd[j] = a * xd[j] + b * yd[j]; + } + VecRestoreArray(NV_PVEC_PTC(X[i]), &xd); + VecRestoreArray(NV_PVEC_PTC(Y[i]), &yd); + VecRestoreArray(NV_PVEC_PTC(Z[i]), &zd); + } + + return(0); +} + + +int N_VScaleVectorArray_Petsc(int nvec, realtype* c, N_Vector* X, N_Vector* Z) +{ + int i; + sunindextype j, N; + PetscScalar *xd, *zd; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VScale */ + if (nvec == 1) { + N_VScale_Petsc(c[0], X[0], Z[0]); + return(0); + } + + /* get vector length */ + N = NV_LOCLENGTH_PTC(Z[0]); + + /* + * X[i] *= c[i] + */ + if (X == Z) { + for (i=0; i<nvec; i++) { + VecGetArray(NV_PVEC_PTC(X[i]), &xd); + for (j=0; j<N; j++) { + xd[j] *= c[i]; + } + VecRestoreArray(NV_PVEC_PTC(X[i]), &xd); + } + return(0); + } + + /* + * Z[i] = c[i] * X[i] + */ + for (i=0; i<nvec; i++) { + VecGetArray(NV_PVEC_PTC(X[i]), &xd); + VecGetArray(NV_PVEC_PTC(Z[i]), &zd); + for (j=0; j<N; j++) { + zd[j] = c[i] * xd[j]; + } + VecRestoreArray(NV_PVEC_PTC(X[i]), &xd); + VecRestoreArray(NV_PVEC_PTC(Z[i]), &zd); + } + return(0); +} + + +int N_VConstVectorArray_Petsc(int nvec, realtype c, N_Vector* Z) +{ + int i; + sunindextype j, N; + PetscScalar *zd; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VConst */ + if (nvec == 1) { + N_VConst_Petsc(c, Z[0]); + return(0); + } + + /* get vector length */ + N = NV_LOCLENGTH_PTC(Z[0]); + + /* set each vector in the vector array to a constant */ + for (i=0; i<nvec; i++) { + VecGetArray(NV_PVEC_PTC(Z[i]), &zd); + for (j=0; j<N; j++) { + zd[j] = c; + } + VecRestoreArray(NV_PVEC_PTC(Z[i]), &zd); + } + + return(0); +} + + +int N_VWrmsNormVectorArray_Petsc(int nvec, N_Vector* X, N_Vector* W, realtype* nrm) +{ + int i; + sunindextype j, Nl, Ng; + realtype* wd=NULL; + realtype* xd=NULL; + MPI_Comm comm; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VWrmsNorm */ + if (nvec == 1) { + nrm[0] = N_VWrmsNorm_Petsc(X[0], W[0]); + return(0); + } + + /* get vector lengths and communicator */ + Nl = NV_LOCLENGTH_PTC(X[0]); + Ng = NV_GLOBLENGTH_PTC(X[0]); + comm = NV_COMM_PTC(X[0]); + + /* compute the WRMS norm for each vector in the vector array */ + for (i=0; i<nvec; i++) { + VecGetArray(NV_PVEC_PTC(X[i]), &xd); + VecGetArray(NV_PVEC_PTC(W[i]), &wd); + nrm[i] = ZERO; + for (j=0; j<Nl; j++) { + nrm[i] += PetscSqr(PetscAbsScalar(xd[j] * wd[j])); + } + VecRestoreArray(NV_PVEC_PTC(X[i]), &xd); + VecRestoreArray(NV_PVEC_PTC(W[i]), &wd); + } + SUNMPI_Allreduce(nrm, nvec, 1, comm); + + for (i=0; i<nvec; i++) + nrm[i] = SUNRsqrt(nrm[i]/Ng); + + return(0); +} + + +int N_VWrmsNormMaskVectorArray_Petsc(int nvec, N_Vector* X, N_Vector* W, + N_Vector id, realtype* nrm) +{ + int i; + sunindextype j, Nl, Ng; + PetscScalar *wd, *xd, *idd; + MPI_Comm comm; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VWrmsNorm */ + if (nvec == 1) { + nrm[0] = N_VWrmsNormMask_Petsc(X[0], W[0], id); + return(0); + } + + /* get vector lengths and communicator */ + Nl = NV_LOCLENGTH_PTC(X[0]); + Ng = NV_GLOBLENGTH_PTC(X[0]); + comm = NV_COMM_PTC(X[0]); + + /* compute the WRMS norm for each vector in the vector array */ + VecGetArray(NV_PVEC_PTC(id), &idd); + for (i=0; i<nvec; i++) { + VecGetArray(NV_PVEC_PTC(X[i]), &xd); + VecGetArray(NV_PVEC_PTC(W[i]), &wd); + nrm[i] = ZERO; + for (j=0; j<Nl; j++) { + if (idd[j] > ZERO) + nrm[i] += SUNSQR(xd[j] * wd[j]); + } + VecRestoreArray(NV_PVEC_PTC(X[i]), &xd); + VecRestoreArray(NV_PVEC_PTC(W[i]), &wd); + } + VecRestoreArray(NV_PVEC_PTC(id), &idd); + + SUNMPI_Allreduce(nrm, nvec, 1, comm); + + for (i=0; i<nvec; i++) + nrm[i] = SUNRsqrt(nrm[i]/Ng); + + return(0); +} + + +int N_VScaleAddMultiVectorArray_Petsc(int nvec, int nsum, realtype* a, + N_Vector* X, N_Vector** Y, N_Vector** Z) +{ + int i, j; + sunindextype k, N; + PetscScalar *xd, *yd, *zd; + + int retval; + N_Vector* YY; + N_Vector* ZZ; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + if (nsum < 1) return(-1); + + /* --------------------------- + * Special cases for nvec == 1 + * --------------------------- */ + + if (nvec == 1) { + + /* should have called N_VLinearSum */ + if (nsum == 1) { + N_VLinearSum_Petsc(a[0], X[0], ONE, Y[0][0], Z[0][0]); + return(0); + } + + /* should have called N_VScaleAddMulti */ + YY = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + ZZ = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + + for (j=0; j<nsum; j++) { + YY[j] = Y[j][0]; + ZZ[j] = Z[j][0]; + } + + retval = N_VScaleAddMulti_Petsc(nsum, a, X[0], YY, ZZ); + + free(YY); + free(ZZ); + return(retval); + } + + /* -------------------------- + * Special cases for nvec > 1 + * -------------------------- */ + + /* should have called N_VLinearSumVectorArray */ + if (nsum == 1) { + retval = N_VLinearSumVectorArray_Petsc(nvec, a[0], X, ONE, Y[0], Z[0]); + return(retval); + } + + /* ---------------------------- + * Compute multiple linear sums + * ---------------------------- */ + + /* get vector length */ + N = NV_LOCLENGTH_PTC(X[0]); + + /* + * Y[i][j] += a[i] * x[j] + */ + if (Y == Z) { + for (i=0; i<nvec; i++) { + VecGetArray(NV_PVEC_PTC(X[i]), &xd); + for (j=0; j<nsum; j++) { + VecGetArray(NV_PVEC_PTC(Y[j][i]), &yd); + for (k=0; k<N; k++) { + yd[k] += a[j] * xd[k]; + } + VecRestoreArray(NV_PVEC_PTC(Y[j][i]), &yd); + } + VecRestoreArray(NV_PVEC_PTC(X[i]), &xd); + } + return(0); + } + + /* + * Z[i][j] = Y[i][j] + a[i] * x[j] + */ + for (i=0; i<nvec; i++) { + VecGetArray(NV_PVEC_PTC(X[i]), &xd); + for (j=0; j<nsum; j++) { + VecGetArray(NV_PVEC_PTC(Y[j][i]), &yd); + VecGetArray(NV_PVEC_PTC(Z[j][i]), &zd); + for (k=0; k<N; k++) { + zd[k] = a[j] * xd[k] + yd[k]; + } + VecRestoreArray(NV_PVEC_PTC(Y[j][i]), &yd); + VecRestoreArray(NV_PVEC_PTC(Z[j][i]), &zd); + } + VecRestoreArray(NV_PVEC_PTC(X[i]), &xd); + } + + return(0); +} + + +int N_VLinearCombinationVectorArray_Petsc(int nvec, int nsum, + realtype* c, + N_Vector** X, + N_Vector* Z) +{ + int i; /* vector arrays index in summation [0,nsum) */ + int j; /* vector index in vector array [0,nvec) */ + sunindextype k; /* element index in vector [0,N) */ + sunindextype N; + PetscScalar *zd, *xd; + + realtype* ctmp; + N_Vector* Y; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + if (nsum < 1) return(-1); + + /* --------------------------- + * Special cases for nvec == 1 + * --------------------------- */ + + if (nvec == 1) { + + /* should have called N_VScale */ + if (nsum == 1) { + N_VScale_Petsc(c[0], X[0][0], Z[0]); + return(0); + } + + /* should have called N_VLinearSum */ + if (nsum == 2) { + N_VLinearSum_Petsc(c[0], X[0][0], c[1], X[1][0], Z[0]); + return(0); + } + + /* should have called N_VLinearCombination */ + Y = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + + for (i=0; i<nsum; i++) { + Y[i] = X[i][0]; + } + + N_VLinearCombination_Petsc(nsum, c, Y, Z[0]); + + free(Y); + return(0); + } + + /* -------------------------- + * Special cases for nvec > 1 + * -------------------------- */ + + /* should have called N_VScaleVectorArray */ + if (nsum == 1) { + + ctmp = (realtype*) malloc(nvec * sizeof(realtype)); + + for (j=0; j<nvec; j++) { + ctmp[j] = c[0]; + } + + N_VScaleVectorArray_Petsc(nvec, ctmp, X[0], Z); + + free(ctmp); + return(0); + } + + /* should have called N_VLinearSumVectorArray */ + if (nsum == 2) { + N_VLinearSumVectorArray_Petsc(nvec, c[0], X[0], c[1], X[1], Z); + return(0); + } + + /* -------------------------- + * Compute linear combination + * -------------------------- */ + + /* get vector length */ + N = NV_LOCLENGTH_PTC(Z[0]); + + /* + * X[0][j] += c[i]*X[i][j], i = 1,...,nvec-1 + */ + if ((X[0] == Z) && (c[0] == ONE)) { + for (j=0; j<nvec; j++) { + VecGetArray(NV_PVEC_PTC(Z[j]), &zd); + for (i=1; i<nsum; i++) { + VecGetArray(NV_PVEC_PTC(X[i][j]), &xd); + for (k=0; k<N; k++) { + zd[k] += c[i] * xd[k]; + } + VecRestoreArray(NV_PVEC_PTC(X[i][j]), &xd); + } + VecRestoreArray(NV_PVEC_PTC(Z[j]), &zd); + } + return(0); + } + + /* + * X[0][j] = c[0] * X[0][j] + sum{ c[i] * X[i][j] }, i = 1,...,nvec-1 + */ + if (X[0] == Z) { + for (j=0; j<nvec; j++) { + VecGetArray(NV_PVEC_PTC(Z[j]), &zd); + for (k=0; k<N; k++) { + zd[k] *= c[0]; + } + for (i=1; i<nsum; i++) { + VecGetArray(NV_PVEC_PTC(X[i][j]), &xd); + for (k=0; k<N; k++) { + zd[k] += c[i] * xd[k]; + } + VecRestoreArray(NV_PVEC_PTC(X[i][j]), &xd); + } + VecRestoreArray(NV_PVEC_PTC(Z[j]), &zd); + } + return(0); + } + + /* + * Z[j] = sum{ c[i] * X[i][j] }, i = 0,...,nvec-1 + */ + for (j=0; j<nvec; j++) { + VecGetArray(NV_PVEC_PTC(X[0][j]), &xd); + VecGetArray(NV_PVEC_PTC(Z[j]), &zd); + for (k=0; k<N; k++) { + zd[k] = c[0] * xd[k]; + } + VecRestoreArray(NV_PVEC_PTC(X[0][j]), &xd); + for (i=1; i<nsum; i++) { + VecGetArray(NV_PVEC_PTC(X[i][j]), &xd); + for (k=0; k<N; k++) { + zd[k] += c[i] * xd[k]; + } + VecRestoreArray(NV_PVEC_PTC(X[i][j]), &xd); + } + VecRestoreArray(NV_PVEC_PTC(Z[j]), &zd); + } + return(0); +} + +/* + * ----------------------------------------------------------------- + * Enable / Disable fused and vector array operations + * ----------------------------------------------------------------- + */ + +int N_VEnableFusedOps_Petsc(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); + + if (tf) { + /* enable all fused vector operations */ + v->ops->nvlinearcombination = N_VLinearCombination_Petsc; + v->ops->nvscaleaddmulti = N_VScaleAddMulti_Petsc; + v->ops->nvdotprodmulti = N_VDotProdMulti_Petsc; + /* enable all vector array operations */ + v->ops->nvlinearsumvectorarray = N_VLinearSumVectorArray_Petsc; + v->ops->nvscalevectorarray = N_VScaleVectorArray_Petsc; + v->ops->nvconstvectorarray = N_VConstVectorArray_Petsc; + v->ops->nvwrmsnormvectorarray = N_VWrmsNormVectorArray_Petsc; + v->ops->nvwrmsnormmaskvectorarray = N_VWrmsNormMaskVectorArray_Petsc; + v->ops->nvscaleaddmultivectorarray = N_VScaleAddMultiVectorArray_Petsc; + v->ops->nvlinearcombinationvectorarray = N_VLinearCombinationVectorArray_Petsc; + } 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 N_VEnableLinearCombination_Petsc(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 = N_VLinearCombination_Petsc; + else + v->ops->nvlinearcombination = NULL; + + /* return success */ + return(0); +} + +int N_VEnableScaleAddMulti_Petsc(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 = N_VScaleAddMulti_Petsc; + else + v->ops->nvscaleaddmulti = NULL; + + /* return success */ + return(0); +} + +int N_VEnableDotProdMulti_Petsc(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 = N_VDotProdMulti_Petsc; + else + v->ops->nvdotprodmulti = NULL; + + /* return success */ + return(0); +} + +int N_VEnableLinearSumVectorArray_Petsc(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 = N_VLinearSumVectorArray_Petsc; + else + v->ops->nvlinearsumvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableScaleVectorArray_Petsc(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 = N_VScaleVectorArray_Petsc; + else + v->ops->nvscalevectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableConstVectorArray_Petsc(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 = N_VConstVectorArray_Petsc; + else + v->ops->nvconstvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableWrmsNormVectorArray_Petsc(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 = N_VWrmsNormVectorArray_Petsc; + else + v->ops->nvwrmsnormvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableWrmsNormMaskVectorArray_Petsc(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 = N_VWrmsNormMaskVectorArray_Petsc; + else + v->ops->nvwrmsnormmaskvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableScaleAddMultiVectorArray_Petsc(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->nvscaleaddmultivectorarray = N_VScaleAddMultiVectorArray_Petsc; + else + v->ops->nvscaleaddmultivectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableLinearCombinationVectorArray_Petsc(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->nvlinearcombinationvectorarray = N_VLinearCombinationVectorArray_Petsc; + else + v->ops->nvlinearcombinationvectorarray = NULL; + + /* return success */ + return(0); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/pthreads/fnvector_pthreads.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/pthreads/fnvector_pthreads.c new file mode 100644 index 0000000..9ca0999 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/pthreads/fnvector_pthreads.c @@ -0,0 +1,154 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Steven Smith @ 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 (companion of nvector_pthreads.h) contains the + * implementation needed for the Fortran initialization of pthreads + * vector operations. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fnvector_pthreads.h" + +/* Define global vector variables */ + +N_Vector F2C_CVODE_vec; +N_Vector F2C_CVODE_vecQ; +N_Vector *F2C_CVODE_vecS; +N_Vector F2C_CVODE_vecB; +N_Vector F2C_CVODE_vecQB; + +N_Vector F2C_IDA_vec; +N_Vector F2C_IDA_vecQ; +N_Vector *F2C_IDA_vecS; +N_Vector F2C_IDA_vecB; +N_Vector F2C_IDA_vecQB; + +N_Vector F2C_KINSOL_vec; + +N_Vector F2C_ARKODE_vec; + +/* Fortran callable interfaces */ + +void FNV_INITPTS(int *code, long int *N, int *num_threads, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + F2C_CVODE_vec = NULL; + F2C_CVODE_vec = N_VNewEmpty_Pthreads(*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); + if (F2C_IDA_vec == NULL) *ier = -1; + break; + case FCMIX_KINSOL: + F2C_KINSOL_vec = NULL; + F2C_KINSOL_vec = N_VNewEmpty_Pthreads(*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); + if (F2C_ARKODE_vec == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + +void FNV_INITPTS_Q(int *code, long int *Nq, int *num_threads, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + F2C_CVODE_vecQ = NULL; + F2C_CVODE_vecQ = N_VNewEmpty_Pthreads(*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); + if (F2C_IDA_vecQ == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + +void FNV_INITPTS_B(int *code, long int *NB, int *num_threads, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + F2C_CVODE_vecB = NULL; + F2C_CVODE_vecB = N_VNewEmpty_Pthreads(*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); + if (F2C_IDA_vecB == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + +void FNV_INITPTS_QB(int *code, long int *NqB, int *num_threads, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + F2C_CVODE_vecQB = NULL; + F2C_CVODE_vecQB = N_VNewEmpty_Pthreads(*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); + if (F2C_IDA_vecQB == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + +void FNV_INITPTS_S(int *code, int *Ns, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + F2C_CVODE_vecS = NULL; + F2C_CVODE_vecS = (N_Vector *) N_VCloneVectorArrayEmpty_Pthreads(*Ns, F2C_CVODE_vec); + if (F2C_CVODE_vecS == NULL) *ier = -1; + break; + case FCMIX_IDA: + F2C_IDA_vecS = NULL; + F2C_IDA_vecS = (N_Vector *) N_VCloneVectorArrayEmpty_Pthreads(*Ns, F2C_IDA_vec); + if (F2C_IDA_vecS == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/pthreads/fnvector_pthreads.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/pthreads/fnvector_pthreads.h new file mode 100644 index 0000000..0fd2f60 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/pthreads/fnvector_pthreads.h @@ -0,0 +1,92 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Steven Smith @ 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 (companion of nvector_pthreads.h) contains the + * definitions needed for the initialization of pthreads + * vector operations in Fortran. + * ----------------------------------------------------------------- + */ + +#ifndef _FNVECTOR_PTHREADS_H +#define _FNVECTOR_PTHREADS_H + +#include <nvector/nvector_pthreads.h> +#include <sundials/sundials_fnvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +#if defined(SUNDIALS_F77_FUNC) +#define FNV_INITPTS SUNDIALS_F77_FUNC(fnvinitpts, FNVINITPTS) +#else +#define FNV_INITPTS fnvinitpts_ +#endif + +#if defined(SUNDIALS_F77_FUNC_) + +#define FNV_INITPTS_Q SUNDIALS_F77_FUNC_(fnvinitpts_q, FNVINITPTS_Q) +#define FNV_INITPTS_S SUNDIALS_F77_FUNC_(fnvinitpts_s, FNVINITPTS_S) +#define FNV_INITPTS_B SUNDIALS_F77_FUNC_(fnvinitpts_b, FNVINITPTS_B) +#define FNV_INITPTS_QB SUNDIALS_F77_FUNC_(fnvinitpts_qb, FNVINITPTS_QB) + +#else + +#define FNV_INITPTS_Q fnvinitpts_q_ +#define FNV_INITPTS_S fnvinitpts_s_ +#define FNV_INITPTS_B fnvinitpts_b_ +#define FNV_INITPTS_QB fnvinitpts_qb_ + +#endif + +/* Declarations of global variables */ + +extern N_Vector F2C_CVODE_vec; +extern N_Vector F2C_CVODE_vecQ; +extern N_Vector *F2C_CVODE_vecS; +extern N_Vector F2C_CVODE_vecB; +extern N_Vector F2C_CVODE_vecQB; + +extern N_Vector F2C_IDA_vec; +extern N_Vector F2C_IDA_vecQ; +extern N_Vector *F2C_IDA_vecS; +extern N_Vector F2C_IDA_vecB; +extern N_Vector F2C_IDA_vecQB; + +extern N_Vector F2C_KINSOL_vec; + +extern N_Vector F2C_ARKODE_vec; + +/* + * Prototypes of exported functions + * + * FNV_INITPTS - initializes pthreads vector operations for main problem + * FNV_INITPTS_Q - initializes pthreads vector operations for quadratures + * FNV_INITPTS_S - initializes pthreads vector operations for sensitivities + * FNV_INITPTS_B - initializes pthreads vector operations for adjoint problem + * FNV_INITPTS_QB - initializes pthreads vector operations for adjoint quadratures + * + */ + +void FNV_INITPTS(int *code, long int *neq, int *num_threads, int *ier); +void FNV_INITPTS_Q(int *code, long int *Nq, int *num_threads, int *ier); +void FNV_INITPTS_S(int *code, int *Ns, int *ier); +void FNV_INITPTS_B(int *code, long int *NB, int *num_threads, int *ier); +void FNV_INITPTS_QB(int *code, long int *NqB, int *num_threads, int *ier); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/pthreads/nvector_pthreads.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/pthreads/nvector_pthreads.c new file mode 100644 index 0000000..70883fd --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/pthreads/nvector_pthreads.c @@ -0,0 +1,5385 @@ +/* ----------------------------------------------------------------- + * 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 + * @ 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 a POSIX Threads (Pthreads) + * implementation of the NVECTOR package using a LOCAL array of + * structures to pass data to threads. + * -----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include <nvector/nvector_pthreads.h> +#include <sundials/sundials_math.h> +#include <math.h> /* define NAN */ + +#define ZERO RCONST(0.0) +#define HALF RCONST(0.5) +#define ONE RCONST(1.0) +#define ONEPT5 RCONST(1.5) + +/* Private functions for special cases of vector operations */ +static void VCopy_Pthreads(N_Vector x, N_Vector z); /* z=x */ +static void VSum_Pthreads(N_Vector x, N_Vector y, N_Vector z); /* z=x+y */ +static void VDiff_Pthreads(N_Vector x, N_Vector y, N_Vector z); /* z=x-y */ +static void VNeg_Pthreads(N_Vector x, N_Vector z); /* z=-x */ +static void VScaleSum_Pthreads(realtype c, N_Vector x, N_Vector y, N_Vector z); /* z=c(x+y) */ +static void VScaleDiff_Pthreads(realtype c, N_Vector x, N_Vector y, N_Vector z); /* z=c(x-y) */ +static void VLin1_Pthreads(realtype a, N_Vector x, N_Vector y, N_Vector z); /* z=ax+y */ +static void VLin2_Pthreads(realtype a, N_Vector x, N_Vector y, N_Vector z); /* z=ax-y */ +static void Vaxpy_Pthreads(realtype a, N_Vector x, N_Vector y); /* y <- ax+y */ +static void VScaleBy_Pthreads(realtype a, N_Vector x); /* x <- ax */ + +/* Private functions for special cases of vector array operations */ +static int VSumVectorArray_Pthreads(int nvec, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=X+Y */ +static int VDiffVectorArray_Pthreads(int nvec, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=X-Y */ +static int VScaleSumVectorArray_Pthreads(int nvec, realtype c, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=c(X+Y) */ +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 */ + +/* Pthread companion functions for vector operations */ +static void *N_VLinearSum_PT(void *thread_data); +static void *N_VConst_PT(void *thread_data); +static void *N_VProd_PT(void *thread_data); +static void *N_VDiv_PT(void *thread_data); +static void *N_VScale_PT(void *thread_data); +static void *N_VAbs_PT(void *thread_data); +static void *N_VInv_PT(void *thread_data); +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_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_VConstrMask_PT(void *thread_data); +static void *N_VMinQuotient_PT(void *thread_data); + +/* Pthread companion functions special cases of vector operations */ +static void *VCopy_PT(void *thread_data); +static void *VSum_PT(void *thread_data); +static void *VDiff_PT(void *thread_data); +static void *VNeg_PT(void *thread_data); +static void *VScaleSum_PT(void *thread_data); +static void *VScaleDiff_PT(void *thread_data); +static void *VLin1_PT(void *thread_data); +static void *VLin2_PT(void *thread_data); +static void *VScaleBy_PT(void *thread_data); +static void *Vaxpy_PT(void *thread_data); + +/* Pthread companion functions for fused vector operations */ +static void *N_VLinearCombination_PT(void *thread_data); +static void *N_VScaleAddMulti_PT(void *thread_data); +static void *N_VDotProdMulti_PT(void *thread_data); + +/* Pthread companion functions for vector array operations */ +static void *N_VLinearSumVectorArray_PT(void *thread_data); +static void *N_VScaleVectorArray_PT(void *thread_data); +static void *N_VConstVectorArray_PT(void *thread_data); +static void *N_VWrmsNormVectorArray_PT(void *thread_data); +static void *N_VWrmsNormMaskVectorArray_PT(void *thread_data); +static void *N_VScaleAddMultiVectorArray_PT(void *thread_data); +static void *N_VLinearCombinationVectorArray_PT(void *thread_data); + +/* Pthread companion functions special cases of vector array operations */ +static void *VSumVectorArray_PT(void *thread_data); +static void *VDiffVectorArray_PT(void *thread_data); +static void *VScaleSumVectorArray_PT(void *thread_data); +static void *VScaleDiffVectorArray_PT(void *thread_data); +static void *VLin1VectorArray_PT(void *thread_data); +static void *VLin2VectorArray_PT(void *thread_data); +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); + +/* Function to initialize thread data */ +static void N_VInitThreadData(Pthreads_Data *thread_data); + +/* + * ----------------------------------------------------------------- + * exported functions + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------- + * Returns vector type ID. Used to identify vector implementation + * from abstract N_Vector interface. + */ +N_Vector_ID N_VGetVectorID_Pthreads(N_Vector v) +{ + return SUNDIALS_NVEC_PTHREADS; +} + +/* ---------------------------------------------------------------------------- + * Function to create a new empty vector + */ + +N_Vector N_VNewEmpty_Pthreads(sunindextype length, int num_threads) +{ + N_Vector v; + N_Vector_Ops ops; + N_VectorContent_Pthreads content; + + /* Create vector */ + v = NULL; + v = (N_Vector) malloc(sizeof *v); + 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 = 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; + + /* 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; + + /* Create content */ + content = NULL; + content = (N_VectorContent_Pthreads) malloc(sizeof(struct _N_VectorContent_Pthreads)); + if (content == NULL) { free(ops); free(v); return(NULL); } + + 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); +} + +/* ---------------------------------------------------------------------------- + * Function to create a new vector + */ + +N_Vector N_VNew_Pthreads(sunindextype length, int num_threads) +{ + N_Vector v; + realtype *data; + + v = NULL; + v = N_VNewEmpty_Pthreads(length, num_threads); + if (v == NULL) return(NULL); + + /* Create data */ + if (length > 0) { + + /* Allocate memory */ + data = NULL; + data = (realtype *) malloc(length * sizeof(realtype)); + if(data == NULL) { N_VDestroy_Pthreads(v); return(NULL); } + + /* Attach data */ + NV_OWN_DATA_PT(v) = SUNTRUE; + NV_DATA_PT(v) = data; + + } + + return(v); +} + +/* ---------------------------------------------------------------------------- + * Function to create a vector with user data component + */ + +N_Vector N_VMake_Pthreads(sunindextype length, int num_threads, realtype *v_data) +{ + N_Vector v; + + v = NULL; + v = N_VNewEmpty_Pthreads(length, num_threads); + if (v == NULL) return(NULL); + + if (length > 0) { + /* Attach data */ + NV_OWN_DATA_PT(v) = SUNFALSE; + NV_DATA_PT(v) = v_data; + } + + return(v); +} + +/* ---------------------------------------------------------------------------- + * Function to create an array of new vectors. + */ + +N_Vector *N_VCloneVectorArray_Pthreads(int count, N_Vector w) +{ + N_Vector *vs; + int j; + + if (count <= 0) return(NULL); + + vs = NULL; + vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + if(vs == NULL) return(NULL); + + for (j = 0; j < count; j++) { + vs[j] = NULL; + vs[j] = N_VClone_Pthreads(w); + if (vs[j] == NULL) { + N_VDestroyVectorArray_Pthreads(vs, j-1); + return(NULL); + } + } + + return(vs); +} + +/* ---------------------------------------------------------------------------- + * Function to create an array of new vectors with NULL data array. + */ + +N_Vector *N_VCloneVectorArrayEmpty_Pthreads(int count, N_Vector w) +{ + N_Vector *vs; + int j; + + if (count <= 0) return(NULL); + + vs = NULL; + vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + if(vs == NULL) return(NULL); + + for (j = 0; j < count; j++) { + vs[j] = NULL; + vs[j] = N_VCloneEmpty_Pthreads(w); + if (vs[j] == NULL) { + N_VDestroyVectorArray_Pthreads(vs, j-1); + return(NULL); + } + } + + return(vs); +} + +/* ---------------------------------------------------------------------------- + * Function to free an array created with N_VCloneVectorArray_Pthreads + */ + +void N_VDestroyVectorArray_Pthreads(N_Vector *vs, int count) +{ + int j; + + for (j = 0; j < count; j++) N_VDestroy_Pthreads(vs[j]); + + free(vs); vs = NULL; + + return; +} + +/* ---------------------------------------------------------------------------- + * Function to return number of vector elements + */ +sunindextype N_VGetLength_Pthreads(N_Vector v) +{ + return NV_LENGTH_PT(v); +} + +/* ---------------------------------------------------------------------------- + * Function to print a vector to stdout + */ + +void N_VPrint_Pthreads(N_Vector x) +{ + N_VPrintFile_Pthreads(x, stdout); +} + +/* ---------------------------------------------------------------------------- + * Function to print a vector to outfile + */ + +void N_VPrintFile_Pthreads(N_Vector x, FILE *outfile) +{ + sunindextype i, N; + realtype *xd; + + xd = NULL; + + N = NV_LENGTH_PT(x); + xd = NV_DATA_PT(x); + + for (i = 0; i < N; i++) { +#if defined(SUNDIALS_EXTENDED_PRECISION) + fprintf(outfile, "%11.8Lg\n", xd[i]); +#elif defined(SUNDIALS_DOUBLE_PRECISION) + fprintf(outfile, "%11.8g\n", xd[i]); +#else + fprintf(outfile, "%11.8g\n", xd[i]); +#endif + } + fprintf(outfile, "\n"); + + return; +} + +/* + * ----------------------------------------------------------------- + * implementation of vector operations + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------------------- + * Create new vector from existing vector without attaching data + */ + +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); + 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 */ + content = NULL; + content = (N_VectorContent_Pthreads) malloc(sizeof(struct _N_VectorContent_Pthreads)); + if (content == NULL) { free(ops); free(v); return(NULL); } + + 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); +} + + +/* ---------------------------------------------------------------------------- + * Create new vector from existing vector and attach data + */ + +N_Vector N_VClone_Pthreads(N_Vector w) +{ + N_Vector v; + realtype *data; + sunindextype length; + + v = NULL; + v = N_VCloneEmpty_Pthreads(w); + if (v == NULL) return(NULL); + + length = NV_LENGTH_PT(w); + + /* Create data */ + if (length > 0) { + + /* Allocate memory */ + data = NULL; + data = (realtype *) malloc(length * sizeof(realtype)); + if(data == NULL) { N_VDestroy_Pthreads(v); return(NULL); } + + /* Attach data */ + NV_OWN_DATA_PT(v) = SUNTRUE; + NV_DATA_PT(v) = data; + + } + + return(v); +} + +/* ---------------------------------------------------------------------------- + * Destroy vector and free vector memory + */ + +void N_VDestroy_Pthreads(N_Vector v) +{ + if (NV_OWN_DATA_PT(v) == SUNTRUE) { + free(NV_DATA_PT(v)); + NV_DATA_PT(v) = NULL; + } + free(v->content); v->content = NULL; + free(v->ops); v->ops = NULL; + free(v); v = NULL; + + return; +} + +/* ---------------------------------------------------------------------------- + * Get storage requirement for vector + */ + +void N_VSpace_Pthreads(N_Vector v, sunindextype *lrw, sunindextype *liw) +{ + *lrw = NV_LENGTH_PT(v); + *liw = 1; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Get vector data pointer + */ + +realtype *N_VGetArrayPointer_Pthreads(N_Vector v) +{ + return((realtype *) NV_DATA_PT(v)); +} + + +/* ---------------------------------------------------------------------------- + * Set vector data pointer + */ + +void N_VSetArrayPointer_Pthreads(realtype *v_data, N_Vector v) +{ + if (NV_LENGTH_PT(v) > 0) NV_DATA_PT(v) = v_data; + + return; +} + + +/* ---------------------------------------------------------------------------- + * Compute linear sum z[i] = a*x[i]+b*y[i] + */ + +void N_VLinearSum_Pthreads(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + realtype c; + N_Vector v1, v2; + booleantype test; + + if ((b == ONE) && (z == y)) { /* BLAS usage: axpy y <- ax+y */ + Vaxpy_Pthreads(a,x,y); + return; + } + + if ((a == ONE) && (z == x)) { /* BLAS usage: axpy x <- by+x */ + Vaxpy_Pthreads(b,y,x); + return; + } + + /* Case: a == b == 1.0 */ + + if ((a == ONE) && (b == ONE)) { + VSum_Pthreads(x, y, z); + return; + } + + /* Cases: (1) a == 1.0, b = -1.0, (2) a == -1.0, b == 1.0 */ + + if ((test = ((a == ONE) && (b == -ONE))) || ((a == -ONE) && (b == ONE))) { + v1 = test ? y : x; + v2 = test ? x : y; + VDiff_Pthreads(v2, v1, z); + return; + } + + /* Cases: (1) a == 1.0, b == other or 0.0, (2) a == other or 0.0, b == 1.0 */ + /* if a or b is 0.0, then user should have called N_VScale */ + + if ((test = (a == ONE)) || (b == ONE)) { + c = test ? b : a; + v1 = test ? y : x; + v2 = test ? x : y; + VLin1_Pthreads(c, v1, v2, z); + return; + } + + /* Cases: (1) a == -1.0, b != 1.0, (2) a != 1.0, b == -1.0 */ + + if ((test = (a == -ONE)) || (b == -ONE)) { + c = test ? b : a; + v1 = test ? y : x; + v2 = test ? x : y; + VLin2_Pthreads(c, v1, v2, z); + return; + } + + /* Case: a == b */ + /* catches case both a and b are 0.0 - user should have called N_VConst */ + + if (a == b) { + VScaleSum_Pthreads(a, x, y, z); + return; + } + + /* Case: a == -b */ + + if (a == -b) { + VScaleDiff_Pthreads(a, x, y, z); + return; + } + + /* Do all cases not handled above: + (1) a == other, b == 0.0 - user should have called N_VScale + (2) a == 0.0, b == other - user should have called N_VScale + (3) a,b == other, a !=b, a != -b */ + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = (pthread_t *) malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].c1 = a; + thread_data[i].c2 = b; + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].v2 = NV_DATA_PT(y); + thread_data[i].v3 = NV_DATA_PT(z); + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VLinearSum_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return; +} + +/* ---------------------------------------------------------------------------- + * Pthread companion function to N_VLinearSum + */ + +static void *N_VLinearSum_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype a, b; + realtype *xd, *yd, *zd; + Pthreads_Data *my_data; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + a = my_data->c1; + b = my_data->c2; + xd = my_data->v1; + yd = my_data->v2; + zd = my_data->v3; + + start = my_data->start; + end = my_data->end; + + /* compute linear sum */ + for (i = start; i < end; i++){ + zd[i] = (a*xd[i])+(b*yd[i]); + } + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Assigns constant value to all vector elements, z[i] = c + */ + +void N_VConst_Pthreads(realtype c, N_Vector z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(z); + nthreads = NV_NUM_THREADS_PT(z); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].c1 = c; + thread_data[i].v1 = NV_DATA_PT(z); + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VConst_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return; +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to N_VConst + */ + +static void *N_VConst_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype c; + realtype *zd; + Pthreads_Data *my_data; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + c = my_data->c1; + zd = my_data->v1; + + start = my_data->start; + end = my_data->end; + + /* assign constant values */ + for (i = start; i < end; i++) + zd[i] = c; + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Compute componentwise product z[i] = x[i]*y[i] + */ + +void N_VProd_Pthreads(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].v2 = NV_DATA_PT(y); + thread_data[i].v3 = NV_DATA_PT(z); + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VProd_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and exit */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return; +} + +/* ---------------------------------------------------------------------------- + * Pthread companion function to N_VProd + */ + +static void *N_VProd_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype *xd, *yd, *zd; + Pthreads_Data *my_data; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + xd = my_data->v1; + yd = my_data->v2; + zd = my_data->v3; + + start = my_data->start; + end = my_data->end; + + /* compute componentwise product */ + for (i = start; i < end; i++) + zd[i] = xd[i]*yd[i]; + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Compute componentwise division z[i] = x[i]/y[i] + */ + +void N_VDiv_Pthreads(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].v2 = NV_DATA_PT(y); + thread_data[i].v3 = NV_DATA_PT(z); + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VDiv_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return; +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to N_VDiv + */ + +static void *N_VDiv_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype *xd, *yd, *zd; + Pthreads_Data *my_data; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + xd = my_data->v1; + yd = my_data->v2; + zd = my_data->v3; + + start = my_data->start; + end = my_data->end; + + /* compute componentwise division */ + for (i = start; i < end; i++) + zd[i] = xd[i]/yd[i]; + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Compute scaler multiplication z[i] = c*x[i] + */ + +void N_VScale_Pthreads(realtype c, N_Vector x, N_Vector z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + if (z == x) { /* BLAS usage: scale x <- cx */ + VScaleBy_Pthreads(c, x); + return; + } + + if (c == ONE) { + VCopy_Pthreads(x, z); + } else if (c == -ONE) { + VNeg_Pthreads(x, z); + } else { + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].c1 = c; + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].v2 = NV_DATA_PT(z); + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VScale_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + } + + return; +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to N_VScale + */ + +static void *N_VScale_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype c; + realtype *xd, *zd; + Pthreads_Data *my_data; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + c = my_data->c1; + xd = my_data->v1; + zd = my_data->v2; + + start = my_data->start; + end = my_data->end; + + /* compute scaler multiplication */ + for (i = start; i < end; i++) + zd[i] = c*xd[i]; + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Compute absolute value of vector components z[i] = SUNRabs(x[i]) + */ + +void N_VAbs_Pthreads(N_Vector x, N_Vector z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].v2 = NV_DATA_PT(z); + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VAbs_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return; +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to N_VAbs + */ + +static void *N_VAbs_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype *xd, *zd; + Pthreads_Data *my_data; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + xd = my_data->v1; + zd = my_data->v2; + + start = my_data->start; + end = my_data->end; + + /* compute absolute value of components */ + for (i = start; i < end; i++) + zd[i] = SUNRabs(xd[i]); + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Compute componentwise inverse z[i] = 1 / x[i] + */ + +void N_VInv_Pthreads(N_Vector x, N_Vector z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].v2 = NV_DATA_PT(z); + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VInv_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return; +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to N_VInv + */ + +static void *N_VInv_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype *xd, *zd; + Pthreads_Data *my_data; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + xd = my_data->v1; + zd = my_data->v2; + + start = my_data->start; + end = my_data->end; + + /* compute componentwise inverse */ + for (i = start; i < end; i++) + zd[i] = ONE/xd[i]; + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Compute componentwise addition of a scaler to a vector z[i] = x[i] + b + */ + +void N_VAddConst_Pthreads(N_Vector x, realtype b, N_Vector z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].c1 = b; + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].v2 = NV_DATA_PT(z); + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VAddConst_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return; +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to N_VAddConst + */ + +static void *N_VAddConst_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype b; + realtype *xd, *zd; + Pthreads_Data *my_data; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + b = my_data->c1; + xd = my_data->v1; + zd = my_data->v2; + + start = my_data->start; + end = my_data->end; + + /* compute componentwise constant addition */ + for (i = start; i < end; i++) + zd[i] = xd[i] + b; + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Computes the dot product of two vectors, a = sum(x[i]*y[i]) + */ + +realtype N_VDotProd_Pthreads(N_Vector x, N_Vector y) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + pthread_mutex_t global_mutex; + realtype sum = ZERO; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + /* lock for reduction */ + pthread_mutex_init(&global_mutex, NULL); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].v2 = NV_DATA_PT(y); + thread_data[i].global_val = ∑ + thread_data[i].global_mutex = &global_mutex; + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VDotProd_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + pthread_mutex_destroy(&global_mutex); + free(threads); + free(thread_data); + + return(sum); +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to N_VDotProd + */ + +static void *N_VDotProd_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype *xd, *yd; + realtype local_sum, *global_sum; + Pthreads_Data *my_data; + pthread_mutex_t *global_mutex; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + xd = my_data->v1; + yd = my_data->v2; + + global_sum = my_data->global_val; + global_mutex = my_data->global_mutex; + + start = my_data->start; + end = my_data->end; + + /* compute dot product */ + local_sum = ZERO; + for (i = start; i < end; i++) + local_sum += xd[i] * yd[i]; + + /* update global sum */ + pthread_mutex_lock(global_mutex); + *global_sum += local_sum; + pthread_mutex_unlock(global_mutex); + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Computes max norm of the vector + */ + +realtype N_VMaxNorm_Pthreads(N_Vector x) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + pthread_mutex_t global_mutex; + realtype max = ZERO; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + /* lock for reduction */ + pthread_mutex_init(&global_mutex, NULL); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].global_val = &max; + thread_data[i].global_mutex = &global_mutex; + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VMaxNorm_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + pthread_mutex_destroy(&global_mutex); + free(threads); + free(thread_data); + + return(max); +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to N_VMaxNorm + */ + +static void *N_VMaxNorm_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype *xd; + realtype local_max, *global_max; + Pthreads_Data *my_data; + pthread_mutex_t *global_mutex; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + xd = my_data->v1; + + global_max = my_data->global_val; + global_mutex = my_data->global_mutex; + + start = my_data->start; + end = my_data->end; + + /* find local max */ + local_max = ZERO; + for (i = start; i < end; i++) + if (SUNRabs(xd[i]) > local_max) local_max = SUNRabs(xd[i]); + + /* update global max */ + pthread_mutex_lock(global_mutex); + if (local_max > *global_max) { + *global_max = local_max; + } + pthread_mutex_unlock(global_mutex); + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Computes weighted root mean square norm of a vector + */ + +realtype N_VWrmsNorm_Pthreads(N_Vector x, N_Vector w) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + pthread_mutex_t global_mutex; + realtype sum = ZERO; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + /* lock for reduction */ + pthread_mutex_init(&global_mutex, NULL); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].v2 = NV_DATA_PT(w); + thread_data[i].global_val = ∑ + 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]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + pthread_mutex_destroy(&global_mutex); + free(threads); + free(thread_data); + + return(SUNRsqrt(sum/N)); +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to N_VWrmsNorm + */ + +static void *N_VWrmsNorm_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype *xd, *wd; + realtype local_sum, *global_sum; + Pthreads_Data *my_data; + pthread_mutex_t *global_mutex; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + xd = my_data->v1; + wd = my_data->v2; + + global_sum = my_data->global_val; + global_mutex = my_data->global_mutex; + + start = my_data->start; + end = my_data->end; + + /* compute wrms norm */ + local_sum = ZERO; + for (i = start; i < end; i++) + local_sum += SUNSQR(xd[i] * wd[i]); + + /* update global sum */ + pthread_mutex_lock(global_mutex); + *global_sum += local_sum; + pthread_mutex_unlock(global_mutex); + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Computes weighted root mean square norm of a masked vector + */ + +realtype N_VWrmsNormMask_Pthreads(N_Vector x, N_Vector w, N_Vector id) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + pthread_mutex_t global_mutex; + realtype sum = ZERO; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + /* lock for reduction */ + pthread_mutex_init(&global_mutex, NULL); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].v2 = NV_DATA_PT(w); + thread_data[i].v3 = NV_DATA_PT(id); + thread_data[i].global_val = ∑ + 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]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + pthread_mutex_destroy(&global_mutex); + free(threads); + free(thread_data); + + return(SUNRsqrt(sum/N)); +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to N_VWrmsNormMask + */ + +static void *N_VWrmsNormMask_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype *xd, *wd, *idd; + realtype local_sum, *global_sum; + Pthreads_Data *my_data; + pthread_mutex_t *global_mutex; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + xd = my_data->v1; + wd = my_data->v2; + idd = my_data->v3; + + global_sum = my_data->global_val; + global_mutex = my_data->global_mutex; + + start = my_data->start; + end = my_data->end; + + /* compute wrms norm with mask */ + local_sum = ZERO; + for (i = start; i < end; i++) { + if (idd[i] > ZERO) + local_sum += SUNSQR(xd[i]*wd[i]); + } + + /* update global sum */ + pthread_mutex_lock(global_mutex); + *global_sum += local_sum; + pthread_mutex_unlock(global_mutex); + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Finds the minimun component of a vector + */ + +realtype N_VMin_Pthreads(N_Vector x) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + pthread_mutex_t global_mutex; + realtype min; + + /* initialize global min */ + min = NV_Ith_PT(x,0); + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + /* lock for reduction */ + pthread_mutex_init(&global_mutex, NULL); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].global_val = &min; + thread_data[i].global_mutex = &global_mutex; + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VMin_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + pthread_mutex_destroy(&global_mutex); + free(threads); + free(thread_data); + + return(min); +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to N_VMin + */ + +static void *N_VMin_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype *xd; + realtype local_min, *global_min; + Pthreads_Data *my_data; + pthread_mutex_t *global_mutex; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + xd = my_data->v1; + + global_min = my_data->global_val; + global_mutex = my_data->global_mutex; + + start = my_data->start; + end = my_data->end; + + /* find local min */ + local_min = *global_min; + for (i = start; i < end; i++) { + if (xd[i] < local_min) + local_min = xd[i]; + } + + /* update global min */ + pthread_mutex_lock(global_mutex); + if (local_min < *global_min) + *global_min = local_min; + pthread_mutex_unlock(global_mutex); + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Computes weighted L2 norm of a vector + */ + +realtype N_VWL2Norm_Pthreads(N_Vector x, N_Vector w) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + pthread_mutex_t global_mutex; + realtype sum = ZERO; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + /* lock for reduction */ + pthread_mutex_init(&global_mutex, NULL); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].v2 = NV_DATA_PT(w); + thread_data[i].global_val = ∑ + thread_data[i].global_mutex = &global_mutex; + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VWL2Norm_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + pthread_mutex_destroy(&global_mutex); + free(threads); + free(thread_data); + + return(SUNRsqrt(sum)); +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to N_VWL2Norm + */ + +static void *N_VWL2Norm_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype *xd, *wd; + realtype local_sum, *global_sum; + Pthreads_Data *my_data; + pthread_mutex_t *global_mutex; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + xd = my_data->v1; + wd = my_data->v2; + + global_sum = my_data->global_val; + global_mutex = my_data->global_mutex; + + start = my_data->start; + end = my_data->end; + + /* compute WL2 norm */ + local_sum = ZERO; + for (i = start; i < end; i++) + local_sum += SUNSQR(xd[i]*wd[i]); + + /* update global sum */ + pthread_mutex_lock(global_mutex); + *global_sum += local_sum; + pthread_mutex_unlock(global_mutex); + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Computes L1 norm of a vector + */ + +realtype N_VL1Norm_Pthreads(N_Vector x) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + pthread_mutex_t global_mutex; + realtype sum = ZERO; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + /* lock for reduction */ + pthread_mutex_init(&global_mutex, NULL); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].global_val = ∑ + thread_data[i].global_mutex = &global_mutex; + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VL1Norm_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + pthread_mutex_destroy(&global_mutex); + free(threads); + free(thread_data); + + return(sum); +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to N_VL1Norm + */ + +static void *N_VL1Norm_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype *xd; + realtype local_sum, *global_sum; + Pthreads_Data *my_data; + pthread_mutex_t *global_mutex; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + xd = my_data->v1; + + global_sum = my_data->global_val; + global_mutex = my_data->global_mutex; + + start = my_data->start; + end = my_data->end; + + /* compute L1 norm */ + local_sum = ZERO; + for (i = start; i < end; i++) + local_sum += SUNRabs(xd[i]); + + /* update global sum */ + pthread_mutex_lock(global_mutex); + *global_sum += local_sum; + pthread_mutex_unlock(global_mutex); + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Compare vector component values to a scaler + */ + +void N_VCompare_Pthreads(realtype c, N_Vector x, N_Vector z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].c1 = c; + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].v2 = NV_DATA_PT(z); + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VCompare_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return; +} + +/* ---------------------------------------------------------------------------- + * Pthread companion function to N_VCompare + */ + +static void *N_VCompare_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype c; + realtype *xd, *zd; + Pthreads_Data *my_data; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + c = my_data->c1; + xd = my_data->v1; + zd = my_data->v2; + + start = my_data->start; + end = my_data->end; + + /* compare component to scaler */ + for (i = start; i < end; i++) + zd[i] = (SUNRabs(xd[i]) >= c) ? ONE : ZERO; + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Compute componentwise inverse z[i] = ONE/x[i] and check if x[i] == ZERO + */ + +booleantype N_VInvTest_Pthreads(N_Vector x, N_Vector z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + realtype val = ZERO; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].v2 = NV_DATA_PT(z); + thread_data[i].global_val = &val; + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VInvTest_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + if (val > ZERO) + return (SUNFALSE); + else + return (SUNTRUE); +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to N_VInvTest + */ + +static void *N_VInvTest_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype *xd, *zd; + realtype local_val, *global_val; + Pthreads_Data *my_data; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + xd = my_data->v1; + zd = my_data->v2; + + global_val = my_data->global_val; + + start = my_data->start; + end = my_data->end; + + /* compute inverse with check for divide by ZERO */ + local_val = ZERO; + for (i = start; i < end; i++) { + if (xd[i] == ZERO) + local_val = ONE; + else + zd[i] = ONE/xd[i]; + } + + /* update global val */ + if (local_val > ZERO) { + *global_val = local_val; + } + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Compute constraint mask of a vector + */ + +booleantype N_VConstrMask_Pthreads(N_Vector c, N_Vector x, N_Vector m) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + realtype val = ZERO; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].v1 = NV_DATA_PT(c); + thread_data[i].v2 = NV_DATA_PT(x); + thread_data[i].v3 = NV_DATA_PT(m); + thread_data[i].global_val = &val; + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VConstrMask_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + if (val > ZERO) + return(SUNFALSE); + else + return(SUNTRUE); +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to N_VConstrMask + */ + +static void *N_VConstrMask_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype *cd, *xd, *md; + realtype local_val, *global_val; + Pthreads_Data *my_data; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + cd = my_data->v1; + xd = my_data->v2; + md = my_data->v3; + + global_val = my_data->global_val; + + start = my_data->start; + end = my_data->end; + + /* compute constraint mask */ + local_val = ZERO; + for (i = start; i < end; i++) { + md[i] = ZERO; + + /* Continue if no constraints were set for the variable */ + if (cd[i] == ZERO) + continue; + + /* Check if a set constraint has been violated */ + if ((SUNRabs(cd[i]) > ONEPT5 && xd[i]*cd[i] <= ZERO) || + (SUNRabs(cd[i]) > HALF && xd[i]*cd[i] < ZERO)) { + local_val = md[i] = ONE; + } + } + + /* update global val */ + if (local_val > ZERO) { + *global_val = local_val; + } + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Compute minimum componentwise quotient + */ + +realtype N_VMinQuotient_Pthreads(N_Vector num, N_Vector denom) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + pthread_mutex_t global_mutex; + realtype min = BIG_REAL; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(num); + nthreads = NV_NUM_THREADS_PT(num); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + /* lock for reduction */ + pthread_mutex_init(&global_mutex, NULL); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].v1 = NV_DATA_PT(num); + thread_data[i].v2 = NV_DATA_PT(denom); + thread_data[i].global_val = &min; + thread_data[i].global_mutex = &global_mutex; + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VMinQuotient_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + pthread_mutex_destroy(&global_mutex); + free(threads); + free(thread_data); + + return(min); +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to N_VConstrMask + */ + +static void *N_VMinQuotient_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype *nd, *dd; + realtype local_min, *global_min; + Pthreads_Data *my_data; + pthread_mutex_t *global_mutex; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + nd = my_data->v1; + dd = my_data->v2; + + global_min = my_data->global_val; + global_mutex = my_data->global_mutex; + + start = my_data->start; + end = my_data->end; + + /* compute minimum quotient */ + local_min = BIG_REAL; + for (i = start; i < end; i++) { + if (dd[i] == ZERO) + continue; + local_min = SUNMIN(local_min, nd[i]/dd[i]); + } + + /* update global min */ + pthread_mutex_lock(global_mutex); + if (local_min < *global_min) + *global_min = local_min; + pthread_mutex_unlock(global_mutex); + + /* exit */ + pthread_exit(NULL); +} + + +/* + * ----------------------------------------------------------------------------- + * fused vector operations + * ----------------------------------------------------------------------------- + */ + + +/* ----------------------------------------------------------------------------- + * Compute the linear combination z = c[i]*X[i] + */ + +int N_VLinearCombination_Pthreads(int nvec, realtype* c, N_Vector* X, N_Vector z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VScale */ + if (nvec == 1) { + N_VScale_Pthreads(c[0], X[0], z); + return(0); + } + + /* should have called N_VLinearSum */ + if (nvec == 2) { + N_VLinearSum_Pthreads(c[0], X[0], c[1], X[1], z); + return(0); + } + + /* get vector length and data array */ + N = NV_LENGTH_PT(z); + nthreads = NV_NUM_THREADS_PT(z); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].nvec = nvec; + thread_data[i].cvals = c; + thread_data[i].Y1 = X; + thread_data[i].x1 = z; + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VLinearCombination_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return(0); +} + + +/* ----------------------------------------------------------------------------- + * Pthread companion function to N_VLinearCombination + */ + +static void *N_VLinearCombination_PT(void *thread_data) +{ + Pthreads_Data *my_data; + sunindextype j, start, end; + + int i; + realtype* c=NULL; + realtype* xd=NULL; + realtype* zd=NULL; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + start = my_data->start; + end = my_data->end; + + c = my_data->cvals; + zd = NV_DATA_PT(my_data->x1); + + /* + * X[0] += c[i]*X[i], i = 1,...,nvec-1 + */ + if ((my_data->Y1[0] == my_data->x1) && (c[0] == ONE)) { + for (i=1; i<my_data->nvec; i++) { + xd = NV_DATA_PT(my_data->Y1[i]); + for (j=start; j<end; j++) { + zd[j] += c[i] * xd[j]; + } + } + pthread_exit(NULL); + } + + /* + * X[0] = c[0] * X[0] + sum{ c[i] * X[i] }, i = 1,...,nvec-1 + */ + if ((my_data->Y1[0] == my_data->x1)) { + for (j=start; j<end; j++) { + zd[j] *= c[0]; + } + for (i=1; i<my_data->nvec; i++) { + xd = NV_DATA_PT(my_data->Y1[i]); + for (j=start; j<end; j++) { + zd[j] += c[i] * xd[j]; + } + } + pthread_exit(NULL); + } + + /* + * z = sum{ c[i] * X[i] }, i = 0,...,nvec-1 + */ + xd = NV_DATA_PT(my_data->Y1[0]); + for (j=start; j<end; j++) { + zd[j] = c[0] * xd[j]; + } + for (i=1; i<my_data->nvec; i++) { + xd = NV_DATA_PT(my_data->Y1[i]); + for (j=start; j<end; j++) { + zd[j] += c[i] * xd[j]; + } + } + pthread_exit(NULL); +} + + +/* ----------------------------------------------------------------------------- + * Compute multiple linear sums Z[i] = Y[i] + a*x + */ + +int N_VScaleAddMulti_Pthreads(int nvec, realtype* a, N_Vector x, N_Vector* Y, N_Vector* Z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VLinearSum */ + if (nvec == 1) { + N_VLinearSum_Pthreads(a[0], x, ONE, Y[0], Z[0]); + return(0); + } + + /* get vector length and data array */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].nvec = nvec; + thread_data[i].cvals = a; + thread_data[i].x1 = x; + thread_data[i].Y1 = Y; + thread_data[i].Y2 = Z; + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VScaleAddMulti_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return(0); +} + + +/* ----------------------------------------------------------------------------- + * Pthread companion function to N_VScaleAddMulti + */ + +static void *N_VScaleAddMulti_PT(void *thread_data) +{ + Pthreads_Data *my_data; + sunindextype j, start, end; + + int i; + realtype* a=NULL; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + start = my_data->start; + end = my_data->end; + + a = my_data->cvals; + xd = NV_DATA_PT(my_data->x1); + + /* + * Y[i][j] += a[i] * x[j] + */ + if (my_data->Y1 == my_data->Y2) { + for (i=0; i<my_data->nvec; i++) { + yd = NV_DATA_PT(my_data->Y1[i]); + for (j=start; j<end; j++) { + yd[j] += a[i] * xd[j]; + } + } + pthread_exit(NULL); + } + + /* + * Z[i][j] = Y[i][j] + a[i] * x[j] + */ + for (i=0; i<my_data->nvec; i++) { + yd = NV_DATA_PT(my_data->Y1[i]); + zd = NV_DATA_PT(my_data->Y2[i]); + for (j=start; j<end; j++) { + zd[j] = a[i] * xd[j] + yd[j]; + } + } + pthread_exit(NULL); +} + + +/* ----------------------------------------------------------------------------- + * Compute the dot product of a vector with multiple vectors, a[i] = sum(x*Y[i]) + */ + +int N_VDotProdMulti_Pthreads(int nvec, N_Vector x, N_Vector* Y, realtype* dotprods) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + pthread_mutex_t global_mutex; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VDotProd */ + if (nvec == 1) { + dotprods[0] = N_VDotProd_Pthreads(x, Y[0]); + return(0); + } + + /* initialize output array */ + for (i=0; i<nvec; i++) + dotprods[i] = ZERO; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + /* lock for reduction */ + pthread_mutex_init(&global_mutex, NULL); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].nvec = nvec; + thread_data[i].x1 = x; + thread_data[i].Y1 = Y; + thread_data[i].cvals = dotprods; + + thread_data[i].global_mutex = &global_mutex; + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VDotProdMulti_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + pthread_mutex_destroy(&global_mutex); + free(threads); + free(thread_data); + + return(0); +} + + +/* ----------------------------------------------------------------------------- + * Pthread companion function to N_VDotProdMulti + */ + +static void *N_VDotProdMulti_PT(void *thread_data) +{ + Pthreads_Data *my_data; + sunindextype j, start, end; + pthread_mutex_t *lock; + + int i; + realtype sum; + realtype* dotprods=NULL; + realtype* xd=NULL; + realtype* yd=NULL; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + start = my_data->start; + end = my_data->end; + lock = my_data->global_mutex; + + xd = NV_DATA_PT(my_data->x1); + dotprods = my_data->cvals; + + /* compute multiple dot products */ + for (i=0; i<my_data->nvec; i++) { + yd = NV_DATA_PT(my_data->Y1[i]); + sum = ZERO; + for (j=start; j<end; j++) { + sum += xd[j] * yd[j]; + } + /* update global sum */ + pthread_mutex_lock(lock); + dotprods[i] += sum; + pthread_mutex_unlock(lock); + } + + /* exit */ + pthread_exit(NULL); +} + + +/* + * ----------------------------------------------------------------------------- + * vector array operations + * ----------------------------------------------------------------------------- + */ + + +/* ----------------------------------------------------------------------------- + * Compute multiple linear sums Z[i] = a*X[i] + b*Y[i] + */ + +int N_VLinearSumVectorArray_Pthreads(int nvec, realtype a, N_Vector* X, + realtype b, N_Vector* Y, N_Vector* Z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + realtype c; + N_Vector* V1; + N_Vector* V2; + booleantype test; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VLinearSum */ + if (nvec == 1) { + N_VLinearSum_Pthreads(a, X[0], b, Y[0], Z[0]); + return(0); + } + + /* BLAS usage: axpy y <- ax+y */ + if ((b == ONE) && (Z == Y)) + return(VaxpyVectorArray_Pthreads(nvec, a, X, Y)); + + /* BLAS usage: axpy x <- by+x */ + if ((a == ONE) && (Z == X)) + return(VaxpyVectorArray_Pthreads(nvec, b, Y, X)); + + /* Case: a == b == 1.0 */ + if ((a == ONE) && (b == ONE)) + return(VSumVectorArray_Pthreads(nvec, X, Y, Z)); + + /* Cases: */ + /* (1) a == 1.0, b = -1.0, */ + /* (2) a == -1.0, b == 1.0 */ + if ((test = ((a == ONE) && (b == -ONE))) || ((a == -ONE) && (b == ONE))) { + V1 = test ? Y : X; + V2 = test ? X : Y; + return(VDiffVectorArray_Pthreads(nvec, V2, V1, Z)); + } + + /* Cases: */ + /* (1) a == 1.0, b == other or 0.0, */ + /* (2) a == other or 0.0, b == 1.0 */ + /* if a or b is 0.0, then user should have called N_VScale */ + if ((test = (a == ONE)) || (b == ONE)) { + c = test ? b : a; + V1 = test ? Y : X; + V2 = test ? X : Y; + return(VLin1VectorArray_Pthreads(nvec, c, V1, V2, Z)); + } + + /* Cases: */ + /* (1) a == -1.0, b != 1.0, */ + /* (2) a != 1.0, b == -1.0 */ + if ((test = (a == -ONE)) || (b == -ONE)) { + c = test ? b : a; + V1 = test ? Y : X; + V2 = test ? X : Y; + return(VLin2VectorArray_Pthreads(nvec, c, V1, V2, Z)); + } + + /* Case: a == b */ + /* catches case both a and b are 0.0 - user should have called N_VConst */ + if (a == b) + return(VScaleSumVectorArray_Pthreads(nvec, a, X, Y, Z)); + + /* Case: a == -b */ + if (a == -b) + return(VScaleDiffVectorArray_Pthreads(nvec, a, X, Y, Z)); + + /* Do all cases not handled above: */ + /* (1) a == other, b == 0.0 - user should have called N_VScale */ + /* (2) a == 0.0, b == other - user should have called N_VScale */ + /* (3) a,b == other, a !=b, a != -b */ + + /* get vector length and data array */ + N = NV_LENGTH_PT(Z[0]); + nthreads = NV_NUM_THREADS_PT(Z[0]); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].nvec = nvec; + thread_data[i].c1 = a; + thread_data[i].c2 = b; + thread_data[i].Y1 = X; + thread_data[i].Y2 = Y; + thread_data[i].Y3 = Z; + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VLinearSumVectorArray_PT, + (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return(0); +} + + +/* ----------------------------------------------------------------------------- + * Pthread companion function to N_VLinearSumVectorArray + */ + +static void *N_VLinearSumVectorArray_PT(void *thread_data) +{ + Pthreads_Data *my_data; + sunindextype j, start, end; + + int i; + realtype a, b; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + start = my_data->start; + end = my_data->end; + + a = my_data->c1; + b = my_data->c2; + + /* compute linear sum for each vector pair in vector arrays */ + for (i=0; i<my_data->nvec; i++) { + xd = NV_DATA_PT(my_data->Y1[i]); + yd = NV_DATA_PT(my_data->Y2[i]); + zd = NV_DATA_PT(my_data->Y3[i]); + for (j=start; j<end; j++) { + zd[j] = a * xd[j] + b * yd[j]; + } + } + + /* exit */ + pthread_exit(NULL); +} + + +/* ----------------------------------------------------------------------------- + * Scale multiple vectors Z[i] = c[i]*X[i] + */ + +int N_VScaleVectorArray_Pthreads(int nvec, realtype* c, N_Vector* X, N_Vector* Z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VScale */ + if (nvec == 1) { + N_VScale_Pthreads(c[0], X[0], Z[0]); + return(0); + } + + /* get vector length and data array */ + N = NV_LENGTH_PT(Z[0]); + nthreads = NV_NUM_THREADS_PT(Z[0]); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].nvec = nvec; + thread_data[i].cvals = c; + thread_data[i].Y1 = X; + thread_data[i].Y2 = Z; + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VScaleVectorArray_PT, + (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return(0); +} + + +/* ----------------------------------------------------------------------------- + * Pthread companion function to N_VScaleVectorArray + */ + +static void *N_VScaleVectorArray_PT(void *thread_data) +{ + Pthreads_Data *my_data; + sunindextype j, start, end; + + int i; + realtype* c; + realtype* xd=NULL; + realtype* zd=NULL; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + start = my_data->start; + end = my_data->end; + + c = my_data->cvals; + + /* + * X[i] *= c[i] + */ + if (my_data->Y1 == my_data->Y2) { + for (i=0; i<my_data->nvec; i++) { + xd = NV_DATA_PT(my_data->Y1[i]); + for (j=start; j<end; j++) { + xd[j] *= c[i]; + } + } + pthread_exit(NULL); + } + + /* + * Z[i] = c[i] * X[i] + */ + for (i=0; i<my_data->nvec; i++) { + xd = NV_DATA_PT(my_data->Y1[i]); + zd = NV_DATA_PT(my_data->Y2[i]); + for (j=start; j<end; j++) { + zd[j] = c[i] * xd[j]; + } + } + pthread_exit(NULL); +} + + +/* ----------------------------------------------------------------------------- + * Set multiple vectors to a constant value Z[i] = c + */ + +int N_VConstVectorArray_Pthreads(int nvec, realtype c, N_Vector* Z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VConst */ + if (nvec == 1) { + N_VConst_Pthreads(c, Z[0]); + return(0); + } + + /* get vector length and data array */ + N = NV_LENGTH_PT(Z[0]); + nthreads = NV_NUM_THREADS_PT(Z[0]); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].nvec = nvec; + thread_data[i].c1 = c; + thread_data[i].Y1 = Z; + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VConstVectorArray_PT, + (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return(0); +} + + +/* ----------------------------------------------------------------------------- + * Pthread companion function to N_VConstVectorArray + */ + +static void *N_VConstVectorArray_PT(void *thread_data) +{ + Pthreads_Data *my_data; + sunindextype j, start, end; + + int i; + realtype* zd=NULL; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + start = my_data->start; + end = my_data->end; + + /* set each vector in the vector array to a constant */ + for (i=0; i<my_data->nvec; i++) { + zd = NV_DATA_PT(my_data->Y1[i]); + for (j=start; j<end; j++) { + zd[j] = my_data->c1; + } + } + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Compute the weighted root mean square norm of multiple vectors + */ + +int N_VWrmsNormVectorArray_Pthreads(int nvec, N_Vector* X, N_Vector* W, realtype* nrm) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + pthread_mutex_t global_mutex; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VWrmsNorm */ + if (nvec == 1) { + nrm[0] = N_VWrmsNorm_Pthreads(X[0], W[0]); + return(0); + } + + /* initialize output array */ + for (i=0; i<nvec; i++) + nrm[i] = ZERO; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(X[0]); + nthreads = NV_NUM_THREADS_PT(X[0]); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + /* lock for reduction */ + pthread_mutex_init(&global_mutex, NULL); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].nvec = nvec; + thread_data[i].Y1 = X; + thread_data[i].Y2 = W; + thread_data[i].cvals = nrm; + + thread_data[i].global_mutex = &global_mutex; + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VWrmsNormVectorArray_PT, + (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* finalize wrms calculation */ + for (i=0; i<nvec; i++) + nrm[i] = SUNRsqrt(nrm[i]/N); + + /* clean up and return */ + pthread_attr_destroy(&attr); + pthread_mutex_destroy(&global_mutex); + free(threads); + free(thread_data); + + return(0); +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to N_VWrmsNormVectorArray + */ + +static void *N_VWrmsNormVectorArray_PT(void *thread_data) +{ + Pthreads_Data *my_data; + sunindextype j, start, end; + pthread_mutex_t *lock; + + int i; + realtype sum; + realtype* nrm=NULL; + realtype* xd=NULL; + realtype* wd=NULL; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + start = my_data->start; + end = my_data->end; + lock = my_data->global_mutex; + + nrm = my_data->cvals; + + /* compute the WRMS norm for each vector in the vector array */ + for (i=0; i<my_data->nvec; i++) { + xd = NV_DATA_PT(my_data->Y1[i]); + wd = NV_DATA_PT(my_data->Y2[i]); + sum = ZERO; + for (j=start; j<end; j++) { + sum += SUNSQR(xd[j] * wd[j]); + } + /* update global sum */ + pthread_mutex_lock(lock); + nrm[i] += sum; + pthread_mutex_unlock(lock); + } + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Compute the weighted root mean square norm of multiple vectors + */ + +int N_VWrmsNormMaskVectorArray_Pthreads(int nvec, N_Vector* X, N_Vector* W, + N_Vector id, realtype* nrm) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + pthread_mutex_t global_mutex; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VWrmsNorm */ + if (nvec == 1) { + nrm[0] = N_VWrmsNormMask_Pthreads(X[0], W[0], id); + return(0); + } + + /* initialize output array */ + for (i=0; i<nvec; i++) + nrm[i] = ZERO; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(X[0]); + nthreads = NV_NUM_THREADS_PT(X[0]); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + /* lock for reduction */ + pthread_mutex_init(&global_mutex, NULL); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].nvec = nvec; + thread_data[i].Y1 = X; + thread_data[i].Y2 = W; + thread_data[i].x1 = id; + thread_data[i].cvals = nrm; + + thread_data[i].global_mutex = &global_mutex; + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VWrmsNormMaskVectorArray_PT, + (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* finalize wrms calculation */ + for (i=0; i<nvec; i++) + nrm[i] = SUNRsqrt(nrm[i]/N); + + /* clean up and return */ + pthread_attr_destroy(&attr); + pthread_mutex_destroy(&global_mutex); + free(threads); + free(thread_data); + + return(0); +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to N_VWrmsNormVectorArray + */ + +static void *N_VWrmsNormMaskVectorArray_PT(void *thread_data) +{ + Pthreads_Data *my_data; + sunindextype j, start, end; + pthread_mutex_t *lock; + + int i; + realtype sum; + realtype* nrm=NULL; + realtype* xd=NULL; + realtype* wd=NULL; + realtype* idd=NULL; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + start = my_data->start; + end = my_data->end; + lock = my_data->global_mutex; + + nrm = my_data->cvals; + idd = NV_DATA_PT(my_data->x1); + + /* compute the WRMS norm for each vector in the vector array */ + for (i=0; i<my_data->nvec; i++) { + xd = NV_DATA_PT(my_data->Y1[i]); + wd = NV_DATA_PT(my_data->Y2[i]); + sum = ZERO; + for (j=start; j<end; j++) { + if (idd[j] > ZERO) + sum += SUNSQR(xd[j] * wd[j]); + } + /* update global sum */ + pthread_mutex_lock(lock); + nrm[i] += sum; + pthread_mutex_unlock(lock); + } + + /* exit */ + pthread_exit(NULL); +} + + +/* ----------------------------------------------------------------------------- + * Scale and add a vector to multiple vectors Z = Y + a*X + */ + +int N_VScaleAddMultiVectorArray_Pthreads(int nvec, int nsum, realtype* a, + N_Vector* X, N_Vector** Y, N_Vector** Z) +{ + sunindextype N; + int i, j, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + int retval; + N_Vector* YY; + N_Vector* ZZ; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + if (nsum < 1) return(-1); + + /* --------------------------- + * Special cases for nvec == 1 + * --------------------------- */ + + if (nvec == 1) { + + /* should have called N_VLinearSum */ + if (nsum == 1) { + N_VLinearSum_Pthreads(a[0], X[0], ONE, Y[0][0], Z[0][0]); + return(0); + } + + /* should have called N_VScaleAddMulti */ + YY = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + ZZ = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + + for (j=0; j<nsum; j++) { + YY[j] = Y[j][0]; + ZZ[j] = Z[j][0]; + } + + retval = N_VScaleAddMulti_Pthreads(nsum, a, X[0], YY, ZZ); + + free(YY); + free(ZZ); + return(retval); + } + + /* -------------------------- + * Special cases for nvec > 1 + * -------------------------- */ + + /* should have called N_VLinearSumVectorArray */ + if (nsum == 1) { + retval = N_VLinearSumVectorArray_Pthreads(nvec, a[0], X, ONE, Y[0], Z[0]); + return(retval); + } + + /* ---------------------------- + * Compute multiple linear sums + * ---------------------------- */ + + /* get vector length and data array */ + N = NV_LENGTH_PT(X[0]); + nthreads = NV_NUM_THREADS_PT(X[0]); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].nvec = nvec; + thread_data[i].nsum = nsum; + thread_data[i].cvals = a; + thread_data[i].Y1 = X; + thread_data[i].ZZ1 = Y; + thread_data[i].ZZ2 = Z; + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VScaleAddMultiVectorArray_PT, + (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return(0); +} + + +/* ----------------------------------------------------------------------------- + * Pthread companion function to N_VScaleAddMultiVectorArray + */ + +static void *N_VScaleAddMultiVectorArray_PT(void *thread_data) +{ + Pthreads_Data *my_data; + sunindextype k, start, end; + + int i, j; + realtype* a=NULL; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + start = my_data->start; + end = my_data->end; + + a = my_data->cvals; + + /* + * Y[i][j] += a[i] * x[j] + */ + if (my_data->ZZ1 == my_data->ZZ2) { + for (i=0; i<my_data->nvec; i++) { + xd = NV_DATA_PT(my_data->Y1[i]); + for (j=0; j<my_data->nsum; j++){ + yd = NV_DATA_PT(my_data->ZZ1[j][i]); + for (k=start; k<end; k++) { + yd[k] += a[j] * xd[k]; + } + } + } + pthread_exit(NULL); + } + + /* + * Z[i][j] = Y[i][j] + a[i] * x[j] + */ + for (i=0; i<my_data->nvec; i++) { + xd = NV_DATA_PT(my_data->Y1[i]); + for (j=0; j<my_data->nsum; j++){ + yd = NV_DATA_PT(my_data->ZZ1[j][i]); + zd = NV_DATA_PT(my_data->ZZ2[j][i]); + for (k=start; k<end; k++) { + zd[k] = a[j] * xd[k] + yd[k]; + } + } + } + pthread_exit(NULL); +} + + +/* ----------------------------------------------------------------------------- + * Compute a linear combination for multiple vectors + */ + +int N_VLinearCombinationVectorArray_Pthreads(int nvec, int nsum, realtype* c, + N_Vector** X, N_Vector* Z) +{ + sunindextype N; + int i, j, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + int retval; + realtype* ctmp; + N_Vector* Y; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + if (nsum < 1) return(-1); + + /* --------------------------- + * Special cases for nvec == 1 + * --------------------------- */ + + if (nvec == 1) { + + /* should have called N_VScale */ + if (nsum == 1) { + N_VScale_Pthreads(c[0], X[0][0], Z[0]); + return(0); + } + + /* should have called N_VLinearSum */ + if (nsum == 2) { + N_VLinearSum_Pthreads(c[0], X[0][0], c[1], X[1][0], Z[0]); + return(0); + } + + /* should have called N_VLinearCombination */ + Y = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + + for (i=0; i<nsum; i++) { + Y[i] = X[i][0]; + } + + retval = N_VLinearCombination_Pthreads(nsum, c, Y, Z[0]); + + free(Y); + return(retval); + } + + /* -------------------------- + * Special cases for nvec > 1 + * -------------------------- */ + + /* should have called N_VScaleVectorArray */ + if (nsum == 1) { + + ctmp = (realtype*) malloc(nvec * sizeof(realtype)); + + for (j=0; j<nvec; j++) { + ctmp[j] = c[0]; + } + + retval = N_VScaleVectorArray_Pthreads(nvec, ctmp, X[0], Z); + + free(ctmp); + return(retval); + } + + /* should have called N_VLinearSumVectorArray */ + if (nsum == 2) { + retval = N_VLinearSumVectorArray_Pthreads(nvec, c[0], X[0], c[1], X[1], Z); + return(retval); + } + + /* -------------------------- + * Compute linear combination + * -------------------------- */ + + /* get vector length and data array */ + N = NV_LENGTH_PT(Z[0]); + nthreads = NV_NUM_THREADS_PT(Z[0]); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].nvec = nvec; + thread_data[i].nsum = nsum; + thread_data[i].cvals = c; + thread_data[i].ZZ1 = X; + thread_data[i].Y1 = Z; + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, N_VLinearCombinationVectorArray_PT, + (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return(0); +} + + +/* ----------------------------------------------------------------------------- + * Pthread companion function to N_VLinearCombinationVectorArray + */ + +static void *N_VLinearCombinationVectorArray_PT(void *thread_data) +{ + Pthreads_Data *my_data; + sunindextype k, start, end; + + int i; /* vector arrays index in summation [0,nsum) */ + int j; /* vector index in vector array [0,nvec) */ + realtype* c=NULL; + realtype* zd=NULL; + realtype* xd=NULL; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + start = my_data->start; + end = my_data->end; + + c = my_data->cvals; + + /* + * X[0][j] += c[i]*X[i][j], i = 1,...,nvec-1 + */ + if ((my_data->ZZ1[0] == my_data->Y1) && (c[0] == ONE)) { + for (j=0; j<my_data->nvec; j++) { + zd = NV_DATA_PT(my_data->Y1[j]); + for (i=1; i<my_data->nsum; i++) { + xd = NV_DATA_PT(my_data->ZZ1[i][j]); + for (k=start; k<end; k++) { + zd[k] += c[i] * xd[k]; + } + } + } + pthread_exit(NULL); + } + + /* + * X[0][j] = c[0] * X[0][j] + sum{ c[i] * X[i][j] }, i = 1,...,nvec-1 + */ + if (my_data->ZZ1[0] == my_data->Y1) { + for (j=0; j<my_data->nvec; j++) { + zd = NV_DATA_PT(my_data->Y1[j]); + for (k=start; k<end; k++) { + zd[k] *= c[0]; + } + for (i=1; i<my_data->nsum; i++) { + xd = NV_DATA_PT(my_data->ZZ1[i][j]); + for (k=start; k<end; k++) { + zd[k] += c[i] * xd[k]; + } + } + } + pthread_exit(NULL); + } + + /* + * Z[j] = sum{ c[i] * X[i][j] }, i = 0,...,nvec-1 + */ + for (j=0; j<my_data->nvec; j++) { + xd = NV_DATA_PT(my_data->ZZ1[0][j]); + zd = NV_DATA_PT(my_data->Y1[j]); + for (k=start; k<end; k++) { + zd[k] = c[0] * xd[k]; + } + for (i=1; i<my_data->nsum; i++) { + xd = NV_DATA_PT(my_data->ZZ1[i][j]); + for (k=start; k<end; k++) { + zd[k] += c[i] * xd[k]; + } + } + } + pthread_exit(NULL); +} + + +/* + * ----------------------------------------------------------------- + * private functions for special cases of vector operations + * ----------------------------------------------------------------- + */ + + +/* ---------------------------------------------------------------------------- + * Copy vector components into second vector + */ + +static void VCopy_Pthreads(N_Vector x, N_Vector z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].v2 = NV_DATA_PT(z); + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, VCopy_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return; +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to VCopy + */ + +static void *VCopy_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype *xd, *zd; + Pthreads_Data *my_data; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + xd = my_data->v1; + zd = my_data->v2; + + start = my_data->start; + end = my_data->end; + + /* copy vector components */ + for (i = start; i < end; i++) + zd[i] = xd[i]; + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Compute vector sum + */ + +static void VSum_Pthreads(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].v2 = NV_DATA_PT(y); + thread_data[i].v3 = NV_DATA_PT(z); + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, VSum_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return; +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to VSum + */ + +static void *VSum_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype *xd, *yd, *zd; + Pthreads_Data *my_data; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + xd = my_data->v1; + yd = my_data->v2; + zd = my_data->v3; + + start = my_data->start; + end = my_data->end; + + /* compute vector sum */ + for (i = start; i < end; i++) + zd[i] = xd[i] + yd[i]; + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Compute vector difference + */ + +static void VDiff_Pthreads(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].v2 = NV_DATA_PT(y); + thread_data[i].v3 = NV_DATA_PT(z); + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, VDiff_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return; +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to VDiff + */ + +static void *VDiff_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype *xd, *yd, *zd; + Pthreads_Data *my_data; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + xd = my_data->v1; + yd = my_data->v2; + zd = my_data->v3; + + start = my_data->start; + end = my_data->end; + + /* compute vector difference */ + for (i = start; i < end; i++) + zd[i] = xd[i] - yd[i]; + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Compute the negative of a vector + */ + +static void VNeg_Pthreads(N_Vector x, N_Vector z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].v2 = NV_DATA_PT(z); + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, VNeg_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return; +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to VNeg + */ + +static void *VNeg_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype *xd, *zd; + Pthreads_Data *my_data; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + xd = my_data->v1; + zd = my_data->v2; + + start = my_data->start; + end = my_data->end; + + /* compute negative of vector */ + for (i = start; i < end; i++) + zd[i] = -xd[i]; + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Compute scaled vector sum + */ + +static void VScaleSum_Pthreads(realtype c, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].c1 = c; + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].v2 = NV_DATA_PT(y); + thread_data[i].v3 = NV_DATA_PT(z); + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, VScaleSum_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return; +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to VScaleSum + */ + +static void *VScaleSum_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype c; + realtype *xd, *yd, *zd; + Pthreads_Data *my_data; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + c = my_data->c1; + xd = my_data->v1; + yd = my_data->v2; + zd = my_data->v3; + + start = my_data->start; + end = my_data->end; + + /* compute scaled vector sum */ + for (i = start; i < end; i++) + zd[i] = c*(xd[i] + yd[i]); + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Compute scaled vector difference + */ + +static void VScaleDiff_Pthreads(realtype c, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].c1 = c; + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].v2 = NV_DATA_PT(y); + thread_data[i].v3 = NV_DATA_PT(z); + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, VScaleDiff_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return; +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to VScaleDiff + */ + +static void *VScaleDiff_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype c; + realtype *xd, *yd, *zd; + Pthreads_Data *my_data; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + c = my_data->c1; + xd = my_data->v1; + yd = my_data->v2; + zd = my_data->v3; + + start = my_data->start; + end = my_data->end; + + /* compute scaled vector difference */ + for (i = start; i < end; i++) + zd[i] = c*(xd[i] - yd[i]); + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Compute vector sum z[i] = a*x[i]+y[i] + */ + +static void VLin1_Pthreads(realtype a, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].c1 = a; + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].v2 = NV_DATA_PT(y); + thread_data[i].v3 = NV_DATA_PT(z); + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, VLin1_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return; +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to VLin1 + */ + +static void *VLin1_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype a; + realtype *xd, *yd, *zd; + Pthreads_Data *my_data; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + a = my_data->c1; + xd = my_data->v1; + yd = my_data->v2; + zd = my_data->v3; + + start = my_data->start; + end = my_data->end; + + /* compute vector sum */ + for (i = start; i < end; i++) + zd[i] = (a*xd[i]) + yd[i]; + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Compute vector difference z[i] = a*x[i]-y[i] + */ + +static void VLin2_Pthreads(realtype a, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].c1 = a; + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].v2 = NV_DATA_PT(y); + thread_data[i].v3 = NV_DATA_PT(z); + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, VLin2_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return; +} + +/* ---------------------------------------------------------------------------- + * Pthread companion function to VLin2 + */ + +static void *VLin2_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype a; + realtype *xd, *yd, *zd; + Pthreads_Data *my_data; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + a = my_data->c1; + xd = my_data->v1; + yd = my_data->v2; + zd = my_data->v3; + + start = my_data->start; + end = my_data->end; + + /* compute vector difference */ + for (i = start; i < end; i++) + zd[i] = (a*xd[i]) - yd[i]; + + /* exit */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Compute special cases of linear sum + */ + +static void Vaxpy_Pthreads(realtype a, N_Vector x, N_Vector y) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].c1 = a; + thread_data[i].v1 = NV_DATA_PT(x); + thread_data[i].v2 = NV_DATA_PT(y); + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, Vaxpy_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return; +} + +/* ---------------------------------------------------------------------------- + * Pthread companion function to Vaxpy + */ + +static void *Vaxpy_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype a; + realtype *xd, *yd; + Pthreads_Data *my_data; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + a = my_data->c1; + xd = my_data->v1; + yd = my_data->v2; + + start = my_data->start; + end = my_data->end; + + /* compute axpy */ + if (a == ONE) { + for (i = start; i < end; i++) + yd[i] += xd[i]; + + /* exit */ + pthread_exit(NULL); + } + + if (a == -ONE) { + for (i = start; i < end; i++) + yd[i] -= xd[i]; + + /* exit */ + pthread_exit(NULL); + } + + for (i = start; i < end; i++) + yd[i] += a*xd[i]; + + /* return */ + pthread_exit(NULL); +} + + +/* ---------------------------------------------------------------------------- + * Compute scaled vector + */ + +static void VScaleBy_Pthreads(realtype a, N_Vector x) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(x); + nthreads = NV_NUM_THREADS_PT(x); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i=0; i<nthreads; i++) { + /* initialize thread data */ + N_VInitThreadData(&thread_data[i]); + + /* compute start and end loop index for thread */ + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + /* pack thread data */ + thread_data[i].c1 = a; + thread_data[i].v1 = NV_DATA_PT(x); + + /* create threads and call pthread companion function */ + pthread_create(&threads[i], &attr, VScaleBy_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) { + pthread_join(threads[i], NULL); + } + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return; +} + + +/* ---------------------------------------------------------------------------- + * Pthread companion function to VScaleBy + */ + +static void *VScaleBy_PT(void *thread_data) +{ + sunindextype i, start, end; + realtype a; + realtype *xd; + Pthreads_Data *my_data; + + /* extract thread data */ + my_data = (Pthreads_Data *) thread_data; + + a = my_data->c1; + xd = my_data->v1; + + start = my_data->start; + end = my_data->end; + + /* compute scaled vector */ + for (i = start; i < end; i++) + xd[i] *= a; + + /* exit */ + pthread_exit(NULL); +} + + +/* + * ----------------------------------------------------------------------------- + * private functions for special cases of vector array operations + * ----------------------------------------------------------------------------- + */ + +static int VSumVectorArray_Pthreads(int nvec, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(X[0]); + nthreads = NV_NUM_THREADS_PT(X[0]); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + /* pack thread data, distribute loop indices, and create threads/call kernel */ + for (i=0; i<nthreads; i++) { + N_VInitThreadData(&thread_data[i]); + + thread_data[i].nvec = nvec; + thread_data[i].Y1 = X; + thread_data[i].Y2 = Y; + thread_data[i].Y3 = Z; + + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + pthread_create(&threads[i], &attr, VSumVectorArray_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) + pthread_join(threads[i], NULL); + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return(0); +} + +static void *VSumVectorArray_PT(void *thread_data) +{ + Pthreads_Data *my_data; + sunindextype j, start, end; + + int i; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + my_data = (Pthreads_Data *) thread_data; + start = my_data->start; + end = my_data->end; + + for (i=0; i<my_data->nvec; i++) { + xd = NV_DATA_PT(my_data->Y1[i]); + yd = NV_DATA_PT(my_data->Y2[i]); + zd = NV_DATA_PT(my_data->Y3[i]); + for (j=start; j<end; j++) + zd[j] = xd[j] + yd[j]; + } + + pthread_exit(NULL); +} + + +static int VDiffVectorArray_Pthreads(int nvec, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(X[0]); + nthreads = NV_NUM_THREADS_PT(X[0]); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + /* pack thread data, distribute loop indices, and create threads/call kernel */ + for (i=0; i<nthreads; i++) { + N_VInitThreadData(&thread_data[i]); + + thread_data[i].nvec = nvec; + thread_data[i].Y1 = X; + thread_data[i].Y2 = Y; + thread_data[i].Y3 = Z; + + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + pthread_create(&threads[i], &attr, VDiffVectorArray_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) + pthread_join(threads[i], NULL); + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return(0); +} + +static void *VDiffVectorArray_PT(void *thread_data) +{ + Pthreads_Data *my_data; + sunindextype j, start, end; + + int i; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + my_data = (Pthreads_Data *) thread_data; + start = my_data->start; + end = my_data->end; + + for (i=0; i<my_data->nvec; i++) { + xd = NV_DATA_PT(my_data->Y1[i]); + yd = NV_DATA_PT(my_data->Y2[i]); + zd = NV_DATA_PT(my_data->Y3[i]); + for (j=start; j<end; j++) + zd[j] = xd[j] - yd[j]; + } + + pthread_exit(NULL); +} + + +static int VScaleSumVectorArray_Pthreads(int nvec, realtype c, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(X[0]); + nthreads = NV_NUM_THREADS_PT(X[0]); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + /* pack thread data, distribute loop indices, and create threads/call kernel */ + for (i=0; i<nthreads; i++) { + N_VInitThreadData(&thread_data[i]); + + thread_data[i].nvec = nvec; + thread_data[i].c1 = c; + thread_data[i].Y1 = X; + thread_data[i].Y2 = Y; + thread_data[i].Y3 = Z; + + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + pthread_create(&threads[i], &attr, VScaleSumVectorArray_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) + pthread_join(threads[i], NULL); + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return(0); +} + +static void *VScaleSumVectorArray_PT(void *thread_data) +{ + Pthreads_Data *my_data; + sunindextype j, start, end; + + int i; + realtype c; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + my_data = (Pthreads_Data *) thread_data; + start = my_data->start; + end = my_data->end; + c = my_data->c1; + + for (i=0; i<my_data->nvec; i++) { + xd = NV_DATA_PT(my_data->Y1[i]); + yd = NV_DATA_PT(my_data->Y2[i]); + zd = NV_DATA_PT(my_data->Y3[i]); + for (j=start; j<end; j++) + zd[j] = c * (xd[j] + yd[j]); + } + + pthread_exit(NULL); +} + + +static int VScaleDiffVectorArray_Pthreads(int nvec, realtype c, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(X[0]); + nthreads = NV_NUM_THREADS_PT(X[0]); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + /* pack thread data, distribute loop indices, and create threads/call kernel */ + for (i=0; i<nthreads; i++) { + N_VInitThreadData(&thread_data[i]); + + thread_data[i].nvec = nvec; + thread_data[i].c1 = c; + thread_data[i].Y1 = X; + thread_data[i].Y2 = Y; + thread_data[i].Y3 = Z; + + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + pthread_create(&threads[i], &attr, VScaleDiffVectorArray_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) + pthread_join(threads[i], NULL); + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return(0); +} + +static void *VScaleDiffVectorArray_PT(void *thread_data) +{ + Pthreads_Data *my_data; + sunindextype j, start, end; + + int i; + realtype c; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + my_data = (Pthreads_Data *) thread_data; + start = my_data->start; + end = my_data->end; + c = my_data->c1; + + for (i=0; i<my_data->nvec; i++) { + xd = NV_DATA_PT(my_data->Y1[i]); + yd = NV_DATA_PT(my_data->Y2[i]); + zd = NV_DATA_PT(my_data->Y3[i]); + for (j=start; j<end; j++) + zd[j] = c * (xd[j] - yd[j]); + } + + pthread_exit(NULL); +} + + +static int VLin1VectorArray_Pthreads(int nvec, realtype a, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(X[0]); + nthreads = NV_NUM_THREADS_PT(X[0]); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + /* pack thread data, distribute loop indices, and create threads/call kernel */ + for (i=0; i<nthreads; i++) { + N_VInitThreadData(&thread_data[i]); + + thread_data[i].nvec = nvec; + thread_data[i].c1 = a; + thread_data[i].Y1 = X; + thread_data[i].Y2 = Y; + thread_data[i].Y3 = Z; + + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + pthread_create(&threads[i], &attr, VLin1VectorArray_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) + pthread_join(threads[i], NULL); + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return(0); +} + +static void *VLin1VectorArray_PT(void *thread_data) +{ + Pthreads_Data *my_data; + sunindextype j, start, end; + + int i; + realtype a; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + my_data = (Pthreads_Data *) thread_data; + start = my_data->start; + end = my_data->end; + a = my_data->c1; + + for (i=0; i<my_data->nvec; i++) { + xd = NV_DATA_PT(my_data->Y1[i]); + yd = NV_DATA_PT(my_data->Y2[i]); + zd = NV_DATA_PT(my_data->Y3[i]); + for (j=start; j<end; j++) + zd[j] = (a * xd[j]) + yd[j]; + } + + pthread_exit(NULL); +} + + +static int VLin2VectorArray_Pthreads(int nvec, realtype a, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(X[0]); + nthreads = NV_NUM_THREADS_PT(X[0]); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + /* pack thread data, distribute loop indices, and create threads/call kernel */ + for (i=0; i<nthreads; i++) { + N_VInitThreadData(&thread_data[i]); + + thread_data[i].nvec = nvec; + thread_data[i].c1 = a; + thread_data[i].Y1 = X; + thread_data[i].Y2 = Y; + thread_data[i].Y3 = Z; + + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + pthread_create(&threads[i], &attr, VLin2VectorArray_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) + pthread_join(threads[i], NULL); + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return(0); +} + +static void *VLin2VectorArray_PT(void *thread_data) +{ + Pthreads_Data *my_data; + sunindextype j, start, end; + + int i; + realtype a; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + my_data = (Pthreads_Data *) thread_data; + start = my_data->start; + end = my_data->end; + a = my_data->c1; + + for (i=0; i<my_data->nvec; i++) { + xd = NV_DATA_PT(my_data->Y1[i]); + yd = NV_DATA_PT(my_data->Y2[i]); + zd = NV_DATA_PT(my_data->Y3[i]); + for (j=start; j<end; j++) + zd[j] = (a * xd[j]) - yd[j]; + } + + pthread_exit(NULL); +} + + +static int VaxpyVectorArray_Pthreads(int nvec, realtype a, N_Vector* X, N_Vector* Y) +{ + sunindextype N; + int i, nthreads; + pthread_t *threads; + Pthreads_Data *thread_data; + pthread_attr_t attr; + + /* allocate threads and thread data structs */ + N = NV_LENGTH_PT(X[0]); + nthreads = NV_NUM_THREADS_PT(X[0]); + threads = malloc(nthreads*sizeof(pthread_t)); + thread_data = (Pthreads_Data *) malloc(nthreads*sizeof(struct _Pthreads_Data)); + + /* set thread attributes */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + /* pack thread data, distribute loop indices, and create threads/call kernel */ + for (i=0; i<nthreads; i++) { + N_VInitThreadData(&thread_data[i]); + + thread_data[i].nvec = nvec; + thread_data[i].c1 = a; + thread_data[i].Y1 = X; + thread_data[i].Y2 = Y; + + N_VSplitLoop(i, &nthreads, &N, &thread_data[i].start, &thread_data[i].end); + + pthread_create(&threads[i], &attr, VaxpyVectorArray_PT, (void *) &thread_data[i]); + } + + /* wait for all threads to finish */ + for (i=0; i<nthreads; i++) + pthread_join(threads[i], NULL); + + /* clean up and return */ + pthread_attr_destroy(&attr); + free(threads); + free(thread_data); + + return(0); +} + +static void *VaxpyVectorArray_PT(void *thread_data) +{ + Pthreads_Data *my_data; + sunindextype j, start, end; + + int i; + realtype a; + realtype* xd=NULL; + realtype* yd=NULL; + + my_data = (Pthreads_Data *) thread_data; + start = my_data->start; + end = my_data->end; + a = my_data->c1; + + if (a == ONE) { + for (i=0; i<my_data->nvec; i++) { + xd = NV_DATA_PT(my_data->Y1[i]); + yd = NV_DATA_PT(my_data->Y2[i]); + for (j=start; j<end; j++) + yd[j] += xd[j]; + } + pthread_exit(NULL); + } + + if (a == -ONE) { + for (i=0; i<my_data->nvec; i++) { + xd = NV_DATA_PT(my_data->Y1[i]); + yd = NV_DATA_PT(my_data->Y2[i]); + for (j=start; j<end; j++) + yd[j] -= xd[j]; + } + pthread_exit(NULL); + } + + for (i=0; i<my_data->nvec; i++) { + xd = NV_DATA_PT(my_data->Y1[i]); + yd = NV_DATA_PT(my_data->Y2[i]); + for (j=start; j<end; j++) + yd[j] += a * xd[j]; + } + pthread_exit(NULL); +} + + +/* + * ----------------------------------------------------------------- + * private utility functions + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------------------- + * Determine loop indices for a thread + */ + +static void N_VSplitLoop(int myid, int *nthreads, sunindextype *N, + sunindextype *start, sunindextype *end) +{ + sunindextype q, r; /* quotient and remainder */ + + /* work per thread and leftover work */ + q = *N / *nthreads; + r = *N % *nthreads; + + /* assign work */ + if (myid < r) { + *start = myid * q + myid; + *end = *start + q + 1; + } else { + *start = myid * q + r; + *end = *start + q; + } +} + + +/* ---------------------------------------------------------------------------- + * Initialize values of local thread data struct + */ + +static void N_VInitThreadData(Pthreads_Data *thread_data) +{ + thread_data->start = -1; + thread_data->end = -1; + +#if __STDC_VERSION__ >= 199901L + thread_data->c1 = NAN; + thread_data->c2 = NAN; +#else + thread_data->c1 = ZERO; + thread_data->c2 = ZERO; +#endif + + thread_data->v1 = NULL; + thread_data->v2 = NULL; + thread_data->v3 = NULL; + thread_data->global_val = NULL; + thread_data->global_mutex = NULL; + + thread_data->nvec = ZERO; + thread_data->nsum = ZERO; + thread_data->cvals = NULL; + thread_data->Y1 = NULL; + thread_data->Y2 = NULL; + thread_data->Y3 = NULL; +} + + +/* + * ----------------------------------------------------------------- + * Enable / Disable fused and vector array operations + * ----------------------------------------------------------------- + */ + +int N_VEnableFusedOps_Pthreads(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); + + if (tf) { + /* enable all fused vector operations */ + v->ops->nvlinearcombination = N_VLinearCombination_Pthreads; + v->ops->nvscaleaddmulti = N_VScaleAddMulti_Pthreads; + v->ops->nvdotprodmulti = N_VDotProdMulti_Pthreads; + /* enable all vector array operations */ + v->ops->nvlinearsumvectorarray = N_VLinearSumVectorArray_Pthreads; + v->ops->nvscalevectorarray = N_VScaleVectorArray_Pthreads; + v->ops->nvconstvectorarray = N_VConstVectorArray_Pthreads; + v->ops->nvwrmsnormvectorarray = N_VWrmsNormVectorArray_Pthreads; + v->ops->nvwrmsnormmaskvectorarray = N_VWrmsNormMaskVectorArray_Pthreads; + v->ops->nvscaleaddmultivectorarray = N_VScaleAddMultiVectorArray_Pthreads; + v->ops->nvlinearcombinationvectorarray = N_VLinearCombinationVectorArray_Pthreads; + } 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 N_VEnableLinearCombination_Pthreads(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 = N_VLinearCombination_Pthreads; + else + v->ops->nvlinearcombination = NULL; + + /* return success */ + return(0); +} + +int N_VEnableScaleAddMulti_Pthreads(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 = N_VScaleAddMulti_Pthreads; + else + v->ops->nvscaleaddmulti = NULL; + + /* return success */ + return(0); +} + +int N_VEnableDotProdMulti_Pthreads(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 = N_VDotProdMulti_Pthreads; + else + v->ops->nvdotprodmulti = NULL; + + /* return success */ + return(0); +} + +int N_VEnableLinearSumVectorArray_Pthreads(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 = N_VLinearSumVectorArray_Pthreads; + else + v->ops->nvlinearsumvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableScaleVectorArray_Pthreads(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 = N_VScaleVectorArray_Pthreads; + else + v->ops->nvscalevectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableConstVectorArray_Pthreads(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 = N_VConstVectorArray_Pthreads; + else + v->ops->nvconstvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableWrmsNormVectorArray_Pthreads(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 = N_VWrmsNormVectorArray_Pthreads; + else + v->ops->nvwrmsnormvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableWrmsNormMaskVectorArray_Pthreads(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 = N_VWrmsNormMaskVectorArray_Pthreads; + else + v->ops->nvwrmsnormmaskvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableScaleAddMultiVectorArray_Pthreads(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->nvscaleaddmultivectorarray = N_VScaleAddMultiVectorArray_Pthreads; + else + v->ops->nvscaleaddmultivectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableLinearCombinationVectorArray_Pthreads(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->nvlinearcombinationvectorarray = N_VLinearCombinationVectorArray_Pthreads; + else + v->ops->nvlinearcombinationvectorarray = NULL; + + /* return success */ + return(0); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/serial/fnvector_serial.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/serial/fnvector_serial.c new file mode 100644 index 0000000..12516fc --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/serial/fnvector_serial.c @@ -0,0 +1,154 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): 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 file (companion of nvector_serial.h) contains the + * implementation needed for the Fortran initialization of serial + * vector operations. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fnvector_serial.h" + +/* Define global vector variables */ + +N_Vector F2C_CVODE_vec; +N_Vector F2C_CVODE_vecQ; +N_Vector *F2C_CVODE_vecS; +N_Vector F2C_CVODE_vecB; +N_Vector F2C_CVODE_vecQB; + +N_Vector F2C_IDA_vec; +N_Vector F2C_IDA_vecQ; +N_Vector *F2C_IDA_vecS; +N_Vector F2C_IDA_vecB; +N_Vector F2C_IDA_vecQB; + +N_Vector F2C_KINSOL_vec; + +N_Vector F2C_ARKODE_vec; + +/* Fortran callable interfaces */ + +void FNV_INITS(int *code, long int *N, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + F2C_CVODE_vec = NULL; + F2C_CVODE_vec = N_VNewEmpty_Serial(*N); + if (F2C_CVODE_vec == NULL) *ier = -1; + break; + case FCMIX_IDA: + F2C_IDA_vec = NULL; + F2C_IDA_vec = N_VNewEmpty_Serial(*N); + if (F2C_IDA_vec == NULL) *ier = -1; + break; + case FCMIX_KINSOL: + F2C_KINSOL_vec = NULL; + F2C_KINSOL_vec = N_VNewEmpty_Serial(*N); + if (F2C_KINSOL_vec == NULL) *ier = -1; + break; + case FCMIX_ARKODE: + F2C_ARKODE_vec = NULL; + F2C_ARKODE_vec = N_VNewEmpty_Serial(*N); + if (F2C_ARKODE_vec == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + +void FNV_INITS_Q(int *code, long int *Nq, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + F2C_CVODE_vecQ = NULL; + F2C_CVODE_vecQ = N_VNewEmpty_Serial(*Nq); + if (F2C_CVODE_vecQ == NULL) *ier = -1; + break; + case FCMIX_IDA: + F2C_IDA_vecQ = NULL; + F2C_IDA_vecQ = N_VNewEmpty_Serial(*Nq); + if (F2C_IDA_vecQ == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + +void FNV_INITS_B(int *code, long int *NB, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + F2C_CVODE_vecB = NULL; + F2C_CVODE_vecB = N_VNewEmpty_Serial(*NB); + if (F2C_CVODE_vecB == NULL) *ier = -1; + break; + case FCMIX_IDA: + F2C_IDA_vecB = NULL; + F2C_IDA_vecB = N_VNewEmpty_Serial(*NB); + if (F2C_IDA_vecB == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + +void FNV_INITS_QB(int *code, long int *NqB, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + F2C_CVODE_vecQB = NULL; + F2C_CVODE_vecQB = N_VNewEmpty_Serial(*NqB); + if (F2C_CVODE_vecQB == NULL) *ier = -1; + break; + case FCMIX_IDA: + F2C_IDA_vecQB = NULL; + F2C_IDA_vecQB = N_VNewEmpty_Serial(*NqB); + if (F2C_IDA_vecQB == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + +void FNV_INITS_S(int *code, int *Ns, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + F2C_CVODE_vecS = NULL; + F2C_CVODE_vecS = (N_Vector *) N_VCloneVectorArrayEmpty_Serial(*Ns, F2C_CVODE_vec); + if (F2C_CVODE_vecS == NULL) *ier = -1; + break; + case FCMIX_IDA: + F2C_IDA_vecS = NULL; + F2C_IDA_vecS = (N_Vector *) N_VCloneVectorArrayEmpty_Serial(*Ns, F2C_IDA_vec); + if (F2C_IDA_vecS == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/serial/fnvector_serial.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/serial/fnvector_serial.h new file mode 100644 index 0000000..8ee03b5 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/serial/fnvector_serial.h @@ -0,0 +1,92 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Radu Serban 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 file (companion of nvector_serial.h) contains the + * definitions needed for the initialization of serial + * vector operations in Fortran. + * ----------------------------------------------------------------- + */ + +#ifndef _FNVECTOR_SERIAL_H +#define _FNVECTOR_SERIAL_H + +#include <nvector/nvector_serial.h> +#include <sundials/sundials_fnvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +#if defined(SUNDIALS_F77_FUNC) +#define FNV_INITS SUNDIALS_F77_FUNC(fnvinits, FNVINITS) +#else +#define FNV_INITS fnvinits_ +#endif + +#if defined(SUNDIALS_F77_FUNC_) + +#define FNV_INITS_Q SUNDIALS_F77_FUNC_(fnvinits_q, FNVINITS_Q) +#define FNV_INITS_S SUNDIALS_F77_FUNC_(fnvinits_s, FNVINITS_S) +#define FNV_INITS_B SUNDIALS_F77_FUNC_(fnvinits_b, FNVINITS_B) +#define FNV_INITS_QB SUNDIALS_F77_FUNC_(fnvinits_qb, FNVINITS_QB) + +#else + +#define FNV_INITS_Q fnvinits_q_ +#define FNV_INITS_S fnvinits_s_ +#define FNV_INITS_B fnvinits_b_ +#define FNV_INITS_QB fnvinits_qb_ + +#endif + +/* Declarations of global variables */ + +extern N_Vector F2C_CVODE_vec; +extern N_Vector F2C_CVODE_vecQ; +extern N_Vector *F2C_CVODE_vecS; +extern N_Vector F2C_CVODE_vecB; +extern N_Vector F2C_CVODE_vecQB; + +extern N_Vector F2C_IDA_vec; +extern N_Vector F2C_IDA_vecQ; +extern N_Vector *F2C_IDA_vecS; +extern N_Vector F2C_IDA_vecB; +extern N_Vector F2C_IDA_vecQB; + +extern N_Vector F2C_KINSOL_vec; + +extern N_Vector F2C_ARKODE_vec; + +/* + * Prototypes of exported functions + * + * FNV_INITS - initializes serial vector operations for main problem + * FNV_INITS_Q - initializes serial vector operations for quadratures + * FNV_INITS_S - initializes serial vector operations for sensitivities + * FNV_INITS_B - initializes serial vector operations for adjoint problem + * FNV_INITS_QB - initializes serial vector operations for adjoint quadratures + * + */ + +void FNV_INITS(int *code, long int *neq, int *ier); +void FNV_INITS_Q(int *code, long int *Nq, int *ier); +void FNV_INITS_S(int *code, int *Ns, int *ier); +void FNV_INITS_B(int *code, long int *NB, int *ier); +void FNV_INITS_QB(int *code, long int *NqB, int *ier); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/serial/nvector_serial.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/serial/nvector_serial.c new file mode 100644 index 0000000..25f72c9 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/nvector/serial/nvector_serial.c @@ -0,0 +1,2147 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Scott D. Cohen, Alan C. Hindmarsh, Radu Serban, + * 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 implementation file for a serial implementation + * of the NVECTOR package. + * -----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include <nvector/nvector_serial.h> +#include <sundials/sundials_math.h> + +#define ZERO RCONST(0.0) +#define HALF RCONST(0.5) +#define ONE RCONST(1.0) +#define ONEPT5 RCONST(1.5) + +/* Private functions for special cases of vector operations */ +static void VCopy_Serial(N_Vector x, N_Vector z); /* z=x */ +static void VSum_Serial(N_Vector x, N_Vector y, N_Vector z); /* z=x+y */ +static void VDiff_Serial(N_Vector x, N_Vector y, N_Vector z); /* z=x-y */ +static void VNeg_Serial(N_Vector x, N_Vector z); /* z=-x */ +static void VScaleSum_Serial(realtype c, N_Vector x, N_Vector y, N_Vector z); /* z=c(x+y) */ +static void VScaleDiff_Serial(realtype c, N_Vector x, N_Vector y, N_Vector z); /* z=c(x-y) */ +static void VLin1_Serial(realtype a, N_Vector x, N_Vector y, N_Vector z); /* z=ax+y */ +static void VLin2_Serial(realtype a, N_Vector x, N_Vector y, N_Vector z); /* z=ax-y */ +static void Vaxpy_Serial(realtype a, N_Vector x, N_Vector y); /* y <- ax+y */ +static void VScaleBy_Serial(realtype a, N_Vector x); /* x <- ax */ + +/* Private functions for special cases of vector array operations */ +static int VSumVectorArray_Serial(int nvec, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=X+Y */ +static int VDiffVectorArray_Serial(int nvec, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=X-Y */ +static int VScaleSumVectorArray_Serial(int nvec, realtype c, N_Vector* X, N_Vector* Y, N_Vector* Z); /* Z=c(X+Y) */ +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 */ + +/* + * ----------------------------------------------------------------- + * exported functions + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------- + * Returns vector type ID. Used to identify vector implementation + * from abstract N_Vector interface. + */ +N_Vector_ID N_VGetVectorID_Serial(N_Vector v) +{ + return SUNDIALS_NVEC_SERIAL; +} + +/* ---------------------------------------------------------------------------- + * Function to create a new empty serial vector + */ + +N_Vector N_VNewEmpty_Serial(sunindextype length) +{ + N_Vector v; + N_Vector_Ops ops; + N_VectorContent_Serial content; + + /* Create vector */ + v = NULL; + v = (N_Vector) malloc(sizeof *v); + 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 = 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; + + /* 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; + + /* Create content */ + content = NULL; + content = (N_VectorContent_Serial) malloc(sizeof(struct _N_VectorContent_Serial)); + if (content == NULL) { free(ops); free(v); return(NULL); } + + content->length = length; + content->own_data = SUNFALSE; + content->data = NULL; + + /* Attach content and ops */ + v->content = content; + v->ops = ops; + + return(v); +} + +/* ---------------------------------------------------------------------------- + * Function to create a new serial vector + */ + +N_Vector N_VNew_Serial(sunindextype length) +{ + N_Vector v; + realtype *data; + + v = NULL; + v = N_VNewEmpty_Serial(length); + if (v == NULL) return(NULL); + + /* Create data */ + if (length > 0) { + + /* Allocate memory */ + data = NULL; + data = (realtype *) malloc(length * sizeof(realtype)); + if(data == NULL) { N_VDestroy_Serial(v); return(NULL); } + + /* Attach data */ + NV_OWN_DATA_S(v) = SUNTRUE; + NV_DATA_S(v) = data; + + } + + return(v); +} + +/* ---------------------------------------------------------------------------- + * Function to create a serial N_Vector with user data component + */ + +N_Vector N_VMake_Serial(sunindextype length, realtype *v_data) +{ + N_Vector v; + + v = NULL; + v = N_VNewEmpty_Serial(length); + if (v == NULL) return(NULL); + + if (length > 0) { + /* Attach data */ + NV_OWN_DATA_S(v) = SUNFALSE; + NV_DATA_S(v) = v_data; + } + + return(v); +} + +/* ---------------------------------------------------------------------------- + * Function to create an array of new serial vectors. + */ + +N_Vector *N_VCloneVectorArray_Serial(int count, N_Vector w) +{ + N_Vector *vs; + int j; + + if (count <= 0) return(NULL); + + vs = NULL; + vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + if(vs == NULL) return(NULL); + + for (j = 0; j < count; j++) { + vs[j] = NULL; + vs[j] = N_VClone_Serial(w); + if (vs[j] == NULL) { + N_VDestroyVectorArray_Serial(vs, j-1); + return(NULL); + } + } + + return(vs); +} + +/* ---------------------------------------------------------------------------- + * 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 *vs; + int j; + + if (count <= 0) return(NULL); + + vs = NULL; + vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + if(vs == NULL) return(NULL); + + for (j = 0; j < count; j++) { + vs[j] = NULL; + vs[j] = N_VCloneEmpty_Serial(w); + if (vs[j] == NULL) { + N_VDestroyVectorArray_Serial(vs, j-1); + return(NULL); + } + } + + return(vs); +} + +/* ---------------------------------------------------------------------------- + * Function to free an array created with N_VCloneVectorArray_Serial + */ + +void N_VDestroyVectorArray_Serial(N_Vector *vs, int count) +{ + int j; + + for (j = 0; j < count; j++) N_VDestroy_Serial(vs[j]); + + free(vs); vs = NULL; + + return; +} + +/* ---------------------------------------------------------------------------- + * Function to return number of vector elements + */ +sunindextype N_VGetLength_Serial(N_Vector v) +{ + return NV_LENGTH_S(v); +} + +/* ---------------------------------------------------------------------------- + * Function to print the a serial vector to stdout + */ + +void N_VPrint_Serial(N_Vector x) +{ + N_VPrintFile_Serial(x, stdout); +} + +/* ---------------------------------------------------------------------------- + * Function to print the a serial vector to outfile + */ + +void N_VPrintFile_Serial(N_Vector x, FILE* outfile) +{ + sunindextype i, N; + realtype *xd; + + xd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + + for (i = 0; i < N; i++) { +#if defined(SUNDIALS_EXTENDED_PRECISION) + fprintf(outfile, "%35.32Lg\n", xd[i]); +#elif defined(SUNDIALS_DOUBLE_PRECISION) + fprintf(outfile, "%19.16g\n", xd[i]); +#else + fprintf(outfile, "%11.8g\n", xd[i]); +#endif + } + fprintf(outfile, "\n"); + + return; +} + +/* + * ----------------------------------------------------------------- + * implementation of vector operations + * ----------------------------------------------------------------- + */ + +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); + 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 */ + content = NULL; + content = (N_VectorContent_Serial) malloc(sizeof(struct _N_VectorContent_Serial)); + if (content == NULL) { free(ops); free(v); return(NULL); } + + 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); +} + +N_Vector N_VClone_Serial(N_Vector w) +{ + N_Vector v; + realtype *data; + sunindextype length; + + v = NULL; + v = N_VCloneEmpty_Serial(w); + if (v == NULL) return(NULL); + + length = NV_LENGTH_S(w); + + /* Create data */ + if (length > 0) { + + /* Allocate memory */ + data = NULL; + data = (realtype *) malloc(length * sizeof(realtype)); + if(data == NULL) { N_VDestroy_Serial(v); return(NULL); } + + /* Attach data */ + NV_OWN_DATA_S(v) = SUNTRUE; + NV_DATA_S(v) = data; + + } + + return(v); +} + +void N_VDestroy_Serial(N_Vector v) +{ + if (NV_OWN_DATA_S(v) == SUNTRUE) { + free(NV_DATA_S(v)); + NV_DATA_S(v) = NULL; + } + free(v->content); v->content = NULL; + free(v->ops); v->ops = NULL; + free(v); v = NULL; + + return; +} + +void N_VSpace_Serial(N_Vector v, sunindextype *lrw, sunindextype *liw) +{ + *lrw = NV_LENGTH_S(v); + *liw = 1; + + return; +} + +realtype *N_VGetArrayPointer_Serial(N_Vector v) +{ + return((realtype *) NV_DATA_S(v)); +} + +void N_VSetArrayPointer_Serial(realtype *v_data, N_Vector v) +{ + if (NV_LENGTH_S(v) > 0) NV_DATA_S(v) = v_data; + + return; +} + +void N_VLinearSum_Serial(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype c, *xd, *yd, *zd; + N_Vector v1, v2; + booleantype test; + + xd = yd = zd = NULL; + + if ((b == ONE) && (z == y)) { /* BLAS usage: axpy y <- ax+y */ + Vaxpy_Serial(a,x,y); + return; + } + + if ((a == ONE) && (z == x)) { /* BLAS usage: axpy x <- by+x */ + Vaxpy_Serial(b,y,x); + return; + } + + /* Case: a == b == 1.0 */ + + if ((a == ONE) && (b == ONE)) { + VSum_Serial(x, y, z); + return; + } + + /* Cases: (1) a == 1.0, b = -1.0, (2) a == -1.0, b == 1.0 */ + + if ((test = ((a == ONE) && (b == -ONE))) || ((a == -ONE) && (b == ONE))) { + v1 = test ? y : x; + v2 = test ? x : y; + VDiff_Serial(v2, v1, z); + return; + } + + /* Cases: (1) a == 1.0, b == other or 0.0, (2) a == other or 0.0, b == 1.0 */ + /* if a or b is 0.0, then user should have called N_VScale */ + + if ((test = (a == ONE)) || (b == ONE)) { + c = test ? b : a; + v1 = test ? y : x; + v2 = test ? x : y; + VLin1_Serial(c, v1, v2, z); + return; + } + + /* Cases: (1) a == -1.0, b != 1.0, (2) a != 1.0, b == -1.0 */ + + if ((test = (a == -ONE)) || (b == -ONE)) { + c = test ? b : a; + v1 = test ? y : x; + v2 = test ? x : y; + VLin2_Serial(c, v1, v2, z); + return; + } + + /* Case: a == b */ + /* catches case both a and b are 0.0 - user should have called N_VConst */ + + if (a == b) { + VScaleSum_Serial(a, x, y, z); + return; + } + + /* Case: a == -b */ + + if (a == -b) { + VScaleDiff_Serial(a, x, y, z); + return; + } + + /* Do all cases not handled above: + (1) a == other, b == 0.0 - user should have called N_VScale + (2) a == 0.0, b == other - user should have called N_VScale + (3) a,b == other, a !=b, a != -b */ + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + yd = NV_DATA_S(y); + zd = NV_DATA_S(z); + + for (i = 0; i < N; i++) + zd[i] = (a*xd[i])+(b*yd[i]); + + return; +} + +void N_VConst_Serial(realtype c, N_Vector z) +{ + sunindextype i, N; + realtype *zd; + + zd = NULL; + + N = NV_LENGTH_S(z); + zd = NV_DATA_S(z); + + for (i = 0; i < N; i++) zd[i] = c; + + return; +} + +void N_VProd_Serial(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + yd = NV_DATA_S(y); + zd = NV_DATA_S(z); + + for (i = 0; i < N; i++) + zd[i] = xd[i]*yd[i]; + + return; +} + +void N_VDiv_Serial(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + yd = NV_DATA_S(y); + zd = NV_DATA_S(z); + + for (i = 0; i < N; i++) + zd[i] = xd[i]/yd[i]; + + return; +} + +void N_VScale_Serial(realtype c, N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + if (z == x) { /* BLAS usage: scale x <- cx */ + VScaleBy_Serial(c, x); + return; + } + + if (c == ONE) { + VCopy_Serial(x, z); + } else if (c == -ONE) { + VNeg_Serial(x, z); + } else { + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + zd = NV_DATA_S(z); + for (i = 0; i < N; i++) + zd[i] = c*xd[i]; + } + + return; +} + +void N_VAbs_Serial(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + zd = NV_DATA_S(z); + + for (i = 0; i < N; i++) + zd[i] = SUNRabs(xd[i]); + + return; +} + +void N_VInv_Serial(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + zd = NV_DATA_S(z); + + for (i = 0; i < N; i++) + zd[i] = ONE/xd[i]; + + return; +} + +void N_VAddConst_Serial(N_Vector x, realtype b, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + zd = NV_DATA_S(z); + + for (i = 0; i < N; i++) + zd[i] = xd[i]+b; + + return; +} + +realtype N_VDotProd_Serial(N_Vector x, N_Vector y) +{ + sunindextype i, N; + realtype sum, *xd, *yd; + + sum = ZERO; + xd = yd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + yd = NV_DATA_S(y); + + for (i = 0; i < N; i++) + sum += xd[i]*yd[i]; + + return(sum); +} + +realtype N_VMaxNorm_Serial(N_Vector x) +{ + sunindextype i, N; + realtype max, *xd; + + max = ZERO; + xd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + + for (i = 0; i < N; i++) { + if (SUNRabs(xd[i]) > max) max = SUNRabs(xd[i]); + } + + return(max); +} + +realtype N_VWrmsNorm_Serial(N_Vector x, N_Vector w) +{ + sunindextype i, N; + realtype sum, prodi, *xd, *wd; + + sum = ZERO; + xd = wd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + wd = NV_DATA_S(w); + + for (i = 0; i < N; i++) { + prodi = xd[i]*wd[i]; + sum += SUNSQR(prodi); + } + + return(SUNRsqrt(sum/N)); +} + +realtype N_VWrmsNormMask_Serial(N_Vector x, N_Vector w, N_Vector id) +{ + sunindextype i, N; + realtype sum, prodi, *xd, *wd, *idd; + + sum = ZERO; + xd = wd = idd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + wd = NV_DATA_S(w); + idd = NV_DATA_S(id); + + for (i = 0; i < N; i++) { + if (idd[i] > ZERO) { + prodi = xd[i]*wd[i]; + sum += SUNSQR(prodi); + } + } + + return(SUNRsqrt(sum / N)); +} + +realtype N_VMin_Serial(N_Vector x) +{ + sunindextype i, N; + realtype min, *xd; + + xd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + + min = xd[0]; + + for (i = 1; i < N; i++) { + if (xd[i] < min) min = xd[i]; + } + + return(min); +} + +realtype N_VWL2Norm_Serial(N_Vector x, N_Vector w) +{ + sunindextype i, N; + realtype sum, prodi, *xd, *wd; + + sum = ZERO; + xd = wd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + wd = NV_DATA_S(w); + + for (i = 0; i < N; i++) { + prodi = xd[i]*wd[i]; + sum += SUNSQR(prodi); + } + + return(SUNRsqrt(sum)); +} + +realtype N_VL1Norm_Serial(N_Vector x) +{ + sunindextype i, N; + realtype sum, *xd; + + sum = ZERO; + xd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + + for (i = 0; i<N; i++) + sum += SUNRabs(xd[i]); + + return(sum); +} + +void N_VCompare_Serial(realtype c, N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + zd = NV_DATA_S(z); + + for (i = 0; i < N; i++) { + zd[i] = (SUNRabs(xd[i]) >= c) ? ONE : ZERO; + } + + return; +} + +booleantype N_VInvTest_Serial(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + booleantype no_zero_found; + + xd = zd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + zd = NV_DATA_S(z); + + no_zero_found = SUNTRUE; + for (i = 0; i < N; i++) { + if (xd[i] == ZERO) + no_zero_found = SUNFALSE; + else + zd[i] = ONE/xd[i]; + } + + return no_zero_found; +} + +booleantype N_VConstrMask_Serial(N_Vector c, N_Vector x, N_Vector m) +{ + sunindextype i, N; + realtype temp; + realtype *cd, *xd, *md; + booleantype test; + + cd = xd = md = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + cd = NV_DATA_S(c); + md = NV_DATA_S(m); + + temp = ZERO; + + for (i = 0; i < N; i++) { + md[i] = ZERO; + + /* Continue if no constraints were set for the variable */ + if (cd[i] == ZERO) + continue; + + /* Check if a set constraint has been violated */ + test = (SUNRabs(cd[i]) > ONEPT5 && xd[i]*cd[i] <= ZERO) || + (SUNRabs(cd[i]) > HALF && xd[i]*cd[i] < ZERO); + if (test) { + temp = md[i] = ONE; + } + } + + /* Return false if any constraint was violated */ + return (temp == ONE) ? SUNFALSE : SUNTRUE; +} + +realtype N_VMinQuotient_Serial(N_Vector num, N_Vector denom) +{ + booleantype notEvenOnce; + sunindextype i, N; + realtype *nd, *dd, min; + + nd = dd = NULL; + + N = NV_LENGTH_S(num); + nd = NV_DATA_S(num); + dd = NV_DATA_S(denom); + + notEvenOnce = SUNTRUE; + min = BIG_REAL; + + for (i = 0; i < N; i++) { + if (dd[i] == ZERO) continue; + else { + if (!notEvenOnce) min = SUNMIN(min, nd[i]/dd[i]); + else { + min = nd[i]/dd[i]; + notEvenOnce = SUNFALSE; + } + } + } + + return(min); +} + + +/* + * ----------------------------------------------------------------- + * fused vector operations + * ----------------------------------------------------------------- + */ + +int N_VLinearCombination_Serial(int nvec, realtype* c, N_Vector* X, N_Vector z) +{ + int i; + sunindextype j, N; + realtype* zd=NULL; + realtype* xd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VScale */ + if (nvec == 1) { + N_VScale_Serial(c[0], X[0], z); + return(0); + } + + /* should have called N_VLinearSum */ + if (nvec == 2) { + N_VLinearSum_Serial(c[0], X[0], c[1], X[1], z); + return(0); + } + + /* get vector length and data array */ + N = NV_LENGTH_S(z); + zd = NV_DATA_S(z); + + /* + * X[0] += c[i]*X[i], i = 1,...,nvec-1 + */ + if ((X[0] == z) && (c[0] == ONE)) { + for (i=1; i<nvec; i++) { + xd = NV_DATA_S(X[i]); + for (j=0; j<N; j++) { + zd[j] += c[i] * xd[j]; + } + } + return(0); + } + + /* + * X[0] = c[0] * X[0] + sum{ c[i] * X[i] }, i = 1,...,nvec-1 + */ + if (X[0] == z) { + for (j=0; j<N; j++) { + zd[j] *= c[0]; + } + for (i=1; i<nvec; i++) { + xd = NV_DATA_S(X[i]); + for (j=0; j<N; j++) { + zd[j] += c[i] * xd[j]; + } + } + return(0); + } + + /* + * z = sum{ c[i] * X[i] }, i = 0,...,nvec-1 + */ + xd = NV_DATA_S(X[0]); + for (j=0; j<N; j++) { + zd[j] = c[0] * xd[j]; + } + for (i=1; i<nvec; i++) { + xd = NV_DATA_S(X[i]); + for (j=0; j<N; j++) { + zd[j] += c[i] * xd[j]; + } + } + return(0); +} + + +int N_VScaleAddMulti_Serial(int nvec, realtype* a, N_Vector x, N_Vector* Y, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VLinearSum */ + if (nvec == 1) { + N_VLinearSum_Serial(a[0], x, ONE, Y[0], Z[0]); + return(0); + } + + /* get vector length and data array */ + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + + /* + * Y[i][j] += a[i] * x[j] + */ + if (Y == Z) { + for (i=0; i<nvec; i++) { + yd = NV_DATA_S(Y[i]); + for (j=0; j<N; j++) { + yd[j] += a[i] * xd[j]; + } + } + return(0); + } + + /* + * Z[i][j] = Y[i][j] + a[i] * x[j] + */ + for (i=0; i<nvec; i++) { + yd = NV_DATA_S(Y[i]); + zd = NV_DATA_S(Z[i]); + for (j=0; j<N; j++) { + zd[j] = a[i] * xd[j] + yd[j]; + } + } + return(0); +} + + +int N_VDotProdMulti_Serial(int nvec, N_Vector x, N_Vector* Y, realtype* dotprods) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VDotProd */ + if (nvec == 1) { + dotprods[0] = N_VDotProd_Serial(x, Y[0]); + return(0); + } + + /* get vector length and data array */ + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + + /* compute multiple dot products */ + for (i=0; i<nvec; i++) { + yd = NV_DATA_S(Y[i]); + dotprods[i] = ZERO; + for (j=0; j<N; j++) { + dotprods[i] += xd[j] * yd[j]; + } + } + + return(0); +} + + +/* + * ----------------------------------------------------------------- + * vector array operations + * ----------------------------------------------------------------- + */ + +int N_VLinearSumVectorArray_Serial(int nvec, + realtype a, N_Vector* X, + realtype b, N_Vector* Y, + N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + realtype c; + N_Vector* V1; + N_Vector* V2; + booleantype test; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VLinearSum */ + if (nvec == 1) { + N_VLinearSum_Serial(a, X[0], b, Y[0], Z[0]); + return(0); + } + + /* BLAS usage: axpy y <- ax+y */ + if ((b == ONE) && (Z == Y)) + return(VaxpyVectorArray_Serial(nvec, a, X, Y)); + + /* BLAS usage: axpy x <- by+x */ + if ((a == ONE) && (Z == X)) + return(VaxpyVectorArray_Serial(nvec, b, Y, X)); + + /* Case: a == b == 1.0 */ + if ((a == ONE) && (b == ONE)) + return(VSumVectorArray_Serial(nvec, X, Y, Z)); + + /* Cases: */ + /* (1) a == 1.0, b = -1.0, */ + /* (2) a == -1.0, b == 1.0 */ + if ((test = ((a == ONE) && (b == -ONE))) || ((a == -ONE) && (b == ONE))) { + V1 = test ? Y : X; + V2 = test ? X : Y; + return(VDiffVectorArray_Serial(nvec, V2, V1, Z)); + } + + /* Cases: */ + /* (1) a == 1.0, b == other or 0.0, */ + /* (2) a == other or 0.0, b == 1.0 */ + /* if a or b is 0.0, then user should have called N_VScale */ + if ((test = (a == ONE)) || (b == ONE)) { + c = test ? b : a; + V1 = test ? Y : X; + V2 = test ? X : Y; + return(VLin1VectorArray_Serial(nvec, c, V1, V2, Z)); + } + + /* Cases: */ + /* (1) a == -1.0, b != 1.0, */ + /* (2) a != 1.0, b == -1.0 */ + if ((test = (a == -ONE)) || (b == -ONE)) { + c = test ? b : a; + V1 = test ? Y : X; + V2 = test ? X : Y; + return(VLin2VectorArray_Serial(nvec, c, V1, V2, Z)); + } + + /* Case: a == b */ + /* catches case both a and b are 0.0 - user should have called N_VConst */ + if (a == b) + return(VScaleSumVectorArray_Serial(nvec, a, X, Y, Z)); + + /* Case: a == -b */ + if (a == -b) + return(VScaleDiffVectorArray_Serial(nvec, a, X, Y, Z)); + + /* Do all cases not handled above: */ + /* (1) a == other, b == 0.0 - user should have called N_VScale */ + /* (2) a == 0.0, b == other - user should have called N_VScale */ + /* (3) a,b == other, a !=b, a != -b */ + + /* get vector length */ + N = NV_LENGTH_S(Z[0]); + + /* compute linear sum for each vector pair in vector arrays */ + for (i=0; i<nvec; i++) { + xd = NV_DATA_S(X[i]); + yd = NV_DATA_S(Y[i]); + zd = NV_DATA_S(Z[i]); + for (j=0; j<N; j++) { + zd[j] = a * xd[j] + b * yd[j]; + } + } + + return(0); +} + + +int N_VScaleVectorArray_Serial(int nvec, realtype* c, N_Vector* X, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* zd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VScale */ + if (nvec == 1) { + N_VScale_Serial(c[0], X[0], Z[0]); + return(0); + } + + /* get vector length */ + N = NV_LENGTH_S(Z[0]); + + /* + * X[i] *= c[i] + */ + if (X == Z) { + for (i=0; i<nvec; i++) { + xd = NV_DATA_S(X[i]); + for (j=0; j<N; j++) { + xd[j] *= c[i]; + } + } + return(0); + } + + /* + * Z[i] = c[i] * X[i] + */ + for (i=0; i<nvec; i++) { + xd = NV_DATA_S(X[i]); + zd = NV_DATA_S(Z[i]); + for (j=0; j<N; j++) { + zd[j] = c[i] * xd[j]; + } + } + return(0); +} + + +int N_VConstVectorArray_Serial(int nvec, realtype c, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* zd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VConst */ + if (nvec == 1) { + N_VConst_Serial(c, Z[0]); + return(0); + } + + /* get vector length */ + N = NV_LENGTH_S(Z[0]); + + /* set each vector in the vector array to a constant */ + for (i=0; i<nvec; i++) { + zd = NV_DATA_S(Z[i]); + for (j=0; j<N; j++) { + zd[j] = c; + } + } + + return(0); +} + + +int N_VWrmsNormVectorArray_Serial(int nvec, N_Vector* X, N_Vector* W, + realtype* nrm) +{ + int i; + sunindextype j, N; + realtype* wd=NULL; + realtype* xd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VWrmsNorm */ + if (nvec == 1) { + nrm[0] = N_VWrmsNorm_Serial(X[0], W[0]); + return(0); + } + + /* get vector length */ + N = NV_LENGTH_S(X[0]); + + /* compute the WRMS norm for each vector in the vector array */ + for (i=0; i<nvec; i++) { + xd = NV_DATA_S(X[i]); + wd = NV_DATA_S(W[i]); + nrm[i] = ZERO; + for (j=0; j<N; j++) { + nrm[i] += SUNSQR(xd[j] * wd[j]); + } + nrm[i] = SUNRsqrt(nrm[i]/N); + } + + return(0); +} + + +int N_VWrmsNormMaskVectorArray_Serial(int nvec, N_Vector* X, N_Vector* W, + N_Vector id, realtype* nrm) +{ + int i; + sunindextype j, N; + realtype* wd=NULL; + realtype* xd=NULL; + realtype* idd=NULL; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + + /* should have called N_VWrmsNorm */ + if (nvec == 1) { + nrm[0] = N_VWrmsNormMask_Serial(X[0], W[0], id); + return(0); + } + + /* get vector length and mask data array */ + N = NV_LENGTH_S(X[0]); + idd = NV_DATA_S(id); + + /* compute the WRMS norm for each vector in the vector array */ + for (i=0; i<nvec; i++) { + xd = NV_DATA_S(X[i]); + wd = NV_DATA_S(W[i]); + nrm[i] = ZERO; + for (j=0; j<N; j++) { + if (idd[j] > ZERO) + nrm[i] += SUNSQR(xd[j] * wd[j]); + } + nrm[i] = SUNRsqrt(nrm[i]/N); + } + + return(0); +} + + +int N_VScaleAddMultiVectorArray_Serial(int nvec, int nsum, realtype* a, + N_Vector* X, N_Vector** Y, N_Vector** Z) +{ + int i, j; + sunindextype k, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + int retval; + N_Vector* YY; + N_Vector* ZZ; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + if (nsum < 1) return(-1); + + /* --------------------------- + * Special cases for nvec == 1 + * --------------------------- */ + + if (nvec == 1) { + + /* should have called N_VLinearSum */ + if (nsum == 1) { + N_VLinearSum_Serial(a[0], X[0], ONE, Y[0][0], Z[0][0]); + return(0); + } + + /* should have called N_VScaleAddMulti */ + YY = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + ZZ = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + + for (j=0; j<nsum; j++) { + YY[j] = Y[j][0]; + ZZ[j] = Z[j][0]; + } + + retval = N_VScaleAddMulti_Serial(nsum, a, X[0], YY, ZZ); + + free(YY); + free(ZZ); + return(retval); + } + + /* -------------------------- + * Special cases for nvec > 1 + * -------------------------- */ + + /* should have called N_VLinearSumVectorArray */ + if (nsum == 1) { + retval = N_VLinearSumVectorArray_Serial(nvec, a[0], X, ONE, Y[0], Z[0]); + return(retval); + } + + /* ---------------------------- + * Compute multiple linear sums + * ---------------------------- */ + + /* get vector length */ + N = NV_LENGTH_S(X[0]); + + /* + * Y[i][j] += a[i] * x[j] + */ + if (Y == Z) { + for (i=0; i<nvec; i++) { + xd = NV_DATA_S(X[i]); + for (j=0; j<nsum; j++){ + yd = NV_DATA_S(Y[j][i]); + for (k=0; k<N; k++) { + yd[k] += a[j] * xd[k]; + } + } + } + return(0); + } + + /* + * Z[i][j] = Y[i][j] + a[i] * x[j] + */ + for (i=0; i<nvec; i++) { + xd = NV_DATA_S(X[i]); + for (j=0; j<nsum; j++){ + yd = NV_DATA_S(Y[j][i]); + zd = NV_DATA_S(Z[j][i]); + for (k=0; k<N; k++) { + zd[k] = a[j] * xd[k] + yd[k]; + } + } + } + return(0); +} + + +int N_VLinearCombinationVectorArray_Serial(int nvec, int nsum, realtype* c, + N_Vector** X, N_Vector* Z) +{ + int i; /* vector arrays index in summation [0,nsum) */ + int j; /* vector index in vector array [0,nvec) */ + sunindextype k; /* element index in vector [0,N) */ + sunindextype N; + realtype* zd=NULL; + realtype* xd=NULL; + + int retval; + realtype* ctmp; + N_Vector* Y; + + /* invalid number of vectors */ + if (nvec < 1) return(-1); + if (nsum < 1) return(-1); + + /* --------------------------- + * Special cases for nvec == 1 + * --------------------------- */ + + if (nvec == 1) { + + /* should have called N_VScale */ + if (nsum == 1) { + N_VScale_Serial(c[0], X[0][0], Z[0]); + return(0); + } + + /* should have called N_VLinearSum */ + if (nsum == 2) { + N_VLinearSum_Serial(c[0], X[0][0], c[1], X[1][0], Z[0]); + return(0); + } + + /* should have called N_VLinearCombination */ + Y = (N_Vector *) malloc(nsum * sizeof(N_Vector)); + + for (i=0; i<nsum; i++) { + Y[i] = X[i][0]; + } + + retval = N_VLinearCombination_Serial(nsum, c, Y, Z[0]); + + free(Y); + return(retval); + } + + /* -------------------------- + * Special cases for nvec > 1 + * -------------------------- */ + + /* should have called N_VScaleVectorArray */ + if (nsum == 1) { + + ctmp = (realtype*) malloc(nvec * sizeof(realtype)); + + for (j=0; j<nvec; j++) { + ctmp[j] = c[0]; + } + + retval = N_VScaleVectorArray_Serial(nvec, ctmp, X[0], Z); + + free(ctmp); + return(retval); + } + + /* should have called N_VLinearSumVectorArray */ + if (nsum == 2) { + retval = N_VLinearSumVectorArray_Serial(nvec, c[0], X[0], c[1], X[1], Z); + return(retval); + } + + /* -------------------------- + * Compute linear combination + * -------------------------- */ + + /* get vector length */ + N = NV_LENGTH_S(Z[0]); + + /* + * X[0][j] += c[i]*X[i][j], i = 1,...,nvec-1 + */ + if ((X[0] == Z) && (c[0] == ONE)) { + for (j=0; j<nvec; j++) { + zd = NV_DATA_S(Z[j]); + for (i=1; i<nsum; i++) { + xd = NV_DATA_S(X[i][j]); + for (k=0; k<N; k++) { + zd[k] += c[i] * xd[k]; + } + } + } + return(0); + } + + /* + * X[0][j] = c[0] * X[0][j] + sum{ c[i] * X[i][j] }, i = 1,...,nvec-1 + */ + if (X[0] == Z) { + for (j=0; j<nvec; j++) { + zd = NV_DATA_S(Z[j]); + for (k=0; k<N; k++) { + zd[k] *= c[0]; + } + for (i=1; i<nsum; i++) { + xd = NV_DATA_S(X[i][j]); + for (k=0; k<N; k++) { + zd[k] += c[i] * xd[k]; + } + } + } + return(0); + } + + /* + * Z[j] = sum{ c[i] * X[i][j] }, i = 0,...,nvec-1 + */ + for (j=0; j<nvec; j++) { + xd = NV_DATA_S(X[0][j]); + zd = NV_DATA_S(Z[j]); + for (k=0; k<N; k++) { + zd[k] = c[0] * xd[k]; + } + for (i=1; i<nsum; i++) { + xd = NV_DATA_S(X[i][j]); + for (k=0; k<N; k++) { + zd[k] += c[i] * xd[k]; + } + } + } + return(0); +} + + +/* + * ----------------------------------------------------------------- + * private functions for special cases of vector operations + * ----------------------------------------------------------------- + */ + +static void VCopy_Serial(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + zd = NV_DATA_S(z); + + for (i = 0; i < N; i++) + zd[i] = xd[i]; + + return; +} + +static void VSum_Serial(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + yd = NV_DATA_S(y); + zd = NV_DATA_S(z); + + for (i = 0; i < N; i++) + zd[i] = xd[i]+yd[i]; + + return; +} + +static void VDiff_Serial(N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + yd = NV_DATA_S(y); + zd = NV_DATA_S(z); + + for (i = 0; i < N; i++) + zd[i] = xd[i]-yd[i]; + + return; +} + +static void VNeg_Serial(N_Vector x, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *zd; + + xd = zd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + zd = NV_DATA_S(z); + + for (i = 0; i < N; i++) + zd[i] = -xd[i]; + + return; +} + +static void VScaleSum_Serial(realtype c, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + yd = NV_DATA_S(y); + zd = NV_DATA_S(z); + + for (i = 0; i < N; i++) + zd[i] = c*(xd[i]+yd[i]); + + return; +} + +static void VScaleDiff_Serial(realtype c, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + yd = NV_DATA_S(y); + zd = NV_DATA_S(z); + + for (i = 0; i < N; i++) + zd[i] = c*(xd[i]-yd[i]); + + return; +} + +static void VLin1_Serial(realtype a, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + yd = NV_DATA_S(y); + zd = NV_DATA_S(z); + + for (i = 0; i < N; i++) + zd[i] = (a*xd[i])+yd[i]; + + return; +} + +static void VLin2_Serial(realtype a, N_Vector x, N_Vector y, N_Vector z) +{ + sunindextype i, N; + realtype *xd, *yd, *zd; + + xd = yd = zd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + yd = NV_DATA_S(y); + zd = NV_DATA_S(z); + + for (i = 0; i < N; i++) + zd[i] = (a*xd[i])-yd[i]; + + return; +} + +static void Vaxpy_Serial(realtype a, N_Vector x, N_Vector y) +{ + sunindextype i, N; + realtype *xd, *yd; + + xd = yd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + yd = NV_DATA_S(y); + + if (a == ONE) { + for (i = 0; i < N; i++) + yd[i] += xd[i]; + return; + } + + if (a == -ONE) { + for (i = 0; i < N; i++) + yd[i] -= xd[i]; + return; + } + + for (i = 0; i < N; i++) + yd[i] += a*xd[i]; + + return; +} + +static void VScaleBy_Serial(realtype a, N_Vector x) +{ + sunindextype i, N; + realtype *xd; + + xd = NULL; + + N = NV_LENGTH_S(x); + xd = NV_DATA_S(x); + + for (i = 0; i < N; i++) + xd[i] *= a; + + return; +} + + +/* + * ----------------------------------------------------------------- + * private functions for special cases of vector array operations + * ----------------------------------------------------------------- + */ + +static int VSumVectorArray_Serial(int nvec, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + N = NV_LENGTH_S(X[0]); + + for (i=0; i<nvec; i++) { + xd = NV_DATA_S(X[i]); + yd = NV_DATA_S(Y[i]); + zd = NV_DATA_S(Z[i]); + for (j=0; j<N; j++) + zd[j] = xd[j] + yd[j]; + } + + return(0); +} + +static int VDiffVectorArray_Serial(int nvec, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + N = NV_LENGTH_S(X[0]); + + for (i=0; i<nvec; i++) { + xd = NV_DATA_S(X[i]); + yd = NV_DATA_S(Y[i]); + zd = NV_DATA_S(Z[i]); + for (j=0; j<N; j++) + zd[j] = xd[j] - yd[j]; + } + + return(0); +} + +static int VScaleSumVectorArray_Serial(int nvec, realtype c, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + N = NV_LENGTH_S(X[0]); + + for (i=0; i<nvec; i++) { + xd = NV_DATA_S(X[i]); + yd = NV_DATA_S(Y[i]); + zd = NV_DATA_S(Z[i]); + for (j=0; j<N; j++) + zd[j] = c * (xd[j] + yd[j]); + } + + return(0); +} + +static int VScaleDiffVectorArray_Serial(int nvec, realtype c, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + N = NV_LENGTH_S(X[0]); + + for (i=0; i<nvec; i++) { + xd = NV_DATA_S(X[i]); + yd = NV_DATA_S(Y[i]); + zd = NV_DATA_S(Z[i]); + for (j=0; j<N; j++) + zd[j] = c * (xd[j] - yd[j]); + } + + return(0); +} + +static int VLin1VectorArray_Serial(int nvec, realtype a, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + N = NV_LENGTH_S(X[0]); + + for (i=0; i<nvec; i++) { + xd = NV_DATA_S(X[i]); + yd = NV_DATA_S(Y[i]); + zd = NV_DATA_S(Z[i]); + for (j=0; j<N; j++) + zd[j] = (a * xd[j]) + yd[j]; + } + + return(0); +} + +static int VLin2VectorArray_Serial(int nvec, realtype a, N_Vector* X, N_Vector* Y, N_Vector* Z) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + realtype* zd=NULL; + + N = NV_LENGTH_S(X[0]); + + for (i=0; i<nvec; i++) { + xd = NV_DATA_S(X[i]); + yd = NV_DATA_S(Y[i]); + zd = NV_DATA_S(Z[i]); + for (j=0; j<N; j++) + zd[j] = (a * xd[j]) - yd[j]; + } + + return(0); +} + +static int VaxpyVectorArray_Serial(int nvec, realtype a, N_Vector* X, N_Vector* Y) +{ + int i; + sunindextype j, N; + realtype* xd=NULL; + realtype* yd=NULL; + + N = NV_LENGTH_S(X[0]); + + if (a == ONE) { + for (i=0; i<nvec; i++) { + xd = NV_DATA_S(X[i]); + yd = NV_DATA_S(Y[i]); + for (j=0; j<N; j++) + yd[j] += xd[j]; + } + + return(0); + } + + if (a == -ONE) { + for (i=0; i<nvec; i++) { + xd = NV_DATA_S(X[i]); + yd = NV_DATA_S(Y[i]); + for (j=0; j<N; j++) + yd[j] -= xd[j]; + } + + return(0); + } + + for (i=0; i<nvec; i++) { + xd = NV_DATA_S(X[i]); + yd = NV_DATA_S(Y[i]); + for (j=0; j<N; j++) + yd[j] += a * xd[j]; + } + + return(0); +} + + +/* + * ----------------------------------------------------------------- + * Enable / Disable fused and vector array operations + * ----------------------------------------------------------------- + */ + +int N_VEnableFusedOps_Serial(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); + + if (tf) { + /* enable all fused vector operations */ + v->ops->nvlinearcombination = N_VLinearCombination_Serial; + v->ops->nvscaleaddmulti = N_VScaleAddMulti_Serial; + v->ops->nvdotprodmulti = N_VDotProdMulti_Serial; + /* enable all vector array operations */ + v->ops->nvlinearsumvectorarray = N_VLinearSumVectorArray_Serial; + v->ops->nvscalevectorarray = N_VScaleVectorArray_Serial; + v->ops->nvconstvectorarray = N_VConstVectorArray_Serial; + v->ops->nvwrmsnormvectorarray = N_VWrmsNormVectorArray_Serial; + v->ops->nvwrmsnormmaskvectorarray = N_VWrmsNormMaskVectorArray_Serial; + v->ops->nvscaleaddmultivectorarray = N_VScaleAddMultiVectorArray_Serial; + v->ops->nvlinearcombinationvectorarray = N_VLinearCombinationVectorArray_Serial; + } 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 N_VEnableLinearCombination_Serial(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 = N_VLinearCombination_Serial; + else + v->ops->nvlinearcombination = NULL; + + /* return success */ + return(0); +} + +int N_VEnableScaleAddMulti_Serial(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 = N_VScaleAddMulti_Serial; + else + v->ops->nvscaleaddmulti = NULL; + + /* return success */ + return(0); +} + +int N_VEnableDotProdMulti_Serial(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 = N_VDotProdMulti_Serial; + else + v->ops->nvdotprodmulti = NULL; + + /* return success */ + return(0); +} + +int N_VEnableLinearSumVectorArray_Serial(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 = N_VLinearSumVectorArray_Serial; + else + v->ops->nvlinearsumvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableScaleVectorArray_Serial(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 = N_VScaleVectorArray_Serial; + else + v->ops->nvscalevectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableConstVectorArray_Serial(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 = N_VConstVectorArray_Serial; + else + v->ops->nvconstvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableWrmsNormVectorArray_Serial(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 = N_VWrmsNormVectorArray_Serial; + else + v->ops->nvwrmsnormvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableWrmsNormMaskVectorArray_Serial(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 = N_VWrmsNormMaskVectorArray_Serial; + else + v->ops->nvwrmsnormmaskvectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableScaleAddMultiVectorArray_Serial(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->nvscaleaddmultivectorarray = N_VScaleAddMultiVectorArray_Serial; + else + v->ops->nvscaleaddmultivectorarray = NULL; + + /* return success */ + return(0); +} + +int N_VEnableLinearCombinationVectorArray_Serial(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->nvlinearcombinationvectorarray = N_VLinearCombinationVectorArray_Serial; + else + v->ops->nvlinearcombinationvectorarray = NULL; + + /* return success */ + return(0); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_band.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_band.c new file mode 100644 index 0000000..1495a57 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_band.c @@ -0,0 +1,264 @@ +/* + * ----------------------------------------------------------------- + * $Revision$ + * $Date$ + * ----------------------------------------------------------------- + * Programmer(s): 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 a generic BAND linear + * solver package. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <sundials/sundials_band.h> +#include <sundials/sundials_math.h> + +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + +#define ROW(i,j,smu) (i-j+smu) + +/* + * ----------------------------------------------------- + * Functions working on DlsMat + * ----------------------------------------------------- + */ + +sunindextype BandGBTRF(DlsMat A, sunindextype *p) +{ + return(bandGBTRF(A->cols, A->M, A->mu, A->ml, A->s_mu, p)); +} + +void BandGBTRS(DlsMat A, sunindextype *p, realtype *b) +{ + bandGBTRS(A->cols, A->M, A->s_mu, A->ml, p, b); +} + +void BandCopy(DlsMat A, DlsMat B, sunindextype copymu, sunindextype copyml) +{ + bandCopy(A->cols, B->cols, A->M, A->s_mu, B->s_mu, copymu, copyml); +} + +void BandScale(realtype c, DlsMat A) +{ + bandScale(c, A->cols, A->M, A->mu, A->ml, A->s_mu); +} + +void BandMatvec(DlsMat A, realtype *x, realtype *y) +{ + bandMatvec(A->cols, x, y, A->M, A->mu, A->ml, A->s_mu); +} + +/* + * ----------------------------------------------------- + * Functions working on realtype** + * ----------------------------------------------------- + */ + +sunindextype bandGBTRF(realtype **a, sunindextype n, sunindextype mu, sunindextype ml, sunindextype smu, sunindextype *p) +{ + sunindextype c, r, num_rows; + sunindextype i, j, k, l, storage_l, storage_k, last_col_k, last_row_k; + realtype *a_c, *col_k, *diag_k, *sub_diag_k, *col_j, *kptr, *jptr; + realtype max, temp, mult, a_kj; + booleantype swap; + + /* zero out the first smu - mu rows of the rectangular array a */ + + num_rows = smu - mu; + if (num_rows > 0) { + for (c=0; c < n; c++) { + a_c = a[c]; + for (r=0; r < num_rows; r++) { + a_c[r] = ZERO; + } + } + } + + /* k = elimination step number */ + + for (k=0; k < n-1; k++, p++) { + + col_k = a[k]; + diag_k = col_k + smu; + sub_diag_k = diag_k + 1; + last_row_k = SUNMIN(n-1,k+ml); + + /* find l = pivot row number */ + + l=k; + max = SUNRabs(*diag_k); + for (i=k+1, kptr=sub_diag_k; i <= last_row_k; i++, kptr++) { + if (SUNRabs(*kptr) > max) { + l=i; + max = SUNRabs(*kptr); + } + } + storage_l = ROW(l, k, smu); + *p = l; + + /* check for zero pivot element */ + + if (col_k[storage_l] == ZERO) return(k+1); + + /* swap a(l,k) and a(k,k) if necessary */ + + if ( (swap = (l != k) )) { + temp = col_k[storage_l]; + col_k[storage_l] = *diag_k; + *diag_k = temp; + } + + /* Scale the elements below the diagonal in */ + /* column k by -1.0 / a(k,k). After the above swap, */ + /* a(k,k) holds the pivot element. This scaling */ + /* stores the pivot row multipliers -a(i,k)/a(k,k) */ + /* in a(i,k), i=k+1, ..., SUNMIN(n-1,k+ml). */ + + mult = -ONE / (*diag_k); + for (i=k+1, kptr = sub_diag_k; i <= last_row_k; i++, kptr++) + (*kptr) *= mult; + + /* row_i = row_i - [a(i,k)/a(k,k)] row_k, i=k+1, ..., SUNMIN(n-1,k+ml) */ + /* row k is the pivot row after swapping with row l. */ + /* The computation is done one column at a time, */ + /* column j=k+1, ..., SUNMIN(k+smu,n-1). */ + + last_col_k = SUNMIN(k+smu,n-1); + for (j=k+1; j <= last_col_k; j++) { + + col_j = a[j]; + storage_l = ROW(l,j,smu); + storage_k = ROW(k,j,smu); + a_kj = col_j[storage_l]; + + /* Swap the elements a(k,j) and a(k,l) if l!=k. */ + + if (swap) { + col_j[storage_l] = col_j[storage_k]; + col_j[storage_k] = a_kj; + } + + /* a(i,j) = a(i,j) - [a(i,k)/a(k,k)]*a(k,j) */ + /* a_kj = a(k,j), *kptr = - a(i,k)/a(k,k), *jptr = a(i,j) */ + + if (a_kj != ZERO) { + for (i=k+1, kptr=sub_diag_k, jptr=col_j+ROW(k+1,j,smu); + i <= last_row_k; + i++, kptr++, jptr++) + (*jptr) += a_kj * (*kptr); + } + } + } + + /* set the last pivot row to be n-1 and check for a zero pivot */ + + *p = n-1; + if (a[n-1][smu] == ZERO) return(n); + + /* return 0 to indicate success */ + + return(0); +} + +void bandGBTRS(realtype **a, sunindextype n, sunindextype smu, sunindextype ml, sunindextype *p, realtype *b) +{ + sunindextype k, l, i, first_row_k, last_row_k; + realtype mult, *diag_k; + + /* Solve Ly = Pb, store solution y in b */ + + for (k=0; k < n-1; k++) { + l = p[k]; + mult = b[l]; + if (l != k) { + b[l] = b[k]; + b[k] = mult; + } + diag_k = a[k]+smu; + last_row_k = SUNMIN(n-1,k+ml); + for (i=k+1; i <= last_row_k; i++) + b[i] += mult * diag_k[i-k]; + } + + /* Solve Ux = y, store solution x in b */ + + for (k=n-1; k >= 0; k--) { + diag_k = a[k]+smu; + first_row_k = SUNMAX(0,k-smu); + b[k] /= (*diag_k); + mult = -b[k]; + for (i=first_row_k; i <= k-1; i++) + b[i] += mult*diag_k[i-k]; + } +} + +void bandCopy(realtype **a, realtype **b, sunindextype n, sunindextype a_smu, sunindextype b_smu, + sunindextype copymu, sunindextype copyml) +{ + sunindextype i, j, copySize; + realtype *a_col_j, *b_col_j; + + copySize = copymu + copyml + 1; + + for (j=0; j < n; j++) { + a_col_j = a[j]+a_smu-copymu; + b_col_j = b[j]+b_smu-copymu; + for (i=0; i < copySize; i++) + b_col_j[i] = a_col_j[i]; + } +} + +void bandScale(realtype c, realtype **a, sunindextype n, sunindextype mu, sunindextype ml, sunindextype smu) +{ + sunindextype i, j, colSize; + realtype *col_j; + + colSize = mu + ml + 1; + + for(j=0; j < n; j++) { + col_j = a[j]+smu-mu; + for (i=0; i < colSize; i++) + col_j[i] *= c; + } +} + +void bandAddIdentity(realtype **a, sunindextype n, sunindextype smu) +{ + sunindextype j; + + for(j=0; j < n; j++) + a[j][smu] += ONE; +} + +void bandMatvec(realtype **a, realtype *x, realtype *y, sunindextype n, + sunindextype mu, sunindextype ml, sunindextype smu) +{ + sunindextype i, j, is, ie; + realtype *col_j; + + for (i=0; i<n; i++) + y[i] = 0.0; + + for(j=0; j<n; j++) { + col_j = a[j]+smu-mu; + is = (0 > j-mu) ? 0 : j-mu; + ie = (n-1 < j+ml) ? n-1 : j+ml; + for (i=is; i<=ie; i++) + y[i] += col_j[i-j+mu]*x[j]; + } +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_dense.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_dense.c new file mode 100644 index 0000000..debaf7f --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_dense.c @@ -0,0 +1,400 @@ +/* + * ----------------------------------------------------------------- + * $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 a generic package of dense + * matrix operations. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <sundials/sundials_dense.h> +#include <sundials/sundials_math.h> + +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) +#define TWO RCONST(2.0) + +/* + * ----------------------------------------------------- + * Functions working on DlsMat + * ----------------------------------------------------- + */ + +sunindextype DenseGETRF(DlsMat A, sunindextype *p) +{ + return(denseGETRF(A->cols, A->M, A->N, p)); +} + +void DenseGETRS(DlsMat A, sunindextype *p, realtype *b) +{ + denseGETRS(A->cols, A->N, p, b); +} + +sunindextype DensePOTRF(DlsMat A) +{ + return(densePOTRF(A->cols, A->M)); +} + +void DensePOTRS(DlsMat A, realtype *b) +{ + densePOTRS(A->cols, A->M, b); +} + +int DenseGEQRF(DlsMat A, realtype *beta, realtype *wrk) +{ + return(denseGEQRF(A->cols, A->M, A->N, beta, wrk)); +} + +int DenseORMQR(DlsMat A, realtype *beta, realtype *vn, realtype *vm, realtype *wrk) +{ + return(denseORMQR(A->cols, A->M, A->N, beta, vn, vm, wrk)); +} + +void DenseCopy(DlsMat A, DlsMat B) +{ + denseCopy(A->cols, B->cols, A->M, A->N); +} + +void DenseScale(realtype c, DlsMat A) +{ + denseScale(c, A->cols, A->M, A->N); +} + +void DenseMatvec(DlsMat A, realtype *x, realtype *y) +{ + denseMatvec(A->cols, x, y, A->M, A->N); +} + +sunindextype denseGETRF(realtype **a, sunindextype m, sunindextype n, sunindextype *p) +{ + sunindextype i, j, k, l; + realtype *col_j, *col_k; + realtype temp, mult, a_kj; + + /* k-th elimination step number */ + for (k=0; k < n; k++) { + + col_k = a[k]; + + /* find l = pivot row number */ + l=k; + for (i=k+1; i < m; i++) + if (SUNRabs(col_k[i]) > SUNRabs(col_k[l])) l=i; + p[k] = l; + + /* check for zero pivot element */ + if (col_k[l] == ZERO) return(k+1); + + /* swap a(k,1:n) and a(l,1:n) if necessary */ + if ( l!= k ) { + for (i=0; i<n; i++) { + temp = a[i][l]; + a[i][l] = a[i][k]; + a[i][k] = temp; + } + } + + /* Scale the elements below the diagonal in + * column k by 1.0/a(k,k). After the above swap + * a(k,k) holds the pivot element. This scaling + * stores the pivot row multipliers a(i,k)/a(k,k) + * in a(i,k), i=k+1, ..., m-1. + */ + mult = ONE/col_k[k]; + for(i=k+1; i < m; i++) col_k[i] *= mult; + + /* row_i = row_i - [a(i,k)/a(k,k)] row_k, i=k+1, ..., m-1 */ + /* row k is the pivot row after swapping with row l. */ + /* The computation is done one column at a time, */ + /* column j=k+1, ..., n-1. */ + + for (j=k+1; j < n; j++) { + + col_j = a[j]; + a_kj = col_j[k]; + + /* a(i,j) = a(i,j) - [a(i,k)/a(k,k)]*a(k,j) */ + /* a_kj = a(k,j), col_k[i] = - a(i,k)/a(k,k) */ + + if (a_kj != ZERO) { + for (i=k+1; i < m; i++) + col_j[i] -= a_kj * col_k[i]; + } + } + } + + /* return 0 to indicate success */ + + return(0); +} + +void denseGETRS(realtype **a, sunindextype n, sunindextype *p, realtype *b) +{ + sunindextype i, k, pk; + realtype *col_k, tmp; + + /* Permute b, based on pivot information in p */ + for (k=0; k<n; k++) { + pk = p[k]; + if(pk != k) { + tmp = b[k]; + b[k] = b[pk]; + b[pk] = tmp; + } + } + + /* Solve Ly = b, store solution y in b */ + for (k=0; k<n-1; k++) { + col_k = a[k]; + for (i=k+1; i<n; i++) b[i] -= col_k[i]*b[k]; + } + + /* Solve Ux = y, store solution x in b */ + for (k = n-1; k > 0; k--) { + col_k = a[k]; + b[k] /= col_k[k]; + for (i=0; i<k; i++) b[i] -= col_k[i]*b[k]; + } + b[0] /= a[0][0]; + +} + +/* + * Cholesky decomposition of a symmetric positive-definite matrix + * A = C^T*C: gaxpy version. + * Only the lower triangle of A is accessed and it is overwritten with + * the lower triangle of C. + */ +sunindextype densePOTRF(realtype **a, sunindextype m) +{ + realtype *a_col_j, *a_col_k; + realtype a_diag; + sunindextype i, j, k; + + for (j=0; j<m; j++) { + + a_col_j = a[j]; + + if (j>0) { + for(i=j; i<m; i++) { + for(k=0;k<j;k++) { + a_col_k = a[k]; + a_col_j[i] -= a_col_k[i]*a_col_k[j]; + } + } + } + + a_diag = a_col_j[j]; + if (a_diag <= ZERO) return(j+1); + a_diag = SUNRsqrt(a_diag); + + for(i=j; i<m; i++) a_col_j[i] /= a_diag; + + } + + return(0); +} + +/* + * Solution of Ax=b, with A s.p.d., based on the Cholesky decomposition + * obtained with denPOTRF.; A = C*C^T, C lower triangular + * + */ +void densePOTRS(realtype **a, sunindextype m, realtype *b) +{ + realtype *col_j, *col_i; + sunindextype i, j; + + /* Solve C y = b, forward substitution - column version. + Store solution y in b */ + for (j=0; j < m-1; j++) { + col_j = a[j]; + b[j] /= col_j[j]; + for (i=j+1; i < m; i++) + b[i] -= b[j]*col_j[i]; + } + col_j = a[m-1]; + b[m-1] /= col_j[m-1]; + + /* Solve C^T x = y, backward substitution - row version. + Store solution x in b */ + col_j = a[m-1]; + b[m-1] /= col_j[m-1]; + for (i=m-2; i>=0; i--) { + col_i = a[i]; + for (j=i+1; j<m; j++) + b[i] -= col_i[j]*b[j]; + b[i] /= col_i[i]; + } + +} + +/* + * QR factorization of a rectangular matrix A of size m by n (m >= n) + * using Householder reflections. + * + * On exit, the elements on and above the diagonal of A contain the n by n + * upper triangular matrix R; the elements below the diagonal, with the array beta, + * represent the orthogonal matrix Q as a product of elementary reflectors . + * + * v (of length m) must be provided as workspace. + * + */ + +int denseGEQRF(realtype **a, sunindextype m, sunindextype n, realtype *beta, realtype *v) +{ + realtype ajj, s, mu, v1, v1_2; + realtype *col_j, *col_k; + sunindextype i, j, k; + + /* For each column...*/ + for(j=0; j<n; j++) { + + col_j = a[j]; + + ajj = col_j[j]; + + /* Compute the j-th Householder vector (of length m-j) */ + v[0] = ONE; + s = ZERO; + for(i=1; i<m-j; i++) { + v[i] = col_j[i+j]; + s += v[i]*v[i]; + } + + if(s != ZERO) { + mu = SUNRsqrt(ajj*ajj+s); + v1 = (ajj <= ZERO) ? ajj-mu : -s/(ajj+mu); + v1_2 = v1*v1; + beta[j] = TWO * v1_2 / (s + v1_2); + for(i=1; i<m-j; i++) v[i] /= v1; + } else { + beta[j] = ZERO; + } + + /* Update upper triangle of A (load R) */ + for(k=j; k<n; k++) { + col_k = a[k]; + s = ZERO; + for(i=0; i<m-j; i++) s += col_k[i+j]*v[i]; + s *= beta[j]; + for(i=0; i<m-j; i++) col_k[i+j] -= s*v[i]; + } + + /* Update A (load Householder vector) */ + if(j<m-1) { + for(i=1; i<m-j; i++) col_j[i+j] = v[i]; + } + + } + + + return(0); +} + +/* + * Computes vm = Q * vn, where the orthogonal matrix Q is stored as + * elementary reflectors in the m by n matrix A and in the vector beta. + * (NOTE: It is assumed that an QR factorization has been previously + * computed with denGEQRF). + * + * vn (IN) has length n, vm (OUT) has length m, and it's assumed that m >= n. + * + * v (of length m) must be provided as workspace. + */ +int denseORMQR(realtype **a, sunindextype m, sunindextype n, realtype *beta, + realtype *vn, realtype *vm, realtype *v) +{ + realtype *col_j, s; + sunindextype i, j; + + /* Initialize vm */ + for(i=0; i<n; i++) vm[i] = vn[i]; + for(i=n; i<m; i++) vm[i] = ZERO; + + /* Accumulate (backwards) corrections into vm */ + for(j=n-1; j>=0; j--) { + + col_j = a[j]; + + v[0] = ONE; + s = vm[j]; + for(i=1; i<m-j; i++) { + v[i] = col_j[i+j]; + s += v[i]*vm[i+j]; + } + s *= beta[j]; + + for(i=0; i<m-j; i++) vm[i+j] -= s * v[i]; + + } + + return(0); +} + +void denseCopy(realtype **a, realtype **b, sunindextype m, sunindextype n) +{ + sunindextype i, j; + realtype *a_col_j, *b_col_j; + + for (j=0; j < n; j++) { + a_col_j = a[j]; + b_col_j = b[j]; + for (i=0; i < m; i++) + b_col_j[i] = a_col_j[i]; + } + +} + +void denseScale(realtype c, realtype **a, sunindextype m, sunindextype n) +{ + sunindextype i, j; + realtype *col_j; + + for (j=0; j < n; j++) { + col_j = a[j]; + for (i=0; i < m; i++) + col_j[i] *= c; + } +} + +void denseAddIdentity(realtype **a, sunindextype n) +{ + sunindextype i; + + for (i=0; i < n; i++) a[i][i] += ONE; +} + +void denseMatvec(realtype **a, realtype *x, realtype *y, sunindextype m, sunindextype n) +{ + sunindextype i, j; + realtype *col_j; + + for (i=0; i<m; i++) { + y[i] = 0.0; + } + + for (j=0; j<n; j++) { + col_j = a[j]; + for (i=0; i<m; i++) + y[i] += col_j[i]*x[j]; + } +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_direct.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_direct.c new file mode 100644 index 0000000..6d2dab6 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_direct.c @@ -0,0 +1,355 @@ +/* ----------------------------------------------------------------- + * Programmer: 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 operations to be used by a + * generic direct linear solver. + * -----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include <sundials/sundials_direct.h> +#include <sundials/sundials_math.h> + +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + +DlsMat NewDenseMat(sunindextype M, sunindextype N) +{ + DlsMat A; + sunindextype j; + + if ( (M <= 0) || (N <= 0) ) return(NULL); + + A = NULL; + A = (DlsMat) malloc(sizeof *A); + if (A==NULL) return (NULL); + + A->data = (realtype *) malloc(M * N * sizeof(realtype)); + if (A->data == NULL) { + free(A); A = NULL; + return(NULL); + } + A->cols = (realtype **) malloc(N * sizeof(realtype *)); + if (A->cols == NULL) { + free(A->data); A->data = NULL; + free(A); A = NULL; + return(NULL); + } + + for (j=0; j < N; j++) A->cols[j] = A->data + j * M; + + A->M = M; + A->N = N; + A->ldim = M; + A->ldata = M*N; + + A->type = SUNDIALS_DENSE; + + return(A); +} + +realtype **newDenseMat(sunindextype m, sunindextype n) +{ + sunindextype j; + realtype **a; + + if ( (n <= 0) || (m <= 0) ) return(NULL); + + a = NULL; + a = (realtype **) malloc(n * sizeof(realtype *)); + if (a == NULL) return(NULL); + + a[0] = NULL; + a[0] = (realtype *) malloc(m * n * sizeof(realtype)); + if (a[0] == NULL) { + free(a); a = NULL; + return(NULL); + } + + for (j=1; j < n; j++) a[j] = a[0] + j * m; + + return(a); +} + + +DlsMat NewBandMat(sunindextype N, sunindextype mu, sunindextype ml, sunindextype smu) +{ + DlsMat A; + sunindextype j, colSize; + + if (N <= 0) return(NULL); + + A = NULL; + A = (DlsMat) malloc(sizeof *A); + if (A == NULL) return (NULL); + + colSize = smu + ml + 1; + A->data = NULL; + A->data = (realtype *) malloc(N * colSize * sizeof(realtype)); + if (A->data == NULL) { + free(A); A = NULL; + return(NULL); + } + + A->cols = NULL; + A->cols = (realtype **) malloc(N * sizeof(realtype *)); + if (A->cols == NULL) { + free(A->data); + free(A); A = NULL; + return(NULL); + } + + for (j=0; j < N; j++) A->cols[j] = A->data + j * colSize; + + A->M = N; + A->N = N; + A->mu = mu; + A->ml = ml; + A->s_mu = smu; + A->ldim = colSize; + A->ldata = N * colSize; + + A->type = SUNDIALS_BAND; + + return(A); +} + +realtype **newBandMat(sunindextype n, sunindextype smu, sunindextype ml) +{ + realtype **a; + sunindextype j, colSize; + + if (n <= 0) return(NULL); + + a = NULL; + a = (realtype **) malloc(n * sizeof(realtype *)); + if (a == NULL) return(NULL); + + colSize = smu + ml + 1; + a[0] = NULL; + a[0] = (realtype *) malloc(n * colSize * sizeof(realtype)); + if (a[0] == NULL) { + free(a); a = NULL; + return(NULL); + } + + for (j=1; j < n; j++) a[j] = a[0] + j * colSize; + + return(a); +} + +void DestroyMat(DlsMat A) +{ + free(A->data); A->data = NULL; + free(A->cols); + free(A); A = NULL; +} + +void destroyMat(realtype **a) +{ + free(a[0]); a[0] = NULL; + free(a); a = NULL; +} + +int *NewIntArray(int N) +{ + int *vec; + + if (N <= 0) return(NULL); + + vec = NULL; + vec = (int *) malloc(N * sizeof(int)); + + return(vec); +} + +int *newIntArray(int n) +{ + int *v; + + if (n <= 0) return(NULL); + + v = NULL; + v = (int *) malloc(n * sizeof(int)); + + return(v); +} + +sunindextype *NewIndexArray(sunindextype N) +{ + sunindextype *vec; + + if (N <= 0) return(NULL); + + vec = NULL; + vec = (sunindextype *) malloc(N * sizeof(sunindextype)); + + return(vec); +} + +sunindextype *newIndexArray(sunindextype n) +{ + sunindextype *v; + + if (n <= 0) return(NULL); + + v = NULL; + v = (sunindextype *) malloc(n * sizeof(sunindextype)); + + return(v); +} + +realtype *NewRealArray(sunindextype N) +{ + realtype *vec; + + if (N <= 0) return(NULL); + + vec = NULL; + vec = (realtype *) malloc(N * sizeof(realtype)); + + return(vec); +} + +realtype *newRealArray(sunindextype m) +{ + realtype *v; + + if (m <= 0) return(NULL); + + v = NULL; + v = (realtype *) malloc(m * sizeof(realtype)); + + return(v); +} + +void DestroyArray(void *V) +{ + free(V); + V = NULL; +} + +void destroyArray(void *v) +{ + free(v); + v = NULL; +} + + +void AddIdentity(DlsMat A) +{ + sunindextype i; + + switch (A->type) { + + case SUNDIALS_DENSE: + for (i=0; i<A->N; i++) A->cols[i][i] += ONE; + break; + + case SUNDIALS_BAND: + for (i=0; i<A->M; i++) A->cols[i][A->s_mu] += ONE; + break; + + } + +} + + +void SetToZero(DlsMat A) +{ + sunindextype i, j, colSize; + realtype *col_j; + + switch (A->type) { + + case SUNDIALS_DENSE: + + for (j=0; j<A->N; j++) { + col_j = A->cols[j]; + for (i=0; i<A->M; i++) + col_j[i] = ZERO; + } + + break; + + case SUNDIALS_BAND: + + colSize = A->mu + A->ml + 1; + for (j=0; j<A->M; j++) { + col_j = A->cols[j] + A->s_mu - A->mu; + for (i=0; i<colSize; i++) + col_j[i] = ZERO; + } + + break; + + } + +} + + +void PrintMat(DlsMat A, FILE *outfile) +{ + sunindextype i, j, start, finish; + realtype **a; + + switch (A->type) { + + case SUNDIALS_DENSE: + + fprintf(outfile, "\n"); + for (i=0; i < A->M; i++) { + for (j=0; j < A->N; j++) { +#if defined(SUNDIALS_EXTENDED_PRECISION) + fprintf(outfile, "%12Lg ", DENSE_ELEM(A,i,j)); +#elif defined(SUNDIALS_DOUBLE_PRECISION) + fprintf(outfile, "%12g ", DENSE_ELEM(A,i,j)); +#else + fprintf(outfile, "%12g ", DENSE_ELEM(A,i,j)); +#endif + } + fprintf(outfile, "\n"); + } + fprintf(outfile, "\n"); + + break; + + case SUNDIALS_BAND: + + a = A->cols; + fprintf(outfile, "\n"); + for (i=0; i < A->N; i++) { + start = SUNMAX(0,i-A->ml); + finish = SUNMIN(A->N-1,i+A->mu); + for (j=0; j < start; j++) fprintf(outfile, "%12s ",""); + for (j=start; j <= finish; j++) { +#if defined(SUNDIALS_EXTENDED_PRECISION) + fprintf(outfile, "%12Lg ", a[j][i-j+A->s_mu]); +#elif defined(SUNDIALS_DOUBLE_PRECISION) + fprintf(outfile, "%12g ", a[j][i-j+A->s_mu]); +#else + fprintf(outfile, "%12g ", a[j][i-j+A->s_mu]); +#endif + } + fprintf(outfile, "\n"); + } + fprintf(outfile, "\n"); + + break; + + } + +} + + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_iterative.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_iterative.c new file mode 100644 index 0000000..da71f3b --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_iterative.c @@ -0,0 +1,298 @@ +/* + * ----------------------------------------------------------------- + * $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 iterative.h header + * file. It contains the implementation of functions that may be + * useful for many different iterative solvers of A x = b. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> + +#include <sundials/sundials_iterative.h> +#include <sundials/sundials_math.h> + +#define FACTOR RCONST(1000.0) +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + +/* + * ----------------------------------------------------------------- + * Function : ModifiedGS + * ----------------------------------------------------------------- + * This implementation of ModifiedGS is a slight modification of a + * previous modified Gram-Schmidt routine (called mgs) written by + * Milo Dorr. + * ----------------------------------------------------------------- + */ + +int ModifiedGS(N_Vector *v, realtype **h, int k, int p, + realtype *new_vk_norm) +{ + int i, k_minus_1, i0; + realtype new_norm_2, new_product, vk_norm, temp; + + vk_norm = SUNRsqrt(N_VDotProd(v[k],v[k])); + k_minus_1 = k - 1; + i0 = SUNMAX(k-p, 0); + + /* Perform modified Gram-Schmidt */ + + for (i=i0; i < k; i++) { + h[i][k_minus_1] = N_VDotProd(v[i], v[k]); + N_VLinearSum(ONE, v[k], -h[i][k_minus_1], v[i], v[k]); + } + + /* Compute the norm of the new vector at v[k] */ + + *new_vk_norm = SUNRsqrt(N_VDotProd(v[k], v[k])); + + /* If the norm of the new vector at v[k] is less than + FACTOR (== 1000) times unit roundoff times the norm of the + input vector v[k], then the vector will be reorthogonalized + in order to ensure that nonorthogonality is not being masked + by a very small vector length. */ + + temp = FACTOR * vk_norm; + if ((temp + (*new_vk_norm)) != temp) return(0); + + new_norm_2 = ZERO; + + for (i=i0; i < k; i++) { + new_product = N_VDotProd(v[i], v[k]); + temp = FACTOR * h[i][k_minus_1]; + if ((temp + new_product) == temp) continue; + h[i][k_minus_1] += new_product; + N_VLinearSum(ONE, v[k],-new_product, v[i], v[k]); + new_norm_2 += SUNSQR(new_product); + } + + if (new_norm_2 != ZERO) { + new_product = SUNSQR(*new_vk_norm) - new_norm_2; + *new_vk_norm = (new_product > ZERO) ? SUNRsqrt(new_product) : ZERO; + } + + return(0); +} + +/* + * ----------------------------------------------------------------- + * Function : ClassicalGS + * ----------------------------------------------------------------- + * This implementation of ClassicalGS was contributed by Homer Walker + * and Peter Brown. + * ----------------------------------------------------------------- + */ + +int ClassicalGS(N_Vector *v, realtype **h, int k, int p, realtype *new_vk_norm, + realtype *stemp, N_Vector *vtemp) +{ + int i, i0, k_minus_1, retval; + realtype vk_norm; + + k_minus_1 = k - 1; + i0 = SUNMAX(k-p,0); + + /* Perform Classical Gram-Schmidt */ + + retval = N_VDotProdMulti(k-i0+1, v[k], v+i0, stemp); + if (retval != 0) return(-1); + + vk_norm = SUNRsqrt(stemp[k-i0]); + for (i=k-i0-1; i >= 0; i--) { + h[i][k_minus_1] = stemp[i]; + stemp[i+1] = -stemp[i]; + vtemp[i+1] = v[i]; + } + stemp[0] = ONE; + vtemp[0] = v[k]; + + retval = N_VLinearCombination(k-i0+1, stemp, vtemp, v[k]); + if (retval != 0) return(-1); + + /* Compute the norm of the new vector at v[k] */ + + *new_vk_norm = SUNRsqrt(N_VDotProd(v[k], v[k])); + + /* Reorthogonalize if necessary */ + + if ((FACTOR * (*new_vk_norm)) < vk_norm) { + + retval = N_VDotProdMulti(k-i0, v[k], v+i0, stemp+1); + if (retval != 0) return(-1); + + stemp[0] = ONE; + vtemp[0] = v[k]; + for (i=i0; i < k; i++) { + h[i][k_minus_1] += stemp[i-i0+1]; + stemp[i-i0+1] = -stemp[i-i0+1]; + vtemp[i-i0+1] = v[i-i0]; + } + + retval = N_VLinearCombination(k+1, stemp, vtemp, v[k]); + if (retval != 0) return(-1); + + *new_vk_norm = SUNRsqrt(N_VDotProd(v[k],v[k])); + } + + return(0); +} + +/* + * ----------------------------------------------------------------- + * Function : QRfact + * ----------------------------------------------------------------- + * This implementation of QRfact is a slight modification of a + * previous routine (called qrfact) written by Milo Dorr. + * ----------------------------------------------------------------- + */ + +int QRfact(int n, realtype **h, realtype *q, int job) +{ + realtype c, s, temp1, temp2, temp3; + int i, j, k, q_ptr, n_minus_1, code=0; + + switch (job) { + case 0: + + /* Compute a new factorization of H */ + + code = 0; + for (k=0; k < n; k++) { + + /* Multiply column k by the previous k-1 Givens rotations */ + + for (j=0; j < k-1; j++) { + i = 2*j; + temp1 = h[j][k]; + temp2 = h[j+1][k]; + c = q[i]; + s = q[i+1]; + h[j][k] = c*temp1 - s*temp2; + h[j+1][k] = s*temp1 + c*temp2; + } + + /* Compute the Givens rotation components c and s */ + + q_ptr = 2*k; + temp1 = h[k][k]; + temp2 = h[k+1][k]; + if( temp2 == ZERO) { + c = ONE; + s = ZERO; + } else if (SUNRabs(temp2) >= SUNRabs(temp1)) { + temp3 = temp1/temp2; + s = -ONE/SUNRsqrt(ONE+SUNSQR(temp3)); + c = -s*temp3; + } else { + temp3 = temp2/temp1; + c = ONE/SUNRsqrt(ONE+SUNSQR(temp3)); + s = -c*temp3; + } + q[q_ptr] = c; + q[q_ptr+1] = s; + if( (h[k][k] = c*temp1 - s*temp2) == ZERO) code = k+1; + } + break; + + default: + + /* Update the factored H to which a new column has been added */ + + n_minus_1 = n - 1; + code = 0; + + /* Multiply the new column by the previous n-1 Givens rotations */ + + for (k=0; k < n_minus_1; k++) { + i = 2*k; + temp1 = h[k][n_minus_1]; + temp2 = h[k+1][n_minus_1]; + c = q[i]; + s = q[i+1]; + h[k][n_minus_1] = c*temp1 - s*temp2; + h[k+1][n_minus_1] = s*temp1 + c*temp2; + } + + /* Compute new Givens rotation and multiply it times the last two + entries in the new column of H. Note that the second entry of + this product will be 0, so it is not necessary to compute it. */ + + temp1 = h[n_minus_1][n_minus_1]; + temp2 = h[n][n_minus_1]; + if (temp2 == ZERO) { + c = ONE; + s = ZERO; + } else if (SUNRabs(temp2) >= SUNRabs(temp1)) { + temp3 = temp1/temp2; + s = -ONE/SUNRsqrt(ONE+SUNSQR(temp3)); + c = -s*temp3; + } else { + temp3 = temp2/temp1; + c = ONE/SUNRsqrt(ONE+SUNSQR(temp3)); + s = -c*temp3; + } + q_ptr = 2*n_minus_1; + q[q_ptr] = c; + q[q_ptr+1] = s; + if ((h[n_minus_1][n_minus_1] = c*temp1 - s*temp2) == ZERO) + code = n; + } + + return (code); +} + +/* + * ----------------------------------------------------------------- + * Function : QRsol + * ----------------------------------------------------------------- + * This implementation of QRsol is a slight modification of a + * previous routine (called qrsol) written by Milo Dorr. + * ----------------------------------------------------------------- + */ + +int QRsol(int n, realtype **h, realtype *q, realtype *b) +{ + realtype c, s, temp1, temp2; + int i, k, q_ptr, code=0; + + /* Compute Q*b */ + + for (k=0; k < n; k++) { + q_ptr = 2*k; + c = q[q_ptr]; + s = q[q_ptr+1]; + temp1 = b[k]; + temp2 = b[k+1]; + b[k] = c*temp1 - s*temp2; + b[k+1] = s*temp1 + c*temp2; + } + + /* Solve R*x = Q*b */ + + for (k=n-1; k >= 0; k--) { + if (h[k][k] == ZERO) { + code = k + 1; + break; + } + b[k] /= h[k][k]; + for (i=0; i < k; i++) b[i] -= b[k]*h[i][k]; + } + + return (code); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_linearsolver.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_linearsolver.c new file mode 100644 index 0000000..b2895bb --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_linearsolver.c @@ -0,0 +1,132 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * David Gardner, Carol Woodward, 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 the implementation file for a generic SUNLINEARSOLVER + * package. It contains the implementation of the SUNLinearSolver + * operations listed in sundials_linearsolver.h + * ----------------------------------------------------------------- + */ + +#include <stdlib.h> +#include <sundials/sundials_linearsolver.h> + +/* + * ----------------------------------------------------------------- + * Functions in the 'ops' structure + * ----------------------------------------------------------------- + */ + +SUNLinearSolver_Type SUNLinSolGetType(SUNLinearSolver S) +{ + SUNLinearSolver_Type type; + type = S->ops->gettype(S); + return(type); +} + +int SUNLinSolSetATimes(SUNLinearSolver S, void* A_data, + ATimesFn ATimes) +{ + if (S->ops->setatimes) + return ((int) S->ops->setatimes(S, A_data, ATimes)); + else + return SUNLS_SUCCESS; +} + + +int SUNLinSolSetPreconditioner(SUNLinearSolver S, void* P_data, + PSetupFn Pset, PSolveFn Psol) +{ + if (S->ops->setpreconditioner) + return ((int) S->ops->setpreconditioner(S, P_data, Pset, Psol)); + else + return SUNLS_SUCCESS; +} + +int SUNLinSolSetScalingVectors(SUNLinearSolver S, + N_Vector s1, N_Vector s2) +{ + if (S->ops->setscalingvectors) + return ((int) S->ops->setscalingvectors(S, s1, s2)); + else + return SUNLS_SUCCESS; +} + +int SUNLinSolInitialize(SUNLinearSolver S) +{ + return ((int) S->ops->initialize(S)); +} + +int SUNLinSolSetup(SUNLinearSolver S, SUNMatrix A) +{ + return ((int) S->ops->setup(S, A)); +} + +int SUNLinSolSolve(SUNLinearSolver S, SUNMatrix A, N_Vector x, + N_Vector b, realtype tol) +{ + return ((int) S->ops->solve(S, A, x, b, tol)); +} + +int SUNLinSolNumIters(SUNLinearSolver S) +{ + if (S->ops->numiters) + return ((int) S->ops->numiters(S)); + else + return 0; +} + +realtype SUNLinSolResNorm(SUNLinearSolver S) +{ + if (S->ops->resnorm) + return ((realtype) S->ops->resnorm(S)); + else + return RCONST(0.0); +} + +N_Vector SUNLinSolResid(SUNLinearSolver S) +{ + if (S->ops->resid) + return ((N_Vector) S->ops->resid(S)); + else + return NULL; +} + +long int SUNLinSolLastFlag(SUNLinearSolver S) +{ + if (S->ops->lastflag) + return ((long int) S->ops->lastflag(S)); + else + return SUNLS_SUCCESS; +} + +int SUNLinSolSpace(SUNLinearSolver S, long int *lenrwLS, + long int *leniwLS) +{ + if (S->ops->space) + return ((int) S->ops->space(S, lenrwLS, leniwLS)); + else { + *lenrwLS = 0; + *leniwLS = 0; + return SUNLS_SUCCESS; + } +} + +int SUNLinSolFree(SUNLinearSolver S) +{ + if (S==NULL) return 0; + S->ops->free(S); + return 0; +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_math.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_math.c new file mode 100644 index 0000000..bca60cd --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_math.c @@ -0,0 +1,53 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Scott D. Cohen, Alan C. Hindmarsh 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 implementation file for a simple C-language math + * library. + * -----------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> + +#include <sundials/sundials_math.h> + +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + +realtype SUNRpowerI(realtype base, int exponent) +{ + int i, expt; + realtype prod; + + prod = ONE; + expt = abs(exponent); + for(i = 1; i <= expt; i++) prod *= base; + if (exponent < 0) prod = ONE/prod; + return(prod); +} + +realtype SUNRpowerR(realtype base, realtype exponent) +{ + if (base <= ZERO) return(ZERO); + +#if defined(SUNDIALS_USE_GENERIC_MATH) + return((realtype) pow((double) base, (double) exponent)); +#elif defined(SUNDIALS_DOUBLE_PRECISION) + return(pow(base, exponent)); +#elif defined(SUNDIALS_SINGLE_PRECISION) + return(powf(base, exponent)); +#elif defined(SUNDIALS_EXTENDED_PRECISION) + return(powl(base, exponent)); +#endif +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_matrix.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_matrix.c new file mode 100644 index 0000000..e4702c3 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_matrix.c @@ -0,0 +1,82 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * David Gardner, Carol Woodward, 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 the implementation file for a generic SUNMATRIX package. + * It contains the implementation of the SUNMatrix operations listed + * in sundials_matrix.h + * ----------------------------------------------------------------- + */ + +#include <stdlib.h> +#include <sundials/sundials_matrix.h> +#include <sundials/sundials_nvector.h> + +/* + * ----------------------------------------------------------------- + * Functions in the 'ops' structure + * ----------------------------------------------------------------- + */ + +SUNMatrix_ID SUNMatGetID(SUNMatrix A) +{ + SUNMatrix_ID id; + id = A->ops->getid(A); + return(id); +} + +SUNMatrix SUNMatClone(SUNMatrix A) +{ + SUNMatrix B = NULL; + B = A->ops->clone(A); + return(B); +} + +void SUNMatDestroy(SUNMatrix A) +{ + if (A==NULL) return; + A->ops->destroy(A); + return; +} + +int SUNMatZero(SUNMatrix A) +{ + return((int) A->ops->zero(A)); +} + +int SUNMatCopy(SUNMatrix A, SUNMatrix B) +{ + return((int) A->ops->copy(A, B)); +} + +int SUNMatScaleAdd(realtype c, SUNMatrix A, SUNMatrix B) +{ + return((int) A->ops->scaleadd(c, A, B)); +} + +int SUNMatScaleAddI(realtype c, SUNMatrix A) +{ + return((int) A->ops->scaleaddi(c, A)); +} + +int SUNMatMatvec(SUNMatrix A, N_Vector x, N_Vector y) +{ + return((int) A->ops->matvec(A, x, y)); +} + +int SUNMatSpace(SUNMatrix A, long int *lenrw, long int *leniw) +{ + return((int) A->ops->space(A, lenrw, leniw)); +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_mpi.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_mpi.c new file mode 100644 index 0000000..05823af --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_mpi.c @@ -0,0 +1,99 @@ +/* ----------------------------------------------------------------- + * 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 <sundials/sundials_mpi.h> + +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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_nonlinearsolver.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_nonlinearsolver.c new file mode 100644 index 0000000..1a6dc8e --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_nonlinearsolver.c @@ -0,0 +1,161 @@ +/* ----------------------------------------------------------------------------- + * Programmer(s): David 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 is the implementation file for a generic SUNNonlinerSolver package. It + * contains the implementation of the SUNNonlinearSolver operations listed in + * the 'ops' structure in sundials_nonlinearsolver.h + * ---------------------------------------------------------------------------*/ + +#include <stdlib.h> +#include <sundials/sundials_nonlinearsolver.h> + +/* ----------------------------------------------------------------------------- + * core functions + * ---------------------------------------------------------------------------*/ + +SUNNonlinearSolver_Type SUNNonlinSolGetType(SUNNonlinearSolver NLS) +{ + return(NLS->ops->gettype(NLS)); +} + +int SUNNonlinSolInitialize(SUNNonlinearSolver NLS) +{ + if (NLS->ops->initialize) + return((int) NLS->ops->initialize(NLS)); + else + return(SUN_NLS_SUCCESS); +} + +int SUNNonlinSolSetup(SUNNonlinearSolver NLS, N_Vector y, void* mem) +{ + if (NLS->ops->setup) + return((int) NLS->ops->setup(NLS, y, mem)); + else + return(SUN_NLS_SUCCESS); +} + +int SUNNonlinSolSolve(SUNNonlinearSolver NLS, + N_Vector y0, N_Vector y, + N_Vector w, realtype tol, + booleantype callLSetup, void* mem) +{ + return((int) NLS->ops->solve(NLS, y0, y, w, tol, callLSetup, mem)); +} + +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); + } +} + +/* ----------------------------------------------------------------------------- + * set functions + * ---------------------------------------------------------------------------*/ + +/* set the nonlinear system function (required) */ +int SUNNonlinSolSetSysFn(SUNNonlinearSolver NLS, SUNNonlinSolSysFn SysFn) +{ + return((int) NLS->ops->setsysfn(NLS, SysFn)); +} + +/* set the linear solver setup function (optional) */ +int SUNNonlinSolSetLSetupFn(SUNNonlinearSolver NLS, SUNNonlinSolLSetupFn LSetupFn) +{ + if (NLS->ops->setlsetupfn) + return((int) NLS->ops->setlsetupfn(NLS, LSetupFn)); + else + return(SUN_NLS_SUCCESS); +} + +/* set the linear solver solve function (optional) */ +int SUNNonlinSolSetLSolveFn(SUNNonlinearSolver NLS, SUNNonlinSolLSolveFn LSolveFn) +{ + if (NLS->ops->setlsolvefn) + return((int) NLS->ops->setlsolvefn(NLS, LSolveFn)); + else + return(SUN_NLS_SUCCESS); +} + +/* set the convergence test function (optional) */ +int SUNNonlinSolSetConvTestFn(SUNNonlinearSolver NLS, SUNNonlinSolConvTestFn CTestFn) +{ + if (NLS->ops->setctestfn) + return((int) NLS->ops->setctestfn(NLS, CTestFn)); + else + return(SUN_NLS_SUCCESS); +} + +int SUNNonlinSolSetMaxIters(SUNNonlinearSolver NLS, int maxiters) +{ + if (NLS->ops->setmaxiters) + return((int) NLS->ops->setmaxiters(NLS, maxiters)); + else + return(SUN_NLS_SUCCESS); +} + +/* ----------------------------------------------------------------------------- + * get functions + * ---------------------------------------------------------------------------*/ + +/* get the total number on nonlinear iterations (optional) */ +int SUNNonlinSolGetNumIters(SUNNonlinearSolver NLS, long int *niters) +{ + if (NLS->ops->getnumiters) { + return((int) NLS->ops->getnumiters(NLS, niters)); + } else { + *niters = 0; + return(SUN_NLS_SUCCESS); + } +} + + +/* get the iteration count for the current nonlinear solve */ +int SUNNonlinSolGetCurIter(SUNNonlinearSolver NLS, int *iter) +{ + if (NLS->ops->getcuriter) { + return((int) NLS->ops->getcuriter(NLS, iter)); + } else { + *iter = -1; + return(SUN_NLS_SUCCESS); + } +} + + +/* get the total number on nonlinear solve convergence failures (optional) */ +int SUNNonlinSolGetNumConvFails(SUNNonlinearSolver NLS, long int *nconvfails) +{ + if (NLS->ops->getnumconvfails) { + return((int) NLS->ops->getnumconvfails(NLS, nconvfails)); + } else { + *nconvfails = 0; + return(SUN_NLS_SUCCESS); + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_nvector.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_nvector.c new file mode 100644 index 0000000..9227bae --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_nvector.c @@ -0,0 +1,495 @@ +/* ----------------------------------------------------------------- + * Programmer(s): Radu Serban 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 implementation file for a generic NVECTOR package. + * It contains the implementation of the N_Vector operations listed + * in nvector.h. + * -----------------------------------------------------------------*/ + +#include <stdlib.h> + +#include <sundials/sundials_nvector.h> + +/* + * ----------------------------------------------------------------- + * Functions in the 'ops' structure + * ----------------------------------------------------------------- + */ + +N_Vector_ID N_VGetVectorID(N_Vector w) +{ + N_Vector_ID id; + id = w->ops->nvgetvectorid(w); + return(id); +} + +N_Vector N_VClone(N_Vector w) +{ + N_Vector v = NULL; + v = w->ops->nvclone(w); + return(v); +} + +N_Vector N_VCloneEmpty(N_Vector w) +{ + N_Vector v = NULL; + v = w->ops->nvcloneempty(w); + return(v); +} + +void N_VDestroy(N_Vector v) +{ + if (v==NULL) return; + v->ops->nvdestroy(v); + return; +} + +void N_VSpace(N_Vector v, sunindextype *lrw, sunindextype *liw) +{ + v->ops->nvspace(v, lrw, liw); + return; +} + +realtype *N_VGetArrayPointer(N_Vector v) +{ + return((realtype *) v->ops->nvgetarraypointer(v)); +} + +void N_VSetArrayPointer(realtype *v_data, N_Vector v) +{ + v->ops->nvsetarraypointer(v_data, v); + return; +} + +/* ----------------------------------------------------------------- + * standard vector operations + * ----------------------------------------------------------------- */ + +void N_VLinearSum(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z) +{ + z->ops->nvlinearsum(a, x, b, y, z); + return; +} + +void N_VConst(realtype c, N_Vector z) +{ + z->ops->nvconst(c, z); + return; +} + +void N_VProd(N_Vector x, N_Vector y, N_Vector z) +{ + z->ops->nvprod(x, y, z); + return; +} + +void N_VDiv(N_Vector x, N_Vector y, N_Vector z) +{ + z->ops->nvdiv(x, y, z); + return; +} + +void N_VScale(realtype c, N_Vector x, N_Vector z) +{ + z->ops->nvscale(c, x, z); + return; +} + +void N_VAbs(N_Vector x, N_Vector z) +{ + z->ops->nvabs(x, z); + return; +} + +void N_VInv(N_Vector x, N_Vector z) +{ + z->ops->nvinv(x, z); + return; +} + +void N_VAddConst(N_Vector x, realtype b, N_Vector z) +{ + z->ops->nvaddconst(x, b, z); + return; +} + +realtype N_VDotProd(N_Vector x, N_Vector y) +{ + return((realtype) y->ops->nvdotprod(x, y)); +} + +realtype N_VMaxNorm(N_Vector x) +{ + return((realtype) x->ops->nvmaxnorm(x)); +} + +realtype N_VWrmsNorm(N_Vector x, N_Vector w) +{ + return((realtype) x->ops->nvwrmsnorm(x, w)); +} + +realtype N_VWrmsNormMask(N_Vector x, N_Vector w, N_Vector id) +{ + return((realtype) x->ops->nvwrmsnormmask(x, w, id)); +} + +realtype N_VMin(N_Vector x) +{ + return((realtype) x->ops->nvmin(x)); +} + +realtype N_VWL2Norm(N_Vector x, N_Vector w) +{ + return((realtype) x->ops->nvwl2norm(x, w)); +} + +realtype N_VL1Norm(N_Vector x) +{ + return((realtype) x->ops->nvl1norm(x)); +} + +void N_VCompare(realtype c, N_Vector x, N_Vector z) +{ + z->ops->nvcompare(c, x, z); + return; +} + +booleantype N_VInvTest(N_Vector x, N_Vector z) +{ + return((booleantype) z->ops->nvinvtest(x, z)); +} + +booleantype N_VConstrMask(N_Vector c, N_Vector x, N_Vector m) +{ + return((booleantype) x->ops->nvconstrmask(c, x, m)); +} + +realtype N_VMinQuotient(N_Vector num, N_Vector denom) +{ + return((realtype) num->ops->nvminquotient(num, denom)); +} + +/* ----------------------------------------------------------------- + * fused vector operations + * ----------------------------------------------------------------- */ + +int N_VLinearCombination(int nvec, realtype* c, N_Vector* X, N_Vector z) +{ + int i; + realtype ONE=RCONST(1.0); + + if (z->ops->nvlinearcombination != NULL) { + + return(z->ops->nvlinearcombination(nvec, c, X, z)); + + } else { + + z->ops->nvscale(c[0], X[0], z); + for (i=1; i<nvec; i++) { + z->ops->nvlinearsum(c[i], X[i], ONE, z, z); + } + return(0); + + } +} + +int N_VScaleAddMulti(int nvec, realtype* a, N_Vector x, N_Vector* Y, N_Vector* Z) +{ + int i; + realtype ONE=RCONST(1.0); + + if (x->ops->nvscaleaddmulti != NULL) { + + return(x->ops->nvscaleaddmulti(nvec, a, x, Y, Z)); + + } else { + + for (i=0; i<nvec; i++) { + x->ops->nvlinearsum(a[i], x, ONE, Y[i], Z[i]); + } + return(0); + + } +} + +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 { + + for (i=0; i<nvec; i++) { + dotprods[i] = x->ops->nvdotprod(x, Y[i]); + } + return(0); + + } +} + +/* ----------------------------------------------------------------- + * vector array operations + * ----------------------------------------------------------------- */ + +int N_VLinearSumVectorArray(int nvec, realtype a, N_Vector* X, + realtype b, N_Vector* Y, N_Vector* Z) +{ + int i; + + if (Z[0]->ops->nvlinearsumvectorarray != NULL) { + + return(Z[0]->ops->nvlinearsumvectorarray(nvec, a, X, b, Y, Z)); + + } else { + + for (i=0; i<nvec; i++) { + Z[0]->ops->nvlinearsum(a, X[i], b, Y[i], Z[i]); + } + return(0); + + } +} + +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 { + + for (i=0; i<nvec; i++) { + Z[0]->ops->nvscale(c[i], X[i], Z[i]); + } + return(0); + + } +} + +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); + + } else { + + for (i=0; i<nvec; i++) { + Z[0]->ops->nvconst(c, Z[i]); + } + return(0); + + } +} + +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); + + } else { + + for (i=0; i<nvec; i++) { + nrm[i] = X[0]->ops->nvwrmsnorm(X[i], W[i]); + } + return(0); + + } +} + +int N_VWrmsNormMaskVectorArray(int nvec, N_Vector* X, N_Vector* W, N_Vector id, + realtype* nrm) +{ + int i, ier; + + if (id->ops->nvwrmsnormmaskvectorarray != NULL) { + + ier = id->ops->nvwrmsnormmaskvectorarray(nvec, X, W, id, nrm); + return(ier); + + } else { + + for (i=0; i<nvec; i++) { + nrm[i] = id->ops->nvwrmsnormmask(X[i], W[i], id); + } + return(0); + + } +} + +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); + N_Vector* YY=NULL; + N_Vector* ZZ=NULL; + + if (X[0]->ops->nvscaleaddmultivectorarray != NULL) { + + ier = X[0]->ops->nvscaleaddmultivectorarray(nvec, nsum, a, X, Y, Z); + return(ier); + + } 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)); + + for (i=0; i<nvec; i++) { + + for (j=0; j<nsum; j++) { + YY[j] = Y[j][i]; + ZZ[j] = Z[j][i]; + } + + ier = X[0]->ops->nvscaleaddmulti(nsum, a, X[i], YY, ZZ); + if (ier != 0) break; + } + + /* free array of vectors */ + free(YY); + free(ZZ); + + return(ier); + + } else { + + for (i=0; i<nvec; i++) { + for (j=0; j<nsum; j++) { + X[0]->ops->nvlinearsum(a[j], X[i], ONE, Y[j][i], Z[j][i]); + } + } + return(0); + } +} + +int N_VLinearCombinationVectorArray(int nvec, int nsum, realtype* c, N_Vector** X, + N_Vector* Z) +{ + int i, j, ier; + realtype ONE=RCONST(1.0); + N_Vector* Y=NULL; + + if (Z[0]->ops->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)); + + for (i=0; i<nvec; i++) { + + for (j=0; j<nsum; j++) { + Y[j] = X[j][i]; + } + + ier = Z[0]->ops->nvlinearcombination(nsum, c, Y, Z[i]); + if (ier != 0) break; + } + + /* free array of vectors */ + free(Y); + + return(ier); + + } else { + + for (i=0; i<nvec; i++) { + Z[0]->ops->nvscale(c[0], X[0][i], Z[i]); + for (j=1; j<nsum; j++) { + Z[0]->ops->nvlinearsum(c[j], X[j][i], ONE, Z[i], Z[i]); + } + } + return(0); + } +} + +/* + * ----------------------------------------------------------------- + * Additional functions exported by the generic NVECTOR: + * N_VCloneEmptyVectorArray + * N_VCloneVectorArray + * N_VDestroyVectorArray + * ----------------------------------------------------------------- + */ + +N_Vector *N_VCloneEmptyVectorArray(int count, N_Vector w) +{ + N_Vector *vs = NULL; + int j; + + if (count <= 0) return(NULL); + + vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + if(vs == NULL) return(NULL); + + for (j = 0; j < count; j++) { + vs[j] = N_VCloneEmpty(w); + if (vs[j] == NULL) { + N_VDestroyVectorArray(vs, j-1); + return(NULL); + } + } + + return(vs); +} + +N_Vector *N_VCloneVectorArray(int count, N_Vector w) +{ + N_Vector *vs = NULL; + int j; + + if (count <= 0) return(NULL); + + vs = (N_Vector *) malloc(count * sizeof(N_Vector)); + if(vs == NULL) return(NULL); + + for (j = 0; j < count; j++) { + vs[j] = N_VClone(w); + if (vs[j] == NULL) { + N_VDestroyVectorArray(vs, j-1); + return(NULL); + } + } + + return(vs); +} + +void N_VDestroyVectorArray(N_Vector *vs, int count) +{ + int j; + + if (vs==NULL) return; + + for (j = 0; j < count; j++) N_VDestroy(vs[j]); + + free(vs); vs = NULL; + + return; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_nvector_senswrapper.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_nvector_senswrapper.c new file mode 100644 index 0000000..b16f401 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_nvector_senswrapper.c @@ -0,0 +1,544 @@ +/* ----------------------------------------------------------------------------- + * 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 is the implementation file for a vector wrapper for an array of NVECTORS + * ---------------------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include <stdarg.h> +#include <string.h> + +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_nvector_senswrapper.h> + +#define ZERO RCONST(0.0) + +/*============================================================================== + Constructors + ============================================================================*/ + +/*------------------------------------------------------------------------------ + create a new empty vector wrapper with space for <nvecs> vectors + ----------------------------------------------------------------------------*/ +N_Vector N_VNewEmpty_SensWrapper(int nvecs) +{ + int i; + N_Vector v; + N_Vector_Ops ops; + N_VectorContent_SensWrapper content; + + /* return if wrapper is empty */ + if (nvecs < 1) return(NULL); + + /* create vector */ + v = NULL; + v = (N_Vector) malloc(sizeof *v); + if (v == NULL) return(NULL); + + /* create vector operation structure */ + ops = NULL; + ops = (N_Vector_Ops) malloc(sizeof *ops); + if (ops == NULL) {free(v); return(NULL);} + + ops->nvgetvectorid = NULL; + ops->nvclone = N_VClone_SensWrapper; + ops->nvcloneempty = N_VCloneEmpty_SensWrapper; + ops->nvdestroy = N_VDestroy_SensWrapper; + ops->nvspace = NULL; + ops->nvgetarraypointer = NULL; + ops->nvsetarraypointer = NULL; + + /* standard vector operations */ + ops->nvlinearsum = N_VLinearSum_SensWrapper; + ops->nvconst = N_VConst_SensWrapper; + ops->nvprod = N_VProd_SensWrapper; + ops->nvdiv = N_VDiv_SensWrapper; + ops->nvscale = N_VScale_SensWrapper; + ops->nvabs = N_VAbs_SensWrapper; + ops->nvinv = N_VInv_SensWrapper; + ops->nvaddconst = N_VAddConst_SensWrapper; + ops->nvdotprod = N_VDotProd_SensWrapper; + ops->nvmaxnorm = N_VMaxNorm_SensWrapper; + ops->nvwrmsnormmask = N_VWrmsNormMask_SensWrapper; + ops->nvwrmsnorm = N_VWrmsNorm_SensWrapper; + ops->nvmin = N_VMin_SensWrapper; + ops->nvwl2norm = N_VWL2Norm_SensWrapper; + ops->nvl1norm = N_VL1Norm_SensWrapper; + ops->nvcompare = N_VCompare_SensWrapper; + ops->nvinvtest = N_VInvTest_SensWrapper; + ops->nvconstrmask = N_VConstrMask_SensWrapper; + ops->nvminquotient = N_VMinQuotient_SensWrapper; + + /* 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; + + /* create content */ + content = NULL; + content = (N_VectorContent_SensWrapper) malloc(sizeof *content); + if (content == NULL) {free(ops); free(v); return(NULL);} + + content->nvecs = nvecs; + content->own_vecs = SUNFALSE; + content->vecs = NULL; + content->vecs = (N_Vector*) malloc(nvecs * sizeof(N_Vector)); + if (content->vecs == NULL) {free(ops); free(v); free(content); return(NULL);} + + /* initialize vector array to null */ + for (i=0; i < nvecs; i++) + content->vecs[i] = NULL; + + /* attach content and ops */ + v->content = content; + v->ops = ops; + + return(v); +} + + +N_Vector N_VNew_SensWrapper(int count, N_Vector w) +{ + N_Vector v; + int i; + + v = NULL; + v = N_VNewEmpty_SensWrapper(count); + if (v == NULL) return(NULL); + + for (i=0; i < NV_NVECS_SW(v); i++) { + NV_VEC_SW(v,i) = N_VClone(w); + if (NV_VEC_SW(v,i) == NULL) { N_VDestroy(v); return(NULL); } + } + + /* update own vectors status */ + NV_OWN_VECS_SW(v) = SUNTRUE; + + return(v); +} + + +/*============================================================================== + Clone operations + ============================================================================*/ + +/*------------------------------------------------------------------------------ + create an empty clone of the vector wrapper w + ----------------------------------------------------------------------------*/ +N_Vector N_VCloneEmpty_SensWrapper(N_Vector w) +{ + int i; + N_Vector v; + N_Vector_Ops ops; + N_VectorContent_SensWrapper content; + + if (w == NULL) return(NULL); + + if (NV_NVECS_SW(w) < 1) return(NULL); + + /* create vector */ + v = NULL; + v = (N_Vector) malloc(sizeof *v); + if (v == NULL) return(NULL); + + /* create vector operation structure */ + ops = NULL; + ops = (N_Vector_Ops) malloc(sizeof *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 */ + content = NULL; + content = (N_VectorContent_SensWrapper) malloc(sizeof *content); + if (content == NULL) { free(ops); free(v); return(NULL); } + + content->nvecs = NV_NVECS_SW(w); + content->own_vecs = SUNFALSE; + content->vecs = NULL; + content->vecs = (N_Vector*) malloc(NV_NVECS_SW(w) * sizeof(N_Vector)); + if (content->vecs == NULL) {free(ops); free(v); free(content); return(NULL);} + + /* initialize vector array to null */ + for (i=0; i < NV_NVECS_SW(w); i++) + content->vecs[i] = NULL; + + /* Attach content and ops */ + v->content = content; + v->ops = ops; + + return(v); +} + + +/*------------------------------------------------------------------------------ + create a clone of the vector wrapper w + ----------------------------------------------------------------------------*/ +N_Vector N_VClone_SensWrapper(N_Vector w) +{ + N_Vector v; + int i; + + /* create empty wrapper */ + v = NULL; + v = N_VCloneEmpty_SensWrapper(w); + if (v == NULL) return(NULL); + + /* update own vectors status */ + NV_OWN_VECS_SW(v) = SUNTRUE; + + /* allocate arrays */ + for (i=0; i < NV_NVECS_SW(v); i++) { + NV_VEC_SW(v,i) = N_VClone(NV_VEC_SW(w,i)); + if (NV_VEC_SW(v,i) == NULL) { N_VDestroy(v); return(NULL); } + } + + return(v); +} + + +/*============================================================================== + Destructor + ============================================================================*/ + +void N_VDestroy_SensWrapper(N_Vector v) +{ + int i; + + if (NV_OWN_VECS_SW(v) == SUNTRUE) { + for (i=0; i < NV_NVECS_SW(v); i++) { + if (NV_VEC_SW(v,i)) N_VDestroy(NV_VEC_SW(v,i)); + NV_VEC_SW(v,i) = NULL; + } + } + + free(NV_VECS_SW(v)); NV_VECS_SW(v) = NULL; + free(v->content); v->content = NULL; + free(v->ops); v->ops = NULL; + free(v); v = NULL; + + return; +} + + +/*============================================================================== + Standard vector operations + ============================================================================*/ + +void N_VLinearSum_SensWrapper(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z) +{ + int i; + + for (i=0; i < NV_NVECS_SW(x); i++) + N_VLinearSum(a, NV_VEC_SW(x,i), b, NV_VEC_SW(y,i), NV_VEC_SW(z,i)); + + return; +} + + +void N_VConst_SensWrapper(realtype c, N_Vector z) +{ + int i; + + for (i=0; i < NV_NVECS_SW(z); i++) + N_VConst(c, NV_VEC_SW(z,i)); + + return; +} + + +void N_VProd_SensWrapper(N_Vector x, N_Vector y, N_Vector z) +{ + int i; + + for (i=0; i < NV_NVECS_SW(x); i++) + N_VProd(NV_VEC_SW(x,i), NV_VEC_SW(y,i), NV_VEC_SW(z,i)); + + return; +} + + +void N_VDiv_SensWrapper(N_Vector x, N_Vector y, N_Vector z) +{ + int i; + + for (i=0; i < NV_NVECS_SW(x); i++) + N_VDiv(NV_VEC_SW(x,i), NV_VEC_SW(y,i), NV_VEC_SW(z,i)); + + return; +} + + +void N_VScale_SensWrapper(realtype c, N_Vector x, N_Vector z) +{ + int i; + + for (i=0; i < NV_NVECS_SW(x); i++) + N_VScale(c, NV_VEC_SW(x,i), NV_VEC_SW(z,i)); + + return; +} + + +void N_VAbs_SensWrapper(N_Vector x, N_Vector z) +{ + int i; + + for (i=0; i < NV_NVECS_SW(x); i++) + N_VAbs(NV_VEC_SW(x,i), NV_VEC_SW(z,i)); + + return; +} + + +void N_VInv_SensWrapper(N_Vector x, N_Vector z) +{ + int i; + + for (i=0; i < NV_NVECS_SW(x); i++) + N_VInv(NV_VEC_SW(x,i), NV_VEC_SW(z,i)); + + return; +} + + +void N_VAddConst_SensWrapper(N_Vector x, realtype b, N_Vector z) +{ + int i; + + for (i=0; i < NV_NVECS_SW(x); i++) + N_VAddConst(NV_VEC_SW(x,i), b, NV_VEC_SW(z,i)); + + return; +} + + +realtype N_VDotProd_SensWrapper(N_Vector x, N_Vector y) +{ + int i; + realtype sum; + + sum = ZERO; + + for (i=0; i < NV_NVECS_SW(x); i++) + sum += N_VDotProd(NV_VEC_SW(x,i), NV_VEC_SW(y,i)); + + return(sum); +} + + +realtype N_VMaxNorm_SensWrapper(N_Vector x) +{ + int i; + realtype max, tmp; + + max = ZERO; + + for (i=0; i < NV_NVECS_SW(x); i++) { + tmp = N_VMaxNorm(NV_VEC_SW(x,i)); + if (tmp > max) max = tmp; + } + + return(max); +} + + +realtype N_VWrmsNorm_SensWrapper(N_Vector x, N_Vector w) +{ + int i; + realtype nrm, tmp; + + nrm = ZERO; + + for (i=0; i < NV_NVECS_SW(x); i++) { + tmp = N_VWrmsNorm(NV_VEC_SW(x,i), NV_VEC_SW(w,i)); + if (tmp > nrm) nrm = tmp; + } + + return(nrm); +} + + +realtype N_VWrmsNormMask_SensWrapper(N_Vector x, N_Vector w, N_Vector id) +{ + int i; + realtype nrm, tmp; + + nrm = ZERO; + + for (i=0; i < NV_NVECS_SW(x); i++) { + tmp = N_VWrmsNormMask(NV_VEC_SW(x,i), NV_VEC_SW(w,i), NV_VEC_SW(id,i)); + if (tmp > nrm) nrm = tmp; + } + + return(nrm); +} + + +realtype N_VMin_SensWrapper(N_Vector x) +{ + int i; + realtype min, tmp; + + min = N_VMin(NV_VEC_SW(x,0)); + + for (i=1; i < NV_NVECS_SW(x); i++) { + tmp = N_VMin(NV_VEC_SW(x,i)); + if (tmp < min) min = tmp; + } + + return(min); +} + + +realtype N_VWL2Norm_SensWrapper(N_Vector x, N_Vector w) +{ + int i; + realtype nrm, tmp; + + nrm = ZERO; + + for (i=0; i < NV_NVECS_SW(x); i++) { + tmp = N_VWL2Norm(NV_VEC_SW(x,i), NV_VEC_SW(w,i)); + if (tmp > nrm) nrm = tmp; + } + + return(nrm); +} + + +realtype N_VL1Norm_SensWrapper(N_Vector x) +{ + int i; + realtype nrm, tmp; + + nrm = ZERO; + + for (i=0; i < NV_NVECS_SW(x); i++) { + tmp = N_VL1Norm(NV_VEC_SW(x,i)); + if (tmp > nrm) nrm = tmp; + } + + return(nrm); +} + + +void N_VCompare_SensWrapper(realtype c, N_Vector x, N_Vector z) +{ + int i; + + for (i=0; i < NV_NVECS_SW(x); i++) + N_VCompare(c, NV_VEC_SW(x,i), NV_VEC_SW(z,i)); + + return; +} + + +booleantype N_VInvTest_SensWrapper(N_Vector x, N_Vector z) +{ + int i; + booleantype no_zero_found, tmp; + + no_zero_found = SUNTRUE; + + for (i=0; i < NV_NVECS_SW(x); i++) { + tmp = N_VInvTest(NV_VEC_SW(x,i), NV_VEC_SW(z,i)); + if (tmp != SUNTRUE) no_zero_found = SUNFALSE; + } + + return(no_zero_found); +} + + +booleantype N_VConstrMask_SensWrapper(N_Vector c, N_Vector x, N_Vector m) +{ + int i; + booleantype test, tmp; + + test = SUNTRUE; + + for (i=0; i < NV_NVECS_SW(x); i++) { + tmp = N_VConstrMask(c, NV_VEC_SW(x,i), NV_VEC_SW(m,i)); + if (tmp != SUNTRUE) test = SUNFALSE; + } + + return(test); +} + + +realtype N_VMinQuotient_SensWrapper(N_Vector num, N_Vector denom) +{ + int i; + realtype min, tmp; + + min = N_VMinQuotient(NV_VEC_SW(num,0), NV_VEC_SW(denom,0)); + + for (i=1; i < NV_NVECS_SW(num); i++) { + tmp = N_VMinQuotient(NV_VEC_SW(num,i), NV_VEC_SW(denom,i)); + if (tmp < min) min = tmp; + } + + return(min); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_pcg.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_pcg.c new file mode 100644 index 0000000..affadd2 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_pcg.c @@ -0,0 +1,223 @@ +/*--------------------------------------------------------------- + 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 <stdio.h> +#include <stdlib.h> +#include <sundials/sundials_pcg.h> +#include <sundials/sundials_math.h> + + +/*--------------------------------------------------------------- + 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 <r,z> */ + rz = N_VDotProd(r, z); + + /* Copy z to p */ + N_VScale(ONE, z, p); + + /* Begin main iteration loop */ + for(l=0; l<l_max; l++) { + + /* increment counter */ + (*nli)++; + + /* Generate Ap = A*p */ + ier = atimes(A_data, p, Ap ); + if (ier != 0) + return((ier < 0) ? PCG_ATIMES_FAIL_UNREC : PCG_ATIMES_FAIL_REC); + + /* Calculate alpha = <r,z> / <Ap,p> */ + 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 = <r,z> / <r_old,z_old> */ + 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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_sparse.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_sparse.c new file mode 100644 index 0000000..eeeeb1d --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_sparse.c @@ -0,0 +1,870 @@ +/* + * ----------------------------------------------------------------- + * $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 <stdio.h> +#include <stdlib.h> + +#include <sundials/sundials_sparse.h> +#include <sundials/sundials_math.h> + +#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; j<Ad->N; j++) + for (i=0; i<Ad->M; 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; i<M; i++) { + (As->indexptrs)[i] = nnz; + for (j=0; j<N; j++) { + /* CSR = row major looping; CSC = column major looping */ + dtmp = (sparsetype == CSR_MAT) ? DENSE_ELEM(Ad,i,j) : DENSE_ELEM(Ad,j,i); + if ( dtmp != ZERO ) { + (As->indexvals)[nnz] = j; + As->data[nnz++] = dtmp; + } + } + } + (As->indexptrs)[M] = nnz; + + } else { /* SUNDIALS_BAND */ + + /* determine total number of nonzeros */ + nnz = 0; + for (j=0; j<Ad->N; j++) + for (i=j-(Ad->mu); i<j+(Ad->ml); 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; i<M; i++) { + (As->indexptrs)[i] = nnz; + for (j=i-(Ad->mu); j<i+(Ad->ml); 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; i<A->NNZ; i++) { + A->data[i] = ZERO; + A->indexvals[i] = 0; + } + + for (i=0; i<A->NP; 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; i<A_nz; i++){ + B->data[i] = A->data[i]; + B->indexvals[i] = A->indexvals[i]; + } + + /* copy the column pointers over */ + for (i=0; i<A->NP; 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; i<A->indexptrs[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]; i<A->indexptrs[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]; i<A->indexptrs[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<N; j++) { + + /* set current column (row) pointer to current # nonzeros */ + Cp[j] = nz; + + /* clear out temporary arrays for this column (row) */ + for (i=0; i<M; i++) { + w[i] = 0; + x[i] = 0.0; + } + + /* iterate down column (along row) of A, collecting nonzeros */ + for (p=Ap[j]; p<Ap[j+1]; p++) { + w[Ai[p]] += 1; /* indicate that row is filled */ + x[Ai[p]] = Ax[p]; /* collect value */ + } + + /* add identity to this column (row) */ + if (j < M) { + w[j] += 1; /* indicate that row is filled */ + x[j] += ONE; /* update value */ + } + + /* fill entries of C with this column's (row's) data */ + for (i=0; i<M; i++) { + if ( w[i] > 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; j<N; j++) { + + /* clear work array */ + for (i=0; i<M; i++) w[i] = 0; + + /* scan column of A, incrementing w by one */ + for (i=A->indexptrs[j]; i<A->indexptrs[j+1]; i++) + w[A->indexvals[i]] += 1; + + /* scan column of B, decrementing w by one */ + for (i=B->indexptrs[j]; i<B->indexptrs[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; i<M; i++) + if (w[i] < 0) { + newmat = 1; + break; + } + if (newmat) break; + + } + + /* perform operation */ + + /* case 1: A already contains sparsity pattern of B */ + if (!newmat) { + + /* iterate through columns, adding matrices */ + for (j=0; j<N; j++) { + + /* clear work array */ + for (i=0; i<M; i++) + x[i] = ZERO; + + /* scan column of B, updating work array */ + for (i = B->indexptrs[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<N; j++) { + + /* set current column pointer to current # nonzeros */ + Cp[j] = nz; + + /* clear out temporary arrays for this column */ + for (i=0; i<M; i++) { + w[i] = 0; + x[i] = 0.0; + } + + /* iterate down column of A, collecting nonzeros */ + for (p=Ap[j]; p<Ap[j+1]; p++) { + w[Ai[p]] += 1; /* indicate that row is filled */ + x[Ai[p]] = Ax[p]; /* collect value */ + } + + /* iterate down column of B, collecting nonzeros */ + for (p=Bp[j]; p<Bp[j+1]; p++) { + w[Bi[p]] += 1; /* indicate that row is filled */ + x[Bi[p]] += Bx[p]; /* collect value */ + } + + /* fill entries of C with this column's data */ + for (i=0; i<M; i++) { + if ( w[i] > 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; i<A->M; i++) + y[i] = 0.0; + + /* iterate through matrix columns */ + for (j=0; j<A->N; j++) { + + /* iterate down column of A, performing product */ + for (i=Ap[j]; i<Ap[j+1]; i++) + y[Ai[i]] += Ax[i]*x[j]; + + } + + /* return success */ + return(0); +} + + +/** + * Computes y=A*x, where A is a CSR 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 SparseMatvecCSR(const SlsMat A, const realtype *x, realtype *y) +{ + int j, i; + int *Ap, *Aj; + realtype *Ax; + + /* access data from CSR structure (return if failure) */ + if (*A->rowptrs) 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; i<A->M; i++) + y[i] = 0.0; + + /* iterate through matrix rows */ + for (i=0; i<A->M; ++i) { + + /* iterate along row of A, performing product */ + for (j=Ap[i]; j<Ap[i+1]; ++j) + y[i] += Ax[j]*x[Aj[j]]; + + } + + /* return success */ + return(0); +} + + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_spbcgs.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_spbcgs.c new file mode 100644 index 0000000..6a32bbe --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_spbcgs.c @@ -0,0 +1,384 @@ +/* + * ----------------------------------------------------------------- + * $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 implementation file for the scaled, preconditioned + * Bi-CGSTAB (SPBCG) iterative linear solver. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <sundials/sundials_spbcgs.h> +#include <sundials/sundials_math.h> + +/* + * ----------------------------------------------------------------- + * 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 = <r,r_star>/<Ap,r_star> */ + + 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 = <u,q>/<u,u> */ + + 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 = <rnew,r_star> / <rold,r_start> * 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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_spfgmr.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_spfgmr.c new file mode 100644 index 0000000..c8419ea --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_spfgmr.c @@ -0,0 +1,374 @@ +/*---------------------------------------------------------------- + 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 <stdio.h> +#include <stdlib.h> +#include <sundials/sundials_spfgmr.h> +#include <sundials/sundials_math.h> + +/*---------------------------------------------------------------- + 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; i<k; i++) {free(Hes[i]); Hes[i] = NULL;} + free(Hes); Hes = NULL; + N_VDestroyVectorArray(V, l_max+1); + N_VDestroyVectorArray(Z, 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); + N_VDestroyVectorArray(Z, 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); + N_VDestroyVectorArray(Z, l_max+1); + return(NULL); + } + + /* Get memory to hold SPFGMR 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); + N_VDestroyVectorArray(Z, 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); + N_VDestroyVectorArray(Z, l_max+1); + return(NULL); + } + + /* Get memory for an SpfgmrMemRec containing SPFGMR matrices and vectors. */ + mem = NULL; + mem = (SpfgmrMem) malloc(sizeof(SpfgmrMemRec)); + 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); + N_VDestroyVectorArray(Z, l_max+1); + return(NULL); + } + + /* Set the fields of mem. */ + mem->l_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; 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<maxit; l++) { + + (*nli)++; + + krydim = l + 1; + + /* Generate A-tilde V[l], where A-tilde = s1 A P_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 = Z[l] = P_inv s2_inv V[l]. */ + if (preOnRight) { + N_VScale(ONE, vtemp, V[l+1]); + ier = psolve(P_data, V[l+1], vtemp, delta, PREC_RIGHT); + (*nps)++; + if (ier != 0) + return((ier < 0) ? SPFGMR_PSOLVE_FAIL_UNREC : SPFGMR_PSOLVE_FAIL_REC); + } + N_VScale(ONE, vtemp, Z[l]); + + /* Apply A: V[l+1] = A P_inv s2_inv V[l]. */ + ier = atimes(A_data, vtemp, V[l+1]); + if (ier != 0) + return((ier < 0) ? SPFGMR_ATIMES_FAIL_UNREC : SPFGMR_ATIMES_FAIL_REC); + + /* Apply left scaling: V[l+1] = s1 A P_inv s2_inv V[l]. */ + if (scale1) N_VProd(s1, V[l+1], V[l+1]); + + /* Orthogonalize V[l+1] against previous V[i]: V[l+1] = w_tilde. */ + if (gstype == CLASSICAL_GS) { + if (ClassicalGS(V, Hes, l+1, l_max, &(Hes[l+1][l]), + vtemp, yg) != 0) + return(SPFGMR_GS_FAIL); + } else { + if (ModifiedGS(V, Hes, l+1, l_max, &(Hes[l+1][l])) != 0) + return(SPFGMR_GS_FAIL); + } + + /* Update the QR factorization of Hes. */ + if(QRfact(krydim, Hes, givens, l) != 0 ) + return(SPFGMR_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+1][l], V[l+1], V[l+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(SPFGMR_QRSOL_FAIL); + + /* Add correction vector Z_l y to xcor. */ + for (k=0; k<krydim; k++) + N_VLinearSum(yg[k], Z[k], ONE, xcor, xcor); + + /* If converged, construct the final solution vector x and return. */ + if (converged) { + N_VLinearSum(ONE, x, ONE, xcor, x); + return(SPFGMR_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) { + 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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_spgmr.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_spgmr.c new file mode 100644 index 0000000..fd77851 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_spgmr.c @@ -0,0 +1,459 @@ +/* + * ----------------------------------------------------------------- + * $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 <stdio.h> +#include <stdlib.h> + +#include <sundials/sundials_spgmr.h> +#include <sundials/sundials_math.h> + +/* + * ----------------------------------------------------------------- + * 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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_sptfqmr.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_sptfqmr.c new file mode 100644 index 0000000..7d330ce --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_sptfqmr.c @@ -0,0 +1,521 @@ +/* + * ----------------------------------------------------------------- + * $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 <stdio.h> +#include <stdlib.h> + +#include <sundials/sundials_sptfqmr.h> +#include <sundials/sundials_math.h> + +/* + * ----------------------------------------------------------------- + * 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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_version.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_version.c new file mode 100644 index 0000000..5192f43 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sundials/sundials_version.c @@ -0,0 +1,48 @@ +/* ----------------------------------------------------------------- + * 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 implements functions for getting SUNDIALS version + * information. + * -----------------------------------------------------------------*/ + +#include <string.h> + +#include <sundials/sundials_version.h> + +/* fill string with SUNDIALS version information */ +int SUNDIALSGetVersion(char *version, int len) +{ + if (strlen(SUNDIALS_VERSION) > len) { + return(-1); + } + + strncpy(version, SUNDIALS_VERSION, len); + return(0); +} + +/* fill integers with SUNDIALS major, minor, and patch release + numbers and fill a string with the release label */ +int SUNDIALSGetVersionNumber(int *major, int *minor, int *patch, + char *label, int len) +{ + if (strlen(SUNDIALS_VERSION_LABEL) > len) { + return(-1); + } + + *major = SUNDIALS_VERSION_MAJOR; + *minor = SUNDIALS_VERSION_MINOR; + *patch = SUNDIALS_VERSION_PATCH; + strncpy(label, SUNDIALS_VERSION_LABEL, len); + + return(0); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/band/fsunlinsol_band.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/band/fsunlinsol_band.c new file mode 100644 index 0000000..13170c4 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/band/fsunlinsol_band.c @@ -0,0 +1,96 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunlinsol_band.h) contains the + * implementation needed for the Fortran initialization of band + * linear solver operations. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fsunlinsol_band.h" + +/* Define global linsol variables */ + +SUNLinearSolver F2C_CVODE_linsol; +SUNLinearSolver F2C_IDA_linsol; +SUNLinearSolver F2C_KINSOL_linsol; +SUNLinearSolver F2C_ARKODE_linsol; +SUNLinearSolver F2C_ARKODE_mass_sol; + +/* Declarations of external global variables */ + +extern SUNMatrix F2C_CVODE_matrix; +extern SUNMatrix F2C_IDA_matrix; +extern SUNMatrix F2C_KINSOL_matrix; +extern SUNMatrix F2C_ARKODE_matrix; +extern SUNMatrix F2C_ARKODE_mass_matrix; + +extern N_Vector F2C_CVODE_vec; +extern N_Vector F2C_IDA_vec; +extern N_Vector F2C_KINSOL_vec; +extern N_Vector F2C_ARKODE_vec; + +/* Fortran callable interfaces */ + +void FSUNBANDLINSOL_INIT(int *code, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (F2C_CVODE_linsol) SUNLinSolFree(F2C_CVODE_linsol); + F2C_CVODE_linsol = NULL; + F2C_CVODE_linsol = SUNLinSol_Band(F2C_CVODE_vec, + F2C_CVODE_matrix); + if (F2C_CVODE_linsol == NULL) *ier = -1; + break; + case FCMIX_IDA: + if (F2C_IDA_linsol) SUNLinSolFree(F2C_IDA_linsol); + F2C_IDA_linsol = NULL; + F2C_IDA_linsol = SUNLinSol_Band(F2C_IDA_vec, + F2C_IDA_matrix); + if (F2C_IDA_linsol == NULL) *ier = -1; + break; + case FCMIX_KINSOL: + if (F2C_KINSOL_linsol) SUNLinSolFree(F2C_KINSOL_linsol); + F2C_KINSOL_linsol = NULL; + F2C_KINSOL_linsol = SUNLinSol_Band(F2C_KINSOL_vec, + F2C_KINSOL_matrix); + if (F2C_KINSOL_linsol == NULL) *ier = -1; + break; + case FCMIX_ARKODE: + if (F2C_ARKODE_linsol) SUNLinSolFree(F2C_ARKODE_linsol); + F2C_ARKODE_linsol = NULL; + F2C_ARKODE_linsol = SUNLinSol_Band(F2C_ARKODE_vec, + F2C_ARKODE_matrix); + if (F2C_ARKODE_linsol == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + + +void FSUNMASSBANDLINSOL_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_Band(F2C_ARKODE_vec, + F2C_ARKODE_mass_matrix); + if (F2C_ARKODE_mass_sol == NULL) *ier = -1; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/band/fsunlinsol_band.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/band/fsunlinsol_band.h new file mode 100644 index 0000000..c32cee6 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/band/fsunlinsol_band.h @@ -0,0 +1,62 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunlinsol_band.c) contains the + * definitions needed for the initialization of band + * linear solver operations in Fortran. + * ----------------------------------------------------------------- + */ + +#ifndef _FSUNLINSOL_BAND_H +#define _FSUNLINSOL_BAND_H + +#include <sunlinsol/sunlinsol_band.h> +#include <sundials/sundials_fnvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +#if defined(SUNDIALS_F77_FUNC) +#define FSUNBANDLINSOL_INIT SUNDIALS_F77_FUNC(fsunbandlinsolinit, FSUNBANDLINSOLINIT) +#define FSUNMASSBANDLINSOL_INIT SUNDIALS_F77_FUNC(fsunmassbandlinsolinit, FSUNMASSBANDLINSOLINIT) +#else +#define FSUNBANDLINSOL_INIT fsunbandlinsolinit_ +#define FSUNMASSBANDLINSOL_INIT fsunmassbandlinsolinit_ +#endif + + +/* Declarations of global variables */ + +extern SUNLinearSolver F2C_CVODE_linsol; +extern SUNLinearSolver F2C_IDA_linsol; +extern SUNLinearSolver F2C_KINSOL_linsol; +extern SUNLinearSolver F2C_ARKODE_linsol; +extern SUNLinearSolver F2C_ARKODE_mass_sol; + +/* + * Prototypes of exported functions + * + * FSUNBANDLINSOL_INIT - initializes band linear solver for main problem + * FSUNMASSBANDLINSOL_INIT - initializes band linear solver for mass matrix solve + */ + +void FSUNBANDLINSOL_INIT(int *code, int *ier); +void FSUNMASSBANDLINSOL_INIT(int *ier); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/band/sunlinsol_band.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/band/sunlinsol_band.c new file mode 100644 index 0000000..5385328 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/band/sunlinsol_band.c @@ -0,0 +1,286 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 the band implementation of + * the SUNLINSOL package. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <sunlinsol/sunlinsol_band.h> +#include <sundials/sundials_math.h> + +#define ZERO RCONST(0.0) +#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: + * ----------------------------------------------------------------- + */ + +#define BAND_CONTENT(S) ( (SUNLinearSolverContent_Band)(S->content) ) +#define PIVOTS(S) ( BAND_CONTENT(S)->pivots ) +#define LASTFLAG(S) ( BAND_CONTENT(S)->last_flag ) + +/* + * ----------------------------------------------------------------- + * deprecated wrapper functions + * ----------------------------------------------------------------- + */ + +SUNLinearSolver SUNBandLinearSolver(N_Vector y, SUNMatrix A) +{ return(SUNLinSol_Band(y, A)); } + +/* + * ----------------------------------------------------------------- + * exported functions + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------------------- + * Function to create a new band linear solver + */ + +SUNLinearSolver SUNLinSol_Band(N_Vector y, SUNMatrix A) +{ + SUNLinearSolver S; + SUNLinearSolver_Ops ops; + SUNLinearSolverContent_Band content; + sunindextype MatrixRows, VecLength; + + /* 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 ( (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 */ + if (SUNBandMatrix_StoredUpperBandwidth(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 */ + S = NULL; + S = (SUNLinearSolver) malloc(sizeof *S); + 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; + + /* Create content */ + content = NULL; + content = (SUNLinearSolverContent_Band) malloc(sizeof(struct _SUNLinearSolverContent_Band)); + if (content == NULL) { free(ops); free(S); return(NULL); } + + /* Fill content */ + content->N = MatrixRows; + content->last_flag = 0; + content->pivots = NULL; + 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; + + return(S); +} + +/* + * ----------------------------------------------------------------- + * implementation of linear solver operations + * ----------------------------------------------------------------- + */ + +SUNLinearSolver_Type SUNLinSolGetType_Band(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_DIRECT); +} + +int SUNLinSolInitialize_Band(SUNLinearSolver S) +{ + /* all solver-specific memory has already been allocated */ + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + +int SUNLinSolSetup_Band(SUNLinearSolver S, SUNMatrix A) +{ + realtype **A_cols; + sunindextype *pivots; + + /* check for valid inputs */ + 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)); + } + + /* access data pointers (return with failure on NULL) */ + A_cols = NULL; + pivots = NULL; + A_cols = SM_COLS_B(A); + pivots = PIVOTS(S); + if ( (A_cols == NULL) || (pivots == NULL) ) { + LASTFLAG(S) = SUNLS_MEM_FAIL; + return(LASTFLAG(S)); + } + + /* 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)); + } + + /* 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); + + /* 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, + N_Vector b, realtype tol) +{ + realtype **A_cols, *xdata; + sunindextype *pivots; + + /* check for valid inputs */ + if ( (A == NULL) || (S == NULL) || (x == NULL) || (b == NULL) ) + return(SUNLS_MEM_NULL); + + /* copy b into x */ + N_VScale(ONE, b, x); + + /* access data pointers (return with failure on NULL) */ + A_cols = NULL; + xdata = NULL; + pivots = NULL; + A_cols = SUNBandMatrix_Cols(A); + xdata = N_VGetArrayPointer(x); + pivots = PIVOTS(S); + if ( (A_cols == NULL) || (xdata == NULL) || (pivots == NULL) ) { + LASTFLAG(S) = SUNLS_MEM_FAIL; + return(LASTFLAG(S)); + } + + /* solve using LU factors */ + bandGBTRS(A_cols, SM_COLUMNS_B(A), SM_SUBAND_B(A), + SM_LBAND_B(A), pivots, xdata); + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + +long int SUNLinSolLastFlag_Band(SUNLinearSolver S) +{ + /* return the stored 'last_flag' value */ + return(LASTFLAG(S)); +} + +int SUNLinSolSpace_Band(SUNLinearSolver S, + long int *lenrwLS, + long int *leniwLS) +{ + *leniwLS = 2 + BAND_CONTENT(S)->N; + *lenrwLS = 0; + return(SUNLS_SUCCESS); +} + +int SUNLinSolFree_Band(SUNLinearSolver S) +{ + /* return if S is already free */ + 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); + S->content = NULL; + } + if (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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/dense/fsunlinsol_dense.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/dense/fsunlinsol_dense.c new file mode 100644 index 0000000..2330b1d --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/dense/fsunlinsol_dense.c @@ -0,0 +1,96 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunlinsol_dense.h) contains the + * implementation needed for the Fortran initialization of dense + * linear solver operations. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fsunlinsol_dense.h" + +/* Define global linsol variables */ + +SUNLinearSolver F2C_CVODE_linsol; +SUNLinearSolver F2C_IDA_linsol; +SUNLinearSolver F2C_KINSOL_linsol; +SUNLinearSolver F2C_ARKODE_linsol; +SUNLinearSolver F2C_ARKODE_mass_sol; + +/* Declarations of external global variables */ + +extern SUNMatrix F2C_CVODE_matrix; +extern SUNMatrix F2C_IDA_matrix; +extern SUNMatrix F2C_KINSOL_matrix; +extern SUNMatrix F2C_ARKODE_matrix; +extern SUNMatrix F2C_ARKODE_mass_matrix; + +extern N_Vector F2C_CVODE_vec; +extern N_Vector F2C_IDA_vec; +extern N_Vector F2C_KINSOL_vec; +extern N_Vector F2C_ARKODE_vec; + +/* Fortran callable interfaces */ + +void FSUNDENSELINSOL_INIT(int *code, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (F2C_CVODE_linsol) SUNLinSolFree(F2C_CVODE_linsol); + F2C_CVODE_linsol = NULL; + F2C_CVODE_linsol = SUNLinSol_Dense(F2C_CVODE_vec, + F2C_CVODE_matrix); + if (F2C_CVODE_linsol == NULL) *ier = -1; + break; + case FCMIX_IDA: + if (F2C_IDA_linsol) SUNLinSolFree(F2C_IDA_linsol); + F2C_IDA_linsol = NULL; + F2C_IDA_linsol = SUNLinSol_Dense(F2C_IDA_vec, + F2C_IDA_matrix); + if (F2C_IDA_linsol == NULL) *ier = -1; + break; + case FCMIX_KINSOL: + if (F2C_KINSOL_linsol) SUNLinSolFree(F2C_KINSOL_linsol); + F2C_KINSOL_linsol = NULL; + F2C_KINSOL_linsol = SUNLinSol_Dense(F2C_KINSOL_vec, + F2C_KINSOL_matrix); + if (F2C_KINSOL_linsol == NULL) *ier = -1; + break; + case FCMIX_ARKODE: + if (F2C_ARKODE_linsol) SUNLinSolFree(F2C_ARKODE_linsol); + F2C_ARKODE_linsol = NULL; + F2C_ARKODE_linsol = SUNLinSol_Dense(F2C_ARKODE_vec, + F2C_ARKODE_matrix); + if (F2C_ARKODE_linsol == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + + +void FSUNMASSDENSELINSOL_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_Dense(F2C_ARKODE_vec, + F2C_ARKODE_mass_matrix); + if (F2C_ARKODE_mass_sol == NULL) *ier = -1; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/dense/fsunlinsol_dense.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/dense/fsunlinsol_dense.h new file mode 100644 index 0000000..872bdba --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/dense/fsunlinsol_dense.h @@ -0,0 +1,62 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds, Ashley Crawford @ 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 (companion of fsunlinsol_dense.c) contains the + * definitions needed for the initialization of dense + * linear solver operations in Fortran. + * ----------------------------------------------------------------- + */ + +#ifndef _FSUNLINSOL_DENSE_H +#define _FSUNLINSOL_DENSE_H + +#include <sunlinsol/sunlinsol_dense.h> +#include <sundials/sundials_fnvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +#if defined(SUNDIALS_F77_FUNC) +#define FSUNDENSELINSOL_INIT SUNDIALS_F77_FUNC(fsundenselinsolinit, FSUNDENSELINSOLINIT) +#define FSUNMASSDENSELINSOL_INIT SUNDIALS_F77_FUNC(fsunmassdenselinsolinit, FSUNMASSDENSELINSOLINIT) +#else +#define FSUNDENSELINSOL_INIT fsundenselinsolinit_ +#define FSUNMASSDENSELINSOL_INIT fsunmassdenselinsolinit_ +#endif + + +/* Declarations of global variables */ + +extern SUNLinearSolver F2C_CVODE_linsol; +extern SUNLinearSolver F2C_IDA_linsol; +extern SUNLinearSolver F2C_KINSOL_linsol; +extern SUNLinearSolver F2C_ARKODE_linsol; +extern SUNLinearSolver F2C_ARKODE_mass_sol; + +/* + * Prototypes of exported functions + * + * FSUNDENSELINSOL_INIT - initializes dense linear solver for main problem + * FSUNMASSDENSELINSOL_INIT - initializes dense linear solver for mass matrix solve + */ + +void FSUNDENSELINSOL_INIT(int *code, int *ier); +void FSUNMASSDENSELINSOL_INIT(int *ier); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/dense/sunlinsol_dense.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/dense/sunlinsol_dense.c new file mode 100644 index 0000000..073bc93 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/dense/sunlinsol_dense.c @@ -0,0 +1,271 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds, Ashley Crawford @ 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 the dense implementation of + * the SUNLINSOL package. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <sunlinsol/sunlinsol_dense.h> +#include <sundials/sundials_math.h> + +#define ONE RCONST(1.0) + +/* Private function prototypes */ +sunindextype GlobalVectorLength_DenseLS(N_Vector y); + +/* + * ----------------------------------------------------------------- + * Dense solver structure accessibility macros: + * ----------------------------------------------------------------- + */ + +#define DENSE_CONTENT(S) ( (SUNLinearSolverContent_Dense)(S->content) ) +#define PIVOTS(S) ( DENSE_CONTENT(S)->pivots ) +#define LASTFLAG(S) ( DENSE_CONTENT(S)->last_flag ) + + +/* + * ----------------------------------------------------------------- + * deprecated wrapper functions + * ----------------------------------------------------------------- + */ + +SUNLinearSolver SUNDenseLinearSolver(N_Vector y, SUNMatrix A) +{ return(SUNLinSol_Dense(y, A)); } + +/* + * ----------------------------------------------------------------- + * exported functions + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------------------- + * Function to create a new dense linear solver + */ + +SUNLinearSolver SUNLinSol_Dense(N_Vector y, SUNMatrix A) +{ + SUNLinearSolver S; + SUNLinearSolver_Ops ops; + SUNLinearSolverContent_Dense content; + sunindextype MatrixRows, VecLength; + + /* 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 ( (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 */ + S = NULL; + S = (SUNLinearSolver) malloc(sizeof *S); + 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; + + /* Create content */ + content = NULL; + content = (SUNLinearSolverContent_Dense) malloc(sizeof(struct _SUNLinearSolverContent_Dense)); + if (content == NULL) { free(ops); free(S); return(NULL); } + + /* Fill content */ + content->N = MatrixRows; + content->last_flag = 0; + content->pivots = NULL; + 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; + + return(S); +} + +/* + * ----------------------------------------------------------------- + * implementation of linear solver operations + * ----------------------------------------------------------------- + */ + +SUNLinearSolver_Type SUNLinSolGetType_Dense(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_DIRECT); +} + +int SUNLinSolInitialize_Dense(SUNLinearSolver S) +{ + /* all solver-specific memory has already been allocated */ + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + +int SUNLinSolSetup_Dense(SUNLinearSolver S, SUNMatrix A) +{ + realtype **A_cols; + sunindextype *pivots; + + /* check for valid inputs */ + 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)); + } + + /* access data pointers (return with failure on NULL) */ + A_cols = NULL; + pivots = NULL; + A_cols = SUNDenseMatrix_Cols(A); + pivots = PIVOTS(S); + if ( (A_cols == NULL) || (pivots == NULL) ) { + LASTFLAG(S) = SUNLS_MEM_FAIL; + return(LASTFLAG(S)); + } + + /* perform LU factorization of input matrix */ + LASTFLAG(S) = denseGETRF(A_cols, SUNDenseMatrix_Rows(A), + SUNDenseMatrix_Columns(A), pivots); + + /* store error flag (if nonzero, this row encountered zero-valued pivod) */ + if (LASTFLAG(S) > 0) + return(SUNLS_LUFACT_FAIL); + return(SUNLS_SUCCESS); +} + +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) ) + return(SUNLS_MEM_NULL); + + /* copy b into x */ + N_VScale(ONE, b, x); + + /* access data pointers (return with failure on NULL) */ + A_cols = NULL; + xdata = NULL; + pivots = NULL; + A_cols = SUNDenseMatrix_Cols(A); + xdata = N_VGetArrayPointer(x); + pivots = PIVOTS(S); + if ( (A_cols == NULL) || (xdata == NULL) || (pivots == NULL) ) { + LASTFLAG(S) = SUNLS_MEM_FAIL; + return(LASTFLAG(S)); + } + + /* solve using LU factors */ + denseGETRS(A_cols, SUNDenseMatrix_Rows(A), pivots, xdata); + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + +long int SUNLinSolLastFlag_Dense(SUNLinearSolver S) +{ + /* return the stored 'last_flag' value */ + return(LASTFLAG(S)); +} + +int SUNLinSolSpace_Dense(SUNLinearSolver S, + long int *lenrwLS, + long int *leniwLS) +{ + *leniwLS = 2 + DENSE_CONTENT(S)->N; + *lenrwLS = 0; + return(SUNLS_SUCCESS); +} + +int SUNLinSolFree_Dense(SUNLinearSolver S) +{ + /* return if S is already free */ + 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); + S->content = NULL; + } + if (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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/klu/fsunlinsol_klu.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/klu/fsunlinsol_klu.c new file mode 100644 index 0000000..b63ff1e --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/klu/fsunlinsol_klu.c @@ -0,0 +1,157 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunlinsol_klu.h) contains the + * implementation needed for the Fortran initialization of klu + * linear solver operations. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fsunlinsol_klu.h" + +/* Define global linsol variables */ + +SUNLinearSolver F2C_CVODE_linsol; +SUNLinearSolver F2C_IDA_linsol; +SUNLinearSolver F2C_KINSOL_linsol; +SUNLinearSolver F2C_ARKODE_linsol; +SUNLinearSolver F2C_ARKODE_mass_sol; + +/* Declarations of external global variables */ + +extern SUNMatrix F2C_CVODE_matrix; +extern SUNMatrix F2C_IDA_matrix; +extern SUNMatrix F2C_KINSOL_matrix; +extern SUNMatrix F2C_ARKODE_matrix; +extern SUNMatrix F2C_ARKODE_mass_matrix; + +extern N_Vector F2C_CVODE_vec; +extern N_Vector F2C_IDA_vec; +extern N_Vector F2C_KINSOL_vec; +extern N_Vector F2C_ARKODE_vec; + +/* Fortran callable interfaces */ + +void FSUNKLU_INIT(int *code, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (F2C_CVODE_linsol) SUNLinSolFree(F2C_CVODE_linsol); + F2C_CVODE_linsol = NULL; + F2C_CVODE_linsol = SUNLinSol_KLU(F2C_CVODE_vec, F2C_CVODE_matrix); + if (F2C_CVODE_linsol == NULL) *ier = -1; + break; + case FCMIX_IDA: + if (F2C_IDA_linsol) SUNLinSolFree(F2C_IDA_linsol); + F2C_IDA_linsol = NULL; + F2C_IDA_linsol = SUNLinSol_KLU(F2C_IDA_vec, F2C_IDA_matrix); + if (F2C_IDA_linsol == NULL) *ier = -1; + break; + case FCMIX_KINSOL: + if (F2C_KINSOL_linsol) SUNLinSolFree(F2C_KINSOL_linsol); + F2C_KINSOL_linsol = NULL; + F2C_KINSOL_linsol = SUNLinSol_KLU(F2C_KINSOL_vec, F2C_KINSOL_matrix); + if (F2C_KINSOL_linsol == NULL) *ier = -1; + break; + case FCMIX_ARKODE: + if (F2C_ARKODE_linsol) SUNLinSolFree(F2C_ARKODE_linsol); + F2C_ARKODE_linsol = NULL; + F2C_ARKODE_linsol = SUNLinSol_KLU(F2C_ARKODE_vec, F2C_ARKODE_matrix); + if (F2C_ARKODE_linsol == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + + +void FSUNKLU_REINIT(int *code, long int *NNZ, int *reinit_type, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + *ier = SUNLinSol_KLUReInit(F2C_CVODE_linsol, F2C_CVODE_matrix, + *NNZ, *reinit_type); + break; + case FCMIX_IDA: + *ier = SUNLinSol_KLUReInit(F2C_IDA_linsol, F2C_IDA_matrix, + *NNZ, *reinit_type); + break; + case FCMIX_KINSOL: + *ier = SUNLinSol_KLUReInit(F2C_KINSOL_linsol, F2C_KINSOL_matrix, + *NNZ, *reinit_type); + break; + case FCMIX_ARKODE: + *ier = SUNLinSol_KLUReInit(F2C_ARKODE_linsol, F2C_ARKODE_matrix, + *NNZ, *reinit_type); + break; + default: + *ier = -1; + } +} + + +void FSUNKLU_SETORDERING(int *code, int *ordering_choice, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + *ier = SUNLinSol_KLUSetOrdering(F2C_CVODE_linsol, *ordering_choice); + break; + case FCMIX_IDA: + *ier = SUNLinSol_KLUSetOrdering(F2C_IDA_linsol, *ordering_choice); + break; + case FCMIX_KINSOL: + *ier = SUNLinSol_KLUSetOrdering(F2C_KINSOL_linsol, *ordering_choice); + break; + case FCMIX_ARKODE: + *ier = SUNLinSol_KLUSetOrdering(F2C_ARKODE_linsol, *ordering_choice); + break; + default: + *ier = -1; + } +} + + +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_matrix); + if (F2C_ARKODE_mass_sol == NULL) *ier = -1; +} + + +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); +} + + +void FSUNMASSKLU_SETORDERING(int *ordering_choice, int *ier) +{ + *ier = 0; + *ier = SUNLinSol_KLUSetOrdering(F2C_ARKODE_mass_sol, *ordering_choice); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/klu/fsunlinsol_klu.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/klu/fsunlinsol_klu.h new file mode 100644 index 0000000..b80ca5c --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/klu/fsunlinsol_klu.h @@ -0,0 +1,81 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunlinsol_klu.c) contains the + * definitions needed for the initialization of klu + * linear solver operations in Fortran. + * ----------------------------------------------------------------- + */ + +#ifndef _FSUNLINSOL_KLU_H +#define _FSUNLINSOL_KLU_H + +#include <sunlinsol/sunlinsol_klu.h> +#include <sundials/sundials_fnvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +#if defined(SUNDIALS_F77_FUNC) +#define FSUNKLU_INIT SUNDIALS_F77_FUNC(fsunkluinit, FSUNKLUINIT) +#define FSUNKLU_REINIT SUNDIALS_F77_FUNC(fsunklureinit, FSUNKLUREINIT) +#define FSUNKLU_SETORDERING SUNDIALS_F77_FUNC(fsunklusetordering, FSUNKLUSETORDERING) +#define FSUNMASSKLU_INIT SUNDIALS_F77_FUNC(fsunmasskluinit, FSUNMASSKLUINIT) +#define FSUNMASSKLU_REINIT SUNDIALS_F77_FUNC(fsunmassklureinit, FSUNMASSKLUREINIT) +#define FSUNMASSKLU_SETORDERING SUNDIALS_F77_FUNC(fsunmassklusetordering, FSUNMASSKLUSETORDERING) +#else +#define FSUNKLU_INIT fsunkluinit_ +#define FSUNKLU_REINIT fsunklureinit_ +#define FSUNKLU_SETORDERING fsunklusetordering_ +#define FSUNMASSKLU_INIT fsunmasskluinit_ +#define FSUNMASSKLU_REINIT fsunmassklureinit_ +#define FSUNMASSKLU_SETORDERING fsunmassklusetordering_ +#endif + + +/* Declarations of global variables */ + +extern SUNLinearSolver F2C_CVODE_linsol; +extern SUNLinearSolver F2C_IDA_linsol; +extern SUNLinearSolver F2C_KINSOL_linsol; +extern SUNLinearSolver F2C_ARKODE_linsol; +extern SUNLinearSolver F2C_ARKODE_mass_sol; + +/* + * Prototypes of exported functions + * + * FSUNKLU_INIT - initializes klu linear solver for main problem + * FSUNKLU_REINIT - reinitializes klu linear solver for main problem + * FSUNKLU_SETORDERING - sets the ordering choice used by KLU for main problem + * FSUNMASSKLU_INIT - initializes klu linear solver for mass matrix solve + * FSUNMASSKLU_REINIT - reinitializes klu linear solver for mass matrix solve + * FSUNMASSKLU_SETORDERING - sets the ordering choice used by KLU for mass matrix solve + */ + +void FSUNKLU_INIT(int *code, int *ier); +void FSUNKLU_REINIT(int *code, long int *NNZ, + int *reinit_type, int *ier); +void FSUNKLU_SETORDERING(int *code, int *ordering, + int *ier); +void FSUNMASSKLU_INIT(int *ier); +void FSUNMASSKLU_REINIT(long int *NNZ, + int *reinit_type, int *ier); +void FSUNMASSKLU_SETORDERING(int *ordering, int *ier); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/klu/sunlinsol_klu.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/klu/sunlinsol_klu.c new file mode 100644 index 0000000..8038fe1 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/klu/sunlinsol_klu.c @@ -0,0 +1,457 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * Based on codes <solver>_klu.c, written by Carol 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 + * ----------------------------------------------------------------- + * This is the implementation file for the KLU implementation of + * the SUNLINSOL package. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <sunlinsol/sunlinsol_klu.h> +#include <sundials/sundials_math.h> + +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) +#define TWO RCONST(2.0) +#define TWOTHIRDS RCONST(0.666666666666666666666666666666667) + +/* Private function prototypes */ +sunindextype GlobalVectorLength_KLU(N_Vector y); + +/* + * ----------------------------------------------------------------- + * KLU solver structure accessibility macros: + * ----------------------------------------------------------------- + */ + +#define KLU_CONTENT(S) ( (SUNLinearSolverContent_KLU)(S->content) ) +#define LASTFLAG(S) ( KLU_CONTENT(S)->last_flag ) +#define FIRSTFACTORIZE(S) ( KLU_CONTENT(S)->first_factorize ) +#define SYMBOLIC(S) ( KLU_CONTENT(S)->symbolic ) +#define NUMERIC(S) ( KLU_CONTENT(S)->numeric ) +#define COMMON(S) ( KLU_CONTENT(S)->common ) +#define SOLVE(S) ( KLU_CONTENT(S)->klu_solver ) + +/* + * ----------------------------------------------------------------- + * typedef to handle pointer casts from sunindextype to KLU type + * ----------------------------------------------------------------- + */ + +#if defined(SUNDIALS_INT64_T) +#define KLU_INDEXTYPE long int +#else +#define KLU_INDEXTYPE int +#endif + +/* + * ----------------------------------------------------------------- + * deprecated wrapper functions + * ----------------------------------------------------------------- + */ + +SUNLinearSolver SUNKLU(N_Vector y, SUNMatrix A) +{ return(SUNLinSol_KLU(y, A)); } + +int SUNKLUReInit(SUNLinearSolver S, SUNMatrix A, + sunindextype nnz, int reinit_type) +{ return(SUNLinSol_KLUReInit(S, A, nnz, reinit_type)); } + +int SUNKLUSetOrdering(SUNLinearSolver S, + int ordering_choice) +{ return(SUNLinSol_KLUSetOrdering(S, ordering_choice)); } + +/* + * ----------------------------------------------------------------- + * exported functions + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------------------- + * Function to create a new KLU linear solver + */ + +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 ( (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 */ + S = NULL; + S = (SUNLinearSolver) malloc(sizeof *S); + 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; + + /* Create content */ + content = NULL; + content = (SUNLinearSolverContent_KLU) malloc(sizeof(struct _SUNLinearSolverContent_KLU)); + if (content == NULL) { free(ops); free(S); return(NULL); } + + /* Fill content */ + content->last_flag = 0; + content->first_factorize = 1; +#if defined(SUNDIALS_INT64_T) + if (SUNSparseMatrix_SparseType(A) == CSC_MAT) { + content->klu_solver = (KLUSolveFn) &klu_l_solve; + } else { + content->klu_solver = (KLUSolveFn) &klu_l_tsolve; + } +#elif defined(SUNDIALS_INT32_T) + if (SUNSparseMatrix_SparseType(A) == CSC_MAT) { + content->klu_solver = &klu_solve; + } else { + content->klu_solver = &klu_tsolve; + } +#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); } + (content->common).ordering = SUNKLU_ORDERING_DEFAULT; + + /* Attach content and ops */ + S->content = content; + S->ops = ops; + + return(S); +} + + +/* ---------------------------------------------------------------------------- + * Function to reinitialize a KLU linear solver + */ + +int SUNLinSol_KLUReInit(SUNLinearSolver S, SUNMatrix A, + sunindextype nnz, int reinit_type) +{ + /* Check for non-NULL SUNLinearSolver */ + if ((S == NULL) || (A == NULL)) + return(SUNLS_MEM_NULL); + + /* Check for valid SUNMatrix */ + if (SUNMatGetID(A) != SUNMATRIX_SPARSE) + return(SUNLS_ILL_INPUT); + + /* Check for valid reinit_type */ + if ((reinit_type != SUNKLU_REINIT_FULL) && + (reinit_type != SUNKLU_REINIT_PARTIAL)) + return(SUNLS_ILL_INPUT); + + /* Full re-initialization: reallocate matrix for updated storage */ + if (reinit_type == SUNKLU_REINIT_FULL) + if (SUNSparseMatrix_Reallocate(A, nnz) != 0) + return(SUNLS_MEM_FAIL); + + /* Free the prior factorazation and reset for first factorization */ + if( SYMBOLIC(S) != NULL) + sun_klu_free_symbolic(&SYMBOLIC(S), &COMMON(S)); + if( NUMERIC(S) != NULL) + sun_klu_free_numeric(&NUMERIC(S), &COMMON(S)); + FIRSTFACTORIZE(S) = 1; + + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + +/* ---------------------------------------------------------------------------- + * Function to set the ordering type for a KLU linear solver + */ + +int SUNLinSol_KLUSetOrdering(SUNLinearSolver S, int ordering_choice) +{ + /* Check for legal ordering_choice */ + if ((ordering_choice < 0) || (ordering_choice > 2)) + return(SUNLS_ILL_INPUT); + + /* Check for non-NULL SUNLinearSolver */ + if (S == NULL) return(SUNLS_MEM_NULL); + + /* Set ordering_choice */ + COMMON(S).ordering = ordering_choice; + + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + +/* + * ----------------------------------------------------------------- + * implementation of linear solver operations + * ----------------------------------------------------------------- + */ + +SUNLinearSolver_Type SUNLinSolGetType_KLU(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_DIRECT); +} + + +int SUNLinSolInitialize_KLU(SUNLinearSolver S) +{ + /* Force factorization */ + FIRSTFACTORIZE(S) = 1; + + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +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 */ + if (SUNMatGetID(A) != SUNMATRIX_SPARSE) { + LASTFLAG(S) = SUNLS_ILL_INPUT; + return(LASTFLAG(S)); + } + + /* On first decomposition, get the symbolic factorization */ + if (FIRSTFACTORIZE(S)) { + + /* Perform symbolic analysis of sparsity structure */ + 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), + &COMMON(S)); + if (SYMBOLIC(S) == NULL) { + LASTFLAG(S) = SUNLS_PACKAGE_FAIL_UNREC; + return(LASTFLAG(S)); + } + + /* ------------------------------------------------------------ + Compute the LU factorization of the matrix + ------------------------------------------------------------*/ + 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), + &COMMON(S)); + if (NUMERIC(S) == NULL) { + LASTFLAG(S) = SUNLS_PACKAGE_FAIL_UNREC; + return(LASTFLAG(S)); + } + + FIRSTFACTORIZE(S) = 0; + + } 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), + SYMBOLIC(S), + NUMERIC(S), + &COMMON(S)); + if (retval == 0) { + LASTFLAG(S) = SUNLS_PACKAGE_FAIL_REC; + return(LASTFLAG(S)); + } + + /*----------------------------------------------------------- + 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; + return(LASTFLAG(S)); + } + + if ( COMMON(S).rcond < uround_twothirds ) { + + /* Condition number may be getting large. + Compute more accurate estimate */ + retval = sun_klu_condest((KLU_INDEXTYPE*) SUNSparseMatrix_IndexPointers(A), + SUNSparseMatrix_Data(A), + SYMBOLIC(S), + NUMERIC(S), + &COMMON(S)); + if (retval == 0) { + LASTFLAG(S) = SUNLS_PACKAGE_FAIL_REC; + return(LASTFLAG(S)); + } + + if ( COMMON(S).condest > (ONE/uround_twothirds) ) { + + /* 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), + &COMMON(S)); + if (NUMERIC(S) == NULL) { + LASTFLAG(S) = SUNLS_PACKAGE_FAIL_UNREC; + return(LASTFLAG(S)); + } + } + + } + } + + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +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) ) + 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) = 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, + &COMMON(S)); + if (flag == 0) { + LASTFLAG(S) = SUNLS_PACKAGE_FAIL_REC; + return(LASTFLAG(S)); + } + + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +long int SUNLinSolLastFlag_KLU(SUNLinearSolver S) +{ + /* return the stored 'last_flag' value */ + return(LASTFLAG(S)); +} + + +int SUNLinSolSpace_KLU(SUNLinearSolver S, + long int *lenrwLS, + long int *leniwLS) +{ + /* since the klu structures are opaque objects, we + omit those from these results */ + *leniwLS = 2; + *lenrwLS = 0; + return(SUNLS_SUCCESS); +} + +int SUNLinSolFree_KLU(SUNLinearSolver S) +{ + /* return with success if already freed */ + 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); + S->content = NULL; + } + + /* delete generic structures */ + if (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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackband/fsunlinsol_lapackband.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackband/fsunlinsol_lapackband.c new file mode 100644 index 0000000..c54b9da --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackband/fsunlinsol_lapackband.c @@ -0,0 +1,94 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunlinsol_lapackband.h) contains the + * implementation needed for the Fortran initialization of LAPACK + * band linear solver operations. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fsunlinsol_lapackband.h" + +/* Define global linsol variables */ + +SUNLinearSolver F2C_CVODE_linsol; +SUNLinearSolver F2C_IDA_linsol; +SUNLinearSolver F2C_KINSOL_linsol; +SUNLinearSolver F2C_ARKODE_linsol; +SUNLinearSolver F2C_ARKODE_mass_sol; + +/* Declarations of external global variables */ + +extern SUNMatrix F2C_CVODE_matrix; +extern SUNMatrix F2C_IDA_matrix; +extern SUNMatrix F2C_KINSOL_matrix; +extern SUNMatrix F2C_ARKODE_matrix; +extern SUNMatrix F2C_ARKODE_mass_matrix; + +extern N_Vector F2C_CVODE_vec; +extern N_Vector F2C_IDA_vec; +extern N_Vector F2C_KINSOL_vec; +extern N_Vector F2C_ARKODE_vec; + +/* Fortran callable interfaces */ + +void FSUNLAPACKBAND_INIT(int *code, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (F2C_CVODE_linsol) SUNLinSolFree(F2C_CVODE_linsol); + F2C_CVODE_linsol = NULL; + F2C_CVODE_linsol = SUNLinSol_LapackBand(F2C_CVODE_vec, F2C_CVODE_matrix); + if (F2C_CVODE_linsol == NULL) *ier = -1; + break; + case FCMIX_IDA: + if (F2C_IDA_linsol) SUNLinSolFree(F2C_IDA_linsol); + F2C_IDA_linsol = NULL; + F2C_IDA_linsol = SUNLinSol_LapackBand(F2C_IDA_vec, F2C_IDA_matrix); + if (F2C_IDA_linsol == NULL) *ier = -1; + break; + case FCMIX_KINSOL: + if (F2C_KINSOL_linsol) SUNLinSolFree(F2C_KINSOL_linsol); + F2C_KINSOL_linsol = NULL; + F2C_KINSOL_linsol = SUNLinSol_LapackBand(F2C_KINSOL_vec, F2C_KINSOL_matrix); + if (F2C_KINSOL_linsol == NULL) *ier = -1; + break; + case FCMIX_ARKODE: + if (F2C_ARKODE_linsol) SUNLinSolFree(F2C_ARKODE_linsol); + F2C_ARKODE_linsol = NULL; + F2C_ARKODE_linsol = SUNLinSol_LapackBand(F2C_ARKODE_vec, F2C_ARKODE_matrix); + if (F2C_ARKODE_linsol == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + + +void FSUNMASSLAPACKBAND_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_LapackBand(F2C_ARKODE_vec, + F2C_ARKODE_mass_matrix); + if (F2C_ARKODE_mass_sol == NULL) *ier = -1; +} + + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackband/fsunlinsol_lapackband.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackband/fsunlinsol_lapackband.h new file mode 100644 index 0000000..ef8383d --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackband/fsunlinsol_lapackband.h @@ -0,0 +1,62 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunlinsol_lapackband.c) contains the + * definitions needed for the initialization of LAPACK band + * linear solver operations in Fortran. + * ----------------------------------------------------------------- + */ + +#ifndef _FSUNLINSOL_LAPBAND_H +#define _FSUNLINSOL_LAPBAND_H + +#include <sunlinsol/sunlinsol_lapackband.h> +#include <sundials/sundials_fnvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +#if defined(SUNDIALS_F77_FUNC) +#define FSUNLAPACKBAND_INIT SUNDIALS_F77_FUNC(fsunlapackbandinit, FSUNLAPACKBANDINIT) +#define FSUNMASSLAPACKBAND_INIT SUNDIALS_F77_FUNC(fsunmasslapackbandinit, FSUNMASSLAPACKBANDINIT) +#else +#define FSUNLAPACKBAND_INIT fsunlapackbandinit_ +#define FSUNMASSLAPACKBAND_INIT fsunmasslapackbandinit_ +#endif + + +/* Declarations of global variables */ + +extern SUNLinearSolver F2C_CVODE_linsol; +extern SUNLinearSolver F2C_IDA_linsol; +extern SUNLinearSolver F2C_KINSOL_linsol; +extern SUNLinearSolver F2C_ARKODE_linsol; +extern SUNLinearSolver F2C_ARKODE_mass_sol; + +/* + * Prototypes of exported functions + * + * FSUNLAPACKBAND_INIT - initializes LAPACK band linear solver for main problem + * FSUNMASSLAPACKBAND_INIT - initializes LAPACK band linear solver for mass matrix solve + */ + +void FSUNLAPACKBAND_INIT(int *code, int *ier); +void FSUNMASSLAPACKBAND_INIT(int *ier); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackband/sunlinsol_lapackband.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackband/sunlinsol_lapackband.c new file mode 100644 index 0000000..7c89046 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackband/sunlinsol_lapackband.c @@ -0,0 +1,280 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * Based on codes <solver>_lapack.c by: 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 LAPACK band + * implementation of the SUNLINSOL package. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <sunlinsol/sunlinsol_lapackband.h> +#include <sundials/sundials_math.h> + +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + +/* Private function prototypes */ +sunindextype GlobalVectorLength_LapBand(N_Vector y); + +/* + * ----------------------------------------------------------------- + * Band solver structure accessibility macros: + * ----------------------------------------------------------------- + */ + +#define LAPACKBAND_CONTENT(S) ( (SUNLinearSolverContent_LapackBand)(S->content) ) +#define PIVOTS(S) ( LAPACKBAND_CONTENT(S)->pivots ) +#define LASTFLAG(S) ( LAPACKBAND_CONTENT(S)->last_flag ) + +/* + * ----------------------------------------------------------------- + * deprecated wrapper functions + * ----------------------------------------------------------------- + */ + +SUNLinearSolver SUNLapackBand(N_Vector y, SUNMatrix A) +{ return(SUNLinSol_LapackBand(y, A)); } + +/* + * ----------------------------------------------------------------- + * exported functions + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------------------- + * Function to create a new LAPACK band linear solver + */ + +SUNLinearSolver SUNLinSol_LapackBand(N_Vector y, SUNMatrix A) +{ + SUNLinearSolver S; + SUNLinearSolver_Ops ops; + SUNLinearSolverContent_LapackBand content; + sunindextype MatrixRows, VecLength; + + /* 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 ( (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 */ + S = NULL; + S = (SUNLinearSolver) malloc(sizeof *S); + 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; + + /* Create content */ + content = NULL; + content = (SUNLinearSolverContent_LapackBand) malloc(sizeof(struct _SUNLinearSolverContent_LapackBand)); + if (content == NULL) { free(ops); free(S); return(NULL); } + + /* Fill content */ + content->N = MatrixRows; + content->last_flag = 0; + content->pivots = NULL; + 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; + + return(S); +} + + +/* + * ----------------------------------------------------------------- + * implementation of linear solver operations + * ----------------------------------------------------------------- + */ + +SUNLinearSolver_Type SUNLinSolGetType_LapackBand(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_DIRECT); +} + + +int SUNLinSolInitialize_LapackBand(SUNLinearSolver S) +{ + /* all solver-specific memory has already been allocated */ + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +int SUNLinSolSetup_LapackBand(SUNLinearSolver S, SUNMatrix A) +{ + int n, ml, mu, ldim, ier; + + /* check for valid inputs */ + 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)); + } + + /* 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) + return(SUNLS_LUFACT_FAIL); + if (ier < 0) + return(SUNLS_PACKAGE_FAIL_UNREC); + return(SUNLS_SUCCESS); +} + + +int SUNLinSolSolve_LapackBand(SUNLinearSolver S, SUNMatrix A, N_Vector x, + N_Vector b, realtype tol) +{ + int n, ml, mu, ldim, one, ier; + realtype *xdata; + + /* check for valid inputs */ + 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)); + } + + /* 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) + return(SUNLS_PACKAGE_FAIL_UNREC); + + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +long int SUNLinSolLastFlag_LapackBand(SUNLinearSolver S) +{ + /* return the stored 'last_flag' value */ + return(LASTFLAG(S)); +} + + +int SUNLinSolSpace_LapackBand(SUNLinearSolver S, + long int *lenrwLS, + long int *leniwLS) +{ + *lenrwLS = 0; + *leniwLS = 2 + LAPACKBAND_CONTENT(S)->N; + return(SUNLS_SUCCESS); +} + +int SUNLinSolFree_LapackBand(SUNLinearSolver S) +{ + /* return with success if already freed */ + 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); + S->content = NULL; + } + + if (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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackdense/fsunlinsol_lapackdense.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackdense/fsunlinsol_lapackdense.c new file mode 100644 index 0000000..eaed35e --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackdense/fsunlinsol_lapackdense.c @@ -0,0 +1,92 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunlinsol_lapackdense.h) contains the + * implementation needed for the Fortran initialization of LAPACK + * dense linear solver operations. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fsunlinsol_lapackdense.h" + +/* Define global linsol variables */ + +SUNLinearSolver F2C_CVODE_linsol; +SUNLinearSolver F2C_IDA_linsol; +SUNLinearSolver F2C_KINSOL_linsol; +SUNLinearSolver F2C_ARKODE_linsol; +SUNLinearSolver F2C_ARKODE_mass_sol; + +/* Declarations of external global variables */ + +extern SUNMatrix F2C_CVODE_matrix; +extern SUNMatrix F2C_IDA_matrix; +extern SUNMatrix F2C_KINSOL_matrix; +extern SUNMatrix F2C_ARKODE_matrix; +extern SUNMatrix F2C_ARKODE_mass_matrix; + +extern N_Vector F2C_CVODE_vec; +extern N_Vector F2C_IDA_vec; +extern N_Vector F2C_KINSOL_vec; +extern N_Vector F2C_ARKODE_vec; + +/* Fortran callable interfaces */ + +void FSUNLAPACKDENSE_INIT(int *code, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (F2C_CVODE_linsol) SUNLinSolFree(F2C_CVODE_linsol); + F2C_CVODE_linsol = NULL; + F2C_CVODE_linsol = SUNLinSol_LapackDense(F2C_CVODE_vec, F2C_CVODE_matrix); + if (F2C_CVODE_linsol == NULL) *ier = -1; + break; + case FCMIX_IDA: + if (F2C_IDA_linsol) SUNLinSolFree(F2C_IDA_linsol); + F2C_IDA_linsol = NULL; + F2C_IDA_linsol = SUNLinSol_LapackDense(F2C_IDA_vec, F2C_IDA_matrix); + if (F2C_IDA_linsol == NULL) *ier = -1; + break; + case FCMIX_KINSOL: + if (F2C_KINSOL_linsol) SUNLinSolFree(F2C_KINSOL_linsol); + F2C_KINSOL_linsol = NULL; + F2C_KINSOL_linsol = SUNLinSol_LapackDense(F2C_KINSOL_vec, F2C_KINSOL_matrix); + if (F2C_KINSOL_linsol == NULL) *ier = -1; + break; + case FCMIX_ARKODE: + if (F2C_ARKODE_linsol) SUNLinSolFree(F2C_ARKODE_linsol); + F2C_ARKODE_linsol = NULL; + F2C_ARKODE_linsol = SUNLinSol_LapackDense(F2C_ARKODE_vec, F2C_ARKODE_matrix); + if (F2C_ARKODE_linsol == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + + +void FSUNMASSLAPACKDENSE_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_LapackDense(F2C_ARKODE_vec, + F2C_ARKODE_mass_matrix); + if (F2C_ARKODE_mass_sol == NULL) *ier = -1; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackdense/fsunlinsol_lapackdense.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackdense/fsunlinsol_lapackdense.h new file mode 100644 index 0000000..d97a7f5 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackdense/fsunlinsol_lapackdense.h @@ -0,0 +1,62 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunlinsol_lapackdense.c) contains the + * definitions needed for the initialization of LAPACK dense + * linear solver operations in Fortran. + * ----------------------------------------------------------------- + */ + +#ifndef _FSUNLINSOL_LAPDENSE_H +#define _FSUNLINSOL_LAPDENSE_H + +#include <sunlinsol/sunlinsol_lapackdense.h> +#include <sundials/sundials_fnvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +#if defined(SUNDIALS_F77_FUNC) +#define FSUNLAPACKDENSE_INIT SUNDIALS_F77_FUNC(fsunlapackdenseinit, FSUNLAPACKDENSEINIT) +#define FSUNMASSLAPACKDENSE_INIT SUNDIALS_F77_FUNC(fsunmasslapackdenseinit, FSUNMASSLAPACKDENSEINIT) +#else +#define FSUNLAPACKDENSE_INIT fsunlapackdenseinit_ +#define FSUNMASSLAPACKDENSE_INIT fsunmasslapackdenseinit_ +#endif + + +/* Declarations of global variables */ + +extern SUNLinearSolver F2C_CVODE_linsol; +extern SUNLinearSolver F2C_IDA_linsol; +extern SUNLinearSolver F2C_KINSOL_linsol; +extern SUNLinearSolver F2C_ARKODE_linsol; +extern SUNLinearSolver F2C_ARKODE_mass_sol; + +/* + * Prototypes of exported functions + * + * FSUNLAPACKDENSE_INIT - initializes LAPACK dense linear solver for main problem + * FSUNMASSLAPACKDENSE_INIT - initializes LAPACK dense linear solver for mass matrix solve + */ + +void FSUNLAPACKDENSE_INIT(int *code, int *ier); +void FSUNMASSLAPACKDENSE_INIT(int *ier); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackdense/sunlinsol_lapackdense.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackdense/sunlinsol_lapackdense.c new file mode 100644 index 0000000..e3f4707 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/lapackdense/sunlinsol_lapackdense.c @@ -0,0 +1,271 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * Based on codes <solver>_lapack.c by: 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 LAPACK dense + * implementation of the SUNLINSOL package. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <sunlinsol/sunlinsol_lapackdense.h> +#include <sundials/sundials_math.h> + +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + +/* Private function prototypes */ +sunindextype GlobalVectorLength_LapDense(N_Vector y); + +/* + * ----------------------------------------------------------------- + * LapackDense solver structure accessibility macros: + * ----------------------------------------------------------------- + */ + +#define LAPACKDENSE_CONTENT(S) ( (SUNLinearSolverContent_LapackDense)(S->content) ) +#define PIVOTS(S) ( LAPACKDENSE_CONTENT(S)->pivots ) +#define LASTFLAG(S) ( LAPACKDENSE_CONTENT(S)->last_flag ) + +/* + * ----------------------------------------------------------------- + * deprecated wrapper functions + * ----------------------------------------------------------------- + */ + +SUNLinearSolver SUNLapackDense(N_Vector y, SUNMatrix A) +{ return(SUNLinSol_LapackDense(y, A)); } + +/* + * ----------------------------------------------------------------- + * exported functions + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------------------- + * Function to create a new LAPACK dense linear solver + */ + +SUNLinearSolver SUNLinSol_LapackDense(N_Vector y, SUNMatrix A) +{ + SUNLinearSolver S; + SUNLinearSolver_Ops ops; + SUNLinearSolverContent_LapackDense content; + sunindextype MatrixRows, VecLength; + + /* 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 ( (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); + + /* Create linear solver */ + S = NULL; + S = (SUNLinearSolver) malloc(sizeof *S); + 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; + + /* Create content */ + content = NULL; + content = (SUNLinearSolverContent_LapackDense) + malloc(sizeof(struct _SUNLinearSolverContent_LapackDense)); + if (content == NULL) { free(ops); free(S); return(NULL); } + + /* Fill content */ + content->N = MatrixRows; + content->last_flag = 0; + content->pivots = NULL; + 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; + + return(S); +} + + +/* + * ----------------------------------------------------------------- + * implementation of linear solver operations + * ----------------------------------------------------------------- + */ + +SUNLinearSolver_Type SUNLinSolGetType_LapackDense(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_DIRECT); +} + + +int SUNLinSolInitialize_LapackDense(SUNLinearSolver S) +{ + /* all solver-specific memory has already been allocated */ + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +int SUNLinSolSetup_LapackDense(SUNLinearSolver S, SUNMatrix A) +{ + int n, ier; + + /* check for valid inputs */ + 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)); + } + + /* 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) + return(SUNLS_LUFACT_FAIL); + 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 n, one, ier; + realtype *xdata; + + 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) = SUNLS_MEM_FAIL; + return(LASTFLAG(S)); + } + + /* 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) + return(SUNLS_PACKAGE_FAIL_UNREC); + + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +long int SUNLinSolLastFlag_LapackDense(SUNLinearSolver S) +{ + /* return the stored 'last_flag' value */ + return(LASTFLAG(S)); +} + + +int SUNLinSolSpace_LapackDense(SUNLinearSolver S, + long int *lenrwLS, + long int *leniwLS) +{ + *lenrwLS = 0; + *leniwLS = 2 + LAPACKDENSE_CONTENT(S)->N; + return(SUNLS_SUCCESS); +} + +int SUNLinSolFree_LapackDense(SUNLinearSolver S) +{ + /* return if S is already free */ + 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); + S->content = NULL; + } + if (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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/pcg/fsunlinsol_pcg.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/pcg/fsunlinsol_pcg.c new file mode 100644 index 0000000..03b0499 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/pcg/fsunlinsol_pcg.c @@ -0,0 +1,191 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunlinsol_pcg.h) contains the + * implementation needed for the Fortran initialization of PCG + * linear solver operations. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fsunlinsol_pcg.h" + +/* Define global linsol variables */ + +SUNLinearSolver F2C_CVODE_linsol; +SUNLinearSolver F2C_IDA_linsol; +SUNLinearSolver F2C_KINSOL_linsol; +SUNLinearSolver F2C_ARKODE_linsol; +SUNLinearSolver F2C_ARKODE_mass_sol; + +/* Declarations of external global variables */ + +extern SUNMatrix F2C_CVODE_matrix; +extern SUNMatrix F2C_IDA_matrix; +extern SUNMatrix F2C_KINSOL_matrix; +extern SUNMatrix F2C_ARKODE_matrix; +extern SUNMatrix F2C_ARKODE_mass_matrix; + +extern N_Vector F2C_CVODE_vec; +extern N_Vector F2C_IDA_vec; +extern N_Vector F2C_KINSOL_vec; +extern N_Vector F2C_ARKODE_vec; + +/* Fortran callable interfaces */ + +void FSUNPCG_INIT(int *code, int *pretype, int *maxl, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (F2C_CVODE_linsol) SUNLinSolFree(F2C_CVODE_linsol); + F2C_CVODE_linsol = NULL; + F2C_CVODE_linsol = SUNLinSol_PCG(F2C_CVODE_vec, *pretype, *maxl); + if (F2C_CVODE_linsol == NULL) *ier = -1; + break; + case FCMIX_IDA: + if (F2C_IDA_linsol) SUNLinSolFree(F2C_IDA_linsol); + F2C_IDA_linsol = NULL; + F2C_IDA_linsol = SUNLinSol_PCG(F2C_IDA_vec, *pretype, *maxl); + if (F2C_IDA_linsol == NULL) *ier = -1; + break; + case FCMIX_KINSOL: + if (F2C_KINSOL_linsol) SUNLinSolFree(F2C_KINSOL_linsol); + F2C_KINSOL_linsol = NULL; + F2C_KINSOL_linsol = SUNLinSol_PCG(F2C_KINSOL_vec, *pretype, *maxl); + if (F2C_KINSOL_linsol == NULL) *ier = -1; + break; + case FCMIX_ARKODE: + if (F2C_ARKODE_linsol) SUNLinSolFree(F2C_ARKODE_linsol); + F2C_ARKODE_linsol = NULL; + F2C_ARKODE_linsol = SUNLinSol_PCG(F2C_ARKODE_vec, *pretype, *maxl); + if (F2C_ARKODE_linsol == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + + +void FSUNPCG_SETPRECTYPE(int *code, int *pretype, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (!F2C_CVODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_PCGSetPrecType(F2C_CVODE_linsol, *pretype); + break; + case FCMIX_IDA: + if (!F2C_IDA_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_PCGSetPrecType(F2C_IDA_linsol, *pretype); + break; + case FCMIX_KINSOL: + if (!F2C_KINSOL_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_PCGSetPrecType(F2C_KINSOL_linsol, *pretype); + break; + case FCMIX_ARKODE: + if (!F2C_ARKODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_PCGSetPrecType(F2C_ARKODE_linsol, *pretype); + break; + default: + *ier = -1; + } +} + + +void FSUNPCG_SETMAXL(int *code, int *maxl, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (!F2C_CVODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_PCGSetMaxl(F2C_CVODE_linsol, *maxl); + break; + case FCMIX_IDA: + if (!F2C_IDA_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_PCGSetMaxl(F2C_IDA_linsol, *maxl); + break; + case FCMIX_KINSOL: + if (!F2C_KINSOL_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_PCGSetMaxl(F2C_KINSOL_linsol, *maxl); + break; + case FCMIX_ARKODE: + if (!F2C_ARKODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_PCGSetMaxl(F2C_ARKODE_linsol, *maxl); + break; + default: + *ier = -1; + } +} + + +void FSUNMASSPCG_INIT(int *pretype, int *maxl, int *ier) +{ + *ier = 0; + if (F2C_ARKODE_mass_sol) SUNLinSolFree(F2C_ARKODE_mass_sol); + F2C_ARKODE_mass_sol = NULL; + F2C_ARKODE_mass_sol = SUNLinSol_PCG(F2C_ARKODE_vec, *pretype, *maxl); + if (F2C_ARKODE_mass_sol == NULL) *ier = -1; +} + + +void FSUNMASSPCG_SETPRECTYPE(int *pretype, int *ier) +{ + *ier = 0; + if (!F2C_ARKODE_mass_sol) { + *ier = -1; + return; + } + *ier = SUNLinSol_PCGSetPrecType(F2C_ARKODE_mass_sol, *pretype); +} + + +void FSUNMASSPCG_SETMAXL(int *maxl, int *ier) +{ + *ier = 0; + if (!F2C_ARKODE_mass_sol) { + *ier = -1; + return; + } + *ier = SUNLinSol_PCGSetMaxl(F2C_ARKODE_mass_sol, *maxl); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/pcg/fsunlinsol_pcg.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/pcg/fsunlinsol_pcg.h new file mode 100644 index 0000000..5a7da10 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/pcg/fsunlinsol_pcg.h @@ -0,0 +1,80 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunlinsol_pcg.c) contains the + * definitions needed for the initialization of PCG + * linear solver operations in Fortran. + * ----------------------------------------------------------------- + */ + +#ifndef _FSUNLINSOL_PCG_H +#define _FSUNLINSOL_PCG_H + +#include <sunlinsol/sunlinsol_pcg.h> +#include <sundials/sundials_fnvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +#if defined(SUNDIALS_F77_FUNC) +#define FSUNPCG_INIT SUNDIALS_F77_FUNC(fsunpcginit, FSUNPCGINIT) +#define FSUNPCG_SETPRECTYPE SUNDIALS_F77_FUNC(fsunpcgsetprectype, FSUNPCGSETPRECTYPE) +#define FSUNPCG_SETMAXL SUNDIALS_F77_FUNC(fsunpcgsetmaxl, FSUNPCGSETMAXL) +#define FSUNMASSPCG_INIT SUNDIALS_F77_FUNC(fsunmasspcginit, FSUNMASSPCGINIT) +#define FSUNMASSPCG_SETPRECTYPE SUNDIALS_F77_FUNC(fsunmasspcgsetprectype, FSUNMASSPCGSETPRECTYPE) +#define FSUNMASSPCG_SETMAXL SUNDIALS_F77_FUNC(fsunmasspcgsetmaxl, FSUNMASSPCGSETMAXL) +#else +#define FSUNPCG_INIT fsunpcginit_ +#define FSUNPCG_SETPRECTYPE fsunpcgsetprectype_ +#define FSUNPCG_SETMAXL fsunpcgsetmaxl_ +#define FSUNMASSPCG_INIT fsunmasspcginit_ +#define FSUNMASSPCG_SETPRECTYPE fsunmasspcgsetprectype_ +#define FSUNMASSPCG_SETMAXL fsunmasspcgsetmaxl_ +#endif + + +/* Declarations of global variables */ + +extern SUNLinearSolver F2C_CVODE_linsol; +extern SUNLinearSolver F2C_IDA_linsol; +extern SUNLinearSolver F2C_KINSOL_linsol; +extern SUNLinearSolver F2C_ARKODE_linsol; +extern SUNLinearSolver F2C_ARKODE_mass_sol; + +/* + * Prototypes of exported functions + * + * FSUNPCG_INIT - initializes PCG linear solver for main problem + * FSUNPCG_SETPRECTYPE - sets preconditioning type for main problem + * FSUNPCG_SETMAXL - sets the max number of iterations for main problem + * + * FSUNMASSPCG_INIT - initializes PCG linear solver for mass matrix solve + * FSUNMASSPCG_SETPRECTYPE - sets preconditioning type for mass matrix solve + * FSUNMASSPCG_SETMAXL - sets the max number of iterations for mass matrix solve + */ + +void FSUNPCG_INIT(int *code, int *pretype, int *maxl, int *ier); +void FSUNPCG_SETPRECTYPE(int *code, int *pretype, int *ier); +void FSUNPCG_SETMAXL(int *code, int *maxl, int *ier); + +void FSUNMASSPCG_INIT(int *pretype, int *maxl, int *ier); +void FSUNMASSPCG_SETPRECTYPE(int *pretype, int *ier); +void FSUNMASSPCG_SETMAXL(int *maxl, int *ier); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/pcg/sunlinsol_pcg.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/pcg/sunlinsol_pcg.c new file mode 100644 index 0000000..80e5226 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/pcg/sunlinsol_pcg.c @@ -0,0 +1,481 @@ +/* + * ----------------------------------------------------------------- + * 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 + * 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 PCG implementation of + * the SUNLINSOL package. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <sunlinsol/sunlinsol_pcg.h> +#include <sundials/sundials_math.h> + +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + +/* + * ----------------------------------------------------------------- + * PCG solver structure accessibility macros: + * ----------------------------------------------------------------- + */ + +#define PCG_CONTENT(S) ( (SUNLinearSolverContent_PCG)(S->content) ) +#define PRETYPE(S) ( PCG_CONTENT(S)->pretype ) +#define LASTFLAG(S) ( PCG_CONTENT(S)->last_flag ) + +/* + * ----------------------------------------------------------------- + * deprecated wrapper functions + * ----------------------------------------------------------------- + */ + +SUNLinearSolver SUNPCG(N_Vector y, int pretype, int maxl) +{ return(SUNLinSol_PCG(y, pretype, maxl)); } + +int SUNPCGSetPrecType(SUNLinearSolver S, int pretype) +{ return(SUNLinSol_PCGSetPrecType(S, pretype)); } + +int SUNPCGSetMaxl(SUNLinearSolver S, int maxl) +{ return(SUNLinSol_PCGSetMaxl(S, maxl)); } + +/* + * ----------------------------------------------------------------- + * exported functions + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------------------- + * Function to create a new PCG linear solver + */ + +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)) + pretype = PREC_NONE; + if (maxl <= 0) + maxl = SUNPCG_MAXL_DEFAULT; + + /* Create linear solver */ + S = NULL; + S = (SUNLinearSolver) malloc(sizeof *S); + 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; + + /* Create content */ + content = NULL; + content = (SUNLinearSolverContent_PCG) malloc(sizeof(struct _SUNLinearSolverContent_PCG)); + if (content == NULL) { free(ops); free(S); return(NULL); } + + /* Fill content */ + content->last_flag = 0; + content->maxl = maxl; + content->pretype = pretype; + content->numiters = 0; + content->resnorm = ZERO; + content->r = N_VClone(y); + if (content->r == NULL) return NULL; + content->p = N_VClone(y); + if (content->p == NULL) return NULL; + content->z = N_VClone(y); + if (content->z == NULL) 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; + + return(S); +} + + +/* ---------------------------------------------------------------------------- + * Function to set the type of preconditioning for PCG to use + */ + +SUNDIALS_EXPORT int SUNLinSol_PCGSetPrecType(SUNLinearSolver S, int pretype) +{ + /* Check for legal pretype */ + if ((pretype != PREC_NONE) && (pretype != PREC_LEFT) && + (pretype != PREC_RIGHT) && (pretype != PREC_BOTH)) { + return(SUNLS_ILL_INPUT); + } + + /* Check for non-NULL SUNLinearSolver */ + if (S == NULL) return(SUNLS_MEM_NULL); + + /* Set pretype */ + PRETYPE(S) = pretype; + return(SUNLS_SUCCESS); +} + + +/* ---------------------------------------------------------------------------- + * Function to set the maximum number of iterations for PCG to use + */ + +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 */ + if (maxl <= 0) + maxl = SUNPCG_MAXL_DEFAULT; + + /* Set pretype */ + PCG_CONTENT(S)->maxl = maxl; + return(SUNLS_SUCCESS); +} + + +/* + * ----------------------------------------------------------------- + * implementation of linear solver operations + * ----------------------------------------------------------------- + */ + +SUNLinearSolver_Type SUNLinSolGetType_PCG(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_ITERATIVE); +} + +int SUNLinSolInitialize_PCG(SUNLinearSolver S) +{ + /* ensure valid options */ + 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) + PCG_CONTENT(S)->maxl = SUNPCG_MAXL_DEFAULT; + + /* no additional memory to allocate */ + + /* return with success */ + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +int SUNLinSolSetATimes_PCG(SUNLinearSolver S, void* ATData, + ATimesFn ATimes) +{ + /* set function pointers to integrator-supplied ATimes routine + and data, and return with success */ + if (S == NULL) return(SUNLS_MEM_NULL); + PCG_CONTENT(S)->ATimes = ATimes; + PCG_CONTENT(S)->ATData = ATData; + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +int SUNLinSolSetPreconditioner_PCG(SUNLinearSolver S, void* PData, + PSetupFn Psetup, PSolveFn Psolve) +{ + /* set function pointers to integrator-supplied Psetup and PSolve + routines and data, and return with success */ + if (S == NULL) return(SUNLS_MEM_NULL); + PCG_CONTENT(S)->Psetup = Psetup; + PCG_CONTENT(S)->Psolve = Psolve; + PCG_CONTENT(S)->PData = PData; + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +int SUNLinSolSetScalingVectors_PCG(SUNLinearSolver S, N_Vector s, + N_Vector nul) +{ + /* set N_Vector pointer to integrator-supplied scaling vector + (only use the first one), and return with success */ + if (S == NULL) return(SUNLS_MEM_NULL); + PCG_CONTENT(S)->s = s; + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +int SUNLinSolSetup_PCG(SUNLinearSolver S, SUNMatrix nul) +{ + int ier; + PSetupFn Psetup; + void* PData; + + /* Set shortcuts to PCG memory structures */ + 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 + Psetup routine exists, call that here */ + if (Psetup != NULL) { + ier = Psetup(PData); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSET_FAIL_UNREC : SUNLS_PSET_FAIL_REC; + return(LASTFLAG(S)); + } + } + + /* return with success */ + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +int SUNLinSolSolve_PCG(SUNLinearSolver S, SUNMatrix nul, N_Vector x, + N_Vector b, realtype delta) +{ + /* local data and shortcut variables */ + realtype alpha, beta, r0_norm, rho, rz, rz_old; + N_Vector r, p, z, Ap, w; + booleantype UsePrec, UseScaling, converged; + int l, l_max, pretype, ier; + void *A_data, *P_data; + ATimesFn atimes; + PSolveFn psolve; + realtype *res_norm; + int *nli; + + /* Make local shorcuts to solver variables. */ + if (S == NULL) return(SUNLS_MEM_NULL); + l_max = PCG_CONTENT(S)->maxl; + r = PCG_CONTENT(S)->r; + p = PCG_CONTENT(S)->p; + z = PCG_CONTENT(S)->z; + Ap = PCG_CONTENT(S)->Ap; + w = PCG_CONTENT(S)->s; + A_data = PCG_CONTENT(S)->ATData; + P_data = PCG_CONTENT(S)->PData; + atimes = PCG_CONTENT(S)->ATimes; + psolve = PCG_CONTENT(S)->Psolve; + pretype = PCG_CONTENT(S)->pretype; + nli = &(PCG_CONTENT(S)->numiters); + res_norm = &(PCG_CONTENT(S)->resnorm); + + /* Initialize counters and convergence flag */ + *nli = 0; + converged = SUNFALSE; + + /* set booleantype flags for internal solver options */ + UsePrec = ( (pretype == PREC_BOTH) || + (pretype == PREC_LEFT) || + (pretype == PREC_RIGHT) ); + UseScaling = (w != NULL); + + /* 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) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_ATIMES_FAIL_UNREC : SUNLS_ATIMES_FAIL_REC; + return(LASTFLAG(S)); + } + N_VLinearSum(ONE, b, -ONE, r, r); + } + + /* Set rho to scaled L2 norm of r, and return if small */ + if (UseScaling) N_VProd(r, w, Ap); + else N_VScale(ONE, r, Ap); + *res_norm = r0_norm = rho = SUNRsqrt(N_VDotProd(Ap, Ap)); + if (rho <= delta) { + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); + } + + /* Apply preconditioner and b-scaling to r = r_0 */ + if (UsePrec) { + ier = psolve(P_data, r, z, delta, PREC_LEFT); /* z = P^{-1}r */ + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; + return(LASTFLAG(S)); + } + } + else N_VScale(ONE, r, z); + + /* Initialize rz to <r,z> */ + rz = N_VDotProd(r, z); + + /* Copy z to p */ + N_VScale(ONE, z, p); + + /* Begin main iteration loop */ + for(l=0; l<l_max; l++) { + + /* increment counter */ + (*nli)++; + + /* Generate Ap = A*p */ + ier = atimes(A_data, p, Ap); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_ATIMES_FAIL_UNREC : SUNLS_ATIMES_FAIL_REC; + return(LASTFLAG(S)); + } + + /* Calculate alpha = <r,z> / <Ap,p> */ + 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 */ + if (UseScaling) N_VProd(r, w, Ap); + else N_VScale(ONE, r, Ap); + *res_norm = rho = SUNRsqrt(N_VDotProd(Ap, Ap)); + if (rho <= delta) { + converged = SUNTRUE; + break; + } + + /* Apply preconditioner: z = P^{-1}*r */ + if (UsePrec) { + ier = psolve(P_data, r, z, delta, PREC_LEFT); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; + return(LASTFLAG(S)); + } + } + else N_VScale(ONE, r, z); + + /* update rz */ + rz_old = rz; + rz = N_VDotProd(r, z); + + /* Calculate beta = <r,z> / <r_old,z_old> */ + 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) { + LASTFLAG(S) = SUNLS_SUCCESS; + } else if (rho < r0_norm) { + LASTFLAG(S) = SUNLS_RES_REDUCED; + } else { + LASTFLAG(S) = SUNLS_CONV_FAIL; + } + return(LASTFLAG(S)); +} + + + + +int SUNLinSolNumIters_PCG(SUNLinearSolver S) +{ + /* return the stored 'numiters' value */ + if (S == NULL) return(-1); + return (PCG_CONTENT(S)->numiters); +} + + +realtype SUNLinSolResNorm_PCG(SUNLinearSolver S) +{ + /* return the stored 'resnorm' value */ + if (S == NULL) return(-ONE); + return (PCG_CONTENT(S)->resnorm); +} + + +N_Vector SUNLinSolResid_PCG(SUNLinearSolver S) +{ + /* return the stored 'r' vector */ + return (PCG_CONTENT(S)->r); +} + + +long int SUNLinSolLastFlag_PCG(SUNLinearSolver S) +{ + /* return the stored 'last_flag' value */ + if (S == NULL) return(-1); + return (LASTFLAG(S)); +} + + +int SUNLinSolSpace_PCG(SUNLinearSolver S, + long int *lenrwLS, + long int *leniwLS) +{ + sunindextype liw1, lrw1; + N_VSpace(PCG_CONTENT(S)->r, &lrw1, &liw1); + *lenrwLS = 1 + lrw1*4; + *leniwLS = 4 + liw1*4; + return(SUNLS_SUCCESS); +} + +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; + free(S); S = NULL; + return 0; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spbcgs/fsunlinsol_spbcgs.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spbcgs/fsunlinsol_spbcgs.c new file mode 100644 index 0000000..8987e29 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spbcgs/fsunlinsol_spbcgs.c @@ -0,0 +1,191 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunlinsol_spbcgs.h) contains the + * implementation needed for the Fortran initialization of SPBCGS + * linear solver operations. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fsunlinsol_spbcgs.h" + +/* Define global linsol variables */ + +SUNLinearSolver F2C_CVODE_linsol; +SUNLinearSolver F2C_IDA_linsol; +SUNLinearSolver F2C_KINSOL_linsol; +SUNLinearSolver F2C_ARKODE_linsol; +SUNLinearSolver F2C_ARKODE_mass_sol; + +/* Declarations of external global variables */ + +extern SUNMatrix F2C_CVODE_matrix; +extern SUNMatrix F2C_IDA_matrix; +extern SUNMatrix F2C_KINSOL_matrix; +extern SUNMatrix F2C_ARKODE_matrix; +extern SUNMatrix F2C_ARKODE_mass_matrix; + +extern N_Vector F2C_CVODE_vec; +extern N_Vector F2C_IDA_vec; +extern N_Vector F2C_KINSOL_vec; +extern N_Vector F2C_ARKODE_vec; + +/* Fortran callable interfaces */ + +void FSUNSPBCGS_INIT(int *code, int *pretype, int *maxl, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (F2C_CVODE_linsol) SUNLinSolFree(F2C_CVODE_linsol); + F2C_CVODE_linsol = NULL; + F2C_CVODE_linsol = SUNLinSol_SPBCGS(F2C_CVODE_vec, *pretype, *maxl); + if (F2C_CVODE_linsol == NULL) *ier = -1; + break; + case FCMIX_IDA: + if (F2C_IDA_linsol) SUNLinSolFree(F2C_IDA_linsol); + F2C_IDA_linsol = NULL; + F2C_IDA_linsol = SUNLinSol_SPBCGS(F2C_IDA_vec, *pretype, *maxl); + if (F2C_IDA_linsol == NULL) *ier = -1; + break; + case FCMIX_KINSOL: + if (F2C_KINSOL_linsol) SUNLinSolFree(F2C_KINSOL_linsol); + F2C_KINSOL_linsol = NULL; + F2C_KINSOL_linsol = SUNLinSol_SPBCGS(F2C_KINSOL_vec, *pretype, *maxl); + if (F2C_KINSOL_linsol == NULL) *ier = -1; + break; + case FCMIX_ARKODE: + if (F2C_ARKODE_linsol) SUNLinSolFree(F2C_ARKODE_linsol); + F2C_ARKODE_linsol = NULL; + F2C_ARKODE_linsol = SUNLinSol_SPBCGS(F2C_ARKODE_vec, *pretype, *maxl); + if (F2C_ARKODE_linsol == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + + +void FSUNSPBCGS_SETPRECTYPE(int *code, int *pretype, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (!F2C_CVODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPBCGSSetPrecType(F2C_CVODE_linsol, *pretype); + break; + case FCMIX_IDA: + if (!F2C_IDA_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPBCGSSetPrecType(F2C_IDA_linsol, *pretype); + break; + case FCMIX_KINSOL: + if (!F2C_KINSOL_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPBCGSSetPrecType(F2C_KINSOL_linsol, *pretype); + break; + case FCMIX_ARKODE: + if (!F2C_ARKODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPBCGSSetPrecType(F2C_ARKODE_linsol, *pretype); + break; + default: + *ier = -1; + } +} + + +void FSUNSPBCGS_SETMAXL(int *code, int *maxl, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (!F2C_CVODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPBCGSSetMaxl(F2C_CVODE_linsol, *maxl); + break; + case FCMIX_IDA: + if (!F2C_IDA_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPBCGSSetMaxl(F2C_IDA_linsol, *maxl); + break; + case FCMIX_KINSOL: + if (!F2C_KINSOL_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPBCGSSetMaxl(F2C_KINSOL_linsol, *maxl); + break; + case FCMIX_ARKODE: + if (!F2C_ARKODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPBCGSSetMaxl(F2C_ARKODE_linsol, *maxl); + break; + default: + *ier = -1; + } +} + + +void FSUNMASSSPBCGS_INIT(int *pretype, int *maxl, int *ier) +{ + *ier = 0; + if (F2C_ARKODE_mass_sol) SUNLinSolFree(F2C_ARKODE_mass_sol); + F2C_ARKODE_mass_sol = NULL; + F2C_ARKODE_mass_sol = SUNLinSol_SPBCGS(F2C_ARKODE_vec, *pretype, *maxl); + if (F2C_ARKODE_mass_sol == NULL) *ier = -1; +} + + +void FSUNMASSSPBCGS_SETPRECTYPE(int *pretype, int *ier) +{ + *ier = 0; + if (!F2C_ARKODE_mass_sol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPBCGSSetPrecType(F2C_ARKODE_mass_sol, *pretype); +} + + +void FSUNMASSSPBCGS_SETMAXL(int *maxl, int *ier) +{ + *ier = 0; + if (!F2C_ARKODE_mass_sol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPBCGSSetMaxl(F2C_ARKODE_mass_sol, *maxl); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spbcgs/fsunlinsol_spbcgs.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spbcgs/fsunlinsol_spbcgs.h new file mode 100644 index 0000000..4cd668b --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spbcgs/fsunlinsol_spbcgs.h @@ -0,0 +1,80 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunlinsol_spbcgs.c) contains the + * definitions needed for the initialization of SPBCGS + * linear solver operations in Fortran. + * ----------------------------------------------------------------- + */ + +#ifndef _FSUNLINSOL_SPBCGS_H +#define _FSUNLINSOL_SPBCGS_H + +#include <sunlinsol/sunlinsol_spbcgs.h> +#include <sundials/sundials_fnvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +#if defined(SUNDIALS_F77_FUNC) +#define FSUNSPBCGS_INIT SUNDIALS_F77_FUNC(fsunspbcgsinit, FSUNSPBCGSINIT) +#define FSUNSPBCGS_SETPRECTYPE SUNDIALS_F77_FUNC(fsunspbcgssetprectype, FSUNSPBCGSSETPRECTYPE) +#define FSUNSPBCGS_SETMAXL SUNDIALS_F77_FUNC(fsunspbcgssetmaxl, FSUNSPBCGSSETMAXL) +#define FSUNMASSSPBCGS_INIT SUNDIALS_F77_FUNC(fsunmassspbcgsinit, FSUNMASSSPBCGSINIT) +#define FSUNMASSSPBCGS_SETPRECTYPE SUNDIALS_F77_FUNC(fsunmassspbcgssetprectype, FSUNMASSSPBCGSSETPRECTYPE) +#define FSUNMASSSPBCGS_SETMAXL SUNDIALS_F77_FUNC(fsunmassspbcgssetmaxl, FSUNMASSSPBCGSSETMAXL) +#else +#define FSUNSPBCGS_INIT fsunspbcgsinit_ +#define FSUNSPBCGS_SETPRECTYPE fsunspbcgssetprectype_ +#define FSUNSPBCGS_SETMAXL fsunspbcgssetmaxl_ +#define FSUNMASSSPBCGS_INIT fsunmassspbcgsinit_ +#define FSUNMASSSPBCGS_SETPRECTYPE fsunmassspbcgssetprectype_ +#define FSUNMASSSPBCGS_SETMAXL fsunmassspbcgssetmaxl_ +#endif + + +/* Declarations of global variables */ + +extern SUNLinearSolver F2C_CVODE_linsol; +extern SUNLinearSolver F2C_IDA_linsol; +extern SUNLinearSolver F2C_KINSOL_linsol; +extern SUNLinearSolver F2C_ARKODE_linsol; +extern SUNLinearSolver F2C_ARKODE_mass_sol; + +/* + * Prototypes of exported functions + * + * FSUNSPBCGS_INIT - initializes SPBCGS linear solver for main problem + * FSUNSPBCGS_SETPRECTYPE - sets the preconditioning type for main problem + * FSUNSPBCGS_SETMAXL - sets the max number of iterations for main problem + * + * FSUNMASSSPBCGS_INIT - initializes SPBCGS linear solver for mass matrix solve + * FSUNMASSSPBCGS_SETPRECTYPE - sets the preconditioning type for mass matrix solve + * FSUNMASSSPBCGS_SETMAXL - sets the max number of iterations for mass matrix solve + */ + +void FSUNSPBCGS_INIT(int *code, int *pretype, int *maxl, int *ier); +void FSUNSPBCGS_SETPRECTYPE(int *code, int *pretype, int *ier); +void FSUNSPBCGS_SETMAXL(int *code, int *maxl, int *ier); + +void FSUNMASSSPBCGS_INIT(int *pretype, int *maxl, int *ier); +void FSUNMASSSPBCGS_SETPRECTYPE(int *pretype, int *ier); +void FSUNMASSSPBCGS_SETMAXL(int *maxl, int *ier); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spbcgs/sunlinsol_spbcgs.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spbcgs/sunlinsol_spbcgs.c new file mode 100644 index 0000000..d6eb329 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spbcgs/sunlinsol_spbcgs.c @@ -0,0 +1,649 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * 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 + * 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 SPBCGS implementation of + * the SUNLINSOL package. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <sunlinsol/sunlinsol_spbcgs.h> +#include <sundials/sundials_math.h> + +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + +/* + * ----------------------------------------------------------------- + * SPBCGS solver structure accessibility macros: + * ----------------------------------------------------------------- + */ + +#define SPBCGS_CONTENT(S) ( (SUNLinearSolverContent_SPBCGS)(S->content) ) +#define PRETYPE(S) ( SPBCGS_CONTENT(S)->pretype ) +#define LASTFLAG(S) ( SPBCGS_CONTENT(S)->last_flag ) + +/* + * ----------------------------------------------------------------- + * deprecated wrapper functions + * ----------------------------------------------------------------- + */ + +SUNLinearSolver SUNSPBCGS(N_Vector y, int pretype, int maxl) +{ return(SUNLinSol_SPBCGS(y, pretype, maxl)); } + +int SUNSPBCGSSetPrecType(SUNLinearSolver S, int pretype) +{ return(SUNLinSol_SPBCGSSetPrecType(S, pretype)); } + +int SUNSPBCGSSetMaxl(SUNLinearSolver S, int maxl) +{ return(SUNLinSol_SPBCGSSetMaxl(S, maxl)); } + +/* + * ----------------------------------------------------------------- + * exported functions + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------------------- + * Function to create a new SPBCGS linear solver + */ + +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)) + pretype = PREC_NONE; + if (maxl <= 0) + maxl = SUNSPBCGS_MAXL_DEFAULT; + + /* check that the supplied N_Vector supports all requisite operations */ + if ( (y->ops->nvclone == NULL) || (y->ops->nvdestroy == NULL) || + (y->ops->nvlinearsum == NULL) || (y->ops->nvprod == NULL) || + (y->ops->nvdiv == NULL) || (y->ops->nvscale == NULL) || + (y->ops->nvdotprod == NULL) ) + return(NULL); + + /* Create linear solver */ + S = NULL; + S = (SUNLinearSolver) malloc(sizeof *S); + 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; + + /* Create content */ + content = NULL; + content = (SUNLinearSolverContent_SPBCGS) malloc(sizeof(struct _SUNLinearSolverContent_SPBCGS)); + if (content == NULL) { free(ops); free(S); return(NULL); } + + /* Fill content */ + content->last_flag = 0; + content->maxl = maxl; + content->pretype = pretype; + content->numiters = 0; + content->resnorm = ZERO; + content->r_star = N_VClone(y); + if (content->r_star == NULL) return(NULL); + content->r = N_VClone(y); + if (content->r == NULL) return(NULL); + content->p = N_VClone(y); + if (content->p == NULL) return(NULL); + content->q = N_VClone(y); + if (content->q == NULL) return(NULL); + content->u = N_VClone(y); + if (content->u == NULL) return(NULL); + content->Ap = N_VClone(y); + if (content->Ap == NULL) 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; + + return(S); +} + + +/* ---------------------------------------------------------------------------- + * Function to set the type of preconditioning for SPBCGS to use + */ + +SUNDIALS_EXPORT int SUNLinSol_SPBCGSSetPrecType(SUNLinearSolver S, int pretype) +{ + /* Check for legal pretype */ + if ((pretype != PREC_NONE) && (pretype != PREC_LEFT) && + (pretype != PREC_RIGHT) && (pretype != PREC_BOTH)) { + return(SUNLS_ILL_INPUT); + } + + /* Check for non-NULL SUNLinearSolver */ + if (S == NULL) return(SUNLS_MEM_NULL); + + /* Set pretype */ + PRETYPE(S) = pretype; + return(SUNLS_SUCCESS); +} + + +/* ---------------------------------------------------------------------------- + * Function to set the maximum number of iterations for SPBCGS to use + */ + +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 */ + if (maxl <= 0) + maxl = SUNSPBCGS_MAXL_DEFAULT; + + /* Set pretype */ + SPBCGS_CONTENT(S)->maxl = maxl; + return(SUNLS_SUCCESS); +} + + +/* + * ----------------------------------------------------------------- + * implementation of linear solver operations + * ----------------------------------------------------------------- + */ + +SUNLinearSolver_Type SUNLinSolGetType_SPBCGS(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_ITERATIVE); +} + + +int SUNLinSolInitialize_SPBCGS(SUNLinearSolver S) +{ + /* ensure valid options */ + 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) + 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, + ATimesFn ATimes) +{ + /* set function pointers to integrator-supplied ATimes routine + and data, and return with success */ + if (S == NULL) return(SUNLS_MEM_NULL); + SPBCGS_CONTENT(S)->ATimes = ATimes; + SPBCGS_CONTENT(S)->ATData = ATData; + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +int SUNLinSolSetPreconditioner_SPBCGS(SUNLinearSolver S, void* PData, + PSetupFn Psetup, PSolveFn Psolve) +{ + /* set function pointers to integrator-supplied Psetup and PSolve + routines and data, and return with success */ + if (S == NULL) return(SUNLS_MEM_NULL); + SPBCGS_CONTENT(S)->Psetup = Psetup; + SPBCGS_CONTENT(S)->Psolve = Psolve; + SPBCGS_CONTENT(S)->PData = PData; + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +int SUNLinSolSetScalingVectors_SPBCGS(SUNLinearSolver S, N_Vector s1, + N_Vector s2) +{ + /* 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; + SPBCGS_CONTENT(S)->s2 = s2; + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +int SUNLinSolSetup_SPBCGS(SUNLinearSolver S, SUNMatrix A) +{ + int ier; + PSetupFn Psetup; + void* PData; + + /* Set shortcuts to SPBCGS memory structures */ + 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 + Psetup routine exists, call that here */ + if (Psetup != NULL) { + ier = Psetup(PData); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSET_FAIL_UNREC : SUNLS_PSET_FAIL_REC; + return(LASTFLAG(S)); + } + } + + /* return with success */ + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +int SUNLinSolSolve_SPBCGS(SUNLinearSolver S, SUNMatrix A, N_Vector x, + N_Vector b, realtype delta) +{ + /* local data and shortcut variables */ + 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; + void *A_data, *P_data; + N_Vector sx, sb; + ATimesFn atimes; + PSolveFn psolve; + realtype *res_norm; + int *nli; + + /* 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; + r_star = SPBCGS_CONTENT(S)->r_star; + r = SPBCGS_CONTENT(S)->r; + p = SPBCGS_CONTENT(S)->p; + q = SPBCGS_CONTENT(S)->q; + u = SPBCGS_CONTENT(S)->u; + Ap = SPBCGS_CONTENT(S)->Ap; + vtemp = SPBCGS_CONTENT(S)->vtemp; + sb = SPBCGS_CONTENT(S)->s1; + sx = SPBCGS_CONTENT(S)->s2; + A_data = SPBCGS_CONTENT(S)->ATData; + P_data = SPBCGS_CONTENT(S)->PData; + atimes = SPBCGS_CONTENT(S)->ATimes; + psolve = SPBCGS_CONTENT(S)->Psolve; + nli = &(SPBCGS_CONTENT(S)->numiters); + res_norm = &(SPBCGS_CONTENT(S)->resnorm); + + /* Initialize counters and convergence flag */ + *nli = 0; + converged = SUNFALSE; + + /* set booleantype flags for internal solver options */ + preOnLeft = ( (PRETYPE(S) == PREC_LEFT) || + (PRETYPE(S) == PREC_BOTH) ); + preOnRight = ( (PRETYPE(S) == PREC_RIGHT) || + (PRETYPE(S) == PREC_BOTH) ); + 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) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_ATIMES_FAIL_UNREC : SUNLS_ATIMES_FAIL_REC; + return(LASTFLAG(S)); + } + 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); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; + return(LASTFLAG(S)); + } + } + 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) { + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); + } + + /* 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); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; + return(LASTFLAG(S)); + } + } + + /* Apply A: Ap = A P2_inv sx_inv p */ + + ier = atimes(A_data, vtemp, Ap ); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_ATIMES_FAIL_UNREC : SUNLS_ATIMES_FAIL_REC; + return(LASTFLAG(S)); + } + + /* Apply left preconditioner: vtemp = P1_inv A P2_inv sx_inv p */ + + if (preOnLeft) { + ier = psolve(P_data, Ap, vtemp, delta, PREC_LEFT); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; + return(LASTFLAG(S)); + } + } + 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 = <r,r_star>/<Ap,r_star> */ + + 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); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; + return(LASTFLAG(S)); + } + } + + /* Apply A: u = A P2_inv sx_inv u */ + + ier = atimes(A_data, vtemp, u ); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_ATIMES_FAIL_UNREC : SUNLS_ATIMES_FAIL_REC; + return(LASTFLAG(S)); + } + + /* Apply left preconditioner: vtemp = P1_inv A P2_inv sx_inv p */ + + if (preOnLeft) { + ier = psolve(P_data, u, vtemp, delta, PREC_LEFT); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; + return(LASTFLAG(S)); + } + } + 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 = <u,q>/<u,u> */ + + 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 */ + cv[0] = ONE; + Xv[0] = x; + + cv[1] = alpha; + Xv[1] = p; + + cv[2] = omega; + Xv[2] = q; + + ier = N_VLinearCombination(3, cv, Xv, x); + if (ier != SUNLS_SUCCESS) return(SUNLS_VECTOROP_ERR); + + /* 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 = <rnew,r_star> / <rold,r_start> * alpha / omega */ + + beta_num = N_VDotProd(r, r_star); + beta = ((beta_num / beta_denom) * (alpha / omega)); + + /* Update p = r + beta*(p - omega*Ap) = beta*p - beta*omega*Ap + r */ + cv[0] = beta; + Xv[0] = p; + + cv[1] = -alpha*(beta_num / beta_denom); + Xv[1] = Ap; + + cv[2] = ONE; + Xv[2] = r; + + ier = N_VLinearCombination(3, cv, Xv, p); + if (ier != SUNLS_SUCCESS) return(SUNLS_VECTOROP_ERR); + + /* udpate beta_denom for next iteration */ + beta_denom = beta_num; + } + + /* 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); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; + return(LASTFLAG(S)); + } + N_VScale(ONE, vtemp, x); + } + + if (converged == SUNTRUE) + LASTFLAG(S) = SUNLS_SUCCESS; + else + LASTFLAG(S) = SUNLS_RES_REDUCED; + return(LASTFLAG(S)); + + } + else { + LASTFLAG(S) = SUNLS_CONV_FAIL; + return(LASTFLAG(S)); + } +} + + +int SUNLinSolNumIters_SPBCGS(SUNLinearSolver S) +{ + /* return the stored 'numiters' value */ + if (S == NULL) return(-1); + return (SPBCGS_CONTENT(S)->numiters); +} + + +realtype SUNLinSolResNorm_SPBCGS(SUNLinearSolver S) +{ + /* return the stored 'resnorm' value */ + if (S == NULL) return(-ONE); + return (SPBCGS_CONTENT(S)->resnorm); +} + + +N_Vector SUNLinSolResid_SPBCGS(SUNLinearSolver S) +{ + /* return the stored 'r' vector */ + return (SPBCGS_CONTENT(S)->r); +} + + +long int SUNLinSolLastFlag_SPBCGS(SUNLinearSolver S) +{ + /* return the stored 'last_flag' value */ + if (S == NULL) return(-1); + return (LASTFLAG(S)); +} + + +int SUNLinSolSpace_SPBCGS(SUNLinearSolver S, + long int *lenrwLS, + long int *leniwLS) +{ + sunindextype liw1, lrw1; + if (SPBCGS_CONTENT(S)->vtemp->ops->nvspace) + N_VSpace(SPBCGS_CONTENT(S)->vtemp, &lrw1, &liw1); + else + lrw1 = liw1 = 0; + *lenrwLS = lrw1*9; + *leniwLS = liw1*9; + return(SUNLS_SUCCESS); +} + + +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; + free(S); S = NULL; + return(SUNLS_SUCCESS); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spfgmr/fsunlinsol_spfgmr.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spfgmr/fsunlinsol_spfgmr.c new file mode 100644 index 0000000..add542f --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spfgmr/fsunlinsol_spfgmr.c @@ -0,0 +1,241 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunlinsol_spfgmr.h) contains the + * implementation needed for the Fortran initialization of SPFGMR + * linear solver operations. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fsunlinsol_spfgmr.h" + +/* Define global linsol variables */ + +SUNLinearSolver F2C_CVODE_linsol; +SUNLinearSolver F2C_IDA_linsol; +SUNLinearSolver F2C_KINSOL_linsol; +SUNLinearSolver F2C_ARKODE_linsol; +SUNLinearSolver F2C_ARKODE_mass_sol; + +/* Declarations of external global variables */ + +extern SUNMatrix F2C_CVODE_matrix; +extern SUNMatrix F2C_IDA_matrix; +extern SUNMatrix F2C_KINSOL_matrix; +extern SUNMatrix F2C_ARKODE_matrix; +extern SUNMatrix F2C_ARKODE_mass_matrix; + +extern N_Vector F2C_CVODE_vec; +extern N_Vector F2C_IDA_vec; +extern N_Vector F2C_KINSOL_vec; +extern N_Vector F2C_ARKODE_vec; + +/* Fortran callable interfaces */ + +void FSUNSPFGMR_INIT(int *code, int *pretype, int *maxl, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (F2C_CVODE_linsol) SUNLinSolFree(F2C_CVODE_linsol); + F2C_CVODE_linsol = NULL; + F2C_CVODE_linsol = SUNLinSol_SPFGMR(F2C_CVODE_vec, *pretype, *maxl); + if (F2C_CVODE_linsol == NULL) *ier = -1; + break; + case FCMIX_IDA: + if (F2C_IDA_linsol) SUNLinSolFree(F2C_IDA_linsol); + F2C_IDA_linsol = NULL; + F2C_IDA_linsol = SUNLinSol_SPFGMR(F2C_IDA_vec, *pretype, *maxl); + if (F2C_IDA_linsol == NULL) *ier = -1; + break; + case FCMIX_KINSOL: + if (F2C_KINSOL_linsol) SUNLinSolFree(F2C_KINSOL_linsol); + F2C_KINSOL_linsol = NULL; + F2C_KINSOL_linsol = SUNLinSol_SPFGMR(F2C_KINSOL_vec, *pretype, *maxl); + if (F2C_KINSOL_linsol == NULL) *ier = -1; + break; + case FCMIX_ARKODE: + if (F2C_ARKODE_linsol) SUNLinSolFree(F2C_ARKODE_linsol); + F2C_ARKODE_linsol = NULL; + F2C_ARKODE_linsol = SUNLinSol_SPFGMR(F2C_ARKODE_vec, *pretype, *maxl); + if (F2C_ARKODE_linsol == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + + +void FSUNSPFGMR_SETGSTYPE(int *code, int *gstype, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (!F2C_CVODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPFGMRSetGSType(F2C_CVODE_linsol, *gstype); + break; + case FCMIX_IDA: + if (!F2C_IDA_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPFGMRSetGSType(F2C_IDA_linsol, *gstype); + break; + case FCMIX_KINSOL: + if (!F2C_KINSOL_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPFGMRSetGSType(F2C_KINSOL_linsol, *gstype); + break; + case FCMIX_ARKODE: + if (!F2C_ARKODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPFGMRSetGSType(F2C_ARKODE_linsol, *gstype); + break; + default: + *ier = -1; + } +} + + +void FSUNSPFGMR_SETPRECTYPE(int *code, int *pretype, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (!F2C_CVODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPFGMRSetPrecType(F2C_CVODE_linsol, *pretype); + break; + case FCMIX_IDA: + if (!F2C_IDA_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPFGMRSetPrecType(F2C_IDA_linsol, *pretype); + break; + case FCMIX_KINSOL: + if (!F2C_KINSOL_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPFGMRSetPrecType(F2C_KINSOL_linsol, *pretype); + break; + case FCMIX_ARKODE: + if (!F2C_ARKODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPFGMRSetPrecType(F2C_ARKODE_linsol, *pretype); + break; + default: + *ier = -1; + } +} + + +void FSUNSPFGMR_SETMAXRS(int *code, int *maxrs, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (!F2C_CVODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPFGMRSetMaxRestarts(F2C_CVODE_linsol, *maxrs); + break; + case FCMIX_IDA: + if (!F2C_IDA_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPFGMRSetMaxRestarts(F2C_IDA_linsol, *maxrs); + break; + case FCMIX_KINSOL: + if (!F2C_KINSOL_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPFGMRSetMaxRestarts(F2C_KINSOL_linsol, *maxrs); + break; + case FCMIX_ARKODE: + if (!F2C_ARKODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPFGMRSetMaxRestarts(F2C_ARKODE_linsol, *maxrs); + break; + default: + *ier = -1; + } +} + + +void FSUNMASSSPFGMR_INIT(int *pretype, int *maxl, int *ier) +{ + *ier = 0; + if (F2C_ARKODE_mass_sol) SUNLinSolFree(F2C_ARKODE_mass_sol); + F2C_ARKODE_mass_sol = NULL; + F2C_ARKODE_mass_sol = SUNLinSol_SPFGMR(F2C_ARKODE_vec, *pretype, *maxl); + if (F2C_ARKODE_mass_sol == NULL) *ier = -1; +} + + +void FSUNMASSSPFGMR_SETGSTYPE(int *gstype, int *ier) +{ + *ier = 0; + if (!F2C_ARKODE_mass_sol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPFGMRSetGSType(F2C_ARKODE_mass_sol, *gstype); +} + + +void FSUNMASSSPFGMR_SETPRECTYPE(int *pretype, int *ier) +{ + *ier = 0; + if (!F2C_ARKODE_mass_sol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPFGMRSetPrecType(F2C_ARKODE_mass_sol, *pretype); +} + + +void FSUNMASSSPFGMR_SETMAXRS(int *maxrs, int *ier) +{ + *ier = 0; + if (!F2C_ARKODE_mass_sol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPFGMRSetMaxRestarts(F2C_ARKODE_mass_sol, *maxrs); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spfgmr/fsunlinsol_spfgmr.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spfgmr/fsunlinsol_spfgmr.h new file mode 100644 index 0000000..e5b25f2 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spfgmr/fsunlinsol_spfgmr.h @@ -0,0 +1,88 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunlinsol_spfgmr.c) contains the + * definitions needed for the initialization of SPFGMR + * linear solver operations in Fortran. + * ----------------------------------------------------------------- + */ + +#ifndef _FSUNLINSOL_SPFGMR_H +#define _FSUNLINSOL_SPFGMR_H + +#include <sunlinsol/sunlinsol_spfgmr.h> +#include <sundials/sundials_fnvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +#if defined(SUNDIALS_F77_FUNC) +#define FSUNSPFGMR_INIT SUNDIALS_F77_FUNC(fsunspfgmrinit, FSUNSPFGMRINIT) +#define FSUNSPFGMR_SETGSTYPE SUNDIALS_F77_FUNC(fsunspfgmrsetgstype, FSUNSPFGMRSETGSTYPE) +#define FSUNSPFGMR_SETPRECTYPE SUNDIALS_F77_FUNC(fsunspfgmrsetprectype, FSUNSPFGMRSETPRECTYPE) +#define FSUNSPFGMR_SETMAXRS SUNDIALS_F77_FUNC(fsunspfgmrsetmaxrs, FSUNSPFGMRSETMAXRS) +#define FSUNMASSSPFGMR_INIT SUNDIALS_F77_FUNC(fsunmassspfgmrinit, FSUNMASSSPFGMRINIT) +#define FSUNMASSSPFGMR_SETGSTYPE SUNDIALS_F77_FUNC(fsunmassspfgmrsetgstype, FSUNMASSSPFGMRSETGSTYPE) +#define FSUNMASSSPFGMR_SETPRECTYPE SUNDIALS_F77_FUNC(fsunmassspfgmrsetprectype, FSUNMASSSPFGMRSETPRECTYPE) +#define FSUNMASSSPFGMR_SETMAXRS SUNDIALS_F77_FUNC(fsunmassspfgmrsetmaxrs, FSUNMASSSPFGMRSETMAXRS) +#else +#define FSUNSPFGMR_INIT fsunspfgmrinit_ +#define FSUNSPFGMR_SETGSTYPE fsunspfgmrsetgstype_ +#define FSUNSPFGMR_SETPRECTYPE fsunspfgmrsetprectype_ +#define FSUNSPFGMR_SETMAXRS fsunspfgmrsetmaxrs_ +#define FSUNMASSSPFGMR_INIT fsunmassspfgmrinit_ +#define FSUNMASSSPFGMR_SETGSTYPE fsunmassspfgmrsetgstype_ +#define FSUNMASSSPFGMR_SETPRECTYPE fsunmassspfgmrsetprectype_ +#define FSUNMASSSPFGMR_SETMAXRS fsunmassspfgmrsetmaxrs_ +#endif + + +/* Declarations of global variables */ + +extern SUNLinearSolver F2C_CVODE_linsol; +extern SUNLinearSolver F2C_IDA_linsol; +extern SUNLinearSolver F2C_KINSOL_linsol; +extern SUNLinearSolver F2C_ARKODE_linsol; +extern SUNLinearSolver F2C_ARKODE_mass_sol; + +/* + * Prototypes of exported functions + * + * FSUNSPFGMR_INIT - initializes SPFGMR linear solver for main problem + * FSUNSPFGMR_SETGSTYPE - sets the Gram-Scmidt orthogonalization type for main problem + * FSUNSPFGMR_SETPRECTYPE - sets the preconditioning type for main problem + * FSUNSPFGMR_SETMAXRS - sets the maximum number of restarts to allow for main problem + * + * FSUNMASSSPFGMR_INIT - initializes SPFGMR linear solver for mass matrix solve + * FSUNMASSSPFGMR_SETGSTYPE - sets the Gram-Scmidt orthogonalization type for mass matrix solve + * FSUNMASSSPFGMR_SETPRECTYPE - sets the preconditioning type for mass matrix solve + * FSUNMASSSPFGMR_SETMAXRS - sets the maximum number of restarts to allow for mass matrix solve + */ + +void FSUNSPFGMR_INIT(int *code, int *pretype, int *maxl, int *ier); +void FSUNSPFGMR_SETGSTYPE(int *code, int *gstype, int *ier); +void FSUNSPFGMR_SETPRECTYPE(int *code, int *pretype, int *ier); +void FSUNSPFGMR_SETMAXRS(int *code, int *maxrs, int *ier); + +void FSUNMASSSPFGMR_INIT(int *pretype, int *maxl, int *ier); +void FSUNMASSSPFGMR_SETGSTYPE(int *gstype, int *ier); +void FSUNMASSSPFGMR_SETPRECTYPE(int *pretype, int *ier); +void FSUNMASSSPFGMR_SETMAXRS(int *maxrs, int *ier); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spfgmr/sunlinsol_spfgmr.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spfgmr/sunlinsol_spfgmr.c new file mode 100644 index 0000000..51da6eb --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spfgmr/sunlinsol_spfgmr.c @@ -0,0 +1,719 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * 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 + * 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 SPFGMR implementation of + * the SUNLINSOL package. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <sunlinsol/sunlinsol_spfgmr.h> +#include <sundials/sundials_math.h> + +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + +/* + * ----------------------------------------------------------------- + * SPFGMR solver structure accessibility macros: + * ----------------------------------------------------------------- + */ + +#define SPFGMR_CONTENT(S) ( (SUNLinearSolverContent_SPFGMR)(S->content) ) +#define LASTFLAG(S) ( SPFGMR_CONTENT(S)->last_flag ) + +/* + * ----------------------------------------------------------------- + * deprecated wrapper functions + * ----------------------------------------------------------------- + */ + +SUNLinearSolver SUNSPFGMR(N_Vector y, int pretype, int maxl) +{ return(SUNLinSol_SPFGMR(y, pretype, maxl)); } + +int SUNSPFGMRSetPrecType(SUNLinearSolver S, int pretype) +{ return(SUNLinSol_SPFGMRSetPrecType(S, pretype)); } + +int SUNSPFGMRSetGSType(SUNLinearSolver S, int gstype) +{ return(SUNLinSol_SPFGMRSetGSType(S, gstype)); } + +int SUNSPFGMRSetMaxRestarts(SUNLinearSolver S, int maxrs) +{ return(SUNLinSol_SPFGMRSetMaxRestarts(S, maxrs)); } + +/* + * ----------------------------------------------------------------- + * exported functions + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------------------- + * Function to create a new SPFGMR linear solver + */ + +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 + preconditioning, since SPFGMR does not support left preconditioning) */ + pretype = ( (pretype == PREC_LEFT) || + (pretype == PREC_RIGHT) || + (pretype == PREC_BOTH) ) ? PREC_RIGHT : PREC_NONE; + + /* if maxl input is illegal, set to default */ + if (maxl <= 0) maxl = SUNSPFGMR_MAXL_DEFAULT; + + /* check that the supplied N_Vector supports all requisite operations */ + if ( (y->ops->nvclone == NULL) || (y->ops->nvdestroy == NULL) || + (y->ops->nvlinearsum == NULL) || (y->ops->nvconst == NULL) || + (y->ops->nvprod == NULL) || (y->ops->nvdiv == NULL) || + (y->ops->nvscale == NULL) || (y->ops->nvdotprod == NULL) ) + return(NULL); + + /* Create linear solver */ + S = NULL; + S = (SUNLinearSolver) malloc(sizeof *S); + 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; + + /* Create content */ + content = NULL; + content = (SUNLinearSolverContent_SPFGMR) malloc(sizeof(struct _SUNLinearSolverContent_SPFGMR)); + if (content == NULL) { free(ops); free(S); return(NULL); } + + /* Fill content */ + 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->xcor = N_VClone(y); + if (content->xcor == NULL) 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; + + return(S); +} + + +/* ---------------------------------------------------------------------------- + * 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) +{ + /* Check for legal pretype */ + pretype = ( (pretype == PREC_LEFT) || + (pretype == PREC_RIGHT) || + (pretype == PREC_BOTH) ) ? PREC_RIGHT : PREC_NONE; + + /* Check for non-NULL SUNLinearSolver */ + if (S == NULL) return(SUNLS_MEM_NULL); + + /* Set pretype */ + SPFGMR_CONTENT(S)->pretype = pretype; + return(SUNLS_SUCCESS); +} + + +/* ---------------------------------------------------------------------------- + * Function to set the type of Gram-Schmidt orthogonalization for SPFGMR to use + */ + +SUNDIALS_EXPORT int SUNLinSol_SPFGMRSetGSType(SUNLinearSolver S, int gstype) +{ + /* Check for legal gstype */ + if ((gstype != MODIFIED_GS) && (gstype != CLASSICAL_GS)) { + return(SUNLS_ILL_INPUT); + } + + /* Check for non-NULL SUNLinearSolver */ + if (S == NULL) return(SUNLS_MEM_NULL); + + /* Set pretype */ + SPFGMR_CONTENT(S)->gstype = gstype; + return(SUNLS_SUCCESS); +} + + +/* ---------------------------------------------------------------------------- + * Function to set the maximum number of FGMRES restarts to allow + */ + +SUNDIALS_EXPORT int SUNLinSol_SPFGMRSetMaxRestarts(SUNLinearSolver S, int maxrs) +{ + /* Illegal maxrs implies use of default value */ + if (maxrs < 0) + maxrs = SUNSPFGMR_MAXRS_DEFAULT; + + /* Check for non-NULL SUNLinearSolver */ + if (S == NULL) return(SUNLS_MEM_NULL); + + /* Set max_restarts */ + SPFGMR_CONTENT(S)->max_restarts = maxrs; + return(SUNLS_SUCCESS); +} + + +/* + * ----------------------------------------------------------------- + * implementation of linear solver operations + * ----------------------------------------------------------------- + */ + +SUNLinearSolver_Type SUNLinSolGetType_SPFGMR(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_ITERATIVE); +} + + +int SUNLinSolInitialize_SPFGMR(SUNLinearSolver S) +{ + int k; + SUNLinearSolverContent_SPFGMR content; + + /* set shortcut to SPFGMR memory structure */ + if (S == NULL) return(SUNLS_MEM_NULL); + content = SPFGMR_CONTENT(S); + + /* ensure valid options */ + if (content->max_restarts < 0) + content->max_restarts = SUNSPFGMR_MAXRS_DEFAULT; + if ( (content->pretype != PREC_LEFT) && + (content->pretype != PREC_RIGHT) && + (content->pretype != PREC_BOTH) ) + content->pretype = PREC_NONE; + + + /* allocate solver-specific memory (where the size depends on the + choice of maxl) here */ + + /* Krylov subspace vectors */ + if (content->V == NULL) { + content->V = N_VCloneVectorArray(content->maxl+1, content->vtemp); + if (content->V == NULL) { + SUNLinSolFree(S); + content->last_flag = SUNLS_MEM_FAIL; + return(SUNLS_MEM_FAIL); + } + } + + /* Preconditioned basis vectors */ + if (content->Z == NULL) { + content->Z = N_VCloneVectorArray(content->maxl+1, content->vtemp); + if (content->Z == NULL) { + SUNLinSolFree(S); + content->last_flag = SUNLS_MEM_FAIL; + return(SUNLS_MEM_FAIL); + } + } + + /* Hessenberg matrix Hes */ + if (content->Hes == NULL) { + content->Hes = (realtype **) malloc((content->maxl+1)*sizeof(realtype *)); + if (content->Hes == NULL) { + SUNLinSolFree(S); + content->last_flag = SUNLS_MEM_FAIL; + return(SUNLS_MEM_FAIL); + } + + for (k=0; k<=content->maxl; k++) { + content->Hes[k] = NULL; + content->Hes[k] = (realtype *) malloc(content->maxl*sizeof(realtype)); + if (content->Hes[k] == NULL) { + SUNLinSolFree(S); + content->last_flag = SUNLS_MEM_FAIL; + return(SUNLS_MEM_FAIL); + } + } + } + + /* Givens rotation components */ + if (content->givens == NULL) { + content->givens = (realtype *) malloc(2*content->maxl*sizeof(realtype)); + if (content->givens == NULL) { + SUNLinSolFree(S); + content->last_flag = SUNLS_MEM_FAIL; + return(SUNLS_MEM_FAIL); + } + } + + /* y and g vectors */ + if (content->yg == NULL) { + content->yg = (realtype *) malloc((content->maxl+1)*sizeof(realtype)); + if (content->yg == NULL) { + SUNLinSolFree(S); + content->last_flag = SUNLS_MEM_FAIL; + return(SUNLS_MEM_FAIL); + } + } + + /* cv vector for fused vector ops */ + if (content->cv == NULL) { + content->cv = (realtype *) malloc((content->maxl+1)*sizeof(realtype)); + if (content->cv == NULL) { + SUNLinSolFree(S); + content->last_flag = SUNLS_MEM_FAIL; + return(SUNLS_MEM_FAIL); + } + } + + /* 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) { + SUNLinSolFree(S); + content->last_flag = SUNLS_MEM_FAIL; + return(SUNLS_MEM_FAIL); + } + } + + /* return with success */ + content->last_flag = SUNLS_SUCCESS; + return(SUNLS_SUCCESS); +} + + +int SUNLinSolSetATimes_SPFGMR(SUNLinearSolver S, void* ATData, + ATimesFn ATimes) +{ + /* 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; + SPFGMR_CONTENT(S)->ATData = ATData; + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +int SUNLinSolSetPreconditioner_SPFGMR(SUNLinearSolver S, void* PData, + PSetupFn Psetup, PSolveFn Psolve) +{ + /* set function pointers to integrator-supplied Psetup and PSolve + routines and data, and return with success */ + if (S == NULL) return(SUNLS_MEM_NULL); + SPFGMR_CONTENT(S)->Psetup = Psetup; + SPFGMR_CONTENT(S)->Psolve = Psolve; + SPFGMR_CONTENT(S)->PData = PData; + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +int SUNLinSolSetScalingVectors_SPFGMR(SUNLinearSolver S, N_Vector s1, + N_Vector s2) +{ + /* 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; + SPFGMR_CONTENT(S)->s2 = s2; + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +int SUNLinSolSetup_SPFGMR(SUNLinearSolver S, SUNMatrix A) +{ + int ier; + PSetupFn Psetup; + void* PData; + + /* Set shortcuts to SPFGMR memory structures */ + 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 + Psetup routine exists, call that here */ + if (Psetup != NULL) { + ier = Psetup(PData); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSET_FAIL_UNREC : SUNLS_PSET_FAIL_REC; + return(LASTFLAG(S)); + } + } + + /* return with success */ + return(SUNLS_SUCCESS); +} + + +int SUNLinSolSolve_SPFGMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, + N_Vector b, realtype delta) +{ + /* local data and shortcut variables */ + N_Vector *V, *Z, xcor, vtemp, s1, s2; + realtype **Hes, *givens, *yg, *res_norm; + realtype beta, rotation_product, r_norm, s_product, rho; + booleantype preOnRight, scale1, scale2, converged; + int i, j, k, l, l_max, krydim, ier, ntries, max_restarts, gstype; + int *nli; + void *A_data, *P_data; + ATimesFn atimes; + PSolveFn psolve; + + /* local shortcuts for fused vector operations */ + realtype* cv; + N_Vector* Xv; + + /* Initialize some variables */ + krydim = 0; + + /* Make local shorcuts to solver variables. */ + if (S == NULL) return(SUNLS_MEM_NULL); + l_max = SPFGMR_CONTENT(S)->maxl; + max_restarts = SPFGMR_CONTENT(S)->max_restarts; + gstype = SPFGMR_CONTENT(S)->gstype; + V = SPFGMR_CONTENT(S)->V; + Z = SPFGMR_CONTENT(S)->Z; + Hes = SPFGMR_CONTENT(S)->Hes; + givens = SPFGMR_CONTENT(S)->givens; + xcor = SPFGMR_CONTENT(S)->xcor; + yg = SPFGMR_CONTENT(S)->yg; + vtemp = SPFGMR_CONTENT(S)->vtemp; + s1 = SPFGMR_CONTENT(S)->s1; + s2 = SPFGMR_CONTENT(S)->s2; + A_data = SPFGMR_CONTENT(S)->ATData; + P_data = SPFGMR_CONTENT(S)->PData; + atimes = SPFGMR_CONTENT(S)->ATimes; + psolve = SPFGMR_CONTENT(S)->Psolve; + nli = &(SPFGMR_CONTENT(S)->numiters); + res_norm = &(SPFGMR_CONTENT(S)->resnorm); + cv = SPFGMR_CONTENT(S)->cv; + Xv = SPFGMR_CONTENT(S)->Xv; + + /* Initialize counters and convergence flag */ + *nli = 0; + converged = SUNFALSE; + + /* 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_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) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_ATIMES_FAIL_UNREC : SUNLS_ATIMES_FAIL_REC; + return(LASTFLAG(S)); + } + 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) { + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); + } + + /* 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 + 1; + + /* Generate A-tilde V[l], where A-tilde = s1 A P_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 = Z[l] = P_inv s2_inv V[l]. */ + if (preOnRight) { + N_VScale(ONE, vtemp, V[l+1]); + ier = psolve(P_data, V[l+1], vtemp, delta, PREC_RIGHT); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; + return(LASTFLAG(S)); + } + } + N_VScale(ONE, vtemp, Z[l]); + + /* Apply A: V[l+1] = A P_inv s2_inv V[l]. */ + ier = atimes(A_data, vtemp, V[l+1]); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_ATIMES_FAIL_UNREC : SUNLS_ATIMES_FAIL_REC; + return(LASTFLAG(S)); + } + + /* Apply left scaling: V[l+1] = s1 A P_inv s2_inv V[l]. */ + if (scale1) N_VProd(s1, V[l+1], V[l+1]); + + /* Orthogonalize V[l+1] against previous V[i]: V[l+1] = w_tilde. */ + if (gstype == CLASSICAL_GS) { + if (ClassicalGS(V, Hes, l+1, l_max, &(Hes[l+1][l]), cv, Xv) != 0) { + LASTFLAG(S) = SUNLS_GS_FAIL; + return(LASTFLAG(S)); + } + } else { + if (ModifiedGS(V, Hes, l+1, l_max, &(Hes[l+1][l])) != 0) { + LASTFLAG(S) = SUNLS_GS_FAIL; + return(LASTFLAG(S)); + } + } + + /* Update the QR factorization of Hes. */ + if(QRfact(krydim, Hes, givens, l) != 0 ) { + LASTFLAG(S) = SUNLS_QRFACT_FAIL; + return(LASTFLAG(S)); + } + + /* 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+1][l], V[l+1], V[l+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) { + LASTFLAG(S) = SUNLS_QRSOL_FAIL; + return(LASTFLAG(S)); + } + + /* Add correction vector Z_l y to xcor. */ + cv[0] = ONE; + Xv[0] = xcor; + + for (k=0; k<krydim; k++) { + cv[k+1] = yg[k]; + Xv[k+1] = Z[k]; + } + ier = N_VLinearCombination(krydim+1, cv, Xv, xcor); + if (ier != SUNLS_SUCCESS) return(SUNLS_VECTOROP_ERR); + + /* If converged, construct the final solution vector x and return. */ + if (converged) { + N_VLinearSum(ONE, x, ONE, xcor, x); { + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); + } + } + + /* 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. */ + for (k=0; k<=krydim; k++) { + cv[k] = yg[k]; + Xv[k] = V[k]; + } + 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) { + N_VLinearSum(ONE, x, ONE, xcor, x); { + LASTFLAG(S) = SUNLS_RES_REDUCED; + return(LASTFLAG(S)); + } + } + + LASTFLAG(S) = SUNLS_CONV_FAIL; + return(LASTFLAG(S)); +} + + +int SUNLinSolNumIters_SPFGMR(SUNLinearSolver S) +{ + /* return the stored 'numiters' value */ + if (S == NULL) return(-1); + return (SPFGMR_CONTENT(S)->numiters); +} + + +realtype SUNLinSolResNorm_SPFGMR(SUNLinearSolver S) +{ + /* return the stored 'resnorm' value */ + if (S == NULL) return(-ONE); + return (SPFGMR_CONTENT(S)->resnorm); +} + + +N_Vector SUNLinSolResid_SPFGMR(SUNLinearSolver S) +{ + /* return the stored 'vtemp' vector */ + return (SPFGMR_CONTENT(S)->vtemp); +} + + +long int SUNLinSolLastFlag_SPFGMR(SUNLinearSolver S) +{ + /* return the stored 'last_flag' value */ + if (S == NULL) return(-1); + return (LASTFLAG(S)); +} + + +int SUNLinSolSpace_SPFGMR(SUNLinearSolver S, + long int *lenrwLS, + long int *leniwLS) +{ + int maxl; + sunindextype liw1, lrw1; + maxl = SPFGMR_CONTENT(S)->maxl; + if (SPFGMR_CONTENT(S)->vtemp->ops->nvspace) + N_VSpace(SPFGMR_CONTENT(S)->vtemp, &lrw1, &liw1); + else + lrw1 = liw1 = 0; + *lenrwLS = lrw1*(2*maxl + 4) + maxl*(maxl + 5) + 2; + *leniwLS = liw1*(2*maxl + 4); + return(SUNLS_SUCCESS); +} + +int SUNLinSolFree_SPFGMR(SUNLinearSolver S) +{ + int k; + + 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 (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; + free(S); S = NULL; + return(SUNLS_SUCCESS); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spgmr/fsunlinsol_spgmr.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spgmr/fsunlinsol_spgmr.c new file mode 100644 index 0000000..5e9c237 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spgmr/fsunlinsol_spgmr.c @@ -0,0 +1,241 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunlinsol_spgmr.h) contains the + * implementation needed for the Fortran initialization of SPGMR + * linear solver operations. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fsunlinsol_spgmr.h" + +/* Define global linsol variables */ + +SUNLinearSolver F2C_CVODE_linsol; +SUNLinearSolver F2C_IDA_linsol; +SUNLinearSolver F2C_KINSOL_linsol; +SUNLinearSolver F2C_ARKODE_linsol; +SUNLinearSolver F2C_ARKODE_mass_sol; + +/* Declarations of external global variables */ + +extern SUNMatrix F2C_CVODE_matrix; +extern SUNMatrix F2C_IDA_matrix; +extern SUNMatrix F2C_KINSOL_matrix; +extern SUNMatrix F2C_ARKODE_matrix; +extern SUNMatrix F2C_ARKODE_mass_matrix; + +extern N_Vector F2C_CVODE_vec; +extern N_Vector F2C_IDA_vec; +extern N_Vector F2C_KINSOL_vec; +extern N_Vector F2C_ARKODE_vec; + +/* Fortran callable interfaces */ + +void FSUNSPGMR_INIT(int *code, int *pretype, int *maxl, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (F2C_CVODE_linsol) SUNLinSolFree(F2C_CVODE_linsol); + F2C_CVODE_linsol = NULL; + F2C_CVODE_linsol = SUNLinSol_SPGMR(F2C_CVODE_vec, *pretype, *maxl); + if (F2C_CVODE_linsol == NULL) *ier = -1; + break; + case FCMIX_IDA: + if (F2C_IDA_linsol) SUNLinSolFree(F2C_IDA_linsol); + F2C_IDA_linsol = NULL; + F2C_IDA_linsol = SUNLinSol_SPGMR(F2C_IDA_vec, *pretype, *maxl); + if (F2C_IDA_linsol == NULL) *ier = -1; + break; + case FCMIX_KINSOL: + if (F2C_KINSOL_linsol) SUNLinSolFree(F2C_KINSOL_linsol); + F2C_KINSOL_linsol = NULL; + F2C_KINSOL_linsol = SUNLinSol_SPGMR(F2C_KINSOL_vec, *pretype, *maxl); + if (F2C_KINSOL_linsol == NULL) *ier = -1; + break; + case FCMIX_ARKODE: + if (F2C_ARKODE_linsol) SUNLinSolFree(F2C_ARKODE_linsol); + F2C_ARKODE_linsol = NULL; + F2C_ARKODE_linsol = SUNLinSol_SPGMR(F2C_ARKODE_vec, *pretype, *maxl); + if (F2C_ARKODE_linsol == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + + +void FSUNSPGMR_SETGSTYPE(int *code, int *gstype, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (!F2C_CVODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPGMRSetGSType(F2C_CVODE_linsol, *gstype); + break; + case FCMIX_IDA: + if (!F2C_IDA_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPGMRSetGSType(F2C_IDA_linsol, *gstype); + break; + case FCMIX_KINSOL: + if (!F2C_KINSOL_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPGMRSetGSType(F2C_KINSOL_linsol, *gstype); + break; + case FCMIX_ARKODE: + if (!F2C_ARKODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPGMRSetGSType(F2C_ARKODE_linsol, *gstype); + break; + default: + *ier = -1; + } +} + + +void FSUNSPGMR_SETPRECTYPE(int *code, int *pretype, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (!F2C_CVODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPGMRSetPrecType(F2C_CVODE_linsol, *pretype); + break; + case FCMIX_IDA: + if (!F2C_IDA_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPGMRSetPrecType(F2C_IDA_linsol, *pretype); + break; + case FCMIX_KINSOL: + if (!F2C_KINSOL_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPGMRSetPrecType(F2C_KINSOL_linsol, *pretype); + break; + case FCMIX_ARKODE: + if (!F2C_ARKODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPGMRSetPrecType(F2C_ARKODE_linsol, *pretype); + break; + default: + *ier = -1; + } +} + + +void FSUNSPGMR_SETMAXRS(int *code, int *maxrs, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (!F2C_CVODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPGMRSetMaxRestarts(F2C_CVODE_linsol, *maxrs); + break; + case FCMIX_IDA: + if (!F2C_IDA_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPGMRSetMaxRestarts(F2C_IDA_linsol, *maxrs); + break; + case FCMIX_KINSOL: + if (!F2C_KINSOL_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPGMRSetMaxRestarts(F2C_KINSOL_linsol, *maxrs); + break; + case FCMIX_ARKODE: + if (!F2C_ARKODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPGMRSetMaxRestarts(F2C_ARKODE_linsol, *maxrs); + break; + default: + *ier = -1; + } +} + + +void FSUNMASSSPGMR_INIT(int *pretype, int *maxl, int *ier) +{ + *ier = 0; + if (F2C_ARKODE_mass_sol) SUNLinSolFree(F2C_ARKODE_mass_sol); + F2C_ARKODE_mass_sol = NULL; + F2C_ARKODE_mass_sol = SUNLinSol_SPGMR(F2C_ARKODE_vec, *pretype, *maxl); + if (F2C_ARKODE_mass_sol == NULL) *ier = -1; +} + + +void FSUNMASSSPGMR_SETGSTYPE(int *gstype, int *ier) +{ + *ier = 0; + if (!F2C_ARKODE_mass_sol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPGMRSetGSType(F2C_ARKODE_mass_sol, *gstype); +} + + +void FSUNMASSSPGMR_SETPRECTYPE(int *pretype, int *ier) +{ + *ier = 0; + if (!F2C_ARKODE_mass_sol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPGMRSetPrecType(F2C_ARKODE_mass_sol, *pretype); +} + + +void FSUNMASSSPGMR_SETMAXRS(int *maxrs, int *ier) +{ + *ier = 0; + if (!F2C_ARKODE_mass_sol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPGMRSetMaxRestarts(F2C_ARKODE_mass_sol, *maxrs); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spgmr/fsunlinsol_spgmr.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spgmr/fsunlinsol_spgmr.h new file mode 100644 index 0000000..be3a82f --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spgmr/fsunlinsol_spgmr.h @@ -0,0 +1,88 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunlinsol_spgmr.c) contains the + * definitions needed for the initialization of SPGMR + * linear solver operations in Fortran. + * ----------------------------------------------------------------- + */ + +#ifndef _FSUNLINSOL_SPGMR_H +#define _FSUNLINSOL_SPGMR_H + +#include <sunlinsol/sunlinsol_spgmr.h> +#include <sundials/sundials_fnvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +#if defined(SUNDIALS_F77_FUNC) +#define FSUNSPGMR_INIT SUNDIALS_F77_FUNC(fsunspgmrinit, FSUNSPGMRINIT) +#define FSUNSPGMR_SETGSTYPE SUNDIALS_F77_FUNC(fsunspgmrsetgstype, FSUNSPGMRSETGSTYPE) +#define FSUNSPGMR_SETPRECTYPE SUNDIALS_F77_FUNC(fsunspgmrsetprectype, FSUNSPGMRSETPRECTYPE) +#define FSUNSPGMR_SETMAXRS SUNDIALS_F77_FUNC(fsunspgmrsetmaxrs, FSUNSPGMRSETMAXRS) +#define FSUNMASSSPGMR_INIT SUNDIALS_F77_FUNC(fsunmassspgmrinit, FSUNMASSSPGMRINIT) +#define FSUNMASSSPGMR_SETGSTYPE SUNDIALS_F77_FUNC(fsunmassspgmrsetgstype, FSUNMASSSPGMRSETGSTYPE) +#define FSUNMASSSPGMR_SETPRECTYPE SUNDIALS_F77_FUNC(fsunmassspgmrsetprectype, FSUNMASSSPGMRSETPRECTYPE) +#define FSUNMASSSPGMR_SETMAXRS SUNDIALS_F77_FUNC(fsunmassspgmrsetmaxrs, FSUNMASSSPGMRSETMAXRS) +#else +#define FSUNSPGMR_INIT fsunspgmrinit_ +#define FSUNSPGMR_SETGSTYPE fsunspgmrsetgstype_ +#define FSUNSPGMR_SETPRECTYPE fsunspgmrsetprectype_ +#define FSUNSPGMR_SETMAXRS fsunspgmrsetmaxrs_ +#define FSUNMASSSPGMR_INIT fsunmassspgmrinit_ +#define FSUNMASSSPGMR_SETGSTYPE fsunmassspgmrsetgstype_ +#define FSUNMASSSPGMR_SETPRECTYPE fsunmassspgmrsetprectype_ +#define FSUNMASSSPGMR_SETMAXRS fsunmassspgmrsetmaxrs_ +#endif + + +/* Declarations of global variables */ + +extern SUNLinearSolver F2C_CVODE_linsol; +extern SUNLinearSolver F2C_IDA_linsol; +extern SUNLinearSolver F2C_KINSOL_linsol; +extern SUNLinearSolver F2C_ARKODE_linsol; +extern SUNLinearSolver F2C_ARKODE_mass_sol; + +/* + * Prototypes of exported functions + * + * FSUNSPGMR_INIT - initializes SPGMR linear solver for main problem + * FSUNSPGMR_SETGSTYPE - sets the Gram-Scmidt orthogonalization type for main problem + * FSUNSPGMR_SETPRECTYPE - sets the preconditioning type for main problem + * FSUNSPGMR_SETMAXRS - sets the maximum number of restarts to allow for main problem + * + * FSUNMASSSPGMR_INIT - initializes SPGMR linear solver for mass matrix solve + * FSUNMASSSPGMR_SETGSTYPE - sets the Gram-Scmidt orthogonalization type for mass matrix solve + * FSUNMASSSPGMR_SETPRECTYPE - sets the preconditioning type for mass matrix solve + * FSUNMASSSPGMR_SETMAXRS - sets the maximum number of restarts to allow for mass matrix solve + */ + +void FSUNSPGMR_INIT(int *code, int *pretype, int *maxl, int *ier); +void FSUNSPGMR_SETGSTYPE(int *code, int *gstype, int *ier); +void FSUNSPGMR_SETPRECTYPE(int *code, int *pretype, int *ier); +void FSUNSPGMR_SETMAXRS(int *code, int *maxrs, int *ier); + +void FSUNMASSSPGMR_INIT(int *pretype, int *maxl, int *ier); +void FSUNMASSSPGMR_SETGSTYPE(int *gstype, int *ier); +void FSUNMASSSPGMR_SETPRECTYPE(int *pretype, int *ier); +void FSUNMASSSPGMR_SETMAXRS(int *maxrs, int *ier); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spgmr/sunlinsol_spgmr.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spgmr/sunlinsol_spgmr.c new file mode 100644 index 0000000..533ca7f --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/spgmr/sunlinsol_spgmr.c @@ -0,0 +1,763 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * 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 + * 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 SPGMR implementation of + * the SUNLINSOL package. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <sunlinsol/sunlinsol_spgmr.h> +#include <sundials/sundials_math.h> + +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + +/* + * ----------------------------------------------------------------- + * SPGMR solver structure accessibility macros: + * ----------------------------------------------------------------- + */ + +#define SPGMR_CONTENT(S) ( (SUNLinearSolverContent_SPGMR)(S->content) ) +#define LASTFLAG(S) ( SPGMR_CONTENT(S)->last_flag ) + +/* + * ----------------------------------------------------------------- + * deprecated wrapper functions + * ----------------------------------------------------------------- + */ +SUNLinearSolver SUNSPGMR(N_Vector y, int pretype, int maxl) +{ return(SUNLinSol_SPGMR(y, pretype, maxl)); } + +int SUNSPGMRSetPrecType(SUNLinearSolver S, int pretype) +{ return(SUNLinSol_SPGMRSetPrecType(S, pretype)); } + +int SUNSPGMRSetGSType(SUNLinearSolver S, int gstype) +{ return(SUNLinSol_SPGMRSetGSType(S, gstype)); } + +int SUNSPGMRSetMaxRestarts(SUNLinearSolver S, int maxrs) +{ return(SUNLinSol_SPGMRSetMaxRestarts(S, maxrs)); } + +/* + * ----------------------------------------------------------------- + * exported functions + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------------------- + * Function to create a new SPGMR linear solver + */ + +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)) + pretype = PREC_NONE; + if (maxl <= 0) + maxl = SUNSPGMR_MAXL_DEFAULT; + + /* check that the supplied N_Vector supports all requisite operations */ + if ( (y->ops->nvclone == NULL) || (y->ops->nvdestroy == NULL) || + (y->ops->nvlinearsum == NULL) || (y->ops->nvconst == NULL) || + (y->ops->nvprod == NULL) || (y->ops->nvdiv == NULL) || + (y->ops->nvscale == NULL) || (y->ops->nvdotprod == NULL) ) + return(NULL); + + /* Create linear solver */ + S = NULL; + S = (SUNLinearSolver) malloc(sizeof *S); + 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; + + /* Create content */ + content = NULL; + content = (SUNLinearSolverContent_SPGMR) malloc(sizeof(struct _SUNLinearSolverContent_SPGMR)); + if (content == NULL) { free(ops); free(S); return(NULL); } + + /* Fill content */ + 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->xcor = N_VClone(y); + if (content->xcor == NULL) 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; + + return(S); +} + + +/* ---------------------------------------------------------------------------- + * Function to set the type of preconditioning for SPGMR to use + */ + +SUNDIALS_EXPORT int SUNLinSol_SPGMRSetPrecType(SUNLinearSolver S, int pretype) +{ + /* Check for legal pretype */ + if ((pretype != PREC_NONE) && (pretype != PREC_LEFT) && + (pretype != PREC_RIGHT) && (pretype != PREC_BOTH)) { + return(SUNLS_ILL_INPUT); + } + + /* Check for non-NULL SUNLinearSolver */ + if (S == NULL) return(SUNLS_MEM_NULL); + + /* Set pretype */ + SPGMR_CONTENT(S)->pretype = pretype; + return(SUNLS_SUCCESS); +} + + +/* ---------------------------------------------------------------------------- + * Function to set the type of Gram-Schmidt orthogonalization for SPGMR to use + */ + +SUNDIALS_EXPORT int SUNLinSol_SPGMRSetGSType(SUNLinearSolver S, int gstype) +{ + /* Check for legal gstype */ + if ((gstype != MODIFIED_GS) && (gstype != CLASSICAL_GS)) { + return(SUNLS_ILL_INPUT); + } + + /* Check for non-NULL SUNLinearSolver */ + if (S == NULL) return(SUNLS_MEM_NULL); + + /* Set pretype */ + SPGMR_CONTENT(S)->gstype = gstype; + return(SUNLS_SUCCESS); +} + + +/* ---------------------------------------------------------------------------- + * Function to set the maximum number of GMRES restarts to allow + */ + +SUNDIALS_EXPORT int SUNLinSol_SPGMRSetMaxRestarts(SUNLinearSolver S, int maxrs) +{ + /* Illegal maxrs implies use of default value */ + if (maxrs < 0) + maxrs = SUNSPGMR_MAXRS_DEFAULT; + + /* Check for non-NULL SUNLinearSolver */ + if (S == NULL) return(SUNLS_MEM_NULL); + + /* Set max_restarts */ + SPGMR_CONTENT(S)->max_restarts = maxrs; + return(SUNLS_SUCCESS); +} + + +/* + * ----------------------------------------------------------------- + * implementation of linear solver operations + * ----------------------------------------------------------------- + */ + +SUNLinearSolver_Type SUNLinSolGetType_SPGMR(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_ITERATIVE); +} + + +int SUNLinSolInitialize_SPGMR(SUNLinearSolver S) +{ + int k; + SUNLinearSolverContent_SPGMR content; + + /* set shortcut to SPGMR memory structure */ + if (S == NULL) return(SUNLS_MEM_NULL); + content = SPGMR_CONTENT(S); + + /* ensure valid options */ + if (content->max_restarts < 0) + content->max_restarts = SUNSPGMR_MAXRS_DEFAULT; + if ( (content->pretype != PREC_LEFT) && + (content->pretype != PREC_RIGHT) && + (content->pretype != PREC_BOTH) ) + content->pretype = PREC_NONE; + + + /* allocate solver-specific memory (where the size depends on the + choice of maxl) here */ + + /* Krylov subspace vectors */ + if (content->V == NULL) { + content->V = N_VCloneVectorArray(content->maxl+1, content->vtemp); + if (content->V == NULL) { + SUNLinSolFree(S); + content->last_flag = SUNLS_MEM_FAIL; + return(SUNLS_MEM_FAIL); + } + } + + /* Hessenberg matrix Hes */ + if (content->Hes == NULL) { + content->Hes = (realtype **) malloc((content->maxl+1)*sizeof(realtype *)); + if (content->Hes == NULL) { + SUNLinSolFree(S); + content->last_flag = SUNLS_MEM_FAIL; + return(SUNLS_MEM_FAIL); + } + + for (k=0; k<=content->maxl; k++) { + content->Hes[k] = NULL; + content->Hes[k] = (realtype *) malloc(content->maxl*sizeof(realtype)); + if (content->Hes[k] == NULL) { + SUNLinSolFree(S); + content->last_flag = SUNLS_MEM_FAIL; + return(SUNLS_MEM_FAIL); + } + } + } + + /* Givens rotation components */ + if (content->givens == NULL) { + content->givens = (realtype *) malloc(2*content->maxl*sizeof(realtype)); + if (content->givens == NULL) { + SUNLinSolFree(S); + content->last_flag = SUNLS_MEM_FAIL; + return(SUNLS_MEM_FAIL); + } + } + + /* y and g vectors */ + if (content->yg == NULL) { + content->yg = (realtype *) malloc((content->maxl+1)*sizeof(realtype)); + if (content->yg == NULL) { + SUNLinSolFree(S); + content->last_flag = SUNLS_MEM_FAIL; + return(SUNLS_MEM_FAIL); + } + } + + /* cv vector for fused vector ops */ + if (content->cv == NULL) { + content->cv = (realtype *) malloc((content->maxl+1)*sizeof(realtype)); + if (content->cv == NULL) { + SUNLinSolFree(S); + content->last_flag = SUNLS_MEM_FAIL; + return(SUNLS_MEM_FAIL); + } + } + + /* 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) { + SUNLinSolFree(S); + content->last_flag = SUNLS_MEM_FAIL; + return(SUNLS_MEM_FAIL); + } + } + + /* return with success */ + content->last_flag = SUNLS_SUCCESS; + return(SUNLS_SUCCESS); +} + + +int SUNLinSolSetATimes_SPGMR(SUNLinearSolver S, void* ATData, + ATimesFn ATimes) +{ + /* 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; + SPGMR_CONTENT(S)->ATData = ATData; + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +int SUNLinSolSetPreconditioner_SPGMR(SUNLinearSolver S, void* PData, + PSetupFn Psetup, PSolveFn Psolve) +{ + /* set function pointers to integrator-supplied Psetup and PSolve + routines and data, and return with success */ + if (S == NULL) return(SUNLS_MEM_NULL); + SPGMR_CONTENT(S)->Psetup = Psetup; + SPGMR_CONTENT(S)->Psolve = Psolve; + SPGMR_CONTENT(S)->PData = PData; + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +int SUNLinSolSetScalingVectors_SPGMR(SUNLinearSolver S, N_Vector s1, + N_Vector s2) +{ + /* 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; + SPGMR_CONTENT(S)->s2 = s2; + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +int SUNLinSolSetup_SPGMR(SUNLinearSolver S, SUNMatrix A) +{ + int ier; + PSetupFn Psetup; + void* PData; + + /* Set shortcuts to SPGMR memory structures */ + 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 + Psetup routine exists, call that here */ + if (Psetup != NULL) { + ier = Psetup(PData); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSET_FAIL_UNREC : SUNLS_PSET_FAIL_REC; + return(LASTFLAG(S)); + } + } + + /* return with success */ + return(SUNLS_SUCCESS); +} + + +int SUNLinSolSolve_SPGMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, + N_Vector b, realtype delta) +{ + /* local data and shortcut variables */ + N_Vector *V, xcor, vtemp, s1, s2; + realtype **Hes, *givens, *yg, *res_norm; + 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, max_restarts, gstype; + int *nli; + void *A_data, *P_data; + ATimesFn atimes; + PSolveFn psolve; + + /* local shortcuts for fused vector operations */ + realtype* cv; + N_Vector* Xv; + + /* Initialize some variables */ + l_plus_1 = 0; + krydim = 0; + + /* Make local shorcuts to solver variables. */ + if (S == NULL) return(SUNLS_MEM_NULL); + l_max = SPGMR_CONTENT(S)->maxl; + max_restarts = SPGMR_CONTENT(S)->max_restarts; + gstype = SPGMR_CONTENT(S)->gstype; + V = SPGMR_CONTENT(S)->V; + Hes = SPGMR_CONTENT(S)->Hes; + givens = SPGMR_CONTENT(S)->givens; + xcor = SPGMR_CONTENT(S)->xcor; + yg = SPGMR_CONTENT(S)->yg; + vtemp = SPGMR_CONTENT(S)->vtemp; + s1 = SPGMR_CONTENT(S)->s1; + s2 = SPGMR_CONTENT(S)->s2; + A_data = SPGMR_CONTENT(S)->ATData; + P_data = SPGMR_CONTENT(S)->PData; + atimes = SPGMR_CONTENT(S)->ATimes; + psolve = SPGMR_CONTENT(S)->Psolve; + nli = &(SPGMR_CONTENT(S)->numiters); + res_norm = &(SPGMR_CONTENT(S)->resnorm); + cv = SPGMR_CONTENT(S)->cv; + Xv = SPGMR_CONTENT(S)->Xv; + + /* Initialize counters and convergence flag */ + *nli = 0; + converged = SUNFALSE; + + /* set booleantype flags for internal solver options */ + preOnLeft = ( (SPGMR_CONTENT(S)->pretype == PREC_LEFT) || + (SPGMR_CONTENT(S)->pretype == PREC_BOTH) ); + preOnRight = ( (SPGMR_CONTENT(S)->pretype == PREC_RIGHT) || + (SPGMR_CONTENT(S)->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) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_ATIMES_FAIL_UNREC : SUNLS_ATIMES_FAIL_REC; + return(LASTFLAG(S)); + } + 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); + if (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]); + } 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) { + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); + } + + /* 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); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; + return(LASTFLAG(S)); + } + } + + /* Apply A: V[l+1] = A P2_inv s2_inv V[l] */ + ier = atimes( A_data, vtemp, V[l_plus_1] ); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_ATIMES_FAIL_UNREC : SUNLS_ATIMES_FAIL_REC; + return(LASTFLAG(S)); + } + + /* 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); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; + return(LASTFLAG(S)); + } + } 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]), + cv, Xv) != 0) { + LASTFLAG(S) = SUNLS_GS_FAIL; + return(LASTFLAG(S)); + } + } else { + if (ModifiedGS(V, Hes, l_plus_1, l_max, &(Hes[l_plus_1][l])) != 0) { + LASTFLAG(S) = SUNLS_GS_FAIL; + return(LASTFLAG(S)); + } + } + + /* Update the QR factorization of Hes */ + if(QRfact(krydim, Hes, givens, l) != 0 ) { + LASTFLAG(S) = SUNLS_QRFACT_FAIL; + return(LASTFLAG(S)); + } + + /* 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) { + LASTFLAG(S) = SUNLS_QRSOL_FAIL; + return(LASTFLAG(S)); + } + + /* Add correction vector V_l y to xcor */ + cv[0] = ONE; + Xv[0] = xcor; + + for (k=0; k<krydim; k++) { + cv[k+1] = yg[k]; + Xv[k+1] = V[k]; + } + ier = N_VLinearCombination(krydim+1, cv, Xv, xcor); + if (ier != SUNLS_SUCCESS) return(SUNLS_VECTOROP_ERR); + + /* 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); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; + return(LASTFLAG(S)); + } + } 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); + + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); + } + + /* 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 */ + for (k=0; k<=krydim; k++) { + cv[k] = yg[k]; + Xv[k] = V[k]; + } + 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 */ + 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) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; + return(LASTFLAG(S)); + } + } 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); + + LASTFLAG(S) = SUNLS_RES_REDUCED; + return(LASTFLAG(S)); + } + + LASTFLAG(S) = SUNLS_CONV_FAIL; + return(LASTFLAG(S)); +} + + +int SUNLinSolNumIters_SPGMR(SUNLinearSolver S) +{ + /* return the stored 'numiters' value */ + if (S == NULL) return(-1); + return (SPGMR_CONTENT(S)->numiters); +} + + +realtype SUNLinSolResNorm_SPGMR(SUNLinearSolver S) +{ + /* return the stored 'resnorm' value */ + if (S == NULL) return(-ONE); + return (SPGMR_CONTENT(S)->resnorm); +} + + +N_Vector SUNLinSolResid_SPGMR(SUNLinearSolver S) +{ + /* return the stored 'vtemp' vector */ + return (SPGMR_CONTENT(S)->vtemp); +} + + +long int SUNLinSolLastFlag_SPGMR(SUNLinearSolver S) +{ + /* return the stored 'last_flag' value */ + if (S == NULL) return(-1); + return (LASTFLAG(S)); +} + + +int SUNLinSolSpace_SPGMR(SUNLinearSolver S, + long int *lenrwLS, + long int *leniwLS) +{ + int maxl; + sunindextype liw1, lrw1; + maxl = SPGMR_CONTENT(S)->maxl; + if (SPGMR_CONTENT(S)->vtemp->ops->nvspace) + N_VSpace(SPGMR_CONTENT(S)->vtemp, &lrw1, &liw1); + else + lrw1 = liw1 = 0; + *lenrwLS = lrw1*(maxl + 5) + maxl*(maxl + 5) + 2; + *leniwLS = liw1*(maxl + 5); + return(SUNLS_SUCCESS); +} + + +int SUNLinSolFree_SPGMR(SUNLinearSolver S) +{ + int k; + + 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 (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; + free(S); S = NULL; + return(SUNLS_SUCCESS); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/sptfqmr/fsunlinsol_sptfqmr.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/sptfqmr/fsunlinsol_sptfqmr.c new file mode 100644 index 0000000..f858704 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/sptfqmr/fsunlinsol_sptfqmr.c @@ -0,0 +1,191 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunlinsol_sptfqmr.h) contains the + * implementation needed for the Fortran initialization of SPTFQMR + * linear solver operations. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fsunlinsol_sptfqmr.h" + +/* Define global linsol variables */ + +SUNLinearSolver F2C_CVODE_linsol; +SUNLinearSolver F2C_IDA_linsol; +SUNLinearSolver F2C_KINSOL_linsol; +SUNLinearSolver F2C_ARKODE_linsol; +SUNLinearSolver F2C_ARKODE_mass_sol; + +/* Declarations of external global variables */ + +extern SUNMatrix F2C_CVODE_matrix; +extern SUNMatrix F2C_IDA_matrix; +extern SUNMatrix F2C_KINSOL_matrix; +extern SUNMatrix F2C_ARKODE_matrix; +extern SUNMatrix F2C_ARKODE_mass_matrix; + +extern N_Vector F2C_CVODE_vec; +extern N_Vector F2C_IDA_vec; +extern N_Vector F2C_KINSOL_vec; +extern N_Vector F2C_ARKODE_vec; + +/* Fortran callable interfaces */ + +void FSUNSPTFQMR_INIT(int *code, int *pretype, int *maxl, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (F2C_CVODE_linsol) SUNLinSolFree(F2C_CVODE_linsol); + F2C_CVODE_linsol = NULL; + F2C_CVODE_linsol = SUNLinSol_SPTFQMR(F2C_CVODE_vec, *pretype, *maxl); + if (F2C_CVODE_linsol == NULL) *ier = -1; + break; + case FCMIX_IDA: + if (F2C_IDA_linsol) SUNLinSolFree(F2C_IDA_linsol); + F2C_IDA_linsol = NULL; + F2C_IDA_linsol = SUNLinSol_SPTFQMR(F2C_IDA_vec, *pretype, *maxl); + if (F2C_IDA_linsol == NULL) *ier = -1; + break; + case FCMIX_KINSOL: + if (F2C_KINSOL_linsol) SUNLinSolFree(F2C_KINSOL_linsol); + F2C_KINSOL_linsol = NULL; + F2C_KINSOL_linsol = SUNLinSol_SPTFQMR(F2C_KINSOL_vec, *pretype, *maxl); + if (F2C_KINSOL_linsol == NULL) *ier = -1; + break; + case FCMIX_ARKODE: + if (F2C_ARKODE_linsol) SUNLinSolFree(F2C_ARKODE_linsol); + F2C_ARKODE_linsol = NULL; + F2C_ARKODE_linsol = SUNLinSol_SPTFQMR(F2C_ARKODE_vec, *pretype, *maxl); + if (F2C_ARKODE_linsol == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + + +void FSUNSPTFQMR_SETPRECTYPE(int *code, int *pretype, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (!F2C_CVODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPTFQMRSetPrecType(F2C_CVODE_linsol, *pretype); + break; + case FCMIX_IDA: + if (!F2C_IDA_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPTFQMRSetPrecType(F2C_IDA_linsol, *pretype); + break; + case FCMIX_KINSOL: + if (!F2C_KINSOL_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPTFQMRSetPrecType(F2C_KINSOL_linsol, *pretype); + break; + case FCMIX_ARKODE: + if (!F2C_ARKODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPTFQMRSetPrecType(F2C_ARKODE_linsol, *pretype); + break; + default: + *ier = -1; + } +} + + +void FSUNSPTFQMR_SETMAXL(int *code, int *maxl, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (!F2C_CVODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPTFQMRSetMaxl(F2C_CVODE_linsol, *maxl); + break; + case FCMIX_IDA: + if (!F2C_IDA_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPTFQMRSetMaxl(F2C_IDA_linsol, *maxl); + break; + case FCMIX_KINSOL: + if (!F2C_KINSOL_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPTFQMRSetMaxl(F2C_KINSOL_linsol, *maxl); + break; + case FCMIX_ARKODE: + if (!F2C_ARKODE_linsol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPTFQMRSetMaxl(F2C_ARKODE_linsol, *maxl); + break; + default: + *ier = -1; + } +} + + +void FSUNMASSSPTFQMR_INIT(int *pretype, int *maxl, int *ier) +{ + *ier = 0; + if (F2C_ARKODE_mass_sol) SUNLinSolFree(F2C_ARKODE_mass_sol); + F2C_ARKODE_mass_sol = NULL; + F2C_ARKODE_mass_sol = SUNLinSol_SPTFQMR(F2C_ARKODE_vec, *pretype, *maxl); + if (F2C_ARKODE_mass_sol == NULL) *ier = -1; +} + + +void FSUNMASSSPTFQMR_SETPRECTYPE(int *pretype, int *ier) +{ + *ier = 0; + if (!F2C_ARKODE_mass_sol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPTFQMRSetPrecType(F2C_ARKODE_mass_sol, *pretype); +} + + +void FSUNMASSSPTFQMR_SETMAXL(int *maxl, int *ier) +{ + *ier = 0; + if (!F2C_ARKODE_mass_sol) { + *ier = -1; + return; + } + *ier = SUNLinSol_SPTFQMRSetMaxl(F2C_ARKODE_mass_sol, *maxl); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/sptfqmr/fsunlinsol_sptfqmr.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/sptfqmr/fsunlinsol_sptfqmr.h new file mode 100644 index 0000000..7e3aa4b --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/sptfqmr/fsunlinsol_sptfqmr.h @@ -0,0 +1,80 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunlinsol_sptfqmr.c) contains the + * definitions needed for the initialization of SPTFQMR + * linear solver operations in Fortran. + * ----------------------------------------------------------------- + */ + +#ifndef _FSUNLINSOL_SPTFQMR_H +#define _FSUNLINSOL_SPTFQMR_H + +#include <sunlinsol/sunlinsol_sptfqmr.h> +#include <sundials/sundials_fnvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +#if defined(SUNDIALS_F77_FUNC) +#define FSUNSPTFQMR_INIT SUNDIALS_F77_FUNC(fsunsptfqmrinit, FSUNSPTFQMRINIT) +#define FSUNSPTFQMR_SETPRECTYPE SUNDIALS_F77_FUNC(fsunsptfqmrsetprectype, FSUNSPTFQMRSETPRECTYPE) +#define FSUNSPTFQMR_SETMAXL SUNDIALS_F77_FUNC(fsunsptfqmrsetmaxl, FSUNSPTFQMRSETMAXL) +#define FSUNMASSSPTFQMR_INIT SUNDIALS_F77_FUNC(fsunmasssptfqmrinit, FSUNMASSSPTFQMRINIT) +#define FSUNMASSSPTFQMR_SETPRECTYPE SUNDIALS_F77_FUNC(fsunmasssptfqmrsetprectype, FSUNMASSSPTFQMRSETPRECTYPE) +#define FSUNMASSSPTFQMR_SETMAXL SUNDIALS_F77_FUNC(fsunmasssptfqmrsetmaxl, FSUNMASSSPTFQMRSETMAXL) +#else +#define FSUNSPTFQMR_INIT fsunsptfqmrinit_ +#define FSUNSPTFQMR_SETPRECTYPE fsunsptfqmrsetprectype_ +#define FSUNSPTFQMR_SETMAXL fsunsptfqmrsetmaxl_ +#define FSUNMASSSPTFQMR_INIT fsunmasssptfqmrinit_ +#define FSUNMASSSPTFQMR_SETPRECTYPE fsunmasssptfqmrsetprectype_ +#define FSUNMASSSPTFQMR_SETMAXL fsunmasssptfqmrsetmaxl_ +#endif + + +/* Declarations of global variables */ + +extern SUNLinearSolver F2C_CVODE_linsol; +extern SUNLinearSolver F2C_IDA_linsol; +extern SUNLinearSolver F2C_KINSOL_linsol; +extern SUNLinearSolver F2C_ARKODE_linsol; +extern SUNLinearSolver F2C_ARKODE_mass_sol; + +/* + * Prototypes of exported functions + * + * FSUNSPTFQMR_INIT - initializes SPTFQMR linear solver for main problem + * FSUNSPTFQMR_SETPRECTYPE - sets the preconditioning type for main problem + * FSUNSPTFQMR_SETMAXL - sets the max number of iterations for main problem + * + * FSUNMASSSPTFQMR_INIT - initializes SPTFQMR linear solver for mass matrix solve + * FSUNMASSSPTFQMR_SETPRECTYPE - sets the preconditioning type for mass matrix solve + * FSUNMASSSPTFQMR_SETMAXL - sets the max number of iterations for mass matrix solve + */ + +void FSUNSPTFQMR_INIT(int *code, int *pretype, int *maxl, int *ier); +void FSUNSPTFQMR_SETPRECTYPE(int *code, int *pretype, int *ier); +void FSUNSPTFQMR_SETMAXL(int *code, int *maxl, int *ier); + +void FSUNMASSSPTFQMR_INIT(int *pretype, int *maxl, int *ier); +void FSUNMASSSPTFQMR_SETPRECTYPE(int *pretype, int *ier); +void FSUNMASSSPTFQMR_SETMAXL(int *maxl, int *ier); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/sptfqmr/sunlinsol_sptfqmr.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/sptfqmr/sunlinsol_sptfqmr.c new file mode 100644 index 0000000..e66b159 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/sptfqmr/sunlinsol_sptfqmr.c @@ -0,0 +1,767 @@ +/* + * ----------------------------------------------------------------- + * 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 + * 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 SPTFQMR implementation of + * the SUNLINSOL package. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <sunlinsol/sunlinsol_sptfqmr.h> +#include <sundials/sundials_math.h> + +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + +/* + * ----------------------------------------------------------------- + * SPTFQMR solver structure accessibility macros: + * ----------------------------------------------------------------- + */ + + +#define SPTFQMR_CONTENT(S) ( (SUNLinearSolverContent_SPTFQMR)(S->content) ) +#define LASTFLAG(S) ( SPTFQMR_CONTENT(S)->last_flag ) + + +/* + * ----------------------------------------------------------------- + * deprecated wrapper functions + * ----------------------------------------------------------------- + */ + +SUNLinearSolver SUNSPTFQMR(N_Vector y, int pretype, int maxl) +{ return(SUNLinSol_SPTFQMR(y, pretype, maxl)); } + +int SUNSPTFQMRSetPrecType(SUNLinearSolver S, int pretype) +{ return(SUNLinSol_SPTFQMRSetPrecType(S, pretype)); } + +int SUNSPTFQMRSetMaxl(SUNLinearSolver S, int maxl) +{ return(SUNLinSol_SPTFQMRSetMaxl(S, maxl)); } + +/* + * ----------------------------------------------------------------- + * exported functions + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------------------- + * Function to create a new SPTFQMR linear solver + */ + +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)) + pretype = PREC_NONE; + if (maxl <= 0) + maxl = SUNSPTFQMR_MAXL_DEFAULT; + + /* check that the supplied N_Vector supports all requisite operations */ + if ( (y->ops->nvclone == NULL) || (y->ops->nvdestroy == NULL) || + (y->ops->nvlinearsum == NULL) || (y->ops->nvconst == NULL) || + (y->ops->nvprod == NULL) || (y->ops->nvdiv == NULL) || + (y->ops->nvscale == NULL) || (y->ops->nvdotprod == NULL) ) + return(NULL); + + /* Create linear solver */ + S = NULL; + S = (SUNLinearSolver) malloc(sizeof *S); + 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; + + /* Create content */ + content = NULL; + content = (SUNLinearSolverContent_SPTFQMR) malloc(sizeof(struct _SUNLinearSolverContent_SPTFQMR)); + if (content == NULL) { free(ops); free(S); return(NULL); } + + /* Fill content */ + content->last_flag = 0; + content->maxl = maxl; + content->pretype = pretype; + content->numiters = 0; + content->resnorm = ZERO; + content->r_star = N_VClone(y); + if (content->r_star == NULL) return(NULL); + content->q = N_VClone(y); + if (content->q == NULL) return(NULL); + content->d = N_VClone(y); + if (content->d == NULL) return(NULL); + content->v = N_VClone(y); + if (content->v == NULL) return(NULL); + content->p = N_VClone(y); + if (content->p == NULL) return(NULL); + content->r = N_VCloneVectorArray(2, y); + if (content->r == NULL) return(NULL); + content->u = N_VClone(y); + if (content->u == NULL) return(NULL); + content->vtemp1 = N_VClone(y); + if (content->vtemp1 == NULL) return(NULL); + content->vtemp2 = N_VClone(y); + if (content->vtemp2 == NULL) 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; + + return(S); +} + + +/* ---------------------------------------------------------------------------- + * Function to set the type of preconditioning for SPTFQMR to use + */ + +SUNDIALS_EXPORT int SUNLinSol_SPTFQMRSetPrecType(SUNLinearSolver S, int pretype) +{ + /* Check for legal pretype */ + if ((pretype != PREC_NONE) && (pretype != PREC_LEFT) && + (pretype != PREC_RIGHT) && (pretype != PREC_BOTH)) { + return(SUNLS_ILL_INPUT); + } + + /* Check for non-NULL SUNLinearSolver */ + if (S == NULL) return(SUNLS_MEM_NULL); + + /* Set pretype */ + SPTFQMR_CONTENT(S)->pretype = pretype; + return(SUNLS_SUCCESS); +} + + +/* ---------------------------------------------------------------------------- + * Function to set the maximum number of iterations for SPTFQMR to use + */ + +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 */ + if (maxl <= 0) + maxl = SUNSPTFQMR_MAXL_DEFAULT; + + /* Set pretype */ + SPTFQMR_CONTENT(S)->maxl = maxl; + return(SUNLS_SUCCESS); +} + + +/* + * ----------------------------------------------------------------- + * implementation of linear solver operations + * ----------------------------------------------------------------- + */ + +SUNLinearSolver_Type SUNLinSolGetType_SPTFQMR(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_ITERATIVE); +} + + +int SUNLinSolInitialize_SPTFQMR(SUNLinearSolver S) +{ + SUNLinearSolverContent_SPTFQMR content; + + /* set shortcut to SPTFQMR memory structure */ + if (S == NULL) return(SUNLS_MEM_NULL); + content = SPTFQMR_CONTENT(S); + + /* ensure valid options */ + if ( (content->pretype != PREC_LEFT) && + (content->pretype != PREC_RIGHT) && + (content->pretype != PREC_BOTH) ) + content->pretype = PREC_NONE; + 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, + ATimesFn ATimes) +{ + /* set function pointers to integrator-supplied ATimes routine + and data, and return with success */ + if (S == NULL) return(SUNLS_MEM_NULL); + SPTFQMR_CONTENT(S)->ATimes = ATimes; + SPTFQMR_CONTENT(S)->ATData = ATData; + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +int SUNLinSolSetPreconditioner_SPTFQMR(SUNLinearSolver S, void* PData, + PSetupFn Psetup, PSolveFn Psolve) +{ + /* set function pointers to integrator-supplied Psetup and PSolve + routines and data, and return with success */ + if (S == NULL) return(SUNLS_MEM_NULL); + SPTFQMR_CONTENT(S)->Psetup = Psetup; + SPTFQMR_CONTENT(S)->Psolve = Psolve; + SPTFQMR_CONTENT(S)->PData = PData; + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +int SUNLinSolSetScalingVectors_SPTFQMR(SUNLinearSolver S, + N_Vector s1, + N_Vector s2) +{ + /* 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; + SPTFQMR_CONTENT(S)->s2 = s2; + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +int SUNLinSolSetup_SPTFQMR(SUNLinearSolver S, SUNMatrix A) +{ + int ier; + PSetupFn Psetup; + void* PData; + + /* Set shortcuts to SPTFQMR memory structures */ + 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 + Psetup routine exists, call that here */ + if (Psetup != NULL) { + ier = Psetup(PData); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSET_FAIL_UNREC : SUNLS_PSET_FAIL_REC; + return(LASTFLAG(S)); + } + } + + /* return with success */ + return(SUNLS_SUCCESS); +} + + +int SUNLinSolSolve_SPTFQMR(SUNLinearSolver S, SUNMatrix A, N_Vector x, + N_Vector b, realtype delta) +{ + /* local data and shortcut variables */ + 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, l_max; + void *A_data, *P_data; + ATimesFn atimes; + PSolveFn psolve; + realtype *res_norm; + int *nli; + N_Vector sx, sb, r_star, q, d, v, p, *r, u, vtemp1, vtemp2, vtemp3; + + /* 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; + r_star = SPTFQMR_CONTENT(S)->r_star; + q = SPTFQMR_CONTENT(S)->q; + d = SPTFQMR_CONTENT(S)->d; + v = SPTFQMR_CONTENT(S)->v; + p = SPTFQMR_CONTENT(S)->p; + r = SPTFQMR_CONTENT(S)->r; + u = SPTFQMR_CONTENT(S)->u; + vtemp1 = SPTFQMR_CONTENT(S)->vtemp1; + vtemp2 = SPTFQMR_CONTENT(S)->vtemp2; + vtemp3 = SPTFQMR_CONTENT(S)->vtemp3; + sb = SPTFQMR_CONTENT(S)->s1; + sx = SPTFQMR_CONTENT(S)->s2; + A_data = SPTFQMR_CONTENT(S)->ATData; + P_data = SPTFQMR_CONTENT(S)->PData; + atimes = SPTFQMR_CONTENT(S)->ATimes; + psolve = SPTFQMR_CONTENT(S)->Psolve; + nli = &(SPTFQMR_CONTENT(S)->numiters); + res_norm = &(SPTFQMR_CONTENT(S)->resnorm); + + /* Initialize counters and convergence flag */ + temp_val = r_curr_norm = -ONE; + *nli = 0; + converged = SUNFALSE; + b_ok = SUNFALSE; + + /* set booleantype flags for internal solver options */ + preOnLeft = ( (SPTFQMR_CONTENT(S)->pretype == PREC_LEFT) || + (SPTFQMR_CONTENT(S)->pretype == PREC_BOTH) ); + preOnRight = ( (SPTFQMR_CONTENT(S)->pretype == PREC_RIGHT) || + (SPTFQMR_CONTENT(S)->pretype == PREC_BOTH) ); + 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) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_ATIMES_FAIL_UNREC : SUNLS_ATIMES_FAIL_REC; + return(LASTFLAG(S)); + } + 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); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; + return(LASTFLAG(S)); + } + } + 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) { + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); + } + + /* 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); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; + return(LASTFLAG(S)); + } + } + ier = atimes(A_data, vtemp1, v); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_ATIMES_FAIL_UNREC : SUNLS_ATIMES_FAIL_REC; + return(LASTFLAG(S)); + } + if (preOnLeft) { + ier = psolve(P_data, v, vtemp1, delta, PREC_LEFT); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; + return(LASTFLAG(S)); + } + } + 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); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; + return(LASTFLAG(S)); + } + } + ier = atimes(A_data, r[1], vtemp1); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_ATIMES_FAIL_UNREC : SUNLS_ATIMES_FAIL_REC; + return(LASTFLAG(S)); + } + if (preOnLeft) { + ier = psolve(P_data, vtemp1, r[1], delta, PREC_LEFT); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; + return(LASTFLAG(S)); + } + } + 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); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_UNREC; + return(LASTFLAG(S)); + } + N_VScale(ONE, vtemp2, vtemp1); + } + ier = atimes(A_data, vtemp1, vtemp2); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_ATIMES_FAIL_UNREC : SUNLS_ATIMES_FAIL_REC; + return(LASTFLAG(S)); + } + if (preOnLeft) { + ier = psolve(P_data, vtemp2, vtemp1, delta, PREC_LEFT); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; + return(LASTFLAG(S)); + } + } + 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); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; + return(LASTFLAG(S)); + } + } + 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) = beta*beta*p + beta*q + u */ + cv[0] = SUNSQR(beta); + Xv[0] = p; + + cv[1] = beta; + Xv[1] = q; + + cv[2] = ONE; + Xv[2] = u; + + ier = N_VLinearCombination(3, cv, Xv, p); + if (ier != SUNLS_SUCCESS) return(SUNLS_VECTOROP_ERR); + + /* 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); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; + return(LASTFLAG(S)); + } + } + ier = atimes(A_data, vtemp1, v); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_ATIMES_FAIL_UNREC : SUNLS_ATIMES_FAIL_REC; + return(LASTFLAG(S)); + } + if (preOnLeft) { + ier = psolve(P_data, v, vtemp1, delta, PREC_LEFT); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_REC; + return(LASTFLAG(S)); + } + } + 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); + if (ier != 0) { + LASTFLAG(S) = (ier < 0) ? + SUNLS_PSOLVE_FAIL_UNREC : SUNLS_PSOLVE_FAIL_UNREC; + return(LASTFLAG(S)); + } + N_VScale(ONE, vtemp1, x); + } + if (converged == SUNTRUE) + LASTFLAG(S) = SUNLS_SUCCESS; + else + LASTFLAG(S) = SUNLS_RES_REDUCED; + return(LASTFLAG(S)); + } + /* Otherwise, return error code */ + else { + LASTFLAG(S) = SUNLS_CONV_FAIL; + return(LASTFLAG(S)); + } +} + + +int SUNLinSolNumIters_SPTFQMR(SUNLinearSolver S) +{ + /* return the stored 'numiters' value */ + if (S == NULL) return(-1); + return (SPTFQMR_CONTENT(S)->numiters); +} + + +realtype SUNLinSolResNorm_SPTFQMR(SUNLinearSolver S) +{ + /* return the stored 'resnorm' value */ + if (S == NULL) return(-ONE); + return (SPTFQMR_CONTENT(S)->resnorm); +} + + +N_Vector SUNLinSolResid_SPTFQMR(SUNLinearSolver S) +{ + /* return the stored 'vtemp1' vector */ + return (SPTFQMR_CONTENT(S)->vtemp1); +} + + +long int SUNLinSolLastFlag_SPTFQMR(SUNLinearSolver S) +{ + /* return the stored 'last_flag' value */ + if (S == NULL) return(-1); + return (LASTFLAG(S)); +} + + +int SUNLinSolSpace_SPTFQMR(SUNLinearSolver S, + long int *lenrwLS, + long int *leniwLS) +{ + sunindextype liw1, lrw1; + if (SPTFQMR_CONTENT(S)->vtemp1->ops->nvspace) + N_VSpace(SPTFQMR_CONTENT(S)->vtemp1, &lrw1, &liw1); + else + lrw1 = liw1 = 0; + *lenrwLS = lrw1*11; + *leniwLS = liw1*11; + return(SUNLS_SUCCESS); +} + +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; + free(S); S = NULL; + return(SUNLS_SUCCESS); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/superlumt/fsunlinsol_superlumt.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/superlumt/fsunlinsol_superlumt.c new file mode 100644 index 0000000..711ba5c --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/superlumt/fsunlinsol_superlumt.c @@ -0,0 +1,132 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunlinsol_superlumt.h) contains the + * implementation needed for the Fortran initialization of superlumt + * linear solver operations. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fsunlinsol_superlumt.h" + +/* Define global linsol variables */ + +SUNLinearSolver F2C_CVODE_linsol; +SUNLinearSolver F2C_IDA_linsol; +SUNLinearSolver F2C_KINSOL_linsol; +SUNLinearSolver F2C_ARKODE_linsol; +SUNLinearSolver F2C_ARKODE_mass_sol; + +/* Declarations of external global variables */ + +extern SUNMatrix F2C_CVODE_matrix; +extern SUNMatrix F2C_IDA_matrix; +extern SUNMatrix F2C_KINSOL_matrix; +extern SUNMatrix F2C_ARKODE_matrix; +extern SUNMatrix F2C_ARKODE_mass_matrix; + +extern N_Vector F2C_CVODE_vec; +extern N_Vector F2C_IDA_vec; +extern N_Vector F2C_KINSOL_vec; +extern N_Vector F2C_ARKODE_vec; + +/* Fortran callable interfaces */ + +void FSUNSUPERLUMT_INIT(int *code, int *num_threads, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (F2C_CVODE_linsol) SUNLinSolFree(F2C_CVODE_linsol); + F2C_CVODE_linsol = NULL; + F2C_CVODE_linsol = SUNLinSol_SuperLUMT(F2C_CVODE_vec, + F2C_CVODE_matrix, + *num_threads); + if (F2C_CVODE_linsol == NULL) *ier = -1; + break; + case FCMIX_IDA: + if (F2C_IDA_linsol) SUNLinSolFree(F2C_IDA_linsol); + F2C_IDA_linsol = NULL; + F2C_IDA_linsol = SUNLinSol_SuperLUMT(F2C_IDA_vec, + F2C_IDA_matrix, + *num_threads); + if (F2C_IDA_linsol == NULL) *ier = -1; + break; + case FCMIX_KINSOL: + if (F2C_KINSOL_linsol) SUNLinSolFree(F2C_KINSOL_linsol); + F2C_KINSOL_linsol = NULL; + F2C_KINSOL_linsol = SUNLinSol_SuperLUMT(F2C_KINSOL_vec, + F2C_KINSOL_matrix, + *num_threads); + if (F2C_KINSOL_linsol == NULL) *ier = -1; + break; + case FCMIX_ARKODE: + if (F2C_ARKODE_linsol) SUNLinSolFree(F2C_ARKODE_linsol); + F2C_ARKODE_linsol = NULL; + F2C_ARKODE_linsol = SUNLinSol_SuperLUMT(F2C_ARKODE_vec, + F2C_ARKODE_matrix, + *num_threads); + if (F2C_ARKODE_linsol == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + + +void FSUNSUPERLUMT_SETORDERING(int *code, int *ordering_choice, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + *ier = SUNLinSol_SuperLUMTSetOrdering(F2C_CVODE_linsol, *ordering_choice); + break; + case FCMIX_IDA: + *ier = SUNLinSol_SuperLUMTSetOrdering(F2C_IDA_linsol, *ordering_choice); + break; + case FCMIX_KINSOL: + *ier = SUNLinSol_SuperLUMTSetOrdering(F2C_KINSOL_linsol, *ordering_choice); + break; + case FCMIX_ARKODE: + *ier = SUNLinSol_SuperLUMTSetOrdering(F2C_ARKODE_linsol, *ordering_choice); + break; + default: + *ier = -1; + } +} + + +void FSUNMASSSUPERLUMT_INIT(int *num_threads, int *ier) +{ + *ier = 0; + if (F2C_ARKODE_mass_sol) SUNLinSolFree(F2C_ARKODE_mass_sol); + F2C_ARKODE_mass_sol = NULL; + F2C_ARKODE_mass_sol = SUNLinSol_SuperLUMT(F2C_ARKODE_vec, + F2C_ARKODE_mass_matrix, + *num_threads); + if (F2C_ARKODE_mass_sol == NULL) *ier = -1; +} + + +void FSUNMASSSUPERLUMT_SETORDERING(int *ordering_choice, int *ier) +{ + *ier = 0; + *ier = SUNLinSol_SuperLUMTSetOrdering(F2C_ARKODE_mass_sol, + *ordering_choice); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/superlumt/fsunlinsol_superlumt.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/superlumt/fsunlinsol_superlumt.h new file mode 100644 index 0000000..c393576 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/superlumt/fsunlinsol_superlumt.h @@ -0,0 +1,70 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunlinsol_superlumt.c) contains the + * definitions needed for the initialization of superlumt + * linear solver operations in Fortran. + * ----------------------------------------------------------------- + */ + +#ifndef _FSUNLINSOL_SUPERLUMT_H +#define _FSUNLINSOL_SUPERLUMT_H + +#include <sunlinsol/sunlinsol_superlumt.h> +#include <sundials/sundials_fnvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +#if defined(SUNDIALS_F77_FUNC) +#define FSUNSUPERLUMT_INIT SUNDIALS_F77_FUNC(fsunsuperlumtinit, FSUNSUPERLUMTINIT) +#define FSUNSUPERLUMT_SETORDERING SUNDIALS_F77_FUNC(fsunsuperlumtsetordering, FSUNSUPERLUMTSETORDERING) +#define FSUNMASSSUPERLUMT_INIT SUNDIALS_F77_FUNC(fsunmasssuperlumtinit, FSUNMASSSUPERLUMTINIT) +#define FSUNMASSSUPERLUMT_SETORDERING SUNDIALS_F77_FUNC(fsunmasssuperlumtsetordering, FSUNMASSSUPERLUMTSETORDERING) +#else +#define FSUNSUPERLUMT_INIT fsunsuperlumtinit_ +#define FSUNSUPERLUMT_SETORDERING fsunsuperlumtsetordering_ +#define FSUNMASSSUPERLUMT_INIT fsunmasssuperlumtinit_ +#define FSUNMASSSUPERLUMT_SETORDERING fsunmasssuperlumtsetordering_ +#endif + + +/* Declarations of global variables */ + +extern SUNLinearSolver F2C_CVODE_linsol; +extern SUNLinearSolver F2C_IDA_linsol; +extern SUNLinearSolver F2C_KINSOL_linsol; +extern SUNLinearSolver F2C_ARKODE_linsol; +extern SUNLinearSolver F2C_ARKODE_mass_sol; + +/* + * Prototypes of exported functions + * + * FSUNSUPERLUMT_INIT - initializes superlumt linear solver for main problem + * FSUNSUPERLUMT_SETORDERING - sets the ordering choice used by SUPERLUMT for main problem + * FSUNMASSSUPERLUMT_INIT - initializes superlumt linear solver for mass matrix + * FSUNMASSSUPERLUMT_SETORDERING - sets the ordering choice used by SUPERLUMT for mass matrix + */ + +void FSUNSUPERLUMT_INIT(int *code, int *num_threads, int *ier); +void FSUNSUPERLUMT_SETORDERING(int *code, int *ordering, int *ier); +void FSUNMASSSUPERLUMT_INIT(int *num_threads, int *ier); +void FSUNMASSSUPERLUMT_SETORDERING(int *ordering, int *ier); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/superlumt/sunlinsol_superlumt.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/superlumt/sunlinsol_superlumt.c new file mode 100644 index 0000000..8aa3ca2 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunlinsol/superlumt/sunlinsol_superlumt.c @@ -0,0 +1,431 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * Based on codes <solver>_superlumt.c, written by + * 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 + * ----------------------------------------------------------------- + * This is the implementation file for the SuperLUMT implementation of + * the SUNLINSOL package. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <sunlinsol/sunlinsol_superlumt.h> +#include <sundials/sundials_math.h> + +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) +#define TWO RCONST(2.0) + +/* Private function prototypes */ +sunindextype GlobalVectorLength_SuperLUMT(N_Vector y); + +/* + * ----------------------------------------------------------------- + * SuperLUMT solver structure accessibility macros: + * ----------------------------------------------------------------- + */ + +#define SLUMT_CONTENT(S) ( (SUNLinearSolverContent_SuperLUMT)(S->content) ) +#define LASTFLAG(S) ( SLUMT_CONTENT(S)->last_flag ) +#define FIRSTFACTORIZE(S) ( SLUMT_CONTENT(S)->first_factorize ) +#define SM_A(S) ( SLUMT_CONTENT(S)->A ) +#define SM_AC(S) ( SLUMT_CONTENT(S)->AC ) +#define SM_L(S) ( SLUMT_CONTENT(S)->L ) +#define SM_U(S) ( SLUMT_CONTENT(S)->U ) +#define SM_B(S) ( SLUMT_CONTENT(S)->B ) +#define GSTAT(S) ( SLUMT_CONTENT(S)->Gstat ) +#define PERMR(S) ( SLUMT_CONTENT(S)->perm_r ) +#define PERMC(S) ( SLUMT_CONTENT(S)->perm_c ) +#define SIZE(S) ( SLUMT_CONTENT(S)->N ) +#define NUMTHREADS(S) ( SLUMT_CONTENT(S)->num_threads ) +#define DIAGPIVOTTHRESH(S) ( SLUMT_CONTENT(S)->diag_pivot_thresh ) +#define ORDERING(S) ( SLUMT_CONTENT(S)->ordering ) +#define OPTIONS(S) ( SLUMT_CONTENT(S)->options ) + +/* + * ----------------------------------------------------------------- + * deprecated wrapper functions + * ----------------------------------------------------------------- + */ + +SUNLinearSolver SUNSuperLUMT(N_Vector y, SUNMatrix A, int num_threads) +{ return(SUNLinSol_SuperLUMT(y, A, num_threads)); } + +int SUNSuperLUMTSetOrdering(SUNLinearSolver S, int ordering_choice) +{ return(SUNLinSol_SuperLUMTSetOrdering(S, ordering_choice)); } + + +/* + * ----------------------------------------------------------------- + * exported functions + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------------------- + * Function to create a new SuperLUMT linear solver + */ + +SUNLinearSolver SUNLinSol_SuperLUMT(N_Vector y, SUNMatrix A, int num_threads) +{ + SUNLinearSolver S; + SUNLinearSolver_Ops ops; + SUNLinearSolverContent_SuperLUMT content; + sunindextype MatrixRows, VecLength; + + /* 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 ( (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 */ + S = NULL; + S = (SUNLinearSolver) malloc(sizeof *S); + 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; + + /* Create content */ + content = NULL; + content = (SUNLinearSolverContent_SuperLUMT) + malloc(sizeof(struct _SUNLinearSolverContent_SuperLUMT)); + if (content == NULL) { free(ops); free(S); return(NULL); } + + /* Fill content */ + 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->perm_r = (sunindextype *) malloc(MatrixRows*sizeof(sunindextype)); + if (content->perm_r == NULL) { + free(content); free(ops); free(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); } + + 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); } + + 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); } + 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); } + 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); } + 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); } + 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); } + content->B->Store = NULL; + 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); } + StatAlloc(MatrixRows, num_threads, sp_ienv(1), sp_ienv(2), content->Gstat); + + /* Attach content and ops */ + S->content = content; + S->ops = ops; + + return(S); +} + + +/* ---------------------------------------------------------------------------- + * Function to set the ordering type for a SuperLUMT linear solver + */ + +int SUNLinSol_SuperLUMTSetOrdering(SUNLinearSolver S, int ordering_choice) +{ + /* Check for legal ordering_choice */ + if ((ordering_choice < 0) || (ordering_choice > 3)) + return(SUNLS_ILL_INPUT); + + /* Check for non-NULL SUNLinearSolver */ + if (S == NULL) return(SUNLS_MEM_NULL); + + /* Set ordering_choice */ + ORDERING(S) = ordering_choice; + + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + +/* + * ----------------------------------------------------------------- + * implementation of linear solver operations + * ----------------------------------------------------------------- + */ + +SUNLinearSolver_Type SUNLinSolGetType_SuperLUMT(SUNLinearSolver S) +{ + return(SUNLINEARSOLVER_DIRECT); +} + + +int SUNLinSolInitialize_SuperLUMT(SUNLinearSolver S) +{ + /* force a first factorization */ + FIRSTFACTORIZE(S) = 1; + + /* Initialize statistics variables */ + StatInit(SIZE(S), NUMTHREADS(S), GSTAT(S)); + + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +int SUNLinSolSetup_SuperLUMT(SUNLinearSolver S, SUNMatrix A) +{ + int_t retval; + int panel_size, relax, lwork; + double drop_tol; + fact_t fact; + 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); + fact = EQUILIBRATE; + trans = (SUNSparseMatrix_SparseType(A) == CSC_MAT) ? NOTRANS : TRANS; + usepr = NO; + drop_tol = ZERO; + lwork = 0; + work = NULL; + + /* 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), + SUNSparseMatrix_Columns(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 */ + if (FIRSTFACTORIZE(S)) { + + /* Get column permutation vector perm_c[], according to ordering */ + get_perm_c(ORDERING(S), SM_A(S), (int_t *) PERMC(S)); + refact = NO; + FIRSTFACTORIZE(S) = 0; + + } else { + + /* Re-initialize statistics variables */ + 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 + 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), + work, lwork, SM_A(S), SM_AC(S), OPTIONS(S), GSTAT(S)); + + /* Compute the LU factorization of A. + The following routine will create num_threads threads. */ + 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) ? + 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, + N_Vector b, realtype tol) +{ + int_t retval; + realtype *xdata; + DNformat *Bstore; + trans_t trans; + + /* copy b into x */ + N_VScale(ONE, b, x); + + /* access x data array */ + xdata = N_VGetArrayPointer(x); + if (xdata == NULL) { + LASTFLAG(S) = SUNLS_MEM_FAIL; + return(LASTFLAG(S)); + } + + 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); + if (retval != 0) { + LASTFLAG(S) = SUNLS_PACKAGE_FAIL_UNREC; + return(LASTFLAG(S)); + } + + LASTFLAG(S) = SUNLS_SUCCESS; + return(LASTFLAG(S)); +} + + +long int SUNLinSolLastFlag_SuperLUMT(SUNLinearSolver S) +{ + /* return the stored 'last_flag' value */ + return(LASTFLAG(S)); +} + + +int SUNLinSolSpace_SuperLUMT(SUNLinearSolver S, + long int *lenrwLS, + long int *leniwLS) +{ + /* since the SuperLU_MT structures are opaque objects, we + omit those from these results */ + *leniwLS = 5 + 2*SIZE(S); + *lenrwLS = 1; + return(SUNLS_SUCCESS); +} + +int SUNLinSolFree_SuperLUMT(SUNLinearSolver S) +{ + /* return with success if already freed */ + 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); + S->content = NULL; + } + + /* delete generic structures */ + if (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/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/band/fsunmatrix_band.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/band/fsunmatrix_band.c new file mode 100644 index 0000000..5f2b010 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/band/fsunmatrix_band.c @@ -0,0 +1,80 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunmatrix_band.h) contains the + * implementation needed for the Fortran initialization of band + * vector operations. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fsunmatrix_band.h" + +/* Define global matrix variables */ + +SUNMatrix F2C_CVODE_matrix; +SUNMatrix F2C_IDA_matrix; +SUNMatrix F2C_KINSOL_matrix; +SUNMatrix F2C_ARKODE_matrix; +SUNMatrix F2C_ARKODE_mass_matrix; + +/* Fortran callable interfaces */ + +void FSUNBANDMAT_INIT(int *code, long int *N, long int *mu, + long int *ml, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (F2C_CVODE_matrix) SUNMatDestroy(F2C_CVODE_matrix); + F2C_CVODE_matrix = NULL; + F2C_CVODE_matrix = SUNBandMatrix(*N, *mu, *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); + 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); + 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); + if (F2C_ARKODE_matrix == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + + +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); + if (F2C_ARKODE_mass_matrix == NULL) *ier = -1; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/band/fsunmatrix_band.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/band/fsunmatrix_band.h new file mode 100644 index 0000000..b9276c3 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/band/fsunmatrix_band.h @@ -0,0 +1,62 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunmatrix_band.c) contains the + * definitions needed for the initialization of band + * matrix operations in Fortran. + * ----------------------------------------------------------------- + */ + +#ifndef _FSUNMATRIX_BAND_H +#define _FSUNMATRIX_BAND_H + +#include <sunmatrix/sunmatrix_band.h> +#include <sundials/sundials_fnvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +#if defined(SUNDIALS_F77_FUNC) +#define FSUNBANDMAT_INIT SUNDIALS_F77_FUNC(fsunbandmatinit, FSUNBANDMATINIT) +#define FSUNBANDMASSMAT_INIT SUNDIALS_F77_FUNC(fsunbandmassmatinit, FSUNBANDMASSMATINIT) +#else +#define FSUNBANDMAT_INIT fsunbandmatinit_ +#define FSUNBANDMASSMAT_INIT fsunbandmassmatinit_ +#endif + + +/* Declarations of global variables */ + +extern SUNMatrix F2C_CVODE_matrix; +extern SUNMatrix F2C_IDA_matrix; +extern SUNMatrix F2C_KINSOL_matrix; +extern SUNMatrix F2C_ARKODE_matrix; +extern SUNMatrix F2C_ARKODE_mass_matrix; + +/* + * Prototypes of exported functions + * + * FSUNBANDMAT_INIT - initializes band matrix operations for main problem + * FSUNBANDMASSMAT_INIT - initializes band matrix operations for mass matrix solve + */ + +void FSUNBANDMAT_INIT(int *code, long int *N, long int *mu, long int *ml, int *ier); +void FSUNBANDMASSMAT_INIT(long int *N, long int *mu, long int *ml, int *ier); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/band/sunmatrix_band.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/band/sunmatrix_band.c new file mode 100644 index 0000000..267f8a3 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/band/sunmatrix_band.c @@ -0,0 +1,488 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * David Gardner @ LLNL + * Based on code sundials_band.c by: 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 band implementation of + * the SUNMATRIX package. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <sunmatrix/sunmatrix_band.h> +#include <sundials/sundials_math.h> + +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + + +/* Private function prototypes */ +static booleantype SMCompatible_Band(SUNMatrix A, SUNMatrix B); +static booleantype SMCompatible2_Band(SUNMatrix A, N_Vector x, N_Vector y); +static int SMScaleAddNew_Band(realtype c, SUNMatrix A, SUNMatrix B); + + +/* + * ----------------------------------------------------------------- + * exported functions + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------------------- + * Function to create a new band matrix with default storage upper bandwidth + */ + +SUNMatrix SUNBandMatrix(sunindextype N, sunindextype mu, sunindextype ml) +{ + return (SUNBandMatrixStorage(N, mu, ml, mu+ml)); +} + +/* ---------------------------------------------------------------------------- + * Function to create a new band matrix with specified storage upper bandwidth + */ + +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 */ + A = NULL; + A = (SUNMatrix) malloc(sizeof *A); + 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; + + /* Create content */ + content = NULL; + content = (SUNMatrixContent_Band) malloc(sizeof(struct _SUNMatrixContent_Band)); + if (content == NULL) { free(ops); free(A); return(NULL); } + + /* 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; + content->ldata = N * colSize; + content->data = NULL; + content->data = (realtype *) calloc(N * colSize, sizeof(realtype)); + if (content->data == NULL) { + free(content); free(ops); free(A); return(NULL); + } + content->cols = NULL; + content->cols = (realtype **) malloc(N * sizeof(realtype *)); + if (content->cols == NULL) { + free(content->data); free(content); free(ops); free(A); return(NULL); + } + for (j=0; j<N; j++) content->cols[j] = content->data + j * colSize; + + /* Attach content and ops */ + A->content = content; + A->ops = ops; + + return(A); +} + +/* ---------------------------------------------------------------------------- + * Function to print the band matrix + */ + +void SUNBandMatrix_Print(SUNMatrix A, FILE* outfile) +{ + sunindextype i, j, start, finish; + + /* should not be called unless A is a band matrix; + otherwise return immediately */ + if (SUNMatGetID(A) != SUNMATRIX_BAND) + return; + + /* perform operation */ + fprintf(outfile,"\n"); + for (i=0; i<SM_ROWS_B(A); i++) { + start = SUNMAX(0, i-SM_LBAND_B(A)); + finish = SUNMIN(SM_COLUMNS_B(A)-1, i+SM_UBAND_B(A)); + for (j=0; j<start; j++) + fprintf(outfile,"%12s ",""); + for (j=start; j<=finish; j++) { +#if defined(SUNDIALS_EXTENDED_PRECISION) + fprintf(outfile,"%12Lg ", SM_ELEMENT_B(A,i,j)); +#elif defined(SUNDIALS_DOUBLE_PRECISION) + fprintf(outfile,"%12g ", SM_ELEMENT_B(A,i,j)); +#else + fprintf(outfile,"%12g ", SM_ELEMENT_B(A,i,j)); +#endif + } + fprintf(outfile,"\n"); + } + fprintf(outfile,"\n"); + return; +} + +/* ---------------------------------------------------------------------------- + * Functions to access the contents of the band matrix structure + */ + +sunindextype SUNBandMatrix_Rows(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_BAND) + return SM_ROWS_B(A); + else + return -1; +} + +sunindextype SUNBandMatrix_Columns(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_BAND) + return SM_COLUMNS_B(A); + else + return -1; +} + +sunindextype SUNBandMatrix_LowerBandwidth(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_BAND) + return SM_LBAND_B(A); + else + return -1; +} + +sunindextype SUNBandMatrix_UpperBandwidth(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_BAND) + return SM_UBAND_B(A); + else + return -1; +} + +sunindextype SUNBandMatrix_StoredUpperBandwidth(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_BAND) + return SM_SUBAND_B(A); + else + return -1; +} + +sunindextype SUNBandMatrix_LDim(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_BAND) + return SM_LDIM_B(A); + else + return -1; +} + +realtype* SUNBandMatrix_Data(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_BAND) + return SM_DATA_B(A); + else + return NULL; +} + +realtype** SUNBandMatrix_Cols(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_BAND) + return SM_COLS_B(A); + else + return NULL; +} + +realtype* SUNBandMatrix_Column(SUNMatrix A, sunindextype j) +{ + if (SUNMatGetID(A) == SUNMATRIX_BAND) + return SM_COLUMN_B(A,j); + else + return NULL; +} + +/* + * ----------------------------------------------------------------- + * implementation of matrix operations + * ----------------------------------------------------------------- + */ + +SUNMatrix_ID SUNMatGetID_Band(SUNMatrix A) +{ + return SUNMATRIX_BAND; +} + +SUNMatrix SUNMatClone_Band(SUNMatrix A) +{ + SUNMatrix B = SUNBandMatrixStorage(SM_COLUMNS_B(A), SM_UBAND_B(A), + SM_LBAND_B(A), SM_SUBAND_B(A)); + return(B); +} + +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 (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(A); A = NULL; + return; +} + +int SUNMatZero_Band(SUNMatrix A) +{ + sunindextype i; + realtype *Adata; + + /* Verify that A is a band matrix */ + if (SUNMatGetID(A) != SUNMATRIX_BAND) + return 1; + + /* Perform operation */ + Adata = SM_DATA_B(A); + for (i=0; i<SM_LDATA_B(A); i++) + Adata[i] = ZERO; + return 0; +} + +int SUNMatCopy_Band(SUNMatrix A, SUNMatrix B) +{ + sunindextype i, j, colSize, ml, mu, smu; + realtype *A_colj, *B_colj; + + /* Verify that A and B have compatible dimensions */ + if (!SMCompatible_Band(A, B)) + return 1; + + /* Grow B if A's bandwidth is larger */ + if ( (SM_UBAND_B(A) > SM_UBAND_B(B)) || + (SM_LBAND_B(A) > SM_LBAND_B(B)) ) { + ml = SUNMAX(SM_LBAND_B(B),SM_LBAND_B(A)); + mu = SUNMAX(SM_UBAND_B(B),SM_UBAND_B(A)); + smu = SUNMAX(SM_SUBAND_B(B),SM_SUBAND_B(A)); + colSize = smu + ml + 1; + SM_CONTENT_B(B)->mu = mu; + SM_CONTENT_B(B)->ml = ml; + SM_CONTENT_B(B)->s_mu = smu; + SM_CONTENT_B(B)->ldim = colSize; + SM_CONTENT_B(B)->ldata = SM_COLUMNS_B(B) * colSize; + SM_CONTENT_B(B)->data = (realtype *) + realloc(SM_CONTENT_B(B)->data, SM_COLUMNS_B(B) * colSize*sizeof(realtype)); + for (j=0; j<SM_COLUMNS_B(B); j++) + SM_CONTENT_B(B)->cols[j] = SM_CONTENT_B(B)->data + j * colSize; + } + + /* Perform operation */ + if (SUNMatZero_Band(B) != 0) + return 1; + for (j=0; j<SM_COLUMNS_B(B); j++) { + B_colj = SM_COLUMN_B(B,j); + A_colj = SM_COLUMN_B(A,j); + for (i=-SM_UBAND_B(A); i<=SM_LBAND_B(A); i++) + B_colj[i] = A_colj[i]; + } + return 0; +} + +int SUNMatScaleAddI_Band(realtype c, SUNMatrix A) +{ + sunindextype i, j; + realtype *A_colj; + + /* Verify that A is a band matrix */ + if (SUNMatGetID(A) != SUNMATRIX_BAND) + return 1; + + /* Perform operation */ + for (j=0; j<SM_COLUMNS_B(A); j++) { + A_colj = SM_COLUMN_B(A,j); + for (i=-SM_UBAND_B(A); i<=SM_LBAND_B(A); i++) + A_colj[i] *= c; + SM_ELEMENT_B(A,j,j) += ONE; + } + return 0; +} + +int SUNMatScaleAdd_Band(realtype c, SUNMatrix A, SUNMatrix B) +{ + sunindextype i, j; + realtype *A_colj, *B_colj; + + /* Verify that A and B are compatible */ + if (!SMCompatible_Band(A, B)) + return 1; + + /* Call separate routine in B has larger bandwidth(s) than A */ + if ( (SM_UBAND_B(B) > SM_UBAND_B(A)) || + (SM_LBAND_B(B) > SM_LBAND_B(A)) ) { + return SMScaleAddNew_Band(c,A,B); + } + + /* Otherwise, perform operation in-place */ + for (j=0; j<SM_COLUMNS_B(A); j++) { + A_colj = SM_COLUMN_B(A,j); + B_colj = SM_COLUMN_B(B,j); + for (i=-SM_UBAND_B(B); i<=SM_LBAND_B(B); i++) + A_colj[i] = c*A_colj[i] + B_colj[i]; + } + return 0; +} + +int SUNMatMatvec_Band(SUNMatrix A, N_Vector x, N_Vector y) +{ + sunindextype i, j, is, ie; + realtype *col_j, *xd, *yd; + + /* Verify that A, x and y are compatible */ + if (!SMCompatible2_Band(A, x, y)) + return 1; + + /* access vector data (return if failure) */ + xd = N_VGetArrayPointer(x); + yd = N_VGetArrayPointer(y); + if ((xd == NULL) || (yd == NULL) || (xd == yd)) + return 1; + + /* Perform operation */ + for (i=0; i<SM_ROWS_B(A); i++) + yd[i] = ZERO; + for(j=0; j<SM_COLUMNS_B(A); j++) { + col_j = SM_COLUMN_B(A,j); + is = SUNMAX(0, j-SM_UBAND_B(A)); + ie = SUNMIN(SM_ROWS_B(A)-1, j+SM_LBAND_B(A)); + for (i=is; i<=ie; i++) + yd[i] += col_j[i-j]*xd[j]; + } + return 0; +} + +int SUNMatSpace_Band(SUNMatrix A, long int *lenrw, long int *leniw) +{ + *lenrw = SM_COLUMNS_B(A) * (SM_SUBAND_B(A) + SM_LBAND_B(A) + 1); + *leniw = 7 + SM_COLUMNS_B(A); + return 0; +} + + +/* + * ----------------------------------------------------------------- + * private functions + * ----------------------------------------------------------------- + */ + +static booleantype SMCompatible_Band(SUNMatrix A, SUNMatrix B) +{ + /* both matrices must be SUNMATRIX_BAND */ + if (SUNMatGetID(A) != SUNMATRIX_BAND) + return SUNFALSE; + if (SUNMatGetID(B) != SUNMATRIX_BAND) + return SUNFALSE; + + /* both matrices must have the same number of columns + (note that we do not check for identical bandwidth) */ + if (SM_ROWS_B(A) != SM_ROWS_B(B)) + return SUNFALSE; + if (SM_COLUMNS_B(A) != SM_COLUMNS_B(B)) + return SUNFALSE; + + return SUNTRUE; +} + + +static booleantype SMCompatible2_Band(SUNMatrix A, N_Vector x, N_Vector y) +{ + /* matrix must be SUNMATRIX_BAND */ + if (SUNMatGetID(A) != SUNMATRIX_BAND) + return SUNFALSE; + + /* 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) ) + 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 */ + + return SUNTRUE; +} + + +int SMScaleAddNew_Band(realtype c, SUNMatrix A, SUNMatrix B) +{ + sunindextype i, j, ml, mu, smu; + realtype *A_colj, *B_colj, *C_colj; + SUNMatrix C; + + /* create new matrix large enough to hold both A and B */ + ml = SUNMAX(SM_LBAND_B(A),SM_LBAND_B(B)); + mu = SUNMAX(SM_UBAND_B(A),SM_UBAND_B(B)); + smu = SUNMIN(SM_COLUMNS_B(A)-1, mu + ml); + C = SUNBandMatrixStorage(SM_COLUMNS_B(A), mu, ml, smu); + + /* scale/add c*A into new matrix */ + for (j=0; j<SM_COLUMNS_B(A); j++) { + A_colj = SM_COLUMN_B(A,j); + C_colj = SM_COLUMN_B(C,j); + for (i=-SM_UBAND_B(A); i<=SM_LBAND_B(A); i++) + C_colj[i] = c*A_colj[i]; + } + + /* add B into new matrix */ + for (j=0; j<SM_COLUMNS_B(B); j++) { + B_colj = SM_COLUMN_B(B,j); + C_colj = SM_COLUMN_B(C,j); + for (i=-SM_UBAND_B(B); i<=SM_LBAND_B(B); i++) + C_colj[i] += B_colj[i]; + } + + /* replace A contents with C contents, nullify C content pointer, destroy C */ + free(SM_DATA_B(A)); SM_DATA_B(A) = NULL; + free(SM_COLS_B(A)); SM_COLS_B(A) = NULL; + free(A->content); A->content = NULL; + A->content = C->content; + C->content = NULL; + SUNMatDestroy_Band(C); + + return 0; +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/dense/fsunmatrix_dense.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/dense/fsunmatrix_dense.c new file mode 100644 index 0000000..219fb5c --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/dense/fsunmatrix_dense.c @@ -0,0 +1,78 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunmatrix_dense.h) contains the + * implementation needed for the Fortran initialization of dense + * vector operations. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fsunmatrix_dense.h" + +/* Define global matrix variables */ + +SUNMatrix F2C_CVODE_matrix; +SUNMatrix F2C_IDA_matrix; +SUNMatrix F2C_KINSOL_matrix; +SUNMatrix F2C_ARKODE_matrix; +SUNMatrix F2C_ARKODE_mass_matrix; + +/* Fortran callable interfaces */ + +void FSUNDENSEMAT_INIT(int *code, long int *M, long int *N, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (F2C_CVODE_matrix) SUNMatDestroy(F2C_CVODE_matrix); + F2C_CVODE_matrix = NULL; + F2C_CVODE_matrix = SUNDenseMatrix(*M, *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); + 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); + 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); + if (F2C_ARKODE_matrix == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + + +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); + if (F2C_ARKODE_mass_matrix == NULL) *ier = -1; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/dense/fsunmatrix_dense.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/dense/fsunmatrix_dense.h new file mode 100644 index 0000000..cf952b4 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/dense/fsunmatrix_dense.h @@ -0,0 +1,62 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunmatrix_dense.c) contains the + * definitions needed for the initialization of dense + * matrix operations in Fortran. + * ----------------------------------------------------------------- + */ + +#ifndef _FSUNMATRIX_DENSE_H +#define _FSUNMATRIX_DENSE_H + +#include <sunmatrix/sunmatrix_dense.h> +#include <sundials/sundials_fnvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +#if defined(SUNDIALS_F77_FUNC) +#define FSUNDENSEMAT_INIT SUNDIALS_F77_FUNC(fsundensematinit, FSUNDENSEMATINIT) +#define FSUNDENSEMASSMAT_INIT SUNDIALS_F77_FUNC(fsundensemassmatinit, FSUNDENSEMASSMATINIT) +#else +#define FSUNDENSEMAT_INIT fsundensematinit_ +#define FSUNDENSEMASSMAT_INIT fsundensemassmatinit_ +#endif + + +/* Declarations of global variables */ + +extern SUNMatrix F2C_CVODE_matrix; +extern SUNMatrix F2C_IDA_matrix; +extern SUNMatrix F2C_KINSOL_matrix; +extern SUNMatrix F2C_ARKODE_matrix; +extern SUNMatrix F2C_ARKODE_mass_matrix; + +/* + * Prototypes of exported functions + * + * FSUNDENSEMAT_INIT - initializes dense matrix operations for main problem + * FSUNDENSEMASSMAT_INIT - initializes dense matrix operations for mass matrix solver + */ + +void FSUNDENSEMAT_INIT(int *code, long int *M, long int *N, int *ier); +void FSUNDENSEMASSMAT_INIT(long int *M, long int *N, int *ier); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/dense/sunmatrix_dense.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/dense/sunmatrix_dense.c new file mode 100644 index 0000000..6494e01 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/dense/sunmatrix_dense.c @@ -0,0 +1,348 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * David Gardner @ LLNL + * 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 + * 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 dense implementation of + * the SUNMATRIX package. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <sunmatrix/sunmatrix_dense.h> +#include <sundials/sundials_math.h> + +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + + +/* Private function prototypes */ +static booleantype SMCompatible_Dense(SUNMatrix A, SUNMatrix B); +static booleantype SMCompatible2_Dense(SUNMatrix A, N_Vector x, N_Vector y); + + +/* + * ----------------------------------------------------------------- + * exported functions + * ----------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------------------- + * Function to create a new dense matrix + */ + +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 */ + A = NULL; + A = (SUNMatrix) malloc(sizeof *A); + 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; + + /* Create content */ + content = NULL; + content = (SUNMatrixContent_Dense) malloc(sizeof(struct _SUNMatrixContent_Dense)); + if (content == NULL) { free(ops); free(A); return(NULL); } + + /* Fill content */ + content->M = M; + content->N = N; + content->ldata = M*N; + content->data = NULL; + content->data = (realtype *) calloc(M * N, sizeof(realtype)); + if (content->data == NULL) { + free(content); free(ops); free(A); return(NULL); + } + content->cols = NULL; + content->cols = (realtype **) malloc(N * sizeof(realtype *)); + if (content->cols == NULL) { + free(content->data); free(content); free(ops); free(A); return(NULL); + } + for (j=0; j<N; j++) content->cols[j] = content->data + j * M; + + /* Attach content and ops */ + A->content = content; + A->ops = ops; + + return(A); +} + + +/* ---------------------------------------------------------------------------- + * Function to print the dense matrix + */ + +void SUNDenseMatrix_Print(SUNMatrix A, FILE* outfile) +{ + sunindextype i, j; + + /* should not be called unless A is a dense matrix; + otherwise return immediately */ + if (SUNMatGetID(A) != SUNMATRIX_DENSE) + return; + + /* perform operation */ + fprintf(outfile,"\n"); + for (i=0; i<SM_ROWS_D(A); i++) { + for (j=0; j<SM_COLUMNS_D(A); j++) { +#if defined(SUNDIALS_EXTENDED_PRECISION) + fprintf(outfile,"%12Lg ", SM_ELEMENT_D(A,i,j)); +#elif defined(SUNDIALS_DOUBLE_PRECISION) + fprintf(outfile,"%12g ", SM_ELEMENT_D(A,i,j)); +#else + fprintf(outfile,"%12g ", SM_ELEMENT_D(A,i,j)); +#endif + } + fprintf(outfile,"\n"); + } + fprintf(outfile,"\n"); + return; +} + + +/* ---------------------------------------------------------------------------- + * Functions to access the contents of the dense matrix structure + */ + +sunindextype SUNDenseMatrix_Rows(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_DENSE) + return SM_ROWS_D(A); + else + return -1; +} + +sunindextype SUNDenseMatrix_Columns(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_DENSE) + return SM_COLUMNS_D(A); + else + return -1; +} + +sunindextype SUNDenseMatrix_LData(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_DENSE) + return SM_LDATA_D(A); + else + return -1; +} + +realtype* SUNDenseMatrix_Data(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_DENSE) + return SM_DATA_D(A); + else + return NULL; +} + +realtype** SUNDenseMatrix_Cols(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_DENSE) + return SM_COLS_D(A); + else + return NULL; +} + +realtype* SUNDenseMatrix_Column(SUNMatrix A, sunindextype j) +{ + if (SUNMatGetID(A) == SUNMATRIX_DENSE) + return SM_COLUMN_D(A,j); + else + return NULL; +} + + +/* + * ----------------------------------------------------------------- + * implementation of matrix operations + * ----------------------------------------------------------------- + */ + +SUNMatrix_ID SUNMatGetID_Dense(SUNMatrix A) +{ + return SUNMATRIX_DENSE; +} + +SUNMatrix SUNMatClone_Dense(SUNMatrix A) +{ + SUNMatrix B = SUNDenseMatrix(SM_ROWS_D(A), SM_COLUMNS_D(A)); + return(B); +} + +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; + free(A); A = NULL; + return; +} + +int SUNMatZero_Dense(SUNMatrix A) +{ + sunindextype i; + realtype *Adata; + + /* Perform operation */ + Adata = SM_DATA_D(A); + for (i=0; i<SM_LDATA_D(A); i++) + Adata[i] = ZERO; + return 0; +} + +int SUNMatCopy_Dense(SUNMatrix A, SUNMatrix B) +{ + sunindextype i, j; + + /* Verify that A and B are compatible */ + if (!SMCompatible_Dense(A, B)) + return 1; + + /* Perform operation */ + for (j=0; j<SM_COLUMNS_D(A); j++) + for (i=0; i<SM_ROWS_D(A); i++) + SM_ELEMENT_D(B,i,j) = SM_ELEMENT_D(A,i,j); + return 0; +} + +int SUNMatScaleAddI_Dense(realtype c, SUNMatrix A) +{ + sunindextype i, j; + + /* Perform operation */ + for (j=0; j<SM_COLUMNS_D(A); j++) + for (i=0; i<SM_ROWS_D(A); i++) { + SM_ELEMENT_D(A,i,j) *= c; + if (i == j) + SM_ELEMENT_D(A,i,j) += ONE; + } + return 0; +} + +int SUNMatScaleAdd_Dense(realtype c, SUNMatrix A, SUNMatrix B) +{ + sunindextype i, j; + + /* Verify that A and B are compatible */ + if (!SMCompatible_Dense(A, B)) + return 1; + + /* Perform operation */ + for (j=0; j<SM_COLUMNS_D(A); j++) + for (i=0; i<SM_ROWS_D(A); i++) + SM_ELEMENT_D(A,i,j) = c*SM_ELEMENT_D(A,i,j) + SM_ELEMENT_D(B,i,j); + return 0; +} + +int SUNMatMatvec_Dense(SUNMatrix A, N_Vector x, N_Vector y) +{ + sunindextype i, j; + realtype *col_j, *xd, *yd; + + /* Verify that A, x and y are compatible */ + if (!SMCompatible2_Dense(A, x, y)) + return 1; + + /* access vector data (return if failure) */ + xd = N_VGetArrayPointer(x); + yd = N_VGetArrayPointer(y); + if ((xd == NULL) || (yd == NULL) || (xd == yd)) + return 1; + + /* Perform operation */ + for (i=0; i<SM_ROWS_D(A); i++) + yd[i] = ZERO; + for(j=0; j<SM_COLUMNS_D(A); j++) { + col_j = SM_COLUMN_D(A,j); + for (i=0; i<SM_ROWS_D(A); i++) + yd[i] += col_j[i]*xd[j]; + } + return 0; +} + +int SUNMatSpace_Dense(SUNMatrix A, long int *lenrw, long int *leniw) +{ + *lenrw = SM_LDATA_D(A); + *leniw = 3 + SM_COLUMNS_D(A); + return 0; +} + + +/* + * ----------------------------------------------------------------- + * private functions + * ----------------------------------------------------------------- + */ + +static booleantype SMCompatible_Dense(SUNMatrix A, SUNMatrix B) +{ + /* both matrices must be SUNMATRIX_DENSE */ + if (SUNMatGetID(A) != SUNMATRIX_DENSE) + return SUNFALSE; + if (SUNMatGetID(B) != SUNMATRIX_DENSE) + return SUNFALSE; + + /* both matrices must have the same shape */ + if (SM_ROWS_D(A) != SM_ROWS_D(B)) + return SUNFALSE; + if (SM_COLUMNS_D(A) != SM_COLUMNS_D(B)) + return SUNFALSE; + + return SUNTRUE; +} + + +static booleantype SMCompatible2_Dense(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) ) + 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 */ + + return SUNTRUE; +} + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/sparse/fsunmatrix_sparse.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/sparse/fsunmatrix_sparse.c new file mode 100644 index 0000000..c9cb092 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/sparse/fsunmatrix_sparse.c @@ -0,0 +1,79 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunmatrix_sparse.h) contains the + * implementation needed for the Fortran initialization of sparse + * vector operations. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "fsunmatrix_sparse.h" + +/* Define global matrix variables */ + +SUNMatrix F2C_CVODE_matrix; +SUNMatrix F2C_IDA_matrix; +SUNMatrix F2C_KINSOL_matrix; +SUNMatrix F2C_ARKODE_matrix; +SUNMatrix F2C_ARKODE_mass_matrix; + +/* Fortran callable interfaces */ + +void FSUNSPARSEMAT_INIT(int *code, long int *M, long int *N, + long int *NNZ, int *sparsetype, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (F2C_CVODE_matrix) SUNMatDestroy(F2C_CVODE_matrix); + F2C_CVODE_matrix = NULL; + F2C_CVODE_matrix = SUNSparseMatrix(*M, *N, *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); + 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); + 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); + if (F2C_ARKODE_matrix == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + +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); + if (F2C_ARKODE_mass_matrix == NULL) *ier = -1; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/sparse/fsunmatrix_sparse.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/sparse/fsunmatrix_sparse.h new file mode 100644 index 0000000..1fbcde6 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/sparse/fsunmatrix_sparse.h @@ -0,0 +1,65 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel 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 (companion of fsunmatrix_sparse.c) contains the + * definitions needed for the initialization of sparse + * matrix operations in Fortran. + * ----------------------------------------------------------------- + */ + +#ifndef _FSUNMATRIX_SPARSE_H +#define _FSUNMATRIX_SPARSE_H + +#include <sunmatrix/sunmatrix_sparse.h> +#include <sundials/sundials_fnvector.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +#if defined(SUNDIALS_F77_FUNC) +#define FSUNSPARSEMAT_INIT SUNDIALS_F77_FUNC(fsunsparsematinit, FSUNSPARSEMATINIT) +#define FSUNSPARSEMASSMAT_INIT SUNDIALS_F77_FUNC(fsunsparsemassmatinit, FSUNSPARSEMASSMATINIT) +#else +#define FSUNSPARSEMAT_INIT fsunsparsematinit_ +#define FSUNSPARSEMASSMAT_INIT fsunsparsemassmatinit_ +#endif + + +/* Declarations of global variables */ + +extern SUNMatrix F2C_CVODE_matrix; +extern SUNMatrix F2C_IDA_matrix; +extern SUNMatrix F2C_KINSOL_matrix; +extern SUNMatrix F2C_ARKODE_matrix; +extern SUNMatrix F2C_ARKODE_mass_matrix; + +/* + * Prototypes of exported functions + * + * FSUNSPARSEMAT_INIT - initializes sparse matrix operations for main problem + * FSUNSPARSEMASSMAT_INIT - initializes sparse matrix operations for mass matrix solve + */ + +void FSUNSPARSEMAT_INIT(int *code, long int *M, long int *N, + long int *NNZ, int *sparsetype, int *ier); + +void FSUNSPARSEMASSMAT_INIT(long int *M, long int *N, + long int *NNZ, int *sparsetype, int *ier); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/sparse/sunmatrix_sparse.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/sparse/sunmatrix_sparse.c new file mode 100644 index 0000000..ee34771 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunmatrix/sparse/sunmatrix_sparse.c @@ -0,0 +1,1132 @@ +/* + * ----------------------------------------------------------------- + * Programmer(s): Daniel Reynolds @ SMU + * David Gardner @ LLNL + * 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 + * 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 sparse implementation of + * the SUNMATRIX package. + * ----------------------------------------------------------------- + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <sunmatrix/sunmatrix_sparse.h> +#include <sundials/sundials_nvector.h> +#include <sundials/sundials_math.h> + +#define ZERO RCONST(0.0) +#define ONE RCONST(1.0) + +/* 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); + +/* + * ----------------------------------------------------------------- + * exported functions + * ----------------------------------------------------------------- + */ + +/* + * ================================================================== + * Private function prototypes (functions working on SlsMat) + * ================================================================== + */ + +/* ---------------------------------------------------------------------------- + * Function to create a new sparse matrix + */ + +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 */ + A = NULL; + A = (SUNMatrix) malloc(sizeof *A); + 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; + + /* Create content */ + content = NULL; + content = (SUNMatrixContent_Sparse) malloc(sizeof(struct _SUNMatrixContent_Sparse)); + if (content == NULL) { free(ops); free(A); return(NULL); } + + /* Fill content */ + content->sparsetype = sparsetype; + content->M = M; + content->N = N; + content->NNZ = NNZ; + switch(sparsetype){ + case CSC_MAT: + content->NP = N; + content->rowvals = &(content->indexvals); + content->colptrs = &(content->indexptrs); + /* CSR indices */ + content->colvals = NULL; + content->rowptrs = NULL; + break; + case CSR_MAT: + content->NP = M; + content->colvals = &(content->indexvals); + content->rowptrs = &(content->indexptrs); + /* CSC indices */ + content->rowvals = NULL; + content->colptrs = NULL; + } + content->data = (realtype *) calloc(NNZ, sizeof(realtype)); + if (content->data == NULL) { + free(content); free(ops); free(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); + } + 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); + } + 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 + * if the request for matrix storage cannot be satisfied. + */ + +SUNMatrix SUNSparseFromDenseMatrix(SUNMatrix Ad, realtype droptol, int sparsetype) +{ + sunindextype i, j, nnz; + sunindextype M, N; + SUNMatrix As; + + /* check for legal sparsetype, droptol and input matrix type */ + if ( (sparsetype != CSR_MAT) && (sparsetype != CSC_MAT) ) + return NULL; + if ( droptol < ZERO ) + return NULL; + if (SUNMatGetID(Ad) != SUNMATRIX_DENSE) + return NULL; + + /* set size of new matrix */ + M = SM_ROWS_D(Ad); + N = SM_COLUMNS_D(Ad); + + /* determine total number of nonzeros */ + nnz = 0; + for (j=0; j<N; j++) + for (i=0; i<M; i++) + nnz += (SUNRabs(SM_ELEMENT_D(Ad,i,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<N; j++) { + (SM_INDEXPTRS_S(As))[j] = nnz; + for (i=0; i<M; i++) { + 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); + } + } + } + (SM_INDEXPTRS_S(As))[N] = nnz; + } else { /* CSR_MAT */ + for (i=0; i<M; i++) { + (SM_INDEXPTRS_S(As))[i] = nnz; + for (j=0; j<N; j++) { + 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); + } + } + } + (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 + * if the request for matrix storage cannot be satisfied. + */ + +SUNMatrix SUNSparseFromBandMatrix(SUNMatrix Ad, realtype droptol, int sparsetype) +{ + sunindextype i, j, nnz; + sunindextype M, N; + SUNMatrix As; + + /* check for legal sparsetype, droptol and input matrix type */ + if ( (sparsetype != CSR_MAT) && (sparsetype != CSC_MAT) ) + return NULL; + if ( droptol < ZERO ) + return NULL; + if (SUNMatGetID(Ad) != SUNMATRIX_BAND) + return NULL; + + /* set size of new matrix */ + M = SM_ROWS_B(Ad); + N = SM_COLUMNS_B(Ad); + + /* determine total number of nonzeros */ + nnz = 0; + for (j=0; j<N; j++) + for (i=SUNMAX(0,j-SM_UBAND_B(Ad)); i<=SUNMIN(M-1,j+SM_LBAND_B(Ad)); i++) + nnz += (SUNRabs(SM_ELEMENT_B(Ad,i,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<N; j++) { + (SM_INDEXPTRS_S(As))[j] = nnz; + for (i=SUNMAX(0,j-SM_UBAND_B(Ad)); i<=SUNMIN(M-1,j+SM_LBAND_B(Ad)); i++) { + 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); + } + } + } + (SM_INDEXPTRS_S(As))[N] = nnz; + } else { /* CSR_MAT */ + for (i=0; i<M; i++) { + (SM_INDEXPTRS_S(As))[i] = nnz; + for (j=SUNMAX(0,i-SM_LBAND_B(Ad)); j<=SUNMIN(N-1,i+SM_UBAND_B(Ad)); j++) { + 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); + } + } + } + (SM_INDEXPTRS_S(As))[M] = nnz; + } + + return(As); +} + + +/* ---------------------------------------------------------------------------- + * Function to reallocate internal sparse matrix storage arrays so that the + * resulting sparse matrix holds indexptrs[NP] 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_Realloc(SUNMatrix A) +{ + sunindextype nzmax; + + /* check for valid matrix type */ + if (SUNMatGetID(A) != SUNMATRIX_SPARSE) + return 1; + + /* get total number of nonzeros (return with failure if illegal) */ + nzmax = (SM_INDEXPTRS_S(A))[SM_NP_S(A)]; + if (nzmax < 0) + return 1; + + /* 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; +} + + +/* ---------------------------------------------------------------------------- + * 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, + * or if nnz is negative) + */ + +int SUNSparseMatrix_Reallocate(SUNMatrix A, sunindextype NNZ) +{ + /* check for valid matrix type */ + if (SUNMatGetID(A) != SUNMATRIX_SPARSE) return 1; + + /* check for valid nnz */ + if (NNZ < 0) return 1; + + /* 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; +} + + +/* ---------------------------------------------------------------------------- + * 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; + otherwise return immediately */ + if (SUNMatGetID(A) != SUNMATRIX_SPARSE) + return; + + /* perform operation */ + if (SM_SPARSETYPE_S(A) == CSC_MAT) { + indexname = (char*) "col"; + matrixtype = (char*) "CSC"; + } else { + indexname = (char*) "row"; + matrixtype = (char*) "CSR"; + } + 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), + matrixtype, (long int) SM_NNZ_S(A)); + for (j=0; j<SM_NP_S(A); j++) { + fprintf(outfile, "%s %ld : locations %ld to %ld\n", indexname, + (long int) j, (long int) (SM_INDEXPTRS_S(A))[j], + (long int) (SM_INDEXPTRS_S(A))[j+1]-1); + fprintf(outfile, " "); + for (i=(SM_INDEXPTRS_S(A))[j]; i<(SM_INDEXPTRS_S(A))[j+1]; i++) { +#if defined(SUNDIALS_EXTENDED_PRECISION) + fprintf(outfile, "%ld: %.32Lg ", (long int) (SM_INDEXVALS_S(A))[i], + (SM_DATA_S(A))[i]); +#elif defined(SUNDIALS_DOUBLE_PRECISION) + fprintf(outfile, "%ld: %.16g ", (long int) (SM_INDEXVALS_S(A))[i], + (SM_DATA_S(A))[i]); +#else + fprintf(outfile, "%ld: %.8g ", (long int) (SM_INDEXVALS_S(A))[i], + (SM_DATA_S(A))[i]); +#endif + } + fprintf(outfile, "\n"); + } + fprintf(outfile, "\n"); + return; +} + + +/* ---------------------------------------------------------------------------- + * Functions to access the contents of the sparse matrix structure + */ + +sunindextype SUNSparseMatrix_Rows(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_SPARSE) + return SM_ROWS_S(A); + else + return -1; +} + +sunindextype SUNSparseMatrix_Columns(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_SPARSE) + return SM_COLUMNS_S(A); + else + return -1; +} + +sunindextype SUNSparseMatrix_NNZ(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_SPARSE) + return SM_NNZ_S(A); + else + return -1; +} + +sunindextype SUNSparseMatrix_NP(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_SPARSE) + return SM_NP_S(A); + else + return -1; +} + +int SUNSparseMatrix_SparseType(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_SPARSE) + return SM_SPARSETYPE_S(A); + else + return -1; +} + +realtype* SUNSparseMatrix_Data(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_SPARSE) + return SM_DATA_S(A); + else + return NULL; +} + +sunindextype* SUNSparseMatrix_IndexValues(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_SPARSE) + return SM_INDEXVALS_S(A); + else + return NULL; +} + +sunindextype* SUNSparseMatrix_IndexPointers(SUNMatrix A) +{ + if (SUNMatGetID(A) == SUNMATRIX_SPARSE) + return SM_INDEXPTRS_S(A); + else + return NULL; +} + + +/* + * ----------------------------------------------------------------- + * implementation of matrix operations + * ----------------------------------------------------------------- + */ + +SUNMatrix_ID SUNMatGetID_Sparse(SUNMatrix A) +{ + return SUNMATRIX_SPARSE; +} + +SUNMatrix SUNMatClone_Sparse(SUNMatrix A) +{ + SUNMatrix B = SUNSparseMatrix(SM_ROWS_S(A), SM_COLUMNS_S(A), + SM_NNZ_S(A), SM_SPARSETYPE_S(A)); + return(B); +} + +void SUNMatDestroy_Sparse(SUNMatrix A) +{ + /* perform operation */ + if (SM_DATA_S(A)) { + free(SM_DATA_S(A)); SM_DATA_S(A) = NULL; + } + 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; + } + 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(A->content); A->content = NULL; + free(A->ops); A->ops = NULL; + free(A); A = NULL; + return; +} + +int SUNMatZero_Sparse(SUNMatrix A) +{ + sunindextype i; + + /* Perform operation */ + for (i=0; i<SM_NNZ_S(A); i++) { + (SM_DATA_S(A))[i] = ZERO; + (SM_INDEXVALS_S(A))[i] = 0; + } + for (i=0; i<SM_NP_S(A); i++) + (SM_INDEXPTRS_S(A))[i] = 0; + (SM_INDEXPTRS_S(A))[SM_NP_S(A)] = 0; + return 0; +} + +int SUNMatCopy_Sparse(SUNMatrix A, SUNMatrix B) +{ + sunindextype i, A_nz; + + /* Verify that A and B are compatible */ + if (!SMCompatible_Sparse(A, B)) + return 1; + + /* Perform operation */ + A_nz = (SM_INDEXPTRS_S(A))[SM_NP_S(A)]; + + /* ensure that B is allocated with at least as + much memory as we have nonzeros in A */ + if (SM_NNZ_S(B) < A_nz) { + SM_INDEXVALS_S(B) = (sunindextype *) realloc(SM_INDEXVALS_S(B), A_nz*sizeof(sunindextype)); + SM_DATA_S(B) = (realtype *) realloc(SM_DATA_S(B), A_nz*sizeof(realtype)); + SM_NNZ_S(B) = A_nz; + } + + /* zero out B so that copy works correctly */ + SUNMatZero_Sparse(B); + + /* copy the data and row indices over */ + for (i=0; i<A_nz; i++){ + (SM_DATA_S(B))[i] = (SM_DATA_S(A))[i]; + (SM_INDEXVALS_S(B))[i] = (SM_INDEXVALS_S(A))[i]; + } + + /* copy the column pointers over */ + for (i=0; i<SM_NP_S(A); i++) { + (SM_INDEXPTRS_S(B))[i] = (SM_INDEXPTRS_S(A))[i]; + } + (SM_INDEXPTRS_S(B))[SM_NP_S(A)] = A_nz; + + return 0; +} + +int SUNMatScaleAddI_Sparse(realtype c, SUNMatrix A) +{ + sunindextype j, i, p, nz, newvals, M, N, cend; + booleantype newmat, found; + sunindextype *w, *Ap, *Ai, *Cp, *Ci; + realtype *x, *Ax, *Cx; + SUNMatrix C; + + /* store shortcuts to matrix dimensions (M is inner dimension, N is outer) */ + if (SM_SPARSETYPE_S(A) == CSC_MAT) { + M = SM_ROWS_S(A); + N = SM_COLUMNS_S(A); + } + else { + M = SM_COLUMNS_S(A); + N = SM_ROWS_S(A); + } + + /* access data arrays from A (return if failure) */ + Ap = Ai = NULL; + Ax = NULL; + if (SM_INDEXPTRS_S(A)) Ap = SM_INDEXPTRS_S(A); + else return (-1); + if (SM_INDEXVALS_S(A)) Ai = SM_INDEXVALS_S(A); + else return (-1); + if (SM_DATA_S(A)) Ax = SM_DATA_S(A); + else return (-1); + + + /* determine if A: contains values on the diagonal (so I can just be added in); + if not, then increment counter for extra storage that should be required. */ + newvals = 0; + for (j=0; j < SUNMIN(M,N); j++) { + /* scan column (row if CSR) of A, searching for diagonal value */ + found = SUNFALSE; + for (i=Ap[j]; i<Ap[j+1]; i++) { + if (Ai[i] == j) { + found = SUNTRUE; + break; + } + } + /* if no diagonal found, increment necessary storage counter */ + if (!found) newvals += 1; + } + + /* If extra nonzeros required, check whether matrix has sufficient storage space + for new nonzero entries (so I can be inserted into existing storage) */ + newmat = SUNFALSE; /* no reallocation needed */ + if (newvals > (SM_NNZ_S(A) - Ap[N])) + newmat = SUNTRUE; + + + /* perform operation based on existing/necessary structure */ + + /* case 1: A already contains a diagonal */ + if (newvals == 0) { + + /* iterate through columns, adding 1.0 to diagonal */ + for (j=0; j < SUNMIN(M,N); j++) + for (i=Ap[j]; i<Ap[j+1]; i++) + if (Ai[i] == j) { + Ax[i] = ONE + c*Ax[i]; + } else { + 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)); + + /* 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 */ + 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<M; i++) { + w[i] = 0; + x[i] = RCONST(0.0); + } + + /* iterate down column (row) of A, collecting nonzeros */ + for (p=Ap[j]; p<cend; p++) { + w[Ai[p]] += 1; /* indicate that row (column) is filled */ + x[Ai[p]] = c*Ax[p]; /* collect/scale value */ + } + + /* add identity to this column (row) */ + if (j < M) { + w[j] += 1; /* indicate that row (column) is filled */ + x[j] += ONE; /* update value */ + } + + /* 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; + Ax[nz] = x[i]; + } + } + + /* 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 { + + /* create work arrays for nonzero indices and values */ + w = (sunindextype *) malloc(M * sizeof(sunindextype)); + x = (realtype *) malloc(M * sizeof(realtype)); + + /* create new matrix for sum */ + C = SUNSparseMatrix(SM_ROWS_S(A), SM_COLUMNS_S(A), + Ap[N] + newvals, + SM_SPARSETYPE_S(A)); + + /* access data from CSR structures (return if failure) */ + Cp = Ci = NULL; + Cx = NULL; + if (SM_INDEXPTRS_S(C)) Cp = SM_INDEXPTRS_S(C); + else return (-1); + if (SM_INDEXVALS_S(C)) Ci = SM_INDEXVALS_S(C); + else return (-1); + if (SM_DATA_S(C)) Cx = SM_DATA_S(C); + else return (-1); + + /* initialize total nonzero count */ + nz = 0; + + /* iterate through columns (rows for CSR) */ + for (j=0; j<N; j++) { + + /* set current column (row) pointer to current # nonzeros */ + Cp[j] = nz; + + /* clear out temporary arrays for this column (row) */ + for (i=0; i<M; i++) { + w[i] = 0; + x[i] = 0.0; + } + + /* iterate down column (along row) of A, collecting nonzeros */ + for (p=Ap[j]; p<Ap[j+1]; p++) { + w[Ai[p]] += 1; /* indicate that row is filled */ + x[Ai[p]] = c*Ax[p]; /* collect/scale value */ + } + + /* add identity to this column (row) */ + if (j < M) { + w[j] += 1; /* indicate that row is filled */ + x[j] += ONE; /* update value */ + } + + /* fill entries of C with this column's (row's) data */ + for (i=0; i<M; i++) { + if ( w[i] > 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 */ + SM_NNZ_S(A) = SM_NNZ_S(C); + + if (SM_DATA_S(A)) + free(SM_DATA_S(A)); + SM_DATA_S(A) = SM_DATA_S(C); + SM_DATA_S(C) = NULL; + + if (SM_INDEXVALS_S(A)) + free(SM_INDEXVALS_S(A)); + SM_INDEXVALS_S(A) = SM_INDEXVALS_S(C); + SM_INDEXVALS_S(C) = NULL; + + if (SM_INDEXPTRS_S(A)) + free(SM_INDEXPTRS_S(A)); + SM_INDEXPTRS_S(A) = SM_INDEXPTRS_S(C); + SM_INDEXPTRS_S(C) = NULL; + + /* clean up */ + SUNMatDestroy_Sparse(C); + free(w); + free(x); + + } + return 0; + +} + +int SUNMatScaleAdd_Sparse(realtype c, SUNMatrix A, SUNMatrix B) +{ + sunindextype j, i, p, nz, newvals, M, N, cend; + booleantype newmat; + sunindextype *w, *Ap, *Ai, *Bp, *Bi, *Cp, *Ci; + realtype *x, *Ax, *Bx, *Cx; + SUNMatrix C; + + /* Verify that A and B are compatible */ + if (!SMCompatible_Sparse(A, B)) + return 1; + + /* store shortcuts to matrix dimensions (M is inner dimension, N is outer) */ + if (SM_SPARSETYPE_S(A) == CSC_MAT) { + M = SM_ROWS_S(A); + N = SM_COLUMNS_S(A); + } + else { + M = SM_COLUMNS_S(A); + N = SM_ROWS_S(A); + } + + /* access data arrays from A and B (return if failure) */ + Ap = Ai = Bp = Bi = NULL; + Ax = Bx = NULL; + if (SM_INDEXPTRS_S(A)) Ap = SM_INDEXPTRS_S(A); + else return(-1); + if (SM_INDEXVALS_S(A)) Ai = SM_INDEXVALS_S(A); + else return(-1); + if (SM_DATA_S(A)) Ax = SM_DATA_S(A); + else return(-1); + if (SM_INDEXPTRS_S(B)) Bp = SM_INDEXPTRS_S(B); + else return(-1); + if (SM_INDEXVALS_S(B)) Bi = SM_INDEXVALS_S(B); + else return(-1); + if (SM_DATA_S(B)) Bx = SM_DATA_S(B); + else return(-1); + + /* create work arrays for row indices and nonzero column values */ + w = (sunindextype *) malloc(M * sizeof(sunindextype)); + x = (realtype *) malloc(M * sizeof(realtype)); + + /* determine if A already contains the sparsity pattern of B */ + newvals = 0; + for (j=0; j<N; j++) { + + /* clear work array */ + for (i=0; i<M; i++) w[i] = 0; + + /* scan column of A, incrementing w by one */ + for (i=Ap[j]; i<Ap[j+1]; i++) + w[Ai[i]] += 1; + + /* scan column of B, decrementing w by one */ + for (i=Bp[j]; i<Bp[j+1]; i++) + w[Bi[i]] -= 1; + + /* if any entry of w is negative, A doesn't contain B's sparsity, + so increment necessary storage counter */ + for (i=0; i<M; i++) + if (w[i] < 0) newvals += 1; + } + + /* If extra nonzeros required, check whether A has sufficient storage space + for new nonzero entries (so B can be inserted into existing storage) */ + newmat = SUNFALSE; /* no reallocation needed */ + if (newvals > (SM_NNZ_S(A) - Ap[N])) + newmat = SUNTRUE; + + /* perform operation based on existing/necessary structure */ + + /* case 1: A already contains sparsity pattern of B */ + if (newvals == 0) { + + /* iterate through columns, adding matrices */ + for (j=0; j<N; j++) { + + /* clear work array */ + for (i=0; i<M; i++) + x[i] = ZERO; + + /* scan column of B, updating work array */ + for (i = Bp[j]; i < Bp[j+1]; i++) + x[Bi[i]] = Bx[i]; + + /* scan column of A, updating array entries appropriately */ + for (i = Ap[j]; i < Ap[j+1]; i++) + Ax[i] = c*Ax[i] + x[Ai[i]]; + + } + + + /* 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 */ + 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<M; i++) { + w[i] = 0; + x[i] = RCONST(0.0); + } + + /* iterate down column (row) of A, collecting nonzeros */ + for (p=Ap[j]; p<cend; p++) { + w[Ai[p]] += 1; /* indicate that row (column) is filled */ + x[Ai[p]] = c*Ax[p]; /* collect/scale value */ + } + + /* iterate down column of B, collecting nonzeros */ + for (p=Bp[j]; p<Bp[j+1]; p++) { + w[Bi[p]] += 1; /* indicate that row is filled */ + x[Bi[p]] += Bx[p]; /* collect value */ + } + + /* 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; + Ax[nz] = x[i]; + } + } + + /* 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)); + + /* access data from CSR structures (return if failure) */ + Cp = Ci = NULL; + Cx = NULL; + if (SM_INDEXPTRS_S(C)) Cp = SM_INDEXPTRS_S(C); + else return(-1); + if (SM_INDEXVALS_S(C)) Ci = SM_INDEXVALS_S(C); + else return(-1); + if (SM_DATA_S(C)) Cx = SM_DATA_S(C); + else return(-1); + + /* initialize total nonzero count */ + nz = 0; + + /* iterate through columns (rows) */ + for (j=0; j<N; j++) { + + /* set current column (row) pointer to current # nonzeros */ + Cp[j] = nz; + + /* clear out temporary arrays for this column (row) */ + for (i=0; i<M; i++) { + w[i] = 0; + x[i] = RCONST(0.0); + } + + /* iterate down column of A, collecting nonzeros */ + for (p=Ap[j]; p<Ap[j+1]; p++) { + w[Ai[p]] += 1; /* indicate that row is filled */ + x[Ai[p]] = c*Ax[p]; /* collect/scale value */ + } + + /* iterate down column of B, collecting nonzeros */ + for (p=Bp[j]; p<Bp[j+1]; p++) { + w[Bi[p]] += 1; /* indicate that row is filled */ + x[Bi[p]] += Bx[p]; /* collect value */ + } + + /* fill entries of C with this column's data */ + for (i=0; i<M; i++) { + if ( w[i] > 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 */ + SM_NNZ_S(A) = SM_NNZ_S(C); + + free(SM_DATA_S(A)); + SM_DATA_S(A) = SM_DATA_S(C); + SM_DATA_S(C) = NULL; + + free(SM_INDEXVALS_S(A)); + SM_INDEXVALS_S(A) = SM_INDEXVALS_S(C); + SM_INDEXVALS_S(C) = NULL; + + free(SM_INDEXPTRS_S(A)); + SM_INDEXPTRS_S(A) = SM_INDEXPTRS_S(C); + SM_INDEXPTRS_S(C) = NULL; + + /* clean up */ + SUNMatDestroy_Sparse(C); + + } + + /* clean up */ + free(w); + free(x); + + /* return success */ + return(0); + +} + +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; + + /* Perform operation */ + if(SM_SPARSETYPE_S(A) == CSC_MAT) + return Matvec_SparseCSC(A, x, y); + else + return Matvec_SparseCSR(A, x, y); +} + +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; +} + + +/* + * ================================================================= + * private functions + * ================================================================= + */ + +/* ----------------------------------------------------------------- + * Function to check compatibility of two sparse SUNMatrix objects + */ + +static booleantype SMCompatible_Sparse(SUNMatrix A, SUNMatrix B) +{ + /* both matrices must be sparse */ + if ( (SUNMatGetID(A) != SUNMATRIX_SPARSE) || + (SUNMatGetID(B) != SUNMATRIX_SPARSE) ) + return SUNFALSE; + + /* both matrices must have the same shape and sparsity type */ + if (SUNSparseMatrix_Rows(A) != SUNSparseMatrix_Rows(B)) + return SUNFALSE; + if (SUNSparseMatrix_Columns(A) != SUNSparseMatrix_Columns(B)) + return SUNFALSE; + if (SM_SPARSETYPE_S(A) != SM_SPARSETYPE_S(B)) + return SUNFALSE; + + return SUNTRUE; +} + + +/* ----------------------------------------------------------------- + * Function to check compatibility of a SUNMatrix object with two + * N_Vectors (A*x = 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) ) + 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 */ + + 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 + * N_Vector object of length M. + * + * 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) +{ + sunindextype i, j; + sunindextype *Ap, *Ai; + realtype *Ax, *xd, *yd; + + /* access data from CSC structure (return if failure) */ + Ap = SM_INDEXPTRS_S(A); + Ai = SM_INDEXVALS_S(A); + Ax = SM_DATA_S(A); + if ((Ap == NULL) || (Ai == NULL) || (Ax == NULL)) + return 1; + + /* access vector data (return if failure) */ + xd = N_VGetArrayPointer(x); + yd = N_VGetArrayPointer(y); + if ((xd == NULL) || (yd == NULL) || (xd == yd) ) + return 1; + + /* initialize result */ + for (i=0; i<SM_ROWS_S(A); i++) + yd[i] = 0.0; + + /* iterate through matrix columns */ + for (j=0; j<SM_COLUMNS_S(A); j++) { + + /* iterate down column of A, performing product */ + for (i=Ap[j]; i<Ap[j+1]; i++) + yd[Ai[i]] += Ax[i]*xd[j]; + + } + + return 0; +} + + +/* ----------------------------------------------------------------- + * Computes y=A*x, where A is a CSR 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). + */ +int Matvec_SparseCSR(SUNMatrix A, N_Vector x, N_Vector y) +{ + sunindextype i, j; + sunindextype *Ap, *Aj; + realtype *Ax, *xd, *yd; + + /* access data from CSR structure (return if failure) */ + Ap = SM_INDEXPTRS_S(A); + Aj = SM_INDEXVALS_S(A); + Ax = SM_DATA_S(A); + if ((Ap == NULL) || (Aj == NULL) || (Ax == NULL)) + return 1; + + /* access vector data (return if failure) */ + xd = N_VGetArrayPointer(x); + yd = N_VGetArrayPointer(y); + if ((xd == NULL) || (yd == NULL) || (xd == yd)) + return 1; + + /* initialize result */ + for (i=0; i<SM_ROWS_S(A); i++) + yd[i] = 0.0; + + /* iterate through matrix rows */ + for (i=0; i<SM_ROWS_S(A); i++) { + + /* iterate along row of A, performing product */ + for (j=Ap[i]; j<Ap[i+1]; j++) + yd[i] += Ax[j]*xd[Aj[j]]; + + } + + return(0); +} + + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/fsunnonlinsol_fixedpoint.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/fsunnonlinsol_fixedpoint.c new file mode 100644 index 0000000..baecfe1 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/fsunnonlinsol_fixedpoint.c @@ -0,0 +1,95 @@ +/* ----------------------------------------------------------------------------- + * Programmer(s): 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 the implementation of functions needed for initialization + * of the SUNNonlinearSolver fixed point module operations in Fortran. + *---------------------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "fsunnonlinsol_fixedpoint.h" + +/* Define global nonlinsol variables */ + +SUNNonlinearSolver F2C_CVODE_nonlinsol; +SUNNonlinearSolver F2C_IDA_nonlinsol; +SUNNonlinearSolver F2C_ARKODE_nonlinsol; + +/* Declarations of external global variables */ + +extern N_Vector F2C_CVODE_vec; +extern N_Vector F2C_IDA_vec; +extern N_Vector F2C_ARKODE_vec; + +/* Fortran callable interfaces */ + +void FSUNFIXEDPOINT_INIT(int *code, int *m, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (F2C_CVODE_nonlinsol) SUNNonlinSolFree(F2C_CVODE_nonlinsol); + F2C_CVODE_nonlinsol = NULL; + F2C_CVODE_nonlinsol = SUNNonlinSol_FixedPoint(F2C_CVODE_vec, *m); + if (F2C_CVODE_nonlinsol == NULL) *ier = -1; + break; + case FCMIX_IDA: + if (F2C_IDA_nonlinsol) SUNNonlinSolFree(F2C_IDA_nonlinsol); + F2C_IDA_nonlinsol = NULL; + F2C_IDA_nonlinsol = SUNNonlinSol_FixedPoint(F2C_IDA_vec, *m); + if (F2C_IDA_nonlinsol == NULL) *ier = -1; + break; + case FCMIX_ARKODE: + if (F2C_ARKODE_nonlinsol) SUNNonlinSolFree(F2C_ARKODE_nonlinsol); + F2C_ARKODE_nonlinsol = NULL; + F2C_ARKODE_nonlinsol = SUNNonlinSol_FixedPoint(F2C_ARKODE_vec, *m); + if (F2C_ARKODE_nonlinsol == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + + +void FSUNFIXEDPOINT_SETMAXITERS(int *code, int *maxiters, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (!F2C_CVODE_nonlinsol) { + *ier = -1; + return; + } + *ier = SUNNonlinSolSetMaxIters(F2C_CVODE_nonlinsol, *maxiters); + break; + case FCMIX_IDA: + if (!F2C_IDA_nonlinsol) { + *ier = -1; + return; + } + *ier = SUNNonlinSolSetMaxIters(F2C_IDA_nonlinsol, *maxiters); + break; + case FCMIX_ARKODE: + if (!F2C_ARKODE_nonlinsol) { + *ier = -1; + return; + } + *ier = SUNNonlinSolSetMaxIters(F2C_ARKODE_nonlinsol, *maxiters); + break; + default: + *ier = -1; + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/fsunnonlinsol_fixedpoint.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/fsunnonlinsol_fixedpoint.h new file mode 100644 index 0000000..8373f00 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/fsunnonlinsol_fixedpoint.h @@ -0,0 +1,56 @@ +/*----------------------------------------------------------------------------- + * Programmer(s): 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 the definitions needed for initialization of the + * SUNNonlinearSolver fixed-point moudule operations in Fortran. + *---------------------------------------------------------------------------*/ + +#ifndef _FSUNNONLINSOL_FIXEDPOINT_H +#define _FSUNNONLINSOL_FIXEDPOINT_H + +#include <sundials/sundials_fnvector.h> /* FCMIX_* solver IDs */ +#include <sunnonlinsol/sunnonlinsol_fixedpoint.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +#if defined(SUNDIALS_F77_FUNC) +#define FSUNFIXEDPOINT_INIT SUNDIALS_F77_FUNC(fsunfixedpointinit, FSUNFIXEDPOINTINIT) +#define FSUNFIXEDPOINT_SETMAXITERS SUNDIALS_F77_FUNC(fsunfixedpointsetmaxiters, FSUNFIXEDPOINTSETMAXITERS) +#else +#define FSUNFIXEDPOINT_INIT fsunfixedpointinit_ +#define FSUNFIXEDPOINT_SETMAXITERS fsunfixedpointsetmaxiters_ +#endif + +/* Declarations of global variables */ + +extern SUNNonlinearSolver F2C_CVODE_nonlinsol; +extern SUNNonlinearSolver F2C_IDA_nonlinsol; +extern SUNNonlinearSolver F2C_ARKODE_nonlinsol; + +/*----------------------------------------------------------------------------- + Prototypes of exported functions + + FSUNFIXEDPOINT_INIT - initializes fixed point nonlinear solver for main problem + FSUNFIXEDPOINT_SETMAXITERS - sets the maximum number of nonlinear iterations + ---------------------------------------------------------------------------*/ + +void FSUNFIXEDPOINT_INIT(int *code, int *m, int *ier); +void FSUNFIXEDPOINT_SETMAXITERS(int *code, int *maxiters, int *ier); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/sunnonlinsol_fixedpoint.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/sunnonlinsol_fixedpoint.c new file mode 100644 index 0000000..a27719e --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/fixedpoint/sunnonlinsol_fixedpoint.c @@ -0,0 +1,660 @@ +/* ----------------------------------------------------------------------------- + * Programmer(s): 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 the SUNNonlinearSolver module + * implementation of the Anderson-accelerated Fixed-Point method. + * ---------------------------------------------------------------------------*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <sunnonlinsol/sunnonlinsol_fixedpoint.h> +#include <sundials/sundials_math.h> +#include <sundials/sundials_nvector_senswrapper.h> + +/* Internal utility routines */ +static int AndersonAccelerate(SUNNonlinearSolver NLS, N_Vector gval, N_Vector x, + N_Vector xold, int iter); + +static int AllocateContent(SUNNonlinearSolver NLS, N_Vector tmpl); +static void FreeContent(SUNNonlinearSolver NLS); + +/* Content structure accessibility macros */ +#define FP_CONTENT(S) ( (SUNNonlinearSolverContent_FixedPoint)(S->content) ) + +/* Constant macros */ +#define ONE RCONST(1.0) +#define ZERO RCONST(0.0) + +/*============================================================================== + Constructor to create a new fixed point solver + ============================================================================*/ + +SUNNonlinearSolver SUNNonlinSol_FixedPoint(N_Vector y, int m) +{ + SUNNonlinearSolver NLS; + SUNNonlinearSolver_Ops ops; + SUNNonlinearSolverContent_FixedPoint content; + int retval; + + /* Check that the supplied N_Vector is non-NULL */ + if (y == NULL) return(NULL); + + /* Check that the supplied N_Vector supports all required operations */ + if ( (y->ops->nvclone == NULL) || + (y->ops->nvdestroy == NULL) || + (y->ops->nvscale == NULL) || + (y->ops->nvlinearsum == NULL) || + (y->ops->nvdotprod == NULL) ) + return(NULL); + + /* Create nonlinear linear solver */ + NLS = NULL; + NLS = (SUNNonlinearSolver) malloc(sizeof *NLS); + 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); } + + /* 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; + + /* Initialize all components of content to 0/NULL */ + memset(content, 0, sizeof(struct _SUNNonlinearSolverContent_FixedPoint)); + + /* Fill general content */ + content->Sys = NULL; + content->CTest = NULL; + content->m = m; + content->curiter = 0; + content->maxiters = 3; + content->niters = 0; + content->nconvfails = 0; + + /* 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); + } + + return(NLS); +} + + +/*============================================================================== + Constructor wrapper to create a new fixed point solver for sensitivity solvers + ============================================================================*/ + +SUNNonlinearSolver SUNNonlinSol_FixedPointSens(int count, N_Vector y, int m) +{ + SUNNonlinearSolver NLS; + N_Vector w; + + /* create sensitivity vector wrapper */ + w = N_VNew_SensWrapper(count, y); + + /* create nonlinear solver using sensitivity vector wrapper */ + NLS = SUNNonlinSol_FixedPoint(w, m); + + /* free sensitivity vector wrapper */ + N_VDestroy(w); + + /* return NLS object */ + return(NLS); +} + + +/*============================================================================== + GetType, Initialize, Setup, Solve, and Free operations + ============================================================================*/ + +SUNNonlinearSolver_Type SUNNonlinSolGetType_FixedPoint(SUNNonlinearSolver NLS) +{ + return(SUNNONLINEARSOLVER_FIXEDPOINT); +} + + +int SUNNonlinSolInitialize_FixedPoint(SUNNonlinearSolver NLS) +{ + /* check that the nonlinear solver is non-null */ + if (NLS == 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); + + /* reset the total number of iterations and convergence failures */ + FP_CONTENT(NLS)->niters = 0; + FP_CONTENT(NLS)->nconvfails = 0; + + return(SUN_NLS_SUCCESS); +} + + +/*----------------------------------------------------------------------------- + SUNNonlinSolSolve_FixedPoint: Performs the fixed-point solve 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 that return values beginning with * are package specific values returned + 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, + booleantype callSetup, void* mem) +{ + /* local variables */ + int retval; + N_Vector yprev, gy, delta; + + /* check that the inputs are non-null */ + if ( (NLS == NULL) || (y0 == NULL) || (y == NULL) || (w == NULL) || (mem == NULL) ) + return(SUN_NLS_MEM_NULL); + + /* set local shortcut variables */ + yprev = FP_CONTENT(NLS)->yprev; + 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. + Performs stopping tests. */ + for( FP_CONTENT(NLS)->curiter = 0; + FP_CONTENT(NLS)->curiter < FP_CONTENT(NLS)->maxiters; + FP_CONTENT(NLS)->curiter++ ) { + + /* update previous solution guess */ + N_VScale(ONE, y, yprev); + + /* compute fixed-point iteration function, store in gy */ + retval = FP_CONTENT(NLS)->Sys(y, 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); + } else { /* Anderson-accelerated solver */ + retval = AndersonAccelerate(NLS, gy, y, 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); + + /* test for convergence */ + retval = FP_CONTENT(NLS)->CTest(NLS, y, delta, tol, w, mem); + + /* return if successful */ + if (retval == SUN_NLS_SUCCESS) return(SUN_NLS_SUCCESS); + + /* check if the iterations should continue; otherwise increment the + convergence failure count and return error flag */ + if (retval != SUN_NLS_CONTINUE) { + FP_CONTENT(NLS)->nconvfails++; + return(retval); + } + + } + + /* if we've reached this point, then we exhausted the iteration limit; + increment the convergence failure count and return */ + FP_CONTENT(NLS)->nconvfails++; + return(SUN_NLS_CONV_RECVR); +} + + +int SUNNonlinSolFree_FixedPoint(SUNNonlinearSolver NLS) +{ + /* return if NLS is already free */ + if (NLS == NULL) return(SUN_NLS_SUCCESS); + + /* free items from content structure, then the structure itself */ + if (NLS->content) { + FreeContent(NLS); + free(NLS->content); + NLS->content = NULL; + } + + /* free the ops structure */ + if (NLS->ops) { + free(NLS->ops); + NLS->ops = NULL; + } + + /* free the overall NLS structure */ + free(NLS); + + return(SUN_NLS_SUCCESS); +} + + +/*============================================================================== + Set functions + ============================================================================*/ + +int SUNNonlinSolSetSysFn_FixedPoint(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); + + FP_CONTENT(NLS)->Sys = SysFn; + return(SUN_NLS_SUCCESS); +} + +int SUNNonlinSolSetConvTestFn_FixedPoint(SUNNonlinearSolver NLS, SUNNonlinSolConvTestFn CTestFn) +{ + /* check that the nonlinear solver is non-null */ + if (NLS == NULL) + return(SUN_NLS_MEM_NULL); + + /* check that the convergence test function is non-null */ + if (CTestFn == NULL) + return(SUN_NLS_ILL_INPUT); + + FP_CONTENT(NLS)->CTest = CTestFn; + return(SUN_NLS_SUCCESS); +} + +int SUNNonlinSolSetMaxIters_FixedPoint(SUNNonlinearSolver NLS, int maxiters) +{ + /* check that the nonlinear solver is non-null */ + if (NLS == NULL) + return(SUN_NLS_MEM_NULL); + + /* check that maxiters is a vaild */ + if (maxiters < 1) + return(SUN_NLS_ILL_INPUT); + + FP_CONTENT(NLS)->maxiters = maxiters; + return(SUN_NLS_SUCCESS); +} + + +/*============================================================================== + Get functions + ============================================================================*/ + +int SUNNonlinSolGetNumIters_FixedPoint(SUNNonlinearSolver NLS, long int *niters) +{ + /* check that the nonlinear solver is non-null */ + if (NLS == NULL) + return(SUN_NLS_MEM_NULL); + + /* return the total number of nonlinear iterations */ + *niters = FP_CONTENT(NLS)->niters; + return(SUN_NLS_SUCCESS); +} + + +int SUNNonlinSolGetCurIter_FixedPoint(SUNNonlinearSolver NLS, int *iter) +{ + /* check that the nonlinear solver is non-null */ + if (NLS == NULL) + return(SUN_NLS_MEM_NULL); + + /* return the current nonlinear solver iteration count */ + *iter = FP_CONTENT(NLS)->curiter; + return(SUN_NLS_SUCCESS); +} + + +int SUNNonlinSolGetNumConvFails_FixedPoint(SUNNonlinearSolver NLS, long int *nconvfails) +{ + /* check that the nonlinear solver is non-null */ + if (NLS == NULL) + return(SUN_NLS_MEM_NULL); + + /* return the total number of nonlinear convergence failures */ + *nconvfails = FP_CONTENT(NLS)->nconvfails; + return(SUN_NLS_SUCCESS); +} + + +int SUNNonlinSolGetSysFn_FixedPoint(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 = FP_CONTENT(NLS)->Sys; + return(SUN_NLS_SUCCESS); +} + + +/*============================================================================= + Utility routines + ===========================================================================*/ + +/*--------------------------------------------------------------- + AndersonAccelerate + + This routine computes the Anderson-accelerated fixed point + iterate. Upon entry, the predicted solution is held in xold; + this array is never changed throughout this routine. + + The result of the routine is held in x. + + Possible return values: + SUN_NLS_MEM_NULL --> a required item was missing from memory + SUN_NLS_SUCCESS --> successful completion + -------------------------------------------------------------*/ +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; + + /* local shortcut variables */ + vtemp = x; /* use result as temporary vector */ + ipt_map = FP_CONTENT(NLS)->imap; + maa = FP_CONTENT(NLS)->m; + gold = FP_CONTENT(NLS)->gold; + fold = FP_CONTENT(NLS)->fold; + df = FP_CONTENT(NLS)->df; + dg = FP_CONTENT(NLS)->dg; + Q = FP_CONTENT(NLS)->q; + cvals = FP_CONTENT(NLS)->cvals; + Xvecs = FP_CONTENT(NLS)->Xvecs; + R = FP_CONTENT(NLS)->R; + gamma = FP_CONTENT(NLS)->gamma; + fv = FP_CONTENT(NLS)->delta; + + /* reset ipt_map, i_pt */ + for (i = 0; i < maa; i++) ipt_map[i]=0; + i_pt = iter-1 - ((iter-1)/maa)*maa; + + /* update dg[i_pt], df[i_pt], fv, gold and fold*/ + N_VLinearSum(ONE, gval, -ONE, xold, fv); + if (iter > 0) { + N_VLinearSum(ONE, gval, -ONE, gold, dg[i_pt]); /* dg_new = gval - gold */ + N_VLinearSum(ONE, fv, -ONE, fold, df[i_pt]); /* df_new = fv - fold */ + } + N_VScale(ONE, gval, gold); + N_VScale(ONE, fv, fold); + + /* on first iteration, just do basic fixed-point update */ + if (iter == 0) { + N_VScale(ONE, gval, x); + return(SUN_NLS_SUCCESS); + } + + /* update data structures based on current iteration index */ + + if (iter == 1) { /* second iteration */ + + R[0] = SUNRsqrt( N_VDotProd(df[i_pt], df[i_pt]) ); + N_VScale(ONE/R[0], df[i_pt], Q[i_pt]); + ipt_map[0] = 0; + + } else if (iter <= maa) { /* another iteration before we've reached maa */ + + N_VScale(ONE, df[i_pt], vtemp); + for (j = 0; j < iter-1; j++) { + ipt_map[j] = j; + R[(iter-1)*maa+j] = N_VDotProd(Q[j], vtemp); + N_VLinearSum(ONE, vtemp, -R[(iter-1)*maa+j], Q[j], vtemp); + } + R[(iter-1)*maa+iter-1] = SUNRsqrt( N_VDotProd(vtemp, vtemp) ); + if (R[(iter-1)*maa+iter-1] == ZERO) { + N_VScale(ZERO, vtemp, Q[i_pt]); + } else { + N_VScale((ONE/R[(iter-1)*maa+iter-1]), vtemp, Q[i_pt]); + } + ipt_map[iter-1] = iter-1; + + } else { /* we've filled the acceleration subspace, so start recycling */ + + /* delete left-most column vector from QR factorization */ + for (i = 0; i < maa-1; i++) { + a = R[(i+1)*maa + i]; + b = R[(i+1)*maa + i+1]; + rtemp = SUNRsqrt(a*a + b*b); + c = a / rtemp; + s = b / rtemp; + R[(i+1)*maa + i] = rtemp; + R[(i+1)*maa + i+1] = 0.0; + if (i < maa-1) { + for (j = i+2; j < maa; j++) { + a = R[j*maa + i]; + b = R[j*maa + i+1]; + rtemp = c * a + s * b; + R[j*maa + i+1] = -s*a + c*b; + R[j*maa + i] = rtemp; + } + } + N_VLinearSum(c, Q[i], s, Q[i+1], vtemp); + N_VLinearSum(-s, Q[i], c, Q[i+1], Q[i+1]); + N_VScale(ONE, vtemp, Q[i]); + } + + /* ahift R to the left by one */ + for (i = 1; i < maa; i++) + for (j = 0; j < maa-1; j++) + R[(i-1)*maa + j] = R[i*maa + j]; + + /* add the new df vector */ + N_VScale(ONE, df[i_pt], vtemp); + for (j = 0; j < maa-1; j++) { + R[(maa-1)*maa+j] = N_VDotProd(Q[j], vtemp); + N_VLinearSum(ONE, vtemp, -R[(maa-1)*maa+j], Q[j], vtemp); + } + R[(maa-1)*maa+maa-1] = SUNRsqrt( N_VDotProd(vtemp, vtemp) ); + N_VScale((ONE/R[(maa-1)*maa+maa-1]), vtemp, Q[maa-1]); + + /* update the iteration map */ + j = 0; + for (i = i_pt+1; i < maa; 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 (maa < iter) lAA = maa; + retval = N_VDotProdMulti(lAA, fv, Q, gamma); + if (retval != 0) return(SUN_NLS_VECTOROP_ERR); + + /* set arrays for fused vector operation */ + cvals[0] = ONE; + Xvecs[0] = gval; + nvec = 1; + for (i = lAA-1; i > -1; i--) { + for (j = i+1; j < lAA; j++) + gamma[i] -= R[j*maa+i]*gamma[j]; + if (gamma[i] == ZERO) { + gamma[i] = ZERO; + } else { + gamma[i] /= R[i*maa+i]; + } + cvals[nvec] = -gamma[i]; + Xvecs[nvec] = dg[ipt_map[i]]; + nvec += 1; + } + + /* update solution */ + retval = N_VLinearCombination(nvec, cvals, Xvecs, x); + if (retval != 0) return(SUN_NLS_VECTOROP_ERR); + + return(SUN_NLS_SUCCESS); +} + +static int AllocateContent(SUNNonlinearSolver NLS, N_Vector y) +{ + int m = FP_CONTENT(NLS)->m; + + FP_CONTENT(NLS)->yprev = N_VClone(y); + if (FP_CONTENT(NLS)->yprev == NULL) { FreeContent(NLS); return(SUN_NLS_MEM_FAIL); } + + FP_CONTENT(NLS)->gy = N_VClone(y); + if (FP_CONTENT(NLS)->gy == NULL) { FreeContent(NLS); return(SUN_NLS_MEM_FAIL); } + + FP_CONTENT(NLS)->delta = N_VClone(y); + if (FP_CONTENT(NLS)->delta == NULL) { FreeContent(NLS); return(SUN_NLS_MEM_FAIL); } + + /* Allocate all m-dependent content */ + if (m > 0) { + + FP_CONTENT(NLS)->fold = N_VClone(y); + if (FP_CONTENT(NLS)->fold == NULL) { + FreeContent(NLS); return(SUN_NLS_MEM_FAIL); } + + FP_CONTENT(NLS)->gold = N_VClone(y); + if (FP_CONTENT(NLS)->gold == NULL) { + FreeContent(NLS); return(SUN_NLS_MEM_FAIL); } + + FP_CONTENT(NLS)->imap = (int *) malloc(m * sizeof(int)); + if (FP_CONTENT(NLS)->imap == NULL) { + FreeContent(NLS); return(SUN_NLS_MEM_FAIL); } + + FP_CONTENT(NLS)->R = (realtype *) malloc((m*m) * sizeof(realtype)); + if (FP_CONTENT(NLS)->R == NULL) { + FreeContent(NLS); return(SUN_NLS_MEM_FAIL); } + + FP_CONTENT(NLS)->gamma = (realtype *) malloc(m * sizeof(realtype)); + if (FP_CONTENT(NLS)->gamma == NULL) { + FreeContent(NLS); return(SUN_NLS_MEM_FAIL); } + + FP_CONTENT(NLS)->cvals = (realtype *) malloc((m+1) * sizeof(realtype)); + if (FP_CONTENT(NLS)->cvals == NULL) { + FreeContent(NLS); return(SUN_NLS_MEM_FAIL); } + + FP_CONTENT(NLS)->df = N_VCloneVectorArray(m, y); + if (FP_CONTENT(NLS)->df == NULL) { + FreeContent(NLS); return(SUN_NLS_MEM_FAIL); } + + FP_CONTENT(NLS)->dg = N_VCloneVectorArray(m, y); + if (FP_CONTENT(NLS)->dg == NULL) { + FreeContent(NLS); return(SUN_NLS_MEM_FAIL); } + + FP_CONTENT(NLS)->q = N_VCloneVectorArray(m, 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)); + if (FP_CONTENT(NLS)->Xvecs == NULL) { + FreeContent(NLS); return(SUN_NLS_MEM_FAIL); } + } + + return(SUN_NLS_SUCCESS); +} + +static void FreeContent(SUNNonlinearSolver NLS) +{ + if (FP_CONTENT(NLS)->yprev) { + N_VDestroy(FP_CONTENT(NLS)->yprev); + FP_CONTENT(NLS)->yprev = NULL; } + + if (FP_CONTENT(NLS)->gy) { + N_VDestroy(FP_CONTENT(NLS)->gy); + FP_CONTENT(NLS)->gy = NULL; } + + if (FP_CONTENT(NLS)->fold) { + N_VDestroy(FP_CONTENT(NLS)->fold); + FP_CONTENT(NLS)->fold = NULL; } + + if (FP_CONTENT(NLS)->gold) { + N_VDestroy(FP_CONTENT(NLS)->gold); + FP_CONTENT(NLS)->gold = NULL; } + + if (FP_CONTENT(NLS)->delta) { + N_VDestroy(FP_CONTENT(NLS)->delta); + FP_CONTENT(NLS)->delta = NULL; } + + if (FP_CONTENT(NLS)->imap) { + free(FP_CONTENT(NLS)->imap); + FP_CONTENT(NLS)->imap = NULL; } + + if (FP_CONTENT(NLS)->R) { + free(FP_CONTENT(NLS)->R); + FP_CONTENT(NLS)->R = NULL; } + + if (FP_CONTENT(NLS)->gamma) { + free(FP_CONTENT(NLS)->gamma); + FP_CONTENT(NLS)->gamma = NULL; } + + if (FP_CONTENT(NLS)->cvals) { + free(FP_CONTENT(NLS)->cvals); + FP_CONTENT(NLS)->cvals = NULL; } + + if (FP_CONTENT(NLS)->df) { + N_VDestroyVectorArray(FP_CONTENT(NLS)->df, FP_CONTENT(NLS)->m); + FP_CONTENT(NLS)->df = NULL; } + + if (FP_CONTENT(NLS)->dg) { + N_VDestroyVectorArray(FP_CONTENT(NLS)->dg, FP_CONTENT(NLS)->m); + FP_CONTENT(NLS)->dg = NULL; } + + if (FP_CONTENT(NLS)->q) { + N_VDestroyVectorArray(FP_CONTENT(NLS)->q, FP_CONTENT(NLS)->m); + FP_CONTENT(NLS)->q = NULL; } + + if (FP_CONTENT(NLS)->Xvecs) { + free(FP_CONTENT(NLS)->Xvecs); + FP_CONTENT(NLS)->Xvecs = NULL; } + + return; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/newton/fsunnonlinsol_newton.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/newton/fsunnonlinsol_newton.c new file mode 100644 index 0000000..dfa9909 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/newton/fsunnonlinsol_newton.c @@ -0,0 +1,95 @@ +/* ----------------------------------------------------------------------------- + * 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 the implementation of functions needed for initialization + * of the SUNNonlinearSolver Newton moudule operations in Fortran. + * ---------------------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "fsunnonlinsol_newton.h" + +/* Define global nonlinsol variables */ + +SUNNonlinearSolver F2C_CVODE_nonlinsol; +SUNNonlinearSolver F2C_IDA_nonlinsol; +SUNNonlinearSolver F2C_ARKODE_nonlinsol; + +/* Declarations of external global variables */ + +extern N_Vector F2C_CVODE_vec; +extern N_Vector F2C_IDA_vec; +extern N_Vector F2C_ARKODE_vec; + +/* Fortran callable interfaces */ + +void FSUNNEWTON_INIT(int *code, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (F2C_CVODE_nonlinsol) SUNNonlinSolFree(F2C_CVODE_nonlinsol); + F2C_CVODE_nonlinsol = NULL; + F2C_CVODE_nonlinsol = SUNNonlinSol_Newton(F2C_CVODE_vec); + if (F2C_CVODE_nonlinsol == NULL) *ier = -1; + break; + case FCMIX_IDA: + if (F2C_IDA_nonlinsol) SUNNonlinSolFree(F2C_IDA_nonlinsol); + F2C_IDA_nonlinsol = NULL; + F2C_IDA_nonlinsol = SUNNonlinSol_Newton(F2C_IDA_vec); + if (F2C_IDA_nonlinsol == NULL) *ier = -1; + break; + case FCMIX_ARKODE: + if (F2C_ARKODE_nonlinsol) SUNNonlinSolFree(F2C_ARKODE_nonlinsol); + F2C_ARKODE_nonlinsol = NULL; + F2C_ARKODE_nonlinsol = SUNNonlinSol_Newton(F2C_ARKODE_vec); + if (F2C_ARKODE_nonlinsol == NULL) *ier = -1; + break; + default: + *ier = -1; + } +} + + +void FSUNNEWTON_SETMAXITERS(int *code, int *maxiters, int *ier) +{ + *ier = 0; + + switch(*code) { + case FCMIX_CVODE: + if (!F2C_CVODE_nonlinsol) { + *ier = -1; + return; + } + *ier = SUNNonlinSolSetMaxIters(F2C_CVODE_nonlinsol, *maxiters); + break; + case FCMIX_IDA: + if (!F2C_IDA_nonlinsol) { + *ier = -1; + return; + } + *ier = SUNNonlinSolSetMaxIters(F2C_IDA_nonlinsol, *maxiters); + break; + case FCMIX_ARKODE: + if (!F2C_ARKODE_nonlinsol) { + *ier = -1; + return; + } + *ier = SUNNonlinSolSetMaxIters(F2C_ARKODE_nonlinsol, *maxiters); + break; + default: + *ier = -1; + } +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/newton/fsunnonlinsol_newton.h b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/newton/fsunnonlinsol_newton.h new file mode 100644 index 0000000..289a525 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/newton/fsunnonlinsol_newton.h @@ -0,0 +1,56 @@ +/* ----------------------------------------------------------------------------- + * 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 the definitions needed for initialization of the + * SUNNonlinearSolver Newton moudule operations in Fortran. + * ---------------------------------------------------------------------------*/ + +#ifndef _FSUNNONLINSOL_NEWTON_H +#define _FSUNNONLINSOL_NEWTON_H + +#include <sundials/sundials_fnvector.h> /* FCMIX_* solver IDs */ +#include <sunnonlinsol/sunnonlinsol_newton.h> + +#ifdef __cplusplus /* wrapper to enable C++ usage */ +extern "C" { +#endif + +#if defined(SUNDIALS_F77_FUNC) +#define FSUNNEWTON_INIT SUNDIALS_F77_FUNC(fsunnewtoninit, FSUNNEWTONINIT) +#define FSUNNEWTON_SETMAXITERS SUNDIALS_F77_FUNC(fsunnewtonsetmaxiters, FSUNNEWTONSETMAXITERS) +#else +#define FSUNNEWTON_INIT fsunnewtoninit_ +#define FSUNNEWTON_SETMAXITERS fsunnewtonsetmaxiters_ +#endif + +/* Declarations of global variables */ + +extern SUNNonlinearSolver F2C_CVODE_nonlinsol; +extern SUNNonlinearSolver F2C_IDA_nonlinsol; +extern SUNNonlinearSolver F2C_ARKODE_nonlinsol; + +/* ----------------------------------------------------------------------------- + * Prototypes of exported functions + * + * FSUNNEWTON_INIT - initializes Newton nonlinear solver for main problem + * FSUNNEWTON_SETMAXITERS - sets the maximum number of nonlinear iterations + * ---------------------------------------------------------------------------*/ + +void FSUNNEWTON_INIT(int *code, int *ier); +void FSUNNEWTON_SETMAXITERS(int *code, int *maxiters, int *ier); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/newton/sunnonlinsol_newton.c b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/newton/sunnonlinsol_newton.c new file mode 100644 index 0000000..677f6ed --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/ThirdParty/sundials/src/sunnonlinsol/newton/sunnonlinsol_newton.c @@ -0,0 +1,453 @@ +/* ----------------------------------------------------------------------------- + * 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 is the implementation file for the SUNNonlinearSolver module + * implementation of Newton's method. + * ---------------------------------------------------------------------------*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <sunnonlinsol/sunnonlinsol_newton.h> +#include <sundials/sundials_math.h> +#include <sundials/sundials_nvector_senswrapper.h> + +/* Content structure accessibility macros */ +#define NEWTON_CONTENT(S) ( (SUNNonlinearSolverContent_Newton)(S->content) ) + +/* Constant macros */ +#define ONE RCONST(1.0) /* real 1.0 */ + +/*============================================================================== + Constructor to create a new Newton solver + ============================================================================*/ + +SUNNonlinearSolver SUNNonlinSol_Newton(N_Vector y) +{ + SUNNonlinearSolver NLS; + SUNNonlinearSolver_Ops ops; + SUNNonlinearSolverContent_Newton content; + + /* Check that the supplied N_Vector is non-NULL */ + if (y == NULL) return(NULL); + + /* Check that the supplied N_Vector supports all required operations */ + if ( (y->ops->nvclone == NULL) || + (y->ops->nvdestroy == NULL) || + (y->ops->nvscale == NULL) || + (y->ops->nvlinearsum == NULL) ) + return(NULL); + + /* Create nonlinear linear solver */ + NLS = NULL; + NLS = (SUNNonlinearSolver) malloc(sizeof *NLS); + 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; + + /* Create content */ + content = NULL; + content = (SUNNonlinearSolverContent_Newton) malloc(sizeof *content); + if (content == NULL) { free(ops); free(NLS); return(NULL); } + + /* Initialize all components of content to 0/NULL */ + memset(content, 0, sizeof(struct _SUNNonlinearSolverContent_Newton)); + + /* Fill 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; + + /* 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; + + return(NLS); +} + + +/*============================================================================== + Constructor wrapper to create a new Newton solver for sensitivity solvers + ============================================================================*/ + +SUNNonlinearSolver SUNNonlinSol_NewtonSens(int count, N_Vector y) +{ + SUNNonlinearSolver NLS; + N_Vector w; + + /* create sensitivity vector wrapper */ + w = N_VNew_SensWrapper(count, y); + + /* create nonlinear solver using sensitivity vector wrapper */ + NLS = SUNNonlinSol_Newton(w); + + /* free sensitivity vector wrapper */ + N_VDestroy(w); + + /* return NLS object */ + return(NLS); +} + + +/*============================================================================== + GetType, Initialize, Setup, Solve, and Free operations + ============================================================================*/ + +SUNNonlinearSolver_Type SUNNonlinSolGetType_Newton(SUNNonlinearSolver NLS) +{ + return(SUNNONLINEARSOLVER_ROOTFIND); +} + + +int SUNNonlinSolInitialize_Newton(SUNNonlinearSolver NLS) +{ + /* check that the nonlinear solver is non-null */ + if (NLS == 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) || + (NEWTON_CONTENT(NLS)->CTest == NULL) ) { + return(SUN_NLS_MEM_NULL); + } + + /* reset the total number of iterations and convergence failures */ + NEWTON_CONTENT(NLS)->niters = 0; + NEWTON_CONTENT(NLS)->nconvfails = 0; + + /* reset the Jacobian status */ + NEWTON_CONTENT(NLS)->jcur = SUNFALSE; + + return(SUN_NLS_SUCCESS); +} + + +/*------------------------------------------------------------------------------ + SUNNonlinSolSolve_Newton: Performs the nonlinear solve F(y) = 0 + + Successful solve return code: + SUN_NLS_SUCCESS = 0 + + Recoverable failure return codes (positive): + SUN_NLS_CONV_RECVR + *_RHSFUNC_RECVR (ODEs) or *_RES_RECVR (DAEs) + *_LSETUP_RECVR + *_LSOLVE_RECVR + + Unrecoverable failure return codes (negative): + *_MEM_NULL + *_RHSFUNC_FAIL (ODEs) or *_RES_FAIL (DAEs) + *_LSETUP_FAIL + *_LSOLVE_FAIL + + Note return values beginning with * are package specific values returned by + the Sys, LSetup, and LSolve functions provided to the nonlinear solver. + ----------------------------------------------------------------------------*/ +int SUNNonlinSolSolve_Newton(SUNNonlinearSolver NLS, + N_Vector y0, N_Vector y, + N_Vector w, realtype tol, + booleantype callLSetup, void* mem) +{ + /* local variables */ + int retval; + booleantype jbad; + N_Vector delta; + + /* check that the inputs are non-null */ + if ( (NLS == NULL) || + (y0 == NULL) || + (y == NULL) || + (w == NULL) || + (mem == NULL) ) + return(SUN_NLS_MEM_NULL); + + /* set local shortcut variables */ + delta = NEWTON_CONTENT(NLS)->delta; + + /* assume the Jacobian is good */ + jbad = SUNFALSE; + + /* looping point for attempts at solution of the nonlinear system: + Evaluate the nonlinear residual function (store in delta) + Setup the linear solver if necessary + Preform Newton iteraion */ + for(;;) { + + /* compute the nonlinear residual, store in delta */ + retval = NEWTON_CONTENT(NLS)->Sys(y0, delta, mem); + if (retval != SUN_NLS_SUCCESS) break; + + /* if indicated, setup the linear system */ + if (callLSetup) { + retval = NEWTON_CONTENT(NLS)->LSetup(y0, delta, jbad, + &(NEWTON_CONTENT(NLS)->jcur), + mem); + if (retval != SUN_NLS_SUCCESS) break; + } + + /* 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(;;) { + + /* increment nonlinear solver iteration counter */ + NEWTON_CONTENT(NLS)->niters++; + + /* compute the negative of the residual for the linear system rhs */ + N_VScale(-ONE, delta, delta); + + /* solve the linear system to get Newton update delta */ + retval = NEWTON_CONTENT(NLS)->LSolve(y, delta, mem); + if (retval != SUN_NLS_SUCCESS) break; + + /* update the Newton iterate */ + N_VLinearSum(ONE, y, ONE, delta, y); + + /* test for convergence */ + retval = NEWTON_CONTENT(NLS)->CTest(NLS, y, delta, tol, w, mem); + + /* if successful update Jacobian status and return */ + if (retval == SUN_NLS_SUCCESS) { + NEWTON_CONTENT(NLS)->jcur = SUNFALSE; + return(SUN_NLS_SUCCESS); + } + + /* check if the iteration should continue; otherwise exit Newton loop */ + if (retval != SUN_NLS_CONTINUE) break; + + /* not yet converged. Increment curiter and test for max allowed. */ + NEWTON_CONTENT(NLS)->curiter++; + if (NEWTON_CONTENT(NLS)->curiter >= NEWTON_CONTENT(NLS)->maxiters) { + retval = SUN_NLS_CONV_RECVR; + break; + } + + /* compute the nonlinear residual, store in delta */ + retval = NEWTON_CONTENT(NLS)->Sys(y, delta, mem); + if (retval != SUN_NLS_SUCCESS) break; + + } /* end of Newton iteration loop */ + + /* 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. */ + if ((retval > 0) && !(NEWTON_CONTENT(NLS)->jcur) && (NEWTON_CONTENT(NLS)->LSetup)) { + NEWTON_CONTENT(NLS)->nconvfails++; + callLSetup = SUNTRUE; + jbad = SUNTRUE; + continue; + } else { + break; + } + + } /* end of setup loop */ + + /* increment number of convergence failures */ + NEWTON_CONTENT(NLS)->nconvfails++; + + /* all error returns exit here */ + return(retval); +} + + +int SUNNonlinSolFree_Newton(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 (NEWTON_CONTENT(NLS)->delta) + N_VDestroy(NEWTON_CONTENT(NLS)->delta); + NEWTON_CONTENT(NLS)->delta = NULL; + + 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 + ============================================================================*/ + +int SUNNonlinSolSetSysFn_Newton(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); + + NEWTON_CONTENT(NLS)->Sys = SysFn; + return(SUN_NLS_SUCCESS); +} + + +int SUNNonlinSolSetLSetupFn_Newton(SUNNonlinearSolver NLS, SUNNonlinSolLSetupFn LSetupFn) +{ + /* check that the nonlinear solver is non-null */ + if (NLS == NULL) + return(SUN_NLS_MEM_NULL); + + NEWTON_CONTENT(NLS)->LSetup = LSetupFn; + return(SUN_NLS_SUCCESS); +} + + +int SUNNonlinSolSetLSolveFn_Newton(SUNNonlinearSolver NLS, SUNNonlinSolLSolveFn LSolveFn) +{ + /* check that the nonlinear solver is non-null */ + if (NLS == NULL) + return(SUN_NLS_MEM_NULL); + + /* check that the linear solver solve function is non-null */ + if (LSolveFn == NULL) + return(SUN_NLS_ILL_INPUT); + + NEWTON_CONTENT(NLS)->LSolve = LSolveFn; + return(SUN_NLS_SUCCESS); +} + + +int SUNNonlinSolSetConvTestFn_Newton(SUNNonlinearSolver NLS, SUNNonlinSolConvTestFn CTestFn) +{ + /* check that the nonlinear solver is non-null */ + if (NLS == NULL) + return(SUN_NLS_MEM_NULL); + + /* check that the convergence test function is non-null */ + if (CTestFn == NULL) + return(SUN_NLS_ILL_INPUT); + + NEWTON_CONTENT(NLS)->CTest = CTestFn; + return(SUN_NLS_SUCCESS); +} + + +int SUNNonlinSolSetMaxIters_Newton(SUNNonlinearSolver NLS, int maxiters) +{ + /* check that the nonlinear solver is non-null */ + if (NLS == NULL) + return(SUN_NLS_MEM_NULL); + + /* check that maxiters is a vaild */ + if (maxiters < 1) + return(SUN_NLS_ILL_INPUT); + + NEWTON_CONTENT(NLS)->maxiters = maxiters; + return(SUN_NLS_SUCCESS); +} + + +/*============================================================================== + Get functions + ============================================================================*/ + +int SUNNonlinSolGetNumIters_Newton(SUNNonlinearSolver NLS, long int *niters) +{ + /* check that the nonlinear solver is non-null */ + if (NLS == NULL) + return(SUN_NLS_MEM_NULL); + + /* return the total number of nonlinear iterations */ + *niters = NEWTON_CONTENT(NLS)->niters; + return(SUN_NLS_SUCCESS); +} + + +int SUNNonlinSolGetCurIter_Newton(SUNNonlinearSolver NLS, int *iter) +{ + /* check that the nonlinear solver is non-null */ + if (NLS == NULL) + return(SUN_NLS_MEM_NULL); + + /* return the current nonlinear solver iteration count */ + *iter = NEWTON_CONTENT(NLS)->curiter; + return(SUN_NLS_SUCCESS); +} + + +int SUNNonlinSolGetNumConvFails_Newton(SUNNonlinearSolver NLS, long int *nconvfails) +{ + /* check that the nonlinear solver is non-null */ + if (NLS == NULL) + return(SUN_NLS_MEM_NULL); + + /* return the total number of nonlinear convergence failures */ + *nconvfails = NEWTON_CONTENT(NLS)->nconvfails; + return(SUN_NLS_SUCCESS); +} + + +int SUNNonlinSolGetSysFn_Newton(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 = NEWTON_CONTENT(NLS)->Sys; + return(SUN_NLS_SUCCESS); +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/abstract_model.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/abstract_model.h new file mode 100644 index 0000000..c6cadc3 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/abstract_model.h @@ -0,0 +1,720 @@ +#ifndef AMICI_ABSTRACT_MODEL_H +#define AMICI_ABSTRACT_MODEL_H + +#include "amici/defines.h" +#include "amici/sundials_matrix_wrapper.h" +#include "amici/vector.h" + +#include <sunmatrix/sunmatrix_band.h> +#include <sunmatrix/sunmatrix_sparse.h> +#include <sunmatrix/sunmatrix_dense.h> + +#include <memory> + +namespace amici { + +class Solver; + +/** + * @brief Abstract base class of amici::Model defining functions that need to + * be implemented in an AMICI model. + * + * Some functions have empty default implementations or throw. + * This class shall not have any data members. + */ +class AbstractModel { + public: + + virtual ~AbstractModel() = default; + + /** + * @brief Retrieves the solver object + * @return The Solver instance + */ + virtual std::unique_ptr<Solver> getSolver() = 0; + + /** + * @brief Root function + * @param t time + * @param x state + * @param dx time derivative of state (DAE only) + * @param root array to which values of the root function will be written + */ + virtual void froot(const realtype t, const AmiVector &x, + const AmiVector &dx, gsl::span<realtype> root) = 0; + + /** + * @brief Residual function + * @param t time + * @param x state + * @param dx time derivative of state (DAE only) + * @param xdot array to which values of the residual function will be + * written + */ + virtual void fxdot(const realtype t, const AmiVector &x, + const AmiVector &dx, AmiVector &xdot) = 0; + + /** + * @brief Sensitivity Residual function + * @param t time + * @param x state + * @param dx time derivative of state (DAE only) + * @param ip parameter index + * @param sx sensitivity state + * @param sdx time derivative of sensitivity state (DAE only) + * @param sxdot array to which values of the sensitivity residual function + * will be written + */ + virtual void fsxdot(const realtype t, const AmiVector &x, + const AmiVector &dx, int ip, const AmiVector &sx, + const AmiVector &sdx, AmiVector &sxdot) = 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 xdot values of residual function (unused) + * @param J dense matrix to which values of the jacobian will be written + */ + virtual void fJ(const realtype t, realtype cj, const AmiVector &x, + 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 xdot values of residual function (unused) + * @param J sparse matrix to which values of the Jacobian will be written + */ + virtual void fJSparse(const realtype t, realtype cj, + const AmiVector &x, const AmiVector &dx, + const AmiVector &xdot, SUNMatrix J) = 0; + + /** + * @brief Diagonal Jacobian function + * @param t time + * @param Jdiag array to which the diagonal of the Jacobian will be written + * @param cj scaling factor (inverse of timestep, DAE only) + * @param x state + * @param dx time derivative of state (DAE only) + */ + virtual void fJDiag(const realtype t, AmiVector &Jdiag, + realtype cj, const AmiVector &x, + const AmiVector &dx) = 0; + + /** + * @brief Parameter derivative of residual function + * @param t time + * @param x state + * @param dx time derivative of state (DAE only) + */ + virtual void fdxdotdp(const realtype t, const AmiVector &x, + const AmiVector &dx) = 0; + + /** + * @brief Jacobian multiply function + * @param t time + * @param x state + * @param dx time derivative of state (DAE only) + * @param xdot values of residual function (unused) + * @param v multiplication vector (unused) + * @param nJv array to which result of multiplication will be written + * @param cj scaling factor (inverse of timestep, DAE only) + */ + virtual void fJv(const realtype t, const AmiVector &x, const AmiVector &dx, + const AmiVector &xdot, const AmiVector &v, AmiVector &nJv, + realtype cj) = 0; + + /** + * @brief Returns the amici version that was used to generate the model + * @return ver amici version string + */ + virtual const std::string getAmiciVersion() const; + + /** + * @brief Returns the amici commit that was used to generate the model + * @return ver amici commit string + */ + virtual const std::string getAmiciCommit() const; + + /** + * @brief Model specific implementation of fx0 + * @param x0 initial state + * @param t initial time + * @param p parameter vector + * @param k constant vector + **/ + virtual void fx0(realtype *x0, const realtype t, const realtype *p, + const realtype *k); + + /** + * @brief Function indicating whether reinitialization of states depending on + * fixed parameters is permissible + * @return flag inidication whether reinitialization of states depending on + * fixed parameters is permissible + */ + virtual bool isFixedParameterStateReinitializationAllowed() const; + + /** + * @brief Model specific implementation of fx0_fixedParameters + * @param x0 initial state + * @param t initial time + * @param p parameter vector + * @param k constant vector + **/ + virtual void fx0_fixedParameters(realtype *x0, const realtype t, + const realtype *p, const realtype *k); + + /** + * @brief Model specific implementation of fsx0_fixedParameters + * @param sx0 initial state sensitivities + * @param t initial time + * @param x0 initial state + * @param p parameter vector + * @param k constant vector + * @param ip sensitivity index + **/ + virtual void fsx0_fixedParameters(realtype *sx0, const realtype t, + const realtype *x0, const realtype *p, + const realtype *k, int ip); + + /** + * @brief Model specific implementation of fsx0 + * @param sx0 initial state sensitivities + * @param t initial time + * @param x0 initial state + * @param p parameter vector + * @param k constant vector + * @param ip sensitivity index + **/ + virtual void fsx0(realtype *sx0, const realtype t, const realtype *x0, + const realtype *p, const realtype *k, int ip); + + /** + * @brief Initial value for time derivative of states (only necessary for DAEs) + * @param x0 Vector with the initial states + * @param dx0 Vector to which the initial derivative states will be + * written (only DAE) + **/ + virtual void fdx0(AmiVector &x0, AmiVector &dx0); + + /** + * @brief Model specific implementation of fstau + * @param stau total derivative of event timepoint + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + * @param sx current state sensitivity + * @param ip sensitivity index + * @param ie event index + **/ + virtual void fstau(realtype *stau, const realtype t, const realtype *x, + const realtype *p, const realtype *k, const realtype *h, + const realtype *sx, int ip, int ie); + + /** + * @brief Model specific implementation of fy + * @param y model output at current timepoint + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + * @param w repeating elements vector + **/ + virtual void fy(realtype *y, const realtype t, const realtype *x, + const realtype *p, const realtype *k, const realtype *h, + const realtype *w); + + /** + * @brief Model specific implementation of fdydp + * @param dydp partial derivative of observables y w.r.t. model parameters p + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + * @param ip parameter index w.r.t. which the derivative is requested + * @param w repeating elements vector + * @param dwdp Recurring terms in xdot, parameter derivative + **/ + virtual void fdydp(realtype *dydp, const realtype t, const realtype *x, + const realtype *p, const realtype *k, const realtype *h, + int ip, const realtype *w, const realtype *dwdp); + + /** + * @brief 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 w repeating elements vector + * @param dwdx Recurring terms in xdot, state derivative + **/ + virtual void fdydx(realtype *dydx, const realtype t, const realtype *x, + const realtype *p, const realtype *k, const realtype *h, + const realtype *w, const realtype *dwdx); + + /** + * @brief Model specific implementation of fz + * @param z value of event output + * @param ie event index + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + **/ + virtual void fz(realtype *z, int ie, const realtype t, + const realtype *x, const realtype *p, const realtype *k, + const realtype *h); + + /** + * @brief Model specific implementation of fsz + * @param sz Sensitivity of rz, total derivative + * @param ie event index + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + * @param sx current state sensitivity + * @param ip sensitivity index + **/ + virtual void fsz(realtype *sz, int ie, const realtype t, + const realtype *x, const realtype *p, const realtype *k, + const realtype *h, const realtype *sx, int ip); + + /** + * @brief Model specific implementation of frz + * @param rz value of root function at current timepoint (non-output events + *not included) + * @param ie event index + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + **/ + virtual void frz(realtype *rz, int ie, const realtype t, + const realtype *x, const realtype *p, const realtype *k, + const realtype *h); + + /** + * @brief Model specific implementation of fsrz + * @param srz Sensitivity of rz, total derivative + * @param ie event index + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param sx current state sensitivity + * @param h heavyside vector + * @param ip sensitivity index + **/ + virtual void fsrz(realtype *srz, int ie, const realtype t, + const realtype *x, const realtype *p, const realtype *k, + const realtype *h, const realtype *sx, int ip); + + /** + * @brief Model specific implementation of fdzdp + * @param dzdp partial derivative of event-resolved output z w.r.t. model + *parameters p + * @param ie event index + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + * @param ip parameter index w.r.t. which the derivative is requested + **/ + virtual void fdzdp(realtype *dzdp, int ie, const realtype t, + const realtype *x, const realtype *p, const realtype *k, + const realtype *h, int ip); + + /** + * @brief Model specific implementation of fdzdx + * @param dzdx partial derivative of event-resolved output z w.r.t. model + *states x + * @param ie event index + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + **/ + virtual void fdzdx(realtype *dzdx, int ie, const realtype t, + const realtype *x, const realtype *p, const realtype *k, + const realtype *h); + + /** + * @brief Model specific implementation of fdrzdp + * @param drzdp partial derivative of root output rz w.r.t. model parameters + *p + * @param ie event index + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + * @param ip parameter index w.r.t. which the derivative is requested + **/ + virtual void fdrzdp(realtype *drzdp, int ie, const realtype t, + const realtype *x, const realtype *p, const realtype *k, + const realtype *h, int ip); + + /** + * @brief Model specific implementation of fdrzdx + * @param drzdx partial derivative of root output rz w.r.t. model states x + * @param ie event index + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + **/ + virtual void fdrzdx(realtype *drzdx, int ie, const realtype t, + const realtype *x, const realtype *p, const realtype *k, + const realtype *h); + + /** + * @brief Model specific implementation of fdeltax + * @param deltax state update + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + * @param ie event index + * @param xdot new model right hand side + * @param xdot_old previous model right hand side + **/ + virtual void fdeltax(realtype *deltax, const realtype t, const realtype *x, + const realtype *p, const realtype *k, + const realtype *h, int ie, const realtype *xdot, + const realtype *xdot_old); + + /** + * @brief Model specific implementation of fdeltasx + * @param deltasx sensitivity update + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + * @param w repeating elements vector + * @param ip sensitivity index + * @param ie event index + * @param xdot new model right hand side + * @param xdot_old previous model right hand side + * @param sx state sensitivity + * @param stau event-time sensitivity + **/ + virtual void fdeltasx(realtype *deltasx, const realtype t, + const realtype *x, const realtype *p, + const realtype *k, const realtype *h, + const realtype *w, int ip, int ie, + const realtype *xdot, const realtype *xdot_old, + const realtype *sx, const realtype *stau); + + /** + * @brief Model specific implementation of fdeltaxB + * @param deltaxB adjoint state update + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + * @param ie event index + * @param xdot new model right hand side + * @param xdot_old previous model right hand side + * @param xB current adjoint state + **/ + virtual void fdeltaxB(realtype *deltaxB, const realtype t, + const realtype *x, const realtype *p, + const realtype *k, const realtype *h, int ie, + const realtype *xdot, const realtype *xdot_old, + const realtype *xB); + + /** + * @brief Model specific implementation of fdeltaqB + * @param deltaqB sensitivity update + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + * @param ip sensitivity index + * @param ie event index + * @param xdot new model right hand side + * @param xdot_old previous model right hand side + * @param xB adjoint state + **/ + virtual void fdeltaqB(realtype *deltaqB, const realtype t, + const realtype *x, const realtype *p, + const realtype *k, const realtype *h, int ip, + int ie, const realtype *xdot, + const realtype *xdot_old, const realtype *xB); + + /** + * @brief Model specific implementation of fsigmay + * @param sigmay standard deviation of measurements + * @param t current time + * @param p parameter vector + * @param k constant vector + **/ + virtual void fsigmay(realtype *sigmay, const realtype t, const realtype *p, + const realtype *k); + + /** + * @brief Model specific implementation of fsigmay + * @param dsigmaydp partial derivative of standard deviation of measurements + * @param t current time + * @param p parameter vector + * @param k constant vector + * @param ip sensitivity index + **/ + virtual void fdsigmaydp(realtype *dsigmaydp, const realtype t, + const realtype *p, const realtype *k, int ip); + + /** + * @brief Model specific implementation of fsigmaz + * @param sigmaz standard deviation of event measurements + * @param t current time + * @param p parameter vector + * @param k constant vector + **/ + virtual void fsigmaz(realtype *sigmaz, const realtype t, const realtype *p, + const realtype *k); + + /** + * @brief Model specific implementation of fsigmaz + * @param dsigmazdp partial derivative of standard deviation of event + *measurements + * @param t current time + * @param p parameter vector + * @param k constant vector + * @param ip sensitivity index + **/ + virtual void fdsigmazdp(realtype *dsigmazdp, const realtype t, + const realtype *p, const realtype *k, int ip); + + /** + * @brief Model specific implementation of fJy + * @param nllh negative log-likelihood for measurements y + * @param iy output index + * @param p parameter vector + * @param k constant vector + * @param y model output at timepoint + * @param sigmay measurement standard deviation at timepoint + * @param my measurements at timepoint + **/ + virtual void fJy(realtype *nllh, int iy, const realtype *p, + const realtype *k, const realtype *y, + const realtype *sigmay, const realtype *my); + + /** + * @brief Model specific implementation of fJz + * @param nllh negative log-likelihood for event measurements z + * @param iz event output index + * @param p parameter vector + * @param k constant vector + * @param z model event output at timepoint + * @param sigmaz event measurement standard deviation at timepoint + * @param mz event measurements at timepoint + **/ + virtual void fJz(realtype *nllh, int iz, const realtype *p, + const realtype *k, const realtype *z, + const realtype *sigmaz, const realtype *mz); + + /** + * @brief Model specific implementation of fJrz + * @param nllh regularization for event measurements z + * @param iz event output index + * @param p parameter vector + * @param k constant vector + * @param z model event output at timepoint + * @param sigmaz event measurement standard deviation at timepoint + **/ + virtual void fJrz(realtype *nllh, int iz, const realtype *p, + const realtype *k, const realtype *z, + const realtype *sigmaz); + + /** + * @brief Model specific implementation of fdJydy + * @param dJydy partial derivative of time-resolved measurement negative + *log-likelihood Jy + * @param iy output index + * @param p parameter vector + * @param k constant vector + * @param y model output at timepoint + * @param sigmay measurement standard deviation at timepoint + * @param my measurement at timepoint + **/ + virtual void fdJydy(realtype *dJydy, int iy, const realtype *p, + const realtype *k, const realtype *y, + const realtype *sigmay, const realtype *my); + + /** + * @brief Model specific implementation of fdJydsigma + * @param dJydsigma Sensitivity of time-resolved measurement + * negative log-likelihood Jy w.r.t. standard deviation sigmay + * @param iy output index + * @param p parameter vector + * @param k constant vector + * @param y model output at timepoint + * @param sigmay measurement standard deviation at timepoint + * @param my measurement at timepoint + **/ + virtual void fdJydsigma(realtype *dJydsigma, int iy, + const realtype *p, const realtype *k, + const realtype *y, const realtype *sigmay, + const realtype *my); + + /** + *@brief Model specific implementation of fdJzdz + * @param dJzdz partial derivative of event measurement negative + *log-likelihood Jz + * @param iz event output index + * @param p parameter vector + * @param k constant vector + * @param z model event output at timepoint + * @param sigmaz event measurement standard deviation at timepoint + * @param mz event measurement at timepoint + **/ + virtual void fdJzdz(realtype *dJzdz, int iz, const realtype *p, + const realtype *k, const realtype *z, + const realtype *sigmaz, const realtype *mz); + + /** + * @brief Model specific implementation of fdJzdsigma + * @param dJzdsigma Sensitivity of event measurement + * negative log-likelihood Jz w.r.t. standard deviation sigmaz + * @param iz event output index + * @param p parameter vector + * @param k constant vector + * @param z model event output at timepoint + * @param sigmaz event measurement standard deviation at timepoint + * @param mz event measurement at timepoint + **/ + virtual void fdJzdsigma(realtype *dJzdsigma, int iz, + const realtype *p, const realtype *k, + const realtype *z, const realtype *sigmaz, + const realtype *mz); + + /** + * @brief Model specific implementation of fdJrzdz + * @param dJrzdz partial derivative of event penalization Jrz + * @param iz event output index + * @param p parameter vector + * @param k constant vector + * @param rz model root output at timepoint + * @param sigmaz event measurement standard deviation at timepoint + **/ + virtual void fdJrzdz(realtype *dJrzdz, int iz, const realtype *p, + const realtype *k, const realtype *rz, + const realtype *sigmaz); + + /** + * @brief Model specific implementation of fdJrzdsigma + * @param dJrzdsigma Sensitivity of event penalization Jrz w.r.t. + * standard deviation sigmaz + * @param iz event output index + * @param p parameter vector + * @param k constant vector + * @param rz model root output at timepoint + * @param sigmaz event measurement standard deviation at timepoint + **/ + virtual void fdJrzdsigma(realtype *dJrzdsigma, int iz, + const realtype *p, const realtype *k, + const realtype *rz, const realtype *sigmaz); + + /** + * @brief Model specific implementation of fw + * @param w Recurring terms in xdot + * @param t timepoint + * @param x vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param tcl total abundances for conservations laws + */ + virtual void fw(realtype *w, const realtype t, const realtype *x, + const realtype *p, const realtype *k, const realtype *h, + const realtype *tcl); + + /** + * @brief Model specific sparse implementation of dwdp + * @param dwdp Recurring terms in xdot, parameter derivative + * @param t timepoint + * @param x vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param w vector with helper variables + * @param tcl total abundances for conservations laws + * @param stcl sensitivities of total abundances for conservations laws + */ + virtual void 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); + + /** + * @brief Model specific sensitivity implementation of dwdp + * @param dwdp Recurring terms in xdot, parameter derivative + * @param t timepoint + * @param x vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param w vector with helper variables + * @param tcl total abundances for conservations laws + * @param stcl sensitivities of total abundances for conservations laws + * @param ip sensitivity parameter index + */ + virtual void 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, int ip); + + /** + * @brief Model specific implementation of dwdx, data part + * @param dwdx Recurring terms in xdot, state derivative + * @param t timepoint + * @param x vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param w vector with helper variables + * @param tcl total abundances for conservations laws + */ + virtual void fdwdx(realtype *dwdx, const realtype t, const realtype *x, + const realtype *p, const realtype *k, const realtype *h, + const realtype *w, const realtype *tcl); + + /** + * @brief Model specific implementation for dwdx, column pointers + * @param indexptrs column pointers + **/ + virtual void fdwdx_colptrs(sunindextype *indexptrs); + + /** + * @brief Model specific implementation for dwdx, row values + * @param indexvals row values + **/ + virtual void fdwdx_rowvals(sunindextype *indexvals); +}; + +} // namespace amici + +#endif // AMICI_ABSTRACT_MODEL_H diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/amici.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/amici.h new file mode 100644 index 0000000..c6aee27 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/amici.h @@ -0,0 +1,79 @@ +#ifndef amici_h +#define amici_h + +#include "amici/cblas.h" +#include "amici/defines.h" +#include "amici/edata.h" +#include "amici/exception.h" +#include "amici/model.h" +#include "amici/rdata.h" +#include "amici/solver.h" +#include "amici/symbolic_functions.h" + +namespace amici { + +/*! + * @brief printErrMsgIdAndTxt prints a specified error message associated to the + * specified identifier + * + * @param[in] identifier error identifier @type char + * @param[in] format string with error message printf-style format + * @param ... arguments to be formatted + */ +void +printErrMsgIdAndTxt(const char* identifier, const char* format, ...); + +/*! + * @brief printErrMsgIdAndTxt prints a specified warning message associated to + * the specified identifier + * + * @param[in] identifier warning identifier @type char + * @param[in] format string with error message printf-style format + * @param ... arguments to be formatted + */ +void +printWarnMsgIdAndTxt(const char* identifier, const char* format, ...); + +/** errMsgIdAndTxt is a function pointer for printErrMsgIdAndTxt */ +extern msgIdAndTxtFp errMsgIdAndTxt; + +/** warnMsgIdAndTxt is a function pointer for printWarnMsgIdAndTxt */ +extern msgIdAndTxtFp warnMsgIdAndTxt; + +/*! + * runAmiciSimulation is the core integration routine. It initializes the solver + * and runs the forward and backward problem. + * + * @param solver Solver instance + * @param edata pointer to experimental data object + * @param model model specification object + * @param rethrow rethrow integration exceptions? + * @return rdata pointer to return data object + */ +std::unique_ptr<ReturnData> +runAmiciSimulation(Solver& solver, + const ExpData* edata, + Model& model, + bool rethrow = false); + +/*! + * runAmiciSimulations does the same as runAmiciSimulation, but for multiple + * ExpData instances. + * + * @param solver Solver instance + * @param edatas experimental data objects + * @param model model specification object + * @param failfast flag to allow early termination + * @param num_threads number of threads for parallel execution + * @return vector of pointers to return data objects + */ +std::vector<std::unique_ptr<ReturnData>> +runAmiciSimulations(Solver const& solver, + const std::vector<ExpData*>& edatas, + Model const& model, + bool failfast, + int num_threads); + +} // namespace amici + +#endif /* amici_h */ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/backwardproblem.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/backwardproblem.h new file mode 100644 index 0000000..fcf4a36 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/backwardproblem.h @@ -0,0 +1,153 @@ +#ifndef AMICI_BACKWARDPROBLEM_H +#define AMICI_BACKWARDPROBLEM_H + +#include "amici/defines.h" +#include "amici/vector.h" + +#include <vector> + +namespace amici { + +class ReturnData; +class ExpData; +class Solver; +class Model; +class ForwardProblem; + +//! class to solve backwards problems. +/*! + solves the backwards problem for adjoint sensitivity analysis and handles + events and data-points +*/ + +class BackwardProblem { + public: + /** + * @brief Construct backward problem from forward problem + * @param fwd pointer to corresponding forward problem + */ + explicit BackwardProblem(const ForwardProblem *fwd); + + /** + * @brief Solve the backward problem. + * + * If adjoint sensitivities are enabled this will also compute + * sensitivities. workForwardProblem must be called before this is + * function is called. + */ + void workBackwardProblem(); + + /** + * @brief Accessor for current time t + * @return t + */ + realtype gett() const { + return t; + } + + /** + * @brief Accessor for which + * @return which + */ + int getwhich() const { + return which; + } + + /** + * @brief Accessor for pointer to which + * @return which + */ + int *getwhichptr() { + return &which; + } + + /** + * @brief Accessor for dJydx + * @return dJydx + */ + std::vector<realtype> const& getdJydx() const { + return dJydx; + } + + 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); + + /** + * @brief Execute everything necessary for the handling of data + * points for the backward problems + * + * @param it index of data point @type int + */ + void handleDataPointB(int it); + + + /** + * @brief Compute the next timepoint to integrate to. + * + * 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<realtype> const& troot, int iroot, int it); + + /** + * @brief Compute likelihood sensitivities. + */ + void computeLikelihoodSensitivities(); + + Model *model; + ReturnData *rdata; + Solver *solver; + + /** current time */ + realtype t; + /** parameter derivative of likelihood array */ + std::vector<realtype> llhS0; + /** adjoint state vector */ + AmiVector xB; + /** differential adjoint state vector */ + AmiVector dxB; + /** quadrature state vector */ + AmiVector xQB; + /** array of state vectors at discontinuities*/ + const AmiVectorArray x_disc; + /** array of differential state vectors at discontinuities*/ + const AmiVectorArray xdot_disc; + /** array of old differential state vectors at discontinuities*/ + const AmiVectorArray xdot_old_disc; + /** sensitivity state vector array */ + AmiVectorArray sx0; + /** array of number of found roots for a certain event type */ + std::vector<int> nroots; + /** array containing the time-points of discontinuities*/ + const std::vector<realtype> discs; + /** array containing the index of discontinuities */ + const std::vector<realtype> irdiscs; + /** 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<int> rootidx; + + /** state derivative of data likelihood */ + const std::vector<realtype> dJydx; + /** state derivative of event likelihood */ + const std::vector<realtype> dJzdx; +}; + +} // namespace amici + +#endif // BACKWARDPROBLEM_H diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/cblas.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/cblas.h new file mode 100644 index 0000000..6aed56b --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/cblas.h @@ -0,0 +1,73 @@ +#ifndef AMICI_CBLAS_H +#define AMICI_CBLAS_H + +#include "amici/defines.h" + +namespace amici { + +/** + * amici_dgemm provides an interface to the CBlas matrix vector multiplication + * routine dgemv. This routines computes + * y = alpha*A*x + beta*y with A: [MxN] x:[Nx1] y:[Mx1] + * + * @param layout always needs to be AMICI_BLAS_ColMajor. + * @param TransA flag indicating whether A should be transposed before + * multiplication + * @param M number of rows in A + * @param N number of columns in A + * @param alpha coefficient alpha + * @param A matrix A + * @param lda leading dimension of A (m or n) + * @param X vector X + * @param incX increment for entries of X + * @param beta coefficient beta + * @param Y vector Y + * @param incY increment for entries of Y + */ +void amici_dgemv(BLASLayout layout, BLASTranspose TransA, + int M, int N, double alpha, const double *A, + int lda, const double *X, int incX, + double beta, double *Y, int incY); + +/** + * amici_dgemm provides an interface to the CBlas matrix matrix multiplication + * routine dgemm. This routines computes + * C = alpha*A*B + beta*C with A: [MxK] B:[KxN] C:[MxN] + * + * @param layout memory layout. + * @param TransA flag indicating whether A should be transposed before + * multiplication + * @param TransB flag indicating whether B should be transposed before + * multiplication + * @param M number of rows in A/C + * @param N number of columns in B/C + * @param K number of rows in B, number of columns in A + * @param alpha coefficient alpha + * @param A matrix A + * @param lda leading dimension of A (m or k) + * @param B matrix B + * @param ldb leading dimension of B (k or n) + * @param beta coefficient beta + * @param C matrix C + * @param ldc leading dimension of C (m or n) + */ +void amici_dgemm(BLASLayout layout, BLASTranspose TransA, + BLASTranspose TransB, int M, int N, + int K, double alpha, const double *A, + int lda, const double *B, int ldb, + double beta, double *C, int ldc); + +/** + * @brief Compute y = a*x + y + * @param n number of elements in y + * @param alpha scalar coefficient of x + * @param x vector of length n*incx + * @param incx x stride + * @param y vector of length n*incy + * @param incy y stride + */ +void amici_daxpy(int n, double alpha, const double *x, int incx, double *y, int incy); + +} // namespace amici + +#endif // AMICI_CBLAS_H diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/defines.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/defines.h new file mode 100644 index 0000000..7482578 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/defines.h @@ -0,0 +1,163 @@ +#ifndef AMICI_DEFINES_H +#define AMICI_DEFINES_H + +#include <cmath> + +namespace amici { + +#define _USE_MATH_DEFINES +#ifdef M_PI +/** pi definition from MATH_DEFINES */ +constexpr double pi = M_PI; +#else +/** MS definition of PI and other constants */ +constexpr double pi = 3.14159265358979323846; +#endif + +// clang-format off + +#define 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 + +#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; + +/** BLAS Matrix Layout, affects dgemm and gemv calls */ +enum class BLASLayout{ + rowMajor = 101, + colMajor = 102 +}; + +/** BLAS Matrix Transposition, affects dgemm and gemv calls */ +enum class BLASTranspose { + noTrans = 111, + trans = 112, + conjTrans = 113 +}; + +/** modes for parameter transformations */ +enum class ParameterScaling { + none, + ln, + log10 +}; + +/** modes for second order sensitivity analysis */ +enum class SecondOrderMode { + none, + full, + directional +}; + +/** orders of sensitivity analysis */ +enum class SensitivityOrder { + none, + first, + second +}; + +/** methods for sensitivity computation */ +enum class SensitivityMethod { + none, + forward, + adjoint +}; + +/** linear solvers for CVODES/IDAS */ +enum class LinearSolver { + dense = 1, + band = 2, + LAPACKDense = 3, + LAPACKBand = 4, + diag = 5, + SPGMR = 6, + SPBCG = 7, + SPTFQMR = 8, + KLU = 9, + SuperLUMT = 10, +}; + +/** CVODES/IDAS forward sensitivity computation method */ +enum class InternalSensitivityMethod { + simultaneous = 1, + staggered = 2, + staggered1 = 3 +}; + +/** CVODES/IDAS state interpolation for adjoint sensitivity analysis */ +enum class InterpolationType { + hermite = 1, + polynomial = 2 +}; + +/** CVODES/IDAS linear multistep method */ +enum class LinearMultistepMethod { + adams = 1, + BDF = 2 +}; + +/** CVODES/IDAS Nonlinear Iteration method */ +enum class NonlinearSolverIteration { + functional = 1, /** deprecated */ + fixedpoint = 1, + newton = 2 +}; + +/** Sensitivity computation mode in steadyStateProblem */ +enum class SteadyStateSensitivityMode { + newtonOnly, + simulationFSA +}; + +/** State in which the steady state computation finished */ +enum class NewtonStatus { + failed=-1, + newt=1, + newt_sim=2, + newt_sim_newt=3, +}; + +/** + * @brief msgIdAndTxtFp + * @param identifier string with error message identifier + * @param format string with error message printf-style format + * @param ... arguments to be formatted + */ +using msgIdAndTxtFp = void (*)(const char *, const char *, ...); + +// clang-format on + +} // namespace amici + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/edata.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/edata.h new file mode 100644 index 0000000..400b57d --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/edata.h @@ -0,0 +1,535 @@ +#ifndef AMICI_EDATA_H +#define AMICI_EDATA_H + +#include "amici/defines.h" +#include "amici/vector.h" + +#include <vector> + +namespace amici { + +class Model; +class ReturnData; + +/** @brief ExpData carries all information about experimental or + * condition-specific data */ +class ExpData { + + public: + /** @brief default constructor */ + ExpData() = default; + + /** @brief Copy constructor, needs to be declared to be generated in + * swig*/ + ExpData(const ExpData &) = default; + + /** + * @brief constructor that only initializes dimensions + * @param nytrue + * @param nztrue + * @param nmaxevent + */ + ExpData(int nytrue, int nztrue, int nmaxevent); + + /** + * @brief constructor that initializes timepoints from vectors + * + * @param nytrue (dimension: scalar) + * @param nztrue (dimension: scalar) + * @param nmaxevent (dimension: scalar) + * @param ts (dimension: nt) + */ + ExpData(int nytrue, int nztrue, int nmaxevent, std::vector<realtype> ts); + + /** + * @brief constructor that initializes timepoints and fixed parameters from + * vectors + * + * @param nytrue (dimension: scalar) + * @param nztrue (dimension: scalar) + * @param nmaxevent (dimension: scalar) + * @param ts (dimension: nt) + * @param fixedParameters (dimension: nk) + */ + ExpData(int nytrue, int nztrue, int nmaxevent, std::vector<realtype> ts, + std::vector<realtype> fixedParameters); + + /** + * @brief constructor that initializes timepoints and data from vectors + * + * @param nytrue (dimension: scalar) + * @param nztrue (dimension: scalar) + * @param nmaxevent (dimension: scalar) + * @param ts (dimension: nt) + * @param observedData (dimension: nt x nytrue, row-major) + * @param observedDataStdDev (dimension: nt x nytrue, row-major) + * @param observedEvents (dimension: nmaxevent x nztrue, row-major) + * @param observedEventsStdDev (dimension: nmaxevent x nztrue, row-major) + */ + ExpData(int nytrue, int nztrue, int nmaxevent, std::vector<realtype> ts, + std::vector<realtype> const &observedData, + std::vector<realtype> const &observedDataStdDev, + std::vector<realtype> const &observedEvents, + std::vector<realtype> const &observedEventsStdDev); + + /** + * @brief constructor that initializes with Model + * + * @param model pointer to model specification object + */ + explicit ExpData(const Model &model); + + /** + * @brief constructor that initializes with returnData, adds noise + * according to specified sigmas + * + * @param rdata return data pointer with stored simulation results + * @param sigma_y scalar standard deviations for all observables + * @param sigma_z scalar standard deviations for all event observables + */ + ExpData(const ReturnData &rdata, realtype sigma_y, realtype sigma_z); + + /** + * @brief constructor that initializes with returnData, adds noise + * according to specified sigmas + * + * @param rdata return data pointer with stored simulation results + * @param sigma_y vector of standard deviations for observables (dimension: + * nytrue or nt x nytrue, row-major) + * @param sigma_z vector of standard deviations for event observables + * (dimension: nztrue or nmaxevent x nztrue, row-major) + */ + ExpData(const ReturnData &rdata, std::vector<realtype> sigma_y, + std::vector<realtype> sigma_z); + + ~ExpData() = default; + + /** + * @brief number of observables of the non-augmented model + * + * @return number of observables of the non-augmented model + */ + int nytrue() const; + + /** + * @brief number of event observables of the non-augmented model + * + * @return number of event observables of the non-augmented model + */ + int nztrue() const; + + /** + * @brief maximal number of events to track + * + * @return maximal number of events to track + */ + int nmaxevent() const; + + /** + * @brief number of timepoints + * + * @return number of timepoints + */ + int nt() const; + + /** + * @brief set function that copies data from input to ExpData::ts + * + * @param ts timepoints + */ + void setTimepoints(const std::vector<realtype> &ts); + + /** + * @brief get function that copies data from ExpData::ts to output + * + * @return ExpData::ts + */ + std::vector<realtype> const &getTimepoints() const; + + /** + * @brief get function that returns timepoint at index + * + * @param it timepoint index + * @return timepoint timepoint at index + */ + realtype getTimepoint(int it) const; + + /** + * @brief set function that copies data from input to ExpData::my + * + * @param observedData observed data (dimension: nt x nytrue, row-major) + */ + void setObservedData(const std::vector<realtype> &observedData); + + /** + * @brief set function that copies observed data for specific observable + * + * @param observedData observed data (dimension: nt) + * @param iy oberved data index + */ + void setObservedData(const std::vector<realtype> &observedData, int iy); + + /** + * @brief get function that checks whether data at specified indices has + * been set + * + * @param it time index + * @param iy observable index + * @return boolean specifying if data was set + */ + bool isSetObservedData(int it, int iy) const; + + /** + * @brief get function that copies data from ExpData::observedData to output + * + * @return observed data (dimension: nt x nytrue, row-major) + */ + std::vector<realtype> const &getObservedData() const; + + /** + * @brief get function that returns a pointer to observed data at index + * + * @param it timepoint index + * @return pointer to observed data at index (dimension: nytrue) + */ + const realtype *getObservedDataPtr(int it) const; + + /** + * @brief set function that copies data from input to + * ExpData::observedDataStdDev + * + * @param observedDataStdDev standard deviation of observed data (dimension: + * nt x nytrue, row-major) + */ + void setObservedDataStdDev(const std::vector<realtype> &observedDataStdDev); + + /** + * @brief set function that sets all ExpData::observedDataStdDev to the + * input value + * + * @param stdDev standard deviation (dimension: scalar) + */ + void setObservedDataStdDev(realtype stdDev); + + /** + * @brief set function that copies standard deviation of observed data for + * specific observable + * + * @param observedDataStdDev standard deviation of observed data (dimension: + * nt) + * @param iy observed data index + */ + void setObservedDataStdDev(const std::vector<realtype> &observedDataStdDev, + int iy); + + /** + * @brief set function that sets all standard deviation of a specific + * observable to the input value + * + * @param stdDev standard deviation (dimension: scalar) + * @param iy observed data index + */ + void setObservedDataStdDev(realtype stdDev, int iy); + + /** + * @brief get function that checks whether standard deviation of data at + * specified indices has been set + * + * @param it time index + * @param iy observable index + * @return boolean specifying if standard deviation of data was set + */ + bool isSetObservedDataStdDev(int it, int iy) const; + + /** + * @brief get function that copies data from ExpData::observedDataStdDev to + * output + * + * @return standard deviation of observed data + */ + std::vector<realtype> const &getObservedDataStdDev() const; + + /** + * @brief get function that returns a pointer to standard deviation of + * observed data at index + * + * @param it timepoint index + * @return pointer to standard deviation of observed data at index + */ + const realtype *getObservedDataStdDevPtr(int it) const; + + /** + * @brief set function that copies observed event data from input to + * ExpData::observedEvents + * + * @param observedEvents observed data (dimension: nmaxevent x nztrue, + * row-major) + */ + void setObservedEvents(const std::vector<realtype> &observedEvents); + + /** + * @brief set function that copies observed event data for specific event + * observable + * + * @param observedEvents observed data (dimension: nmaxevent) + * @param iz observed event data index + */ + void setObservedEvents(const std::vector<realtype> &observedEvents, int iz); + + /** + * @brief get function that checks whether event data at specified indices + * has been set + * + * @param ie event index + * @param iz event observable index + * @return boolean specifying if data was set + */ + bool isSetObservedEvents(int ie, int iz) const; + + /** + * @brief get function that copies data from ExpData::mz to output + * + * @return observed event data + */ + std::vector<realtype> const &getObservedEvents() const; + + /** + * @brief get function that returns a pointer to observed data at ieth + * occurence + * + * @param ie event occurence + * @return pointer to observed event data at ieth occurence + */ + const realtype *getObservedEventsPtr(int ie) const; + + /** + * @brief set function that copies data from input to + * ExpData::observedEventsStdDev + * + * @param observedEventsStdDev standard deviation of observed event data + */ + void + setObservedEventsStdDev(const std::vector<realtype> &observedEventsStdDev); + + /** + * @brief set function that sets all ExpData::observedDataStdDev to the + * input value + * + * @param stdDev standard deviation (dimension: scalar) + */ + void setObservedEventsStdDev(realtype stdDev); + + /** + * @brief set function that copies standard deviation of observed data for + * specific observable + * + * @param observedEventsStdDev standard deviation of observed data + * (dimension: nmaxevent) + * @param iz observed data index + */ + void + setObservedEventsStdDev(const std::vector<realtype> &observedEventsStdDev, + int iz); + + /** + * @brief set function that sets all standard deviation of a specific + * observable to the input value + * + * @param stdDev standard deviation (dimension: scalar) + * @param iz observed data index + */ + void setObservedEventsStdDev(realtype stdDev, int iz); + + /** + * @brief get function that checks whether standard deviation of even data + * at specified indices has been set + * + * @param ie event index + * @param iz event observable index + * @return boolean specifying if standard deviation of event data was set + */ + bool isSetObservedEventsStdDev(int ie, int iz) const; + + /** + * @brief get function that copies data from ExpData::observedEventsStdDev + * to output + * + * @return standard deviation of observed event data + */ + std::vector<realtype> const &getObservedEventsStdDev() const; + + /** + * @brief get function that returns a pointer to standard deviation of + * observed event data at ieth occurence + * + * @param ie event occurence + * @return pointer to standard deviation of observed event data at ieth + * occurence + */ + const realtype *getObservedEventsStdDevPtr(int ie) const; + + /** + * @brief condition-specific fixed parameters of size Model::nk() or empty + */ + std::vector<realtype> fixedParameters; + /** @brief condition-specific fixed parameters for pre-equilibration of size + * Model::nk() or empty. Overrides Solver::newton_preeq + */ + std::vector<realtype> fixedParametersPreequilibration; + /** @brief condition-specific fixed parameters for pre-simulation of + * size Model::nk() or empty. + */ + std::vector<realtype> fixedParametersPresimulation; + + /** @brief condition-specific parameters of size Model::np() or empty */ + std::vector<realtype> parameters; + /** @brief condition-specific initial conditions of size Model::nx() or + * empty + */ + std::vector<realtype> x0; + /** @brief condition-specific initial condition sensitivities of size + * Model::nx() * Model::nplist(), Model::nx() * ExpDataplist.size(), if + * ExpData::plist is not empty, or empty + */ + std::vector<realtype> sx0; + /** @brief condition-specific parameter scales of size Model::np() + */ + std::vector<ParameterScaling> pscale; + /** @brief condition-specific parameter list */ + std::vector<int> plist; + + /** + * @brief duration of pre-simulation + * if this is > 0, presimualation will be performed from + * (model->t0 - t_presim) to model->t0 using the fixedParameters in + * fixedParametersPresimulation + */ + realtype t_presim = 0; + + protected: + /** + * @brief resizes observedData, observedDataStdDev, observedEvents and + * observedEventsStdDev + */ + void applyDimensions(); + + /** + * @brief resizes observedData and observedDataStdDev + */ + void applyDataDimension(); + + /** + * @brief resizes observedEvents and observedEventsStdDev + */ + void applyEventDimension(); + + /** + * @brief checker for dimensions of input observedData or observedDataStdDev + * + * @param input vector input to be checked + * @param fieldname name of the input + */ + void checkDataDimension(std::vector<realtype> const &input, + const char *fieldname) const; + + /** + * @brief checker for dimensions of input observedEvents or + * observedEventsStdDev + * + * @param input vector input to be checkedjupyter_contrib_nbextensions + * @param fieldname name of the input + */ + void checkEventsDimension(std::vector<realtype> const &input, + const char *fieldname) const; + + /** @brief number of observables */ + int nytrue_{0}; + + /** @brief number of event observables */ + int nztrue_{0}; + + /** @brief maximal number of event occurences */ + int nmaxevent_{0}; + + /** @brief observation timepoints (dimension: nt) */ + std::vector<realtype> ts; + + /** @brief observed data (dimension: nt x nytrue, row-major) */ + std::vector<realtype> observedData; + /** @brief standard deviation of observed data (dimension: nt x nytrue, + * row-major) */ + std::vector<realtype> observedDataStdDev; + + /** @brief observed events (dimension: nmaxevents x nztrue, row-major) */ + std::vector<realtype> observedEvents; + /** @brief standard deviation of observed events/roots + * (dimension: nmaxevents x nztrue, row-major) + */ + std::vector<realtype> observedEventsStdDev; +}; + +/** + * @brief checks input vector of sigmas for not strictly positive values + * + * @param sigmaVector vector input to be checked + * @param vectorName name of the input + */ +void checkSigmaPositivity(std::vector<realtype> const &sigmaVector, + const char *vectorName); + +/** + * @brief checks input scalar sigma for not strictly positive value + * + * @param sigma input to be checked + * @param sigmaName name of the input + */ +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 { + public: + /** + * @brief Apply condition-specific settings from edata to model while + * keeping a backup of the original values. + * + * @param model + * @param edata + */ + explicit ConditionContext(Model *model, const ExpData *edata = nullptr); + + ~ConditionContext(); + + /** + * @brief Apply condition-specific settings from edata to the + * constructor-supplied model, not changing the settings which were + * backed-up in the constructor call. + * + * @param edata + */ + void applyCondition(const ExpData *edata); + + /** + * @brief Restore original settings on constructor-supplied amici::Model. + * Will be called during destruction. Explicit call is generally not + * necessary. + */ + void restore(); + + private: + Model *model = nullptr; + std::vector<realtype> originalx0; + std::vector<realtype> originalsx0; + std::vector<realtype> originalParameters; + std::vector<realtype> originalFixedParameters; + std::vector<realtype> originalTimepoints; + std::vector<int> originalParameterList; + std::vector<amici::ParameterScaling> originalScaling; + +}; + +} // namespace amici + +#endif /* AMICI_EDATA_H */ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/exception.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/exception.h new file mode 100644 index 0000000..5417304 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/exception.h @@ -0,0 +1,169 @@ +#ifndef amici_exception_h +#define amici_exception_h + +#include "amici/defines.h" // necessary for realtype + +#include <exception> + +namespace amici { + +/** + * @brief AMICI exception class + * + * Has a printf style interface to allow easy generation of error messages + */ +class AmiException : public std::exception { +public: + /** + * @brief Constructor with printf style interface + * @param fmt error message with printf format + * @param ... printf formating variables + */ + AmiException(char const* fmt, ...); + + /** + * @brief Copy constructor + * @param old object to copy from + */ + AmiException(const AmiException& old); + + /** + * @brief Override of default error message function + * @return msg error message + */ + const char* what() const noexcept override; + + /** + * @brief Returns the stored backtrace + * @return trace backtrace + */ + const char *getBacktrace() const; + + /** + * @brief Stores the current backtrace + * @param nMaxFrames number of frames to go back in stacktrace + */ + void storeBacktrace(int nMaxFrames); + +private: + char msg[500]{}; + char trace[500]{}; +}; + + +/** + * @brief cvode exception handler class + */ +class CvodeException : public AmiException { +public: + /** + * @brief Constructor + * @param error_code error code returned by cvode function + * @param function cvode function name + */ + CvodeException(int error_code, const char *function); +}; + + +/** + * @brief ida exception handler class + */ +class IDAException : public AmiException { +public: + /** + * @brief Constructor + * @param error_code error code returned by ida function + * @param function ida function name + */ + IDAException(int error_code, const char *function); +}; + + +/** + * @brief Integration failure exception for the forward problem + * + * This exception should be thrown when an integration failure occured + * for this exception we can assume that we can recover from the exception + * and return a solution struct to the user + */ +class IntegrationFailure : public AmiException { + public: + /** + * @brief Constructor + * @param code error code returned by cvode/ida + * @param t time of integration failure + */ + IntegrationFailure(int code, realtype t); + + /** error code returned by cvodes/idas */ + int error_code; + + /** time of integration failure */ + realtype time; +}; + + +/** + * @brief Integration failure exception for the backward problem + * + * This exception should be thrown when an integration failure occured + * for this exception we can assume that we can recover from the exception + * and return a solution struct to the user + */ +class IntegrationFailureB : public AmiException { + public: + /** + * @brief Constructor + * @param code error code returned by cvode/ida + * @param t time of integration failure + */ + IntegrationFailureB(int code, realtype t); + + /** error code returned by cvode/ida */ + int error_code; + + /** time of integration failure */ + realtype time; +}; + + +/** + * @brief Setup failure exception + * + * This exception should be thrown when the solver setup failed + * for this exception we can assume that we cannot recover from the exception + * and an error will be thrown + */ +class SetupFailure : public AmiException { +public: + /** + * @brief Constructor, simply calls AmiException constructor + * @param msg + */ + explicit SetupFailure(const char *msg) : AmiException(msg) {} +}; + + +/** + * @brief Newton failure exception + * + * This exception should be thrown when the steady state computation + * failed to converge for this exception we can assume that we can + * recover from the exception and return a solution struct to the user + */ +class NewtonFailure : public AmiException { +public: + /** + * @brief Constructor, simply calls AmiException constructor + * @param function name of the function in which the error occured + * @param code error code + */ + NewtonFailure(int code, const char *function); + + /** error code returned by solver */ + int error_code; +}; + +} // namespace amici + +#endif /* amici_exception_h */ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/forwardproblem.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/forwardproblem.h new file mode 100644 index 0000000..1235141 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/forwardproblem.h @@ -0,0 +1,351 @@ +#ifndef AMICI_FORWARDPROBLEM_H +#define AMICI_FORWARDPROBLEM_H + +#include "amici/defines.h" +#include "amici/vector.h" +#include "amici/sundials_matrix_wrapper.h" + +#include <sundials/sundials_direct.h> +#include <vector> +#include <memory> + +namespace amici { + +class ReturnData; +class ExpData; +class Solver; +class Model; + +/** + * @brief The ForwardProblem class groups all functions for solving the + * forward problem. + */ +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); + + ~ForwardProblem() = default; + + /** + * @brief Solve the forward problem. + * + * If forward sensitivities are enabled this will also compute sensitivies. + */ + void workForwardProblem(); + + /** + * @brief Accessor for t + * @return t + */ + realtype getTime() const { + return t; + } + + /** + * @brief Accessor for sx + * @return sx + */ + AmiVectorArray const& getStateSensitivity() const { + return sx; + } + + /** + * @brief Accessor for x_disc + * @return x_disc + */ + AmiVectorArray const& getStatesAtDiscontinuities() const { + return x_disc; + } + + /** + * @brief Accessor for xdot_disc + * @return xdot_disc + */ + AmiVectorArray const& getRHSAtDiscontinuities() const { + return xdot_disc; + } + + /** + * @brief Accessor for xdot_old_disc + * @return xdot_old_disc + */ + AmiVectorArray const& getRHSBeforeDiscontinuities() const { + return xdot_old_disc; + } + + /** + * @brief Accessor for nroots + * @return nroots + */ + std::vector<int> const& getNumberOfRoots() const { + return nroots; + } + + /** + * @brief Accessor for discs + * @return discs + */ + std::vector<realtype> const& getDiscontinuities() const { + return discs; + } + + /** + * @brief Accessor for rootidx + * @return rootidx + */ + std::vector<int> const& getRootIndexes() const { + return rootidx; + } + + /** + * @brief Accessor for dJydx + * @return dJydx + */ + std::vector<realtype> const& getDJydx() const { + return dJydx; + } + + /** + * @brief Accessor for dJzdx + * @return dJzdx + */ + std::vector<realtype> const& getDJzdx() const { + return dJzdx; + } + + /** + * @brief Accessor for iroot + * @return iroot + */ + int getRootCounter() const { + return iroot; + } + + /** + * @brief Accessor for pointer to x + * @return &x + */ + AmiVector *getStatePointer() { + return &x; + } + + /** + * @brief Accessor for pointer to dx + * @return &dx + */ + AmiVector *getStateDerivativePointer() { + return &dx; + } + + /** + * @brief accessor for pointer to sx + * @return &sx + */ + AmiVectorArray *getStateSensitivityPointer() { + return &sx; + } + + /** + * @brief Accessor for pointer to sdx + * @return &sdx + */ + AmiVectorArray *getStateDerivativeSensitivityPointer() { + return &sdx; + } + + /** 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(); + + /** + * @brief Execute everything necessary for the handling of events + * + * @param tlastroot pointer to the timepoint of the last event + */ + + 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); + + /** + * @brief Execute everything necessary for the handling of data points + * + * @param it index of data point + */ + void handleDataPoint(int it); + + /** + * @brief Extracts output information for data-points + * + * @param it index of current timepoint + */ + void getDataOutput(int it); + + /** + * @brief Extracts data information for forward sensitivity analysis + * + * @param it index of current timepoint + */ + void getDataSensisFSA(int it); + + /** + * @brief Applies the event bolus to the current state + * + * @param model pointer to model specification object + */ + void applyEventBolus(); + + /** + * @brief Applies the event bolus to the current sensitivities + */ + void applyEventSensiBolusFSA(); + + /** array of index which root has been found + * (dimension: ne * ne * nmaxevent, ordering = ?) */ + std::vector<int> rootidx; + + /** array of number of found roots for a certain event type + * (dimension: ne) */ + std::vector<int> nroots; + + /** array of values of the root function (dimension: ne) */ + std::vector<realtype> rootvals; + + /** temporary rootval storage to check crossing in secondary event + * (dimension: ne) */ + std::vector<realtype> rvaltmp; + + /** array containing the time-points of discontinuities + * (dimension: nmaxevent x ne, ordering = ?) */ + std::vector<realtype> discs; + + /** array containing the index of discontinuities + * (dimension: nmaxevent x ne, ordering = ?) */ + std::vector<realtype> irdiscs; + + /** current root index, will be increased during the forward solve and + * decreased during backward solve */ + int iroot = 0; + + /** array of state vectors at discontinuities + * (dimension nx x nMaxEvent * ne, ordering =?) */ + AmiVectorArray x_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; + + /** state derivative of data likelihood + * (dimension nJ x nx x nt, ordering =?) */ + std::vector<realtype> dJydx; + + /** state derivative of event likelihood + * (dimension nJ x nx x nMaxEvent, ordering =?) */ + std::vector<realtype> dJzdx; + + /** current time */ + realtype t; + + /** + * @brief Array of flags indicating which root has beend found. + * + * Array of length nr (ne) with the indices of the user functions gi found + * to have a root. For i = 0, . . . ,nr 1 if gi has a root, and = 0 if not. + */ + std::vector<int> rootsfound; + + /** temporary storage of Jacobian, kept here to avoid reallocation + * (dimension: nx x nx, col-major) */ + SUNMatrixWrapper Jtmp; + + /** 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; + + /** differential state vector (dimension: nx_solver) */ + AmiVector dx; + + /** old differential state vector (dimension: nx_solver) */ + AmiVector dx_old; + + /** time derivative state vector (dimension: nx_solver) */ + AmiVector xdot; + + /** old time derivative state vector (dimension: nx_solver) */ + AmiVector xdot_old; + + /** 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<realtype> stau; + + /** storage for last found root */ + realtype tlastroot = 0.0; + +}; + + +} // namespace amici + +#endif // FORWARDPROBLEM_H diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/hdf5.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/hdf5.h new file mode 100644 index 0000000..49f27f8 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/hdf5.h @@ -0,0 +1,213 @@ +#ifndef AMICI_HDF5_H +#define AMICI_HDF5_H + +#include <string> +#include <memory> +#include <vector> + +#include <H5Cpp.h> + +#include <gsl/gsl-lite.hpp> + +#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 + * within the same context, otherwise the stack handler is lost. */ +#define AMICI_H5_SAVE_ERROR_HANDLER \ + herr_t (*old_func)(void *); \ + void *old_client_data; \ + H5Eget_auto1(&old_func, &old_client_data); \ + H5Eset_auto1(NULL, NULL) + +#define AMICI_H5_RESTORE_ERROR_HANDLER H5Eset_auto1(old_func, old_client_data) + +namespace amici { + +class ReturnData; +class ExpData; +class Model; +class Solver; + +namespace hdf5 { + + +/* Functions for reading and writing AMICI data to/from HDF5 files. */ + +/** + * @brief Open the given file for writing. Append if exists, create if not. + * @param hdf5filename + * @return + */ +H5::H5File createOrOpenForWriting(std::string const& hdf5filename); + +/** + * @brief Read solver options from HDF5 file + * @param fileId hdf5 file handle to read from + * @param solver solver to set options on + * @param datasetPath Path inside the HDF5 file + */ +void readSolverSettingsFromHDF5(const H5::H5File &file, Solver& solver, + std::string const& datasetPath); + +/** + * @brief Read solver options from HDF5 file + * @param hdffile Name of HDF5 file + * @param solver solver to set options on + * @param datasetPath Path inside the HDF5 file + */ +void readSolverSettingsFromHDF5(std::string const& hdffile, Solver& solver, + std::string const& datasetPath); + +/** + * @brief Read model data from HDF5 file + * @param hdffile Name of HDF5 file + * @param model model to set data on + * @param datasetPath Path inside the HDF5 file + */ +void readModelDataFromHDF5(std::string const& hdffile, Model& model, + std::string const& datasetPath); + +/** + * @brief Read model data from HDF5 file + * @param fileId hdf5 file handle to read from + * @param model model to set data on + * @param datasetPath Path inside the HDF5 file + */ +void readModelDataFromHDF5(H5::H5File const&file, Model& model, + std::string const& datasetPath); + + +/** + * @brief Write ReturnData struct to HDF5 dataset + * @param rdata Data to write + * @param hdffile Filename of HDF5 file + * @param datasetPath Full dataset path inside the HDF5 file (will be created) + */ + +void writeReturnData(const ReturnData &rdata, + H5::H5File const& file, + const std::string& hdf5Location); + +void writeReturnData(const ReturnData &rdata, + std::string const& hdf5Filename, + const std::string& hdf5Location); + +void writeReturnDataDiagnosis(const ReturnData &rdata, + H5::H5File const& file, + const std::string& hdf5Location); + +/** + * @brief Create the given group and possibly parents + * @param file + * @param groupPath + * @param recursively + */ +void createGroup(const H5::H5File &file, + std::string const& groupPath, + bool recursively = true); + +/** + * @brief readSimulationExpData reads AMICI experimental data from + * attributes in HDF5 file. + * @param hdf5Filename Name of HDF5 file + * @param hdf5Root Path inside the HDF5 file to object having ExpData as + * attributes + * @param model The model for which data is to be read + * @return + */ + +std::unique_ptr<ExpData> readSimulationExpData(const std::string &hdf5Filename, + const std::string &hdf5Root, + const Model &model); + +/** + * @brief writeSimulationExpData writes AMICI experimental data to + * attributes in HDF5 file. + * @param edata The experimental data which is to be written + * @param hdf5Filename Name of HDF5 file + * @param hdf5Root Path inside the HDF5 file to object having ExpData as + * attributes + */ + +void writeSimulationExpData(const ExpData &edata, + H5::H5File const& file, + const std::string &hdf5Location); + +/** + * @brief attributeExists Check whether an attribute with the given + * name exists on the given dataset + * @param fileId The HDF5 file object + * @param datasetPath Dataset of which attributes should be checked + * @param attributeName Name of the attribute of interest + * @return + */ +bool attributeExists(H5::H5File const& file, + const std::string &optionsObject, + const std::string &attributeName); + +bool attributeExists(H5::H5Object const& object, + const std::string &attributeName); + + +void createAndWriteInt1DDataset(H5::H5File const& file, + std::string const& datasetName, + gsl::span<const int> buffer); + +void createAndWriteInt2DDataset(H5::H5File const& file, + std::string const& datasetName, + gsl::span<const int> buffer, hsize_t m, + hsize_t n); + +void createAndWriteDouble1DDataset(H5::H5File const& file, + std::string const& datasetName, + gsl::span<const double> buffer); + +void createAndWriteDouble2DDataset(H5::H5File const& file, + std::string const& datasetName, + gsl::span<const double> buffer, hsize_t m, + hsize_t n); + +void createAndWriteDouble3DDataset(H5::H5File const& file, + std::string const& datasetName, + gsl::span<const double> buffer, hsize_t m, + hsize_t n, hsize_t o); + +double getDoubleScalarAttribute(const H5::H5File& file, + const std::string &optionsObject, + const std::string &attributeName); + +int getIntScalarAttribute(const H5::H5File &file, + const std::string &optionsObject, + const std::string &attributeName); + + +std::vector<int> getIntDataset1D(const H5::H5File &file, + std::string const& name); + +std::vector<double> getDoubleDataset1D(const H5::H5File &file, + std::string const& name); + +std::vector<double> getDoubleDataset2D(const H5::H5File &file, + std::string const& name, + hsize_t &m, hsize_t &n); + +std::vector<double> getDoubleDataset3D(const H5::H5File &file, + std::string const& name, + hsize_t &m, hsize_t &n, hsize_t &o); + +/** + * @brief Check if the given location (group, link or dataset) exists in the + * given file + * @param filename + * @param location + * @return + */ +bool locationExists(std::string const& filename, std::string const& location); + +bool locationExists(H5::H5File const& file, std::string const& location); + +} // namespace hdf5 +} // namespace amici + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/interface_matlab.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/interface_matlab.h new file mode 100644 index 0000000..edb6b78 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/interface_matlab.h @@ -0,0 +1,68 @@ +#ifndef AMICI_INTERFACE_MATLAB_H +#define AMICI_INTERFACE_MATLAB_H + +#include "amici/amici.h" + +#include <mex.h> +#include <memory> + +class Model; +extern std::unique_ptr<amici::Model> getModel(); + +namespace amici { + +class ReturnDataMatlab; + + +/** + * @brief setModelData sets data from the matlab call to the model object + * @param prhs: pointer to the array of input arguments @type mxArray + * @param nrhs: number of elements in prhs + * @param model: model to update + */ +void setModelData(const mxArray *prhs[], int nrhs, Model& model); + +/** + * @brief setSolverOptions solver options from the matlab call to a solver + * object + * @param prhs: pointer to the array of input arguments @type mxArray + * @param nrhs: number of elements in prhs + * @param solver: solver to update + */ +void setSolverOptions(const mxArray *prhs[], int nrhs, Solver& solver); + +/** + * @brief setupReturnData initialises the return data struct + * @param plhs user input @type mxArray + * @param nlhs number of elements in plhs @type mxArray + * @return rdata: return data struct @type *ReturnData + */ +ReturnDataMatlab *setupReturnData(mxArray *plhs[], int nlhs); + + +/*! + * @brief expDataFromMatlabCall parses the experimental data from the matlab + * call and writes it to an ExpData class object + * + * @param prhs pointer to the array of input arguments + * @param model pointer to the model object, this is necessary to perform + * dimension checks @type *mxArray + * @return edata pointer to experimental data object @type *ExpData + */ +std::unique_ptr<ExpData> expDataFromMatlabCall(const mxArray *prhs[], + const Model &model); + +void amici_dgemv(BLASLayout layout, BLASTranspose TransA, + const int M, const int N, const double alpha, const double *A, + const int lda, const double *X, const int incX, + const double beta, double *Y, const int incY); + +void amici_dgemm(BLASLayout layout, BLASTranspose TransA, + BLASTranspose TransB, const int M, const int N, + const int K, const double alpha, const double *A, + const int lda, const double *B, const int ldb, + const double beta, double *C, const int ldc); + +} // namespace amici + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/misc.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/misc.h new file mode 100644 index 0000000..8b6a20c --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/misc.h @@ -0,0 +1,102 @@ +#ifndef AMICI_MISC_H +#define AMICI_MISC_H + +#include "amici/defines.h" +#include <sunmatrix/sunmatrix_sparse.h> // SUNMatrixContent_Sparse + +#include <algorithm> +#include <vector> +#include <memory> + +#include <gsl/gsl-lite.hpp> + +namespace amici { + +/** + * @brief creates a slice from existing data + * + * @param data to be sliced + * @param index slice index + * @param size slice size + * @return span of the slice + */ + + gsl::span<realtype> slice(std::vector<realtype> &data, const int index, + const unsigned size); + +/** + * @brief Checks the values in an array for NaNs and Infs + * + * @param array array + * @param fun name of calling function + * @return AMICI_RECOVERABLE_ERROR if a NaN/Inf value was found, AMICI_SUCCESS otherwise + */ +int checkFinite(gsl::span<const realtype> array, const char* fun); + + +/** + * @brief Remove parameter scaling according to the parameter scaling in pscale + * + * All vectors must be of same length. + * + * @param bufferScaled scaled parameters + * @param pscale parameter scaling + * @param bufferUnscaled unscaled parameters are written to the array + */ +void unscaleParameters(gsl::span<const realtype> bufferScaled, + gsl::span<const ParameterScaling> pscale, + gsl::span<realtype> bufferUnscaled); + +/** + * @brief Remove parameter scaling according to `scaling` + * + * @param scaledParameter scaled parameter + * @param scaling parameter scaling + * + * @return Unscaled parameter + */ +double getUnscaledParameter(double scaledParameter, ParameterScaling scaling); + + +/** + * @brief Apply parameter scaling according to `scaling` + * @param unscaledParameter + * @param scaling parameter scaling + * @return Scaled parameter + */ +double getScaledParameter(double unscaledParameter, ParameterScaling scaling); + + +/** + * @brief Apply parameter scaling according to `scaling` + * @param bufferUnscaled + * @param pscale parameter scaling + * @param bufferScaled destination + */ +void scaleParameters(gsl::span<const realtype> bufferUnscaled, + gsl::span<const ParameterScaling> pscale, + gsl::span<realtype> bufferScaled); + +/** + * @brief Returns the current backtrace as std::string + * @param maxFrames Number of frames to include + * @return Backtrace + */ +std::string backtraceString(int maxFrames); + + +} // namespace amici + +#ifndef __cpp_lib_make_unique +// custom make_unique while we are still using c++11 +namespace std { +template<typename T, typename... Args> +std::unique_ptr<T> make_unique(Args&&... args) +{ + return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); +} +} +#endif + +#endif // AMICI_MISC_H + diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/model.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/model.h new file mode 100644 index 0000000..542abb9 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/model.h @@ -0,0 +1,1780 @@ +#ifndef AMICI_MODEL_H +#define AMICI_MODEL_H + +#include "amici/abstract_model.h" +#include "amici/defines.h" +#include "amici/sundials_matrix_wrapper.h" +#include "amici/vector.h" + +#include <memory> +#include <vector> +#include <map> + +namespace amici { + +class ExpData; +class Model; +class Solver; + +} // namespace amici + +// for serialization friend in amici::Model +namespace boost { +namespace serialization { +template <class Archive> +void serialize(Archive &ar, amici::Model &u, unsigned int version); +} +} // namespace boost + +namespace amici { + +/** + * @brief The Model class represents an AMICI ODE model. + * The model can compute various model related quantities based + * on symbolically generated code. + */ +class Model : public AbstractModel { + public: + /** default constructor */ + Model(); + + /** + * @brief Constructor with model dimensions + * @param nx_rdata number of state variables + * @param nxtrue_rdata number of state variables of the non-augmented 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 ny number of observables + * @param nytrue number of observables of the non-augmented model + * @param nz number of event observables + * @param nztrue number of event observables of the non-augmented model + * @param ne number of events + * @param nJ number of objective functions + * @param nw number of repeating elements + * @param ndwdx number of nonzero elements in the x derivative of the + * repeating elements + * @param ndwdp number of nonzero elements in the p derivative of the + * repeating elements + * @param ndxdotdw number of nonzero elements in the w derivative of xdot + * @param ndJydy number of nonzero elements in the y derivative of dJy + * (dimension nytrue) + * @param nnz number of nonzero elements in Jacobian + * @param ubw upper matrix bandwidth in the Jacobian + * @param lbw lower matrix bandwidth in the Jacobian + * @param o2mode second order sensitivity mode + * @param p parameters + * @param k constants + * @param plist indexes wrt to which sensitivities are to be computed + * @param idlist indexes indicating algebraic components (DAE only) + * @param z2event mapping of event outputs to events + */ + 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<int> ndJydy, int nnz, + int ubw, int lbw, amici::SecondOrderMode o2mode, + const std::vector<amici::realtype> &p, std::vector<amici::realtype> k, + const std::vector<int> &plist, std::vector<amici::realtype> idlist, + std::vector<int> z2event); + + /** destructor */ + ~Model() override = default; + + /** + * Copy assignment is disabled until const members are removed + * @param other object to copy from + * @return + */ + Model &operator=(Model const &other) = delete; + + /** + * @brief Clone this instance + * @return The clone + */ + virtual Model *clone() const = 0; + + /** + * @brief Serialize Model (see boost::serialization::serialize) + * @param ar Archive to serialize to + * @param u Data to serialize + * @param version Version number + */ + template <class Archive> + friend void boost::serialization::serialize(Archive &ar, Model &u, + unsigned int version); + + /** + * @brief Check equality of data members + * @param a first model instance + * @param b second model instance + * @return equality + */ + friend bool operator==(const Model &a, const Model &b); + + // Overloaded base class methods + using AbstractModel::fdeltaqB; + using AbstractModel::fdeltasx; + using AbstractModel::fdeltax; + using AbstractModel::fdeltaxB; + using AbstractModel::fdJrzdsigma; + using AbstractModel::fdJrzdz; + using AbstractModel::fdJydsigma; + using AbstractModel::fdJydy; + using AbstractModel::fdJzdsigma; + using AbstractModel::fdJzdz; + using AbstractModel::fdrzdp; + using AbstractModel::fdrzdx; + using AbstractModel::fdsigmaydp; + using AbstractModel::fdsigmazdp; + using AbstractModel::fdwdp; + using AbstractModel::fdwdx; + using AbstractModel::fdwdx_colptrs; + using AbstractModel::fdwdx_rowvals; + using AbstractModel::fdydp; + using AbstractModel::fdydx; + using AbstractModel::fdzdp; + using AbstractModel::fdzdx; + using AbstractModel::fJrz; + using AbstractModel::fJy; + using AbstractModel::fJz; + using AbstractModel::frz; + using AbstractModel::fsigmay; + using AbstractModel::fsigmaz; + using AbstractModel::fsrz; + using AbstractModel::fstau; + using AbstractModel::fsx0; + using AbstractModel::fsx0_fixedParameters; + using AbstractModel::fsz; + using AbstractModel::fw; + using AbstractModel::fx0; + using AbstractModel::fx0_fixedParameters; + using AbstractModel::fy; + using AbstractModel::fz; + + /** + * Initialization of model properties + * @param x pointer to state variables + * @param dx pointer to time derivative of states (DAE only) + * @param sx pointer to state variable sensititivies + * @param sdx pointer to time derivative of state sensitivities + * (DAE only) + * @param computeSensitivities flag indicating whether sensitivities + * are to be computed + */ + void initialize(AmiVector &x, AmiVector &dx, AmiVectorArray &sx, + AmiVectorArray &sdx, bool computeSensitivities); + + /** + * Initialization of model properties + * @param xB adjoint state variables + * @param dxB time derivative of adjoint states (DAE only) + * @param xQB adjoint quadratures + */ + void initializeB(AmiVector &xB, AmiVector &dxB, AmiVector &xQB); + + /** + * Initialization of initial states + * @param x pointer to state variables + */ + void initializeStates(AmiVector &x); + + /** + * Initialization of initial state sensitivities + * @param sx pointer to state variable sensititivies + * @param x pointer to state variables + */ + void initializeStateSensitivities(AmiVectorArray &sx, AmiVector &x); + + /** + * Initialises the heaviside variables h at the intial time t0 + * heaviside variables activate/deactivate on event occurences + * @param x pointer to state variables + * @param dx pointer to time derivative of states (DAE only) + */ + void initHeaviside(AmiVector &x, AmiVector &dx); + + /** + * @brief Number of parameters wrt to which sensitivities are computed + * @return length of sensitivity index vector + */ + int nplist() const; + + /** + * @brief Total number of model parameters + * @return length of parameter vector + */ + int np() const; + + /** + * @brief Number of constants + * @return length of constant vector + */ + int nk() const; + + /** + * @brief Number of conservation laws + * @return difference between nx_rdata and nx_solver + */ + int ncl() const; + + /** + * @brief Fixed parameters + * @return pointer to constants array + */ + const double *k() const; + + /** + * @brief Get nmaxevent + * @return maximum number of events that may occur for each type + */ + int nMaxEvent() const; + + /** + * @brief Set nmaxevent + * @param nmaxevent maximum number of events that may occur for each type + */ + void setNMaxEvent(int nmaxevent); + + /** + * @brief Get number of timepoints + * @return number of timepoints + */ + int nt() const; + + /** + * @brief Get ParameterScale for each parameter + * @return vector of parameter scale + */ + std::vector<ParameterScaling> const &getParameterScale() const; + + /** + * @brief Set ParameterScale for each parameter, resets initial state + * sensitivities + * @param pscale scalar parameter scale for all parameters + */ + void setParameterScale(ParameterScaling pscale); + + /** + * @brief Set ParameterScale for each parameter, resets initial state + * sensitivities + * @param pscaleVec vector of parameter scales + */ + void setParameterScale(const std::vector<ParameterScaling> &pscaleVec); + + /** + * @brief Gets parameters with transformation according to ParameterScale + * applied + * @return unscaled parameters + */ + std::vector<realtype> const &getUnscaledParameters() const; + + /** + * @brief Get the parameter vector + * @return The user-set parameters (see also getUnscaledParameters) + */ + std::vector<realtype> const &getParameters() const; + + /** + * @brief Get value of first model parameter with the specified id + * @param par_id parameter id + * @return parameter value + */ + realtype getParameterById(std::string const &par_id) const; + + /** + * @brief Get value of first model parameter with the specified name, + * @param par_name parameter name + * @return parameter value + */ + realtype getParameterByName(std::string const &par_name) const; + + /** + * @brief Sets the parameter vector + * @param p vector of parameters + */ + void setParameters(std::vector<realtype> const &p); + + /** + * @brief Sets model parameters according to the parameter IDs and mapped + * values. + * @param p map of parameters IDs and values + * @param ignoreErrors Ignore errors such as parameter IDs in p which are + * not model parameters + */ + void setParameterById(std::map<std::string, realtype> const &p, + bool ignoreErrors = false); + + /** + * @brief Set value of first model parameter with the specified id + * @param par_id parameter id + * @param value parameter value + */ + void setParameterById(std::string const &par_id, realtype value); + + /** + * @brief Set all values of model parameters with ids matching the specified + * regex + * @param par_id_regex parameter id regex + * @param value parameter value + * @return number of parameter ids that matched the regex + */ + int setParametersByIdRegex(std::string const &par_id_regex, realtype value); + + /** + * @brief Set value of first model parameter with the specified name + * @param par_name parameter name + * @param value parameter value + */ + void setParameterByName(std::string const &par_name, realtype value); + + /** + * @brief Sets model parameters according to the parameter name and mapped + * values. + * @param p map of parameters names and values + * @param ignoreErrors Ignore errors such as parameter names in p which are + * not model parameters + */ + void setParameterByName(std::map<std::string, realtype> const &p, + bool ignoreErrors = false); + + /** + * @brief Set all values of all model parameters with names matching the + * specified regex + * @param par_name_regex parameter name regex + * @param value parameter value + * @return number of fixed parameter names that matched the regex + */ + int setParametersByNameRegex(std::string const &par_name_regex, + realtype value); + + /** + * @brief Gets the fixedParameter member + * @return vector of fixed parameters + */ + std::vector<realtype> const &getFixedParameters() const; + + /** + * @brief Get value of fixed parameter with the specified Id + * @param par_id parameter id + * @return parameter value + */ + realtype getFixedParameterById(std::string const &par_id) const; + + /** + * @brief Get value of fixed parameter with the specified name, + if multiple parameters have the same name, + the first parameter with matching name is returned + * @param par_name parameter name + * @return parameter value + */ + realtype getFixedParameterByName(std::string const &par_name) const; + + /** + * @brief Sets the fixedParameter member + * @param k vector of fixed parameters + */ + void setFixedParameters(std::vector<realtype> const &k); + + /** + * @brief Set value of first fixed parameter with the specified id + * @param par_id fixed parameter id + * @param value fixed parameter value + */ + void setFixedParameterById(std::string const &par_id, realtype value); + + /** + * @brief Set values of all fixed parameters with the id matching the + * specified regex + * @param par_id_regex fixed parameter name regex + * @param value fixed parameter value + * @return number of fixed parameter ids that matched the regex + */ + int setFixedParametersByIdRegex(std::string const &par_id_regex, + realtype value); + + /** + * @brief Set value of first fixed parameter with the specified name, + * @param par_name fixed parameter id + * @param value fixed parameter value + */ + void setFixedParameterByName(std::string const &par_name, realtype value); + + /** + * @brief Set value of all fixed parameters with name matching the specified + * regex, + * @param par_name_regex fixed parameter name regex + * @param value fixed parameter value + * @return number of fixed parameter names that matched the regex + */ + int setFixedParametersByNameRegex(std::string const &par_name_regex, + realtype value); + + /** + * @brief Reports whether the model has parameter names set. + * Also returns true if the number of corresponding variables is just zero. + * @return boolean indicating whether parameter names were set + */ + virtual bool hasParameterNames() const; + + /** + * @brief Get names of the model parameters + * @return the names + */ + virtual std::vector<std::string> getParameterNames() const; + + /** + * @brief Reports whether the model has state names set. + * Also returns true if the number of corresponding variables is just zero. + * @return boolean indicating whether state names were set + */ + virtual bool hasStateNames() const; + + /** + * @brief Get names of the model states + * @return the names + */ + virtual std::vector<std::string> getStateNames() const; + + /** + * @brief Reports whether the model has fixed parameter names set. + * Also returns true if the number of corresponding variables is just zero. + * @return boolean indicating whether fixed parameter names were set + */ + virtual bool hasFixedParameterNames() const; + + /** + * @brief Get names of the fixed model parameters + * @return the names + */ + virtual std::vector<std::string> getFixedParameterNames() const; + + /** + * @brief Reports whether the model has observable names set. + * Also returns true if the number of corresponding variables is just zero. + * @return boolean indicating whether observabke names were set + */ + virtual bool hasObservableNames() const; + + /** + * @brief Get names of the observables + * @return the names + */ + virtual std::vector<std::string> getObservableNames() const; + + /** + * @brief Reports whether the model has parameter ids set. + * Also returns true if the number of corresponding variables is just zero. + * @return boolean indicating whether parameter ids were set + */ + virtual bool hasParameterIds() const; + + /** + * @brief Get ids of the model parameters + * @return the ids + */ + virtual std::vector<std::string> getParameterIds() const; + + /** + * @brief Reports whether the model has state ids set. + * Also returns true if the number of corresponding variables is just zero. + * @return boolean indicating whether state ids were set + */ + virtual bool hasStateIds() const; + + /** + * @brief Get ids of the model states + * @return the ids + */ + virtual std::vector<std::string> getStateIds() const; + + /** + * @brief Reports whether the model has fixed parameter ids set. + * Also returns true if the number of corresponding variables is just zero. + * @return boolean indicating whether fixed parameter ids were set + */ + virtual bool hasFixedParameterIds() const; + + /** + * @brief Get ids of the fixed model parameters + * @return the ids + */ + virtual std::vector<std::string> getFixedParameterIds() const; + + /** + * @brief Reports whether the model has observable ids set. + * Also returns true if the number of corresponding variables is just zero. + * @return boolean indicating whether observale ids were set + */ + virtual bool hasObservableIds() const; + + /** + * @brief Get ids of the observables + * @return the ids + */ + virtual std::vector<std::string> getObservableIds() const; + + /** + * @brief Get the timepoint vector + * @return timepoint vector + */ + std::vector<realtype> const &getTimepoints() const; + + /** + * @brief get simulation timepoint for time index it + * @param it time index + * @return t timepoint + */ + realtype getTimepoint(const int it) const; + + /** + * @brief Set the timepoint vector + * @param ts timepoint vector + */ + void setTimepoints(std::vector<realtype> const &ts); + + /** + * @brief get simulation start time + * @return simulation start time + */ + double t0() const; + + /** + * @brief set simulation start time + * @param t0 simulation start time + */ + void setT0(double t0); + + /** + * @brief gets flags indicating whether states should be treated as + * non-negative + * @return vector of flags + */ + std::vector<bool> const &getStateIsNonNegative() const; + + /** + * @brief sets flags indicating whether states should be treated as + * non-negative + * @param stateIsNonNegative vector of flags + */ + void setStateIsNonNegative(std::vector<bool> const &stateIsNonNegative); + + /** + * @brief sets flags indicating that all states should be treated as + * non-negative + */ + void setAllStatesNonNegative(); + + /** + * @brief Get the list of parameters for which sensitivities are computed + * @return list of parameter indices + */ + std::vector<int> const &getParameterList() const; + + /** + * @brief entry in parameter list + * @param pos index + * @return entry + */ + int plist(int pos) const; + + /** + * @brief Set the list of parameters for which sensitivities are + * computed, resets initial state sensitivities + * @param plist list of parameter indices + */ + void setParameterList(std::vector<int> const &plist); + + /** + * @brief Get the initial states + * @return initial state vector + */ + std::vector<realtype> const &getInitialStates() const; + + /** + * @brief Set the initial states + * @param x0 initial state vector + */ + void setInitialStates(std::vector<realtype> const &x0); + + /** + * @brief Get the initial states sensitivities + * @return vector of initial state sensitivities + */ + std::vector<realtype> const &getInitialStateSensitivities() const; + + /** + * @brief Set the initial state sensitivities + * @param sx0 vector of initial state sensitivities with chainrule + * applied. This could be a slice of ReturnData::sx or ReturnData::sx0 + */ + void setInitialStateSensitivities(std::vector<realtype> const &sx0); + + /** + * @brief Set the initial state sensitivities + * @param sx0 vector of initial state sensitivities without chainrule + * applied. This could be the readin from a model.sx0data saved to hdf5. + */ + void setUnscaledInitialStateSensitivities(std::vector<realtype> const &sx0); + + /** + * @brief Sets the mode how sensitivities are computed in the steadystate + * simulation + * @param mode steadyStateSensitivityMode + */ + void setSteadyStateSensitivityMode(SteadyStateSensitivityMode mode); + + /** + * @brief Gets the mode how sensitivities are computed in the steadystate + * simulation + * @return flag value + */ + SteadyStateSensitivityMode getSteadyStateSensitivityMode() const; + + /** + * @brief Set whether initial states depending on fixedParmeters are to be + * reinitialized after preequilibration and presimulation + * @param flag true/false + */ + void setReinitializeFixedParameterInitialStates(bool flag); + + /** + * @brief Get whether initial states depending on fixedParmeters are to be + * reinitialized after preequilibration and presimulation + * @return flag true/false + */ + bool getReinitializeFixedParameterInitialStates() const; + + /** + * @brief Require computation of sensitivities for all parameters p + * [0..np[ in natural order, resets initial state sensitivities + */ + void requireSensitivitiesForAllParameters(); + + /** + * @brief Time-resolved observables, + * @param y buffer (dimension: ny) + * @param t current timepoint + * @param x current state + */ + void getObservable(gsl::span<realtype> y, const realtype t, + const AmiVector &x); + + /** + * @brief Sensitivity of time-resolved observables, + * total derivative sy = dydx * sx + dydp (only for forward sensitivities) + * @param sy buffer (dimension: ny x nplist, row-major) + * @param t timpoint + * @param x state variables + * @param sx state sensitivities + */ + void getObservableSensitivity(gsl::span<realtype> sy, const realtype t, + const AmiVector &x, const AmiVectorArray &sx); + + /** + * @brief Time-resolved observable standard deviations + * @param sigmay buffer (dimension: ny) + * @param it timepoint index + * @param edata pointer to experimental data instance (optional, + * pass nullptr to ignore) + */ + void getObservableSigma(gsl::span<realtype> sigmay, const int it, + const ExpData *edata); + + /** + * @brief Sensitivity of time-resolved observable standard deviation, + * total derivative (can be used with both adjoint and forward sensitivity) + * @param ssigmay buffer (dimension: ny x nplist, row-major) + * @param it timepoint index + * @param edata pointer to experimental data instance (optional, + * pass nullptr to ignore) + */ + void getObservableSigmaSensitivity(gsl::span<realtype> ssigmay, + const int it, const ExpData *edata); + + /** + * @brief Time-resolved measurement negative log-likelihood Jy + * @param Jy buffer (dimension: 1) + * @param it timepoint index + * @param x state variables + * @param edata experimental data instance + */ + void addObservableObjective(realtype &Jy, const int it, const AmiVector &x, + const ExpData &edata); + + /** + * @brief Sensitivity of time-resolved measurement negative log-likelihood + * Jy, total derivative (to be used with forward senstivities) + * @param sllh first order buffer (dimension: nplist) + * @param s2llh second order buffer (dimension: nJ-1 x nplist, row-major) + * @param it timepoint index + * @param x state variables + * @param sx state sensitivities + * @param edata experimental data instance + */ + void addObservableObjectiveSensitivity(std::vector<realtype> &sllh, + std::vector<realtype> &s2llh, + const int it, const AmiVector &x, + const AmiVectorArray &sx, + const ExpData &edata); + + /** + * @brief Sensitivity of time-resolved measurement negative log-likelihood + * Jy, partial derivative (to be used with adjoint senstivities) + * @param sllh first order buffer (dimension: nplist) + * @param s2llh second order buffer (dimension: nJ-1 x nplist, row-major) + * @param it timepoint index + * @param x state variables + * @param edata experimental data instance + */ + void addPartialObservableObjectiveSensitivity(std::vector<realtype> &sllh, + std::vector<realtype> &s2llh, + const int it, + const AmiVector &x, + const ExpData &edata); + + /** + * @brief State sensitivity of the negative loglikelihood Jy, + * partial derivative (to be used with adjoint senstivities) + * @param dJydx buffer (dimension: nJ x nx_solver, row-major) + * @param it timepoint index + * @param x state variables + * @param edata experimental data instance + */ + void getAdjointStateObservableUpdate(gsl::span<realtype> dJydx, + const int it, const AmiVector &x, + const ExpData &edata); + + /** + * @brief Event-resolved observables + * @param z buffer (dimension: nz) + * @param ie event index + * @param t timepoint + * @param x state variables + */ + void getEvent(gsl::span<realtype> z, const int ie, const realtype t, + const AmiVector &x); + /** + * @brief Sensitivities of event-resolved observables, total derivative, + * total derivative (only forward sensitivities) + * @param sz buffer (dimension: nz x nplist, row-major) + * @param ie event index + * @param t timepoint + * @param x state variables + * @param sx state sensitivities + */ + void getEventSensitivity(gsl::span<realtype> sz, const int ie, + const realtype t, const AmiVector &x, + const AmiVectorArray &sx); + + /** + * @brief Sensitivity of z at final timepoint (ignores sensitivity of + * timepoint), total derivative + * @param sz output buffer (dimension: nz x nplist, row-major) + * @param ie event index + */ + void getUnobservedEventSensitivity(gsl::span<realtype> sz, const int ie); + + /** + * @brief Regularization for event-resolved observables + * @param rz buffer (dimension: nz) + * @param ie event index + * @param t timepoint + * @param x state variables + */ + void getEventRegularization(gsl::span<realtype> rz, const int ie, + const realtype t, const AmiVector &x); + + /** + * @brief Sensitivities of regularization for event-resolved observables, + * total derivative (only forward sensitivities) + * @param srz buffer (dimension: nz x nplist, row-major) + * @param ie event index + * @param t timepoint + * @param x state variables + * @param sx state sensitivities + */ + void getEventRegularizationSensitivity(gsl::span<realtype> srz, + const int ie, const realtype t, + const AmiVector &x, + const AmiVectorArray &sx); + /** + * @brief Event-resolved observable standard deviations + * @param sigmaz buffer (dimension: nz) + * @param ie event index + * @param nroots event occurence + * @param t timepoint + * @param edata pointer to experimental data instance (optional, + * pass nullptr to ignore) + */ + void getEventSigma(gsl::span<realtype> sigmaz, const int ie, + const int nroots, const realtype t, + const ExpData *edata); + + /** + * @brief Sensitivities of event-resolved observable standard deviations, + * total derivative (only forward sensitivities) + * @param ssigmaz buffer (dimension: nz x nplist, row-major) + * @param ie event index + * @param nroots event occurence + * @param t timepoint + * @param edata pointer to experimental data instance (optional, + * pass nullptr to ignore) + */ + void getEventSigmaSensitivity(gsl::span<realtype> ssigmaz, const int ie, + const int nroots, const realtype t, + const ExpData *edata); + + /** + * @brief Event-resolved observable negative log-likelihood, + * @param Jz buffer (dimension: 1) + * @param ie event index + * @param nroots event occurence + * @param t timepoint + * @param x state variables + * @param edata experimental data instance + */ + void addEventObjective(realtype &Jz, const int ie, const int nroots, + const realtype t, const AmiVector &x, + const ExpData &edata); + + /** + * @brief Event-resolved observable negative log-likelihood, + * @param Jrz buffer (dimension: 1) + * @param ie event index + * @param nroots event occurence + * @param t timepoint + * @param x state variables + * @param edata experimental data instance + */ + void addEventObjectiveRegularization(realtype &Jrz, const int ie, + const int nroots, const realtype t, + const AmiVector &x, + const ExpData &edata); + + /** + * @brief Sensitivity of time-resolved measurement negative log-likelihood + * Jy, total derivative (to be used with forward senstivities) + * @param sllh first order buffer (dimension: nplist) + * @param s2llh second order buffer (dimension: nJ-1 x nplist, row-major) + * @param ie event index + * @param nroots event occurence + * @param t timepoint + * @param x state variables + * @param sx state sensitivities + * @param edata experimental data instance + */ + void addEventObjectiveSensitivity(std::vector<realtype> &sllh, + std::vector<realtype> &s2llh, + const int ie, const int nroots, + const realtype t, const AmiVector &x, + const AmiVectorArray &sx, + const ExpData &edata); + + /** + * @brief Sensitivity of time-resolved measurement negative log-likelihood + * Jy, partial derivative (to be used with adjoint senstivities) + * @param sllh first order buffer (dimension: nplist) + * @param s2llh second order buffer (dimension: nJ-1 x nplist, row-major) + * @param ie event index + * @param nroots event occurence + * @param t timepoint + * @param x state variables + * @param edata experimental data instance + */ + void addPartialEventObjectiveSensitivity(std::vector<realtype> &sllh, + std::vector<realtype> &s2llh, + const int ie, const int nroots, + const realtype t, + const AmiVector &x, + const ExpData &edata); + + /** + * @brief State sensitivity of the negative loglikelihood Jz, + * partial derivative (to be used with adjoint senstivities) + * @param dJzdx buffer (dimension: nJ x nx_solver, row-major) + * @param ie event index + * @param nroots event occurence + * @param t timepoint + * @param x state variables + * @param edata experimental data instance + */ + void getAdjointStateEventUpdate(gsl::span<realtype> dJzdx, const int ie, + const int nroots, const realtype t, + const AmiVector &x, const ExpData &edata); + + /** + * @brief Sensitivity of event timepoint, total derivative (only forward + * sensi) + * @param stau current timepoint (dimension: nplist) + * @param t timepoint + * @param ie event index + * @param x state variables + * @param sx state sensitivities + */ + void getEventTimeSensitivity(std::vector<realtype> &stau, const realtype t, + const int ie, const AmiVector &x, + const AmiVectorArray &sx); + + /** + * @brief Update state variables after event + * @param x current state (will be overwritten) + * @param ie event index + * @param t current timepoint + * @param xdot current residual function values + * @param xdot_old value of residual function before event + */ + void addStateEventUpdate(AmiVector &x, const int ie, const realtype t, + const AmiVector &xdot, const AmiVector &xdot_old); + + /** + * @brief Update state sensitivity after event + * @param sx current state sensitivity (will be overwritten) + * @param ie event index + * @param t current timepoint + * @param x_old current state + * @param xdot current residual function values + * @param xdot_old value of residual function before event + * @param stau timepoint sensitivity, to be computed with + * Model::getEventTimeSensitivity + */ + void addStateSensitivityEventUpdate(AmiVectorArray &sx, const int ie, + const realtype t, + const AmiVector &x_old, + const AmiVector &xdot, + const AmiVector &xdot_old, + const std::vector<realtype> &stau); + + /** + * @brief Update adjoint state after event + * @param xB current adjoint state (will be overwritten) + * @param ie event index + * @param t current timepoint + * @param x current state + * @param xdot current residual function values + * @param xdot_old value of residual function before event + */ + void addAdjointStateEventUpdate(AmiVector &xB, const int ie, + const realtype t, const AmiVector &x, + const AmiVector &xdot, + const AmiVector &xdot_old); + + /** + * @brief Update adjoint quadratures after event + * @param xQB current quadrature state (will be overwritten) + * @param ie event index + * @param t current timepoint + * @param x current state + * @param xB current adjoint state + * @param xdot current residual function values + * @param xdot_old value of residual function before event + */ + void addAdjointQuadratureEventUpdate(AmiVector xQB, const int ie, + const realtype t, const AmiVector &x, + const AmiVector &xB, + const AmiVector &xdot, + const AmiVector &xdot_old); + + /** + * @brief Update the heaviside variables h on event occurences + * + * @param rootsfound provides the direction of the zero-crossing, so adding + * it will give the right update to the heaviside variables (zero if no root + * was found) + */ + void updateHeaviside(const std::vector<int> &rootsfound); + + /** + * @brief Updates the heaviside variables h on event occurences in the + backward problem + * @param rootsfound provides the direction of the zero-crossing, so adding + it will give the right update to the heaviside variables (zero if no + root was found) + */ + void updateHeavisideB(const int *rootsfound); + + /** + * @brief Check if the given array has only finite elements. + * + * If not try to give hints by which other fields this could be caused. + * + * @param array arrays of values + * @param fun name of the fucntion that generated the values + * @return AMICI_RECOVERABLE_ERROR if a NaN/Inf value was found, + * AMICI_SUCCESS otherwise + */ + int checkFinite(gsl::span<const realtype> array, const char *fun) const; + + /** + * @brief Set if the result of every call to Model::f* should be checked + * for finiteness + * @param alwaysCheck + */ + void setAlwaysCheckFinite(bool alwaysCheck); + + /** + * @brief Get setting of whether the result of every call to Model::f* + * should be checked for finiteness + * @return that + */ + bool getAlwaysCheckFinite() const; + + /** + * @brief check whether the model was generated from python + * @return that + */ + virtual bool wasPythonGenerated() const { return false; } + + /** + * @brief Initial states + * @param x pointer to state variables + */ + void fx0(AmiVector &x); + + /** + * @brief Sets only those initial states that are specified via + * fixedParmeters + * @param x pointer to state variables + */ + void fx0_fixedParameters(AmiVector &x); + + /** + * @brief Initial value for initial state sensitivities + * @param sx pointer to state sensitivity variables + * @param x pointer to state variables + **/ + void fsx0(AmiVectorArray &sx, const AmiVector &x); + + /** + * @brief Sets only those initial states sensitivities that are affected + *from fx0 fixedParmeters + * @param sx pointer to state sensitivity variables + * @param x pointer to state variables + **/ + void fsx0_fixedParameters(AmiVectorArray &sx, const AmiVector &x); + + /** + * @brief Sensitivity of derivative initial states sensitivities sdx0 (only + * necessary for DAEs) + **/ + virtual void fsdx0(); + + /** + * @brief Expands conservation law for states + * @param x_rdata pointer to state variables with conservation laws + * expanded (stored in rdata) + * @param x_solver pointer to state variables with conservation laws + * applied (solver returns this) + */ + void fx_rdata(AmiVector &x_rdata, const AmiVector &x_solver); + + /** + * @brief Expands conservation law for state sensitivities + * @param sx_rdata pointer to state variable sensitivities with + * conservation laws expanded (stored in rdata) + * @param sx_solver pointer to state variable sensitivities with + * conservation laws applied (solver returns this) + */ + void fsx_rdata(AmiVectorArray &sx_rdata, const AmiVectorArray &sx_solver); + + /** number of states */ + int nx_rdata{0}; + + /** number of states in the unaugmented system */ + int nxtrue_rdata{0}; + + /** number of states with conservation laws applied */ + int nx_solver{0}; + + /** number of states in the unaugmented system with conservation laws + * applied */ + int nxtrue_solver{0}; + + /** number of observables */ + int ny{0}; + + /** number of observables in the unaugmented system */ + int nytrue{0}; + + /** number of event outputs */ + int nz{0}; + + /** number of event outputs in the unaugmented system */ + int nztrue{0}; + + /** number of events */ + int ne{0}; + + /** number of common expressions */ + int nw{0}; + + /** number of derivatives of common expressions wrt x */ + int ndwdx{0}; + + /** number of derivatives of common expressions wrt p */ + int ndwdp{0}; + + /** number of nonzero entries in dxdotdw */ + int ndxdotdw{0}; + + /** number of nonzero entries in dJydy */ + std::vector<int> ndJydy; + + /** number of nonzero entries in jacobian */ + int nnz{0}; + + /** dimension of the augmented objective function for 2nd order ASA */ + int nJ{0}; + + /** upper bandwith of the jacobian */ + int ubw{0}; + + /** lower bandwith of the jacobian */ + int lbw{0}; + + /** flag indicating whether for sensi == AMICI_SENSI_ORDER_SECOND + * directional or full second order derivative will be computed */ + SecondOrderMode o2mode{SecondOrderMode::none}; + + /** flag array for DAE equations */ + std::vector<realtype> idlist; + + /** temporary storage of dxdotdp data across functions (dimension: nplist x + * nx_solver, row-major) */ + AmiVectorArray dxdotdp; + + protected: + /** + * @brief Writes part of a slice to a buffer according to indices specified + * in z2event + * @param slice source data slice + * @param buffer output data slice + * @param ie event index + */ + void writeSliceEvent(gsl::span<const realtype> slice, + gsl::span<realtype> buffer, const int ie); + + /** + * @brief Writes part of a sensitivity slice to a buffer according to + * indices specified in z2event + * @param slice source data slice + * @param buffer output data slice + * @param ie event index + */ + void writeSensitivitySliceEvent(gsl::span<const realtype> slice, + gsl::span<realtype> buffer, const int ie); + + /** + * @brief Seperates first and second order objective sensitivity information + * and writes them into the respective buffers + * @param dLLhdp data with mangled first and second order information + * @param sllh first order buffer + * @param s2llh second order buffer + */ + void writeLLHSensitivitySlice(const std::vector<realtype> &dLLhdp, + std::vector<realtype> &sllh, + std::vector<realtype> &s2llh); + + /** + * @brief Verifies that the provided buffers have the expected size. + * @param sllh first order buffer + * @param s2llh second order buffer + */ + void checkLLHBufferSize(std::vector<realtype> &sllh, + std::vector<realtype> &s2llh); + + /** + * @brief Set the nplist-dependent vectors to their proper sizes + */ + void initializeVectors(); + + /** + * @brief Observables / measurements + * @param t current timepoint + * @param x current state + */ + void fy(realtype t, const AmiVector &x); + + /** + * @brief Partial derivative of observables y w.r.t. model parameters p + * @param t current timepoint + * @param x current state + */ + void fdydp(realtype t, const AmiVector &x); + + /** + * @brief Partial derivative of observables y w.r.t. state variables x + * @param t current timepoint + * @param x current state + */ + void fdydx(realtype t, const AmiVector &x); + + /** + * @brief Standard deviation of measurements + * @param it timepoint index + * @param edata pointer to experimental data instance + */ + void fsigmay(int it, const ExpData *edata); + + /** + * @brief Partial derivative of standard deviation of measurements w.r.t. + * model + * @param it timepoint index + * @param edata pointer to ExpData data instance holding sigma values + */ + void fdsigmaydp(int it, const ExpData *edata); + + /** + * @brief Negative log-likelihood of measurements y + * @param Jy variable to which llh will be added + * @param it timepoint index + * @param y simulated observable + * @param edata pointer to experimental data instance + */ + void fJy(realtype &Jy, int it, const AmiVector &y, const ExpData &edata); + + /** + * @brief Model specific implementation of fdJydy colptrs + * @param indexptrs column pointers + * @param index ytrue index + */ + virtual void fdJydy_colptrs(sunindextype *indexptrs, int index); + + /** + * @brief Model specific implementation of fdxdotdw row vals + * @param indexptrs row val pointers + * @param index ytrue index + */ + virtual void fdJydy_rowvals(sunindextype *indexptrs, int index); + + /** + * @brief Partial derivative of time-resolved measurement negative + * log-likelihood Jy + * @param it timepoint index + * @param x state variables + * @param edata pointer to experimental data instance + */ + void fdJydy(int it, const AmiVector &x, const ExpData &edata); + + /** + * @brief Sensitivity of time-resolved measurement negative log-likelihood + * Jy w.r.t. standard deviation sigma + * @param it timepoint index + * @param x state variables + * @param edata pointer to experimental data instance + */ + void fdJydsigma(int it, const AmiVector &x, const ExpData &edata); + + /** + * @brief Compute sensitivity of time-resolved measurement negative + * log-likelihood Jy w.r.t. parameters for the given timepoint. Add result + * to respective fields in rdata. + * @param it timepoint index + * @param x state variables + * @param edata pointer to experimental data instance + */ + void fdJydp(const int it, const AmiVector &x, const ExpData &edata); + + /** + * @brief Sensitivity of time-resolved measurement negative log-likelihood + * Jy w.r.t. state variables + * @param it timepoint index + * @param x state variables + * @param edata pointer to experimental data instance + */ + void fdJydx(const int it, const AmiVector &x, const ExpData &edata); + + /** + * @brief Event-resolved output + * @param ie event index + * @param t current timepoint + * @param x current state + */ + void fz(int ie, realtype t, const AmiVector &x); + + /** + * @brief Partial derivative of event-resolved output z w.r.t. to model + * parameters p + * @param ie event index + * @param t current timepoint + * @param x current state + */ + void fdzdp(int ie, realtype t, const AmiVector &x); + + /** + * @brief Partial derivative of event-resolved output z w.r.t. to model + * states x + * @param ie event index + * @param t current timepoint + * @param x current state + */ + void fdzdx(int ie, realtype t, const AmiVector &x); + + /** + * @brief Event root function of events (equal to froot but does not include + * non-output events) + * @param ie event index + * @param t current timepoint + * @param x current state + */ + void frz(int ie, realtype t, const AmiVector &x); + + /** + * @brief Sensitivity of event-resolved root output w.r.t. to model + * parameters p + * @param ie event index + * @param t current timepoint + * @param x current state + */ + void fdrzdp(int ie, realtype t, const AmiVector &x); + + /** + * @brief Sensitivity of event-resolved measurements rz w.r.t. to model + * states x + * @param ie event index + * @param t current timepoint + * @param x current state + */ + void fdrzdx(int ie, realtype t, const AmiVector &x); + + /** + * @brief Standard deviation of events + * @param ie event index + * @param nroots event index + * @param t current timepoint + * @param edata pointer to experimental data instance + */ + void fsigmaz(const int ie, const int nroots, const realtype t, + const ExpData *edata); + + /** + * @brief Sensitivity of standard deviation of events measurements w.r.t. + * model parameters p + * @param ie event index + * @param nroots event occurence + * @param t current timepoint + * @param edata pointer to experimental data instance + */ + void fdsigmazdp(int ie, int nroots, realtype t, const ExpData *edata); + + /** + * @brief Negative log-likelihood of event-resolved measurements z + * @param Jz variable to which llh will be added + * @param nroots event index + * @param z simulated event + * @param edata pointer to experimental data instance + */ + void fJz(realtype &Jz, int nroots, const AmiVector &z, + const ExpData &edata); + + /** + * @brief Partial derivative of event measurement negative log-likelihood Jz + * @param ie event index + * @param nroots event index + * @param t current timepoint + * @param x state variables + * @param edata pointer to experimental data instance + */ + void fdJzdz(const int ie, const int nroots, const realtype t, + const AmiVector &x, const ExpData &edata); + + /** + * @brief Sensitivity of event measurement negative log-likelihood Jz + * w.r.t. standard deviation sigmaz + * @param ie event index + * @param nroots event index + * @param t current timepoint + * @param x state variables + * @param edata pointer to experimental data instance + */ + void fdJzdsigma(const int ie, const int nroots, const realtype t, + const AmiVector &x, const ExpData &edata); + + /** + * @brief Sensitivity of event-resolved measurement negative log-likelihood + * Jz w.r.t. parameters + * @param ie event index + * @param nroots event index + * @param t current timepoint + * @param x state variables + * @param edata pointer to experimental data instance + */ + void fdJzdp(const int ie, const int nroots, realtype t, const AmiVector &x, + const ExpData &edata); + + /** + * @brief Sensitivity of event-resolved measurement negative log-likelihood + * Jz w.r.t. state variables + * @param ie event index + * @param nroots event index + * @param t current timepoint + * @param x state variables + * @param edata pointer to experimental data instance + */ + void fdJzdx(const int ie, const int nroots, realtype t, const AmiVector &x, + const ExpData &edata); + + /** + * @brief Regularization of negative log-likelihood with roots of + * event-resolved measurements rz + * @param Jrz variable to which regularization will be added + * @param nroots event index + * @param rz regularization variable + * @param edata pointer to experimental data instance + */ + void fJrz(realtype &Jrz, int nroots, const AmiVector &rz, + const ExpData &edata); + + /** + * @brief Partial derivative of event measurement negative log-likelihood Jz + * @param ie event index + * @param nroots event index + * @param t current timepoint + * @param x state variables + * @param edata pointer to experimental data instance + */ + void fdJrzdz(const int ie, const int nroots, const realtype t, + const AmiVector &x, const ExpData &edata); + + /** + * @brief Sensitivity of event measurement negative log-likelihood Jz + * w.r.t. standard deviation sigmaz + * @param ie event index + * @param nroots event index + * @param t current timepoint + * @param x state variables + * @param edata pointer to experimental data instance + */ + void fdJrzdsigma(const int ie, const int nroots, const realtype t, + const AmiVector &x, const ExpData &edata); + + /** + * @brief Recurring terms in xdot + * @param t timepoint + * @param x array with the states + */ + void fw(realtype t, const realtype *x); + + /** + * @brief Recurring terms in xdot, parameter derivative + * @param t timepoint + * @param x array with the states + */ + void fdwdp(realtype t, const realtype *x); + + /** + * @brief Recurring terms in xdot, state derivative + * @param t timepoint + * @param x array with the states + */ + void fdwdx(realtype t, const realtype *x); + + /** + * @brief Model specific implementation of fx_rdata + * @param x_rdata state variables with conservation laws expanded + * @param x_solver state variables with conservation laws applied + * @param tcl total abundances for conservation laws + **/ + virtual void fx_rdata(realtype *x_rdata, const realtype *x_solver, + const realtype *tcl); + + /** + * @brief Model specific implementation of fsx_solver + * @param sx_rdata state sensitivity variables with conservation laws + * expanded + * @param sx_solver state sensitivity variables with conservation laws + * applied + * @param stcl sensitivities of total abundances for conservation laws + * @param ip sensitivity index + **/ + virtual void fsx_rdata(realtype *sx_rdata, const realtype *sx_solver, + const realtype *stcl, int ip); + + /** + * @brief Model specific implementation of fx_solver + * @param x_solver state variables with conservation laws applied + * @param x_rdata state variables with conservation laws expanded + **/ + virtual void fx_solver(realtype *x_solver, const realtype *x_rdata); + + /** + * @brief Model specific implementation of fsx_solver + * @param sx_rdata state sensitivity variables with conservation laws + * expanded + * @param sx_solver state sensitivity variables with conservation laws + *applied + **/ + virtual void fsx_solver(realtype *sx_solver, const realtype *sx_rdata); + + /** + * @brief Model specific implementation of ftotal_cl + * @param total_cl total abundances of conservation laws + * @param x_rdata state variables with conservation laws expanded + **/ + virtual void ftotal_cl(realtype *total_cl, const realtype *x_rdata); + + /** + * @brief Model specific implementation of fstotal_cl + * @param stotal_cl sensitivites for the total abundances of + * conservation laws + * @param sx_rdata state sensitivity variables with conservation laws + * expanded + * @param ip sensitivity index + **/ + virtual void fstotal_cl(realtype *stotal_cl, const realtype *sx_rdata, + int ip); + + /** + * @brief Computes nonnegative state vector according to stateIsNonNegative + * if anyStateNonNegative is set to false, i.e., all entries in + * stateIsNonNegative are false, this function directly returns x, otherwise + * all entries of x are copied in to x_pos_tmp and negative values are + * replaced by 0 where applicable + * + * @param x state vector possibly containing negative values + * @return state vector with negative values replaced by 0 according to + * stateIsNonNegative + */ + N_Vector computeX_pos(const_N_Vector x); + + /** Sparse Jacobian (dimension: nnz)*/ + mutable SUNMatrixWrapper J; + + /** Sparse dxdotdw temporary storage (dimension: ndxdotdw) */ + mutable SUNMatrixWrapper dxdotdw; + + /** Sparse dwdx temporary storage (dimension: ndwdx) */ + mutable SUNMatrixWrapper dwdx; + + /** Dense Mass matrix (dimension: nx_solver x nx_solver) */ + mutable SUNMatrixWrapper M; + + /** current observable (dimension: nytrue) */ + mutable std::vector<realtype> my; + + /** current event measurement (dimension: nztrue) */ + mutable std::vector<realtype> mz; + + /** Sparse observable derivative of data likelihood, + * only used if wasPythonGenerated()==true + * (dimension nytrue, nJ x ny, row-major) */ + mutable std::vector<SUNMatrixWrapper> dJydy; + + /** observable derivative of data likelihood, + * only used if wasPythonGenerated()==false + * (dimension nJ x ny x nytrue, row-major) + */ + mutable std::vector<realtype> dJydy_matlab; + + /** observable sigma derivative of data likelihood + * (dimension nJ x ny x nytrue, row-major) + */ + mutable std::vector<realtype> dJydsigma; + + /** state derivative of data likelihood + * (dimension nJ x nx_solver, row-major) + */ + mutable std::vector<realtype> dJydx; + + /** parameter derivative of data likelihood for current timepoint + * (dimension: nJ x nplist, row-major) + */ + mutable std::vector<realtype> dJydp; + + /** event output derivative of event likelihood + * (dimension nJ x nz x nztrue, row-major) + */ + mutable std::vector<realtype> dJzdz; + + /** event sigma derivative of event likelihood + * (dimension nJ x nz x nztrue, row-major) + */ + mutable std::vector<realtype> dJzdsigma; + + /** event output derivative of event likelihood at final timepoint + * (dimension nJ x nz x nztrue, row-major) + */ + mutable std::vector<realtype> dJrzdz; + + /** event sigma derivative of event likelihood at final timepoint + * (dimension nJ x nz x nztrue, row-major) + */ + mutable std::vector<realtype> dJrzdsigma; + + /** state derivative of event likelihood + * (dimension nJ x nx_solver, row-major) + */ + mutable std::vector<realtype> dJzdx; + + /** parameter derivative of event likelihood for current timepoint + * (dimension: nJ x nplist x, row-major) + */ + mutable std::vector<realtype> dJzdp; + + /** state derivative of event output + * (dimension: nz x nx_solver, row-major) + */ + mutable std::vector<realtype> dzdx; + + /** parameter derivative of event output + * (dimension: nz x nplist, row-major) + */ + mutable std::vector<realtype> dzdp; + + /** state derivative of event regularization variable + * (dimension: nz x nx_solver, row-major) + */ + mutable std::vector<realtype> drzdx; + + /** parameter derivative of event regularization variable + * (dimension: nz x nplist, row-major) + */ + mutable std::vector<realtype> drzdp; + + /** parameter derivative of observable + * (dimension: ny x nplist, row-major) + */ + mutable std::vector<realtype> dydp; + + /** state derivative of time-resolved observable + * (dimension: nx_solver x ny, row-major) + */ + mutable std::vector<realtype> dydx; + + /** tempory storage of w data across functions (dimension: nw) */ + mutable std::vector<realtype> w; + + /** tempory storage of sparse/dense dwdp data across functions + * (dimension: ndwdp) + */ + mutable std::vector<realtype> dwdp; + + /** tempory storage for flattened sx, + * (dimension: nx_solver x nplist, row-major) + */ + mutable std::vector<realtype> sx; + + /** tempory storage for x_rdata (dimension: nx_rdata) */ + mutable std::vector<realtype> x_rdata; + + /** tempory storage for sx_rdata slice (dimension: nx_rdata) */ + mutable std::vector<realtype> sx_rdata; + + /** temporary storage for time-resolved observable (dimension: ny) */ + mutable std::vector<realtype> y; + + /** data standard deviation for current timepoint (dimension: ny) */ + mutable std::vector<realtype> sigmay; + + /** temporary storage for parameter derivative of data standard deviation, + * (dimension: ny x nplist, row-major) + */ + mutable std::vector<realtype> dsigmaydp; + + /** temporary storage for event-resolved observable (dimension: nz) */ + mutable std::vector<realtype> z; + + /** temporary storage for event regularization (dimension: nz) */ + mutable std::vector<realtype> rz; + + /** temporary storage for event standard deviation (dimension: nz) */ + mutable std::vector<realtype> sigmaz; + + /** temporary storage for parameter derivative of event standard deviation, + * (dimension: nz x nplist, row-major) + */ + mutable std::vector<realtype> dsigmazdp; + + /** temporary storage for change in x after event (dimension: nx_solver) */ + mutable std::vector<realtype> deltax; + + /** temporary storage for change in sx after event + * (dimension: nx_solver x nplist, row-major) + */ + mutable std::vector<realtype> deltasx; + + /** temporary storage for change in xB after event (dimension: nx_solver) */ + mutable std::vector<realtype> deltaxB; + + /** temporary storage for change in qB after event + * (dimension: nJ x nplist, row-major) + */ + mutable std::vector<realtype> deltaqB; + + /** flag indicating whether a certain heaviside function should be active or + not (dimension: ne) */ + mutable std::vector<realtype> h; + + /** total abundances for conservation laws + (dimension: nx_rdata-nx_solver) */ + mutable std::vector<realtype> total_cl; + + /** sensitivities of total abundances for conservation laws + (dimension: (nx_rdata-nx_solver) x np, row-major) */ + mutable std::vector<realtype> 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<realtype> unscaledParameters; + + /** orignal user-provided, possibly scaled parameter array (dimension: np) + */ + std::vector<realtype> originalParameters; + + /** constants (dimension: nk) */ + std::vector<realtype> fixedParameters; + + /** index indicating to which event an event output belongs */ + std::vector<int> z2event; + + /** indexes of parameters wrt to which sensitivities are computed + * (dimension: nplist) */ + std::vector<int> plist_; + + /** state initialisation (size nx_solver) */ + std::vector<double> x0data; + + /** sensitivity initialisation (size nx_rdata x nplist, row-major) */ + std::vector<realtype> sx0data; + + /** timepoints (size nt) */ + std::vector<realtype> ts; + + /** vector of bools indicating whether state variables are to be assumed to + * be positive */ + std::vector<bool> stateIsNonNegative; + + /** boolean indicating whether any entry in stateIsNonNegative is `true` */ + bool anyStateNonNegative = false; + + /** maximal number of events to track */ + int nmaxevent = 10; + + /** parameter transformation of `originalParameters` (dimension np) */ + std::vector<ParameterScaling> pscale; + + /** starting time */ + double tstart = 0.0; + + /** flag indicating whether steadystate sensivities are to be computed + * via FSA when steadyStateSimulation is used */ + SteadyStateSensitivityMode steadyStateSensitivityMode = + SteadyStateSensitivityMode::newtonOnly; + + /** flag indicating whether reinitialization of states depending on + * fixed parameters is activated + */ + bool reinitializeFixedParameterInitialStates = false; + + /** Indicates whether the result of every call to Model::f* should be + * checked for finiteness */ + bool alwaysCheckFinite = false; +}; + +bool operator==(const Model &a, const Model &b); + +} // namespace amici + +#endif // AMICI_MODEL_H diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/model_dae.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/model_dae.h new file mode 100644 index 0000000..3d19eb8 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/model_dae.h @@ -0,0 +1,436 @@ +#ifndef AMICI_MODEL_DAE_H +#define AMICI_MODEL_DAE_H + +#include "amici/model.h" + +#include <nvector/nvector_serial.h> + +#include <sunmatrix/sunmatrix_band.h> +#include <sunmatrix/sunmatrix_dense.h> +#include <sunmatrix/sunmatrix_sparse.h> + +#include <utility> +#include <vector> + +namespace amici { +extern msgIdAndTxtFp warnMsgIdAndTxt; + +class ExpData; +class IDASolver; + +/** + * @brief The Model class represents an AMICI DAE model. + * + * The model does not contain any data, but represents the state + * of the model at a specific time t. The states must not always be + * in sync, but may be updated asynchroneously. + */ +class Model_DAE : public Model { + public: + /** default constructor */ + Model_DAE() = default; + + /** + * @brief Constructor with model dimensions + * @param nx_rdata number of state variables + * @param nxtrue_rdata number of state variables of the non-augmented 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 ny number of observables + * @param nytrue number of observables of the non-augmented model + * @param nz number of event observables + * @param nztrue number of event observables of the non-augmented model + * @param ne number of events + * @param nJ number of objective functions + * @param nw number of repeating elements + * @param ndwdx number of nonzero elements in the x derivative of the + * repeating elements + * @param ndwdp number of nonzero elements in the p derivative of the + * repeating elements + * @param ndxdotdw number of nonzero elements dxdotdw + * @param ndJydy number of nonzero elements dJydy + * @param nnz number of nonzero elements in Jacobian + * @param ubw upper matrix bandwidth in the Jacobian + * @param lbw lower matrix bandwidth in the Jacobian + * @param o2mode second order sensitivity mode + * @param p parameters + * @param k constants + * @param plist indexes wrt to which sensitivities are to be computed + * @param idlist indexes indicating algebraic components (DAE only) + * @param z2event mapping of event outputs to events + */ + 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 nz, const int nztrue, const int ne, const int nJ, + const int nw, const int ndwdx, const int ndwdp, + const int ndxdotdw, std::vector<int> ndJydy, const int nnz, + const int ubw, const int lbw, const SecondOrderMode o2mode, + std::vector<realtype> const &p, std::vector<realtype> const &k, + std::vector<int> const &plist, + std::vector<realtype> const &idlist, + std::vector<int> const &z2event) + : Model(nx_rdata, nxtrue_rdata, nx_solver, nxtrue_solver, ny, nytrue, + nz, nztrue, ne, nJ, nw, ndwdx, ndwdp, ndxdotdw, + std::move(ndJydy), nnz, ubw, lbw, o2mode, p, k, plist, idlist, + z2event) {} + + void fJ(realtype t, realtype cj, const AmiVector &x, const AmiVector &dx, + const AmiVector &xdot, SUNMatrix J) override; + + /** + * @brief Jacobian of xdot with respect to states x + * @param t timepoint + * @param cj scaling factor, inverse of the step size + * @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 + **/ + void fJ(realtype t, realtype cj, N_Vector x, N_Vector dx, N_Vector xdot, + SUNMatrix J); + + /** + * @brief Jacobian of xBdot with respect to adjoint state xB + * @param t timepoint + * @param cj scaling factor, inverse of the step size + * @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 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); + + void fJSparse(realtype t, realtype cj, const AmiVector &x, + const AmiVector &dx, const AmiVector &xdot, + SUNMatrix J) override; + + /** + * @brief J in sparse form (for sparse solvers from the SuiteSparse Package) + * @param t timepoint + * @param cj scalar in Jacobian (inverse stepsize) + * @param x Vector with the states + * @param dx Vector with the derivative states + * @param J Matrix to which the Jacobian will be written + */ + 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) + * @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 JB Matrix to which the Jacobian will be written + */ + void fJSparseB(realtype t, realtype cj, N_Vector x, N_Vector dx, + N_Vector xB, N_Vector dxB, SUNMatrix JB); + + /** diagonalized 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 + * @param x Vector with the states + * @param dx Vector with the derivative states + **/ + + void fJDiag(realtype t, AmiVector &JDiag, realtype cj, const AmiVector &x, + const AmiVector &dx) override; + + void fJv(realtype t, const AmiVector &x, const AmiVector &dx, + const AmiVector &xdot, const AmiVector &v, AmiVector &nJv, + realtype cj) override; + + /** Matrix vector product of J with a vector v (for iterative solvers) + * @param t timepoint @type realtype + * @param cj scaling factor, inverse of the step size + * @param x Vector with the states + * @param dx Vector with the derivative states + * @param v Vector with which the Jacobian is multiplied + * @param Jv Vector to which the Jacobian vector product will be + * written + **/ + 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) + * @param t timepoint + * @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 vB Vector with which the Jacobian is multiplied + * @param JvB Vector to which the Jacobian vector product will be + *written + * @param cj scalar in Jacobian (inverse stepsize) + **/ + + void fJvB(realtype t, N_Vector x, N_Vector dx, N_Vector xB, N_Vector dxB, + N_Vector vB, N_Vector JvB, realtype cj); + + void froot(realtype t, const AmiVector &x, const AmiVector &dx, + gsl::span<realtype> root) override; + + /** Event trigger function for events + * @param t timepoint + * @param x Vector with the states + * @param dx Vector with the derivative states + * @param root array with root function values + */ + void froot(realtype t, N_Vector x, N_Vector dx, gsl::span<realtype> root); + + void fxdot(realtype t, const AmiVector &x, const AmiVector &dx, + AmiVector &xdot) override; + + /** + * @brief Residual function of the DAE + * @param t timepoint + * @param x Vector with the states + * @param dx Vector with the derivative states + * @param xdot Vector with the right hand side + */ + void fxdot(realtype t, N_Vector x, N_Vector dx, N_Vector xdot); + + /** 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 + * @param xB Vector with the adjoint states + * @param dxB Vector with the adjoint derivative states + * @param xBdot Vector with the adjoint right hand side + */ + 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 + * @param t timepoint + * @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 qBdot Vector with the adjoint quadrature right hand side + */ + 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 + * @param t timepoint + * @param x Vector with the states + * @param dx Vector with the derivative states + */ + void fdxdotdp(realtype t, const N_Vector x, const N_Vector dx); + void fdxdotdp(const realtype t, const AmiVector &x, + const AmiVector &dx) override { + fdxdotdp(t, x.getNVector(), dx.getNVector()); + }; + + 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 + * @param t timepoint + * @param x Vector with the states + * @param dx Vector with the derivative states + * @param ip parameter index + * @param sx Vector with the state sensitivities + * @param sdx Vector with the derivative state sensitivities + * @param sxdot Vector with the sensitivity right hand side + */ + void fsxdot(realtype t, N_Vector x, N_Vector dx, int ip, N_Vector sx, + N_Vector sdx, N_Vector sxdot); + + /** + * @brief Mass matrix for DAE systems + * @param t timepoint + * @param x Vector with the states + */ + void fM(realtype t, const N_Vector x); + + std::unique_ptr<Solver> getSolver() override; + + protected: + /** + * @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 + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param cj scaling factor, inverse of the step size + * @param dx Vector with the derivative states + * @param w vector with helper variables + * @param dwdx derivative of w wrt x + **/ + virtual void fJ(realtype *J, realtype t, const realtype *x, const double *p, + const double *k, const realtype *h, realtype cj, + const realtype *dx, const realtype *w, + const realtype *dwdx) = 0; + + /** + * @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 + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param cj scaling factor, inverse of the step size + * @param xB Vector with the adjoint states + * @param dx Vector with the derivative states + * @param dxB Vector with the adjoint derivative states + * @param w vector with helper variables + * @param dwdx derivative of w wrt x + **/ + virtual void fJB(realtype *JB, realtype t, const realtype *x, + const double *p, const double *k, const realtype *h, + realtype cj, const realtype *xB, const realtype *dx, + const realtype *dxB, const realtype *w, + const realtype *dwdx); + + /** + * @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 + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param cj scaling factor, inverse of the step size + * @param dx Vector with the derivative states + * @param w vector with helper variables + * @param dwdx derivative of w wrt x + **/ + virtual void fJSparse(SUNMatrixContent_Sparse JSparse, realtype t, + const realtype *x, const double *p, const double *k, + const realtype *h, realtype cj, const realtype *dx, + const realtype *w, const realtype *dwdx) = 0; + + /** + * @brief Model specific implementation for fJSparseB + * @param JSparseB Matrix to which the Jacobian will be written + * @param t timepoint + * @param x Vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param cj scaling factor, inverse of the step size + * @param xB Vector with the adjoint states + * @param dx Vector with the derivative states + * @param dxB Vector with the adjoint derivative states + * @param w vector with helper variables + * @param dwdx derivative of w wrt x + **/ + virtual void fJSparseB(SUNMatrixContent_Sparse JSparseB, const realtype t, + const realtype *x, const double *p, const double *k, + const realtype *h, const realtype cj, + const realtype *xB, const realtype *dx, + const realtype *dxB, const realtype *w, + const realtype *dwdx); + + /** + * @brief Model specific implementation for fJDiag + * @param JDiag array to which the Jacobian diagonal will be written + * @param t timepoint + * @param x Vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param cj scaling factor, inverse of the step size + * @param dx Vector with the derivative states + * @param w vector with helper variables + * @param dwdx derivative of w wrt x + **/ + virtual void fJDiag(realtype *JDiag, realtype t, const realtype *x, + const realtype *p, const realtype *k, const realtype *h, + realtype cj, const realtype *dx, const realtype *w, + const realtype *dwdx); + + /** + * 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 + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param cj scaling factor, inverse of the step size + * @param xB Vector with the adjoint states + * @param dx Vector with the derivative states + * @param dxB Vector with the adjoint derivative states + * @param vB Vector with which the Jacobian is multiplied + * @param w vector with helper variables + * @param dwdx derivative of w wrt x + **/ + virtual void fJvB(realtype *JvB, realtype t, const realtype *x, + const double *p, const double *k, const realtype *h, + realtype cj, const realtype *xB, const realtype *dx, + const realtype *dxB, const realtype *vB, + const realtype *w, const realtype *dwdx); + + /** + * @brief Model specific implementation for froot + * @param root values of the trigger function + * @param t timepoint + * @param x Vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param dx Vector with the derivative states + **/ + virtual void froot(realtype *root, realtype t, const realtype *x, + const double *p, const double *k, const realtype *h, + const realtype *dx); + + /** + * @brief Model specific implementation for fxdot + * @param xdot residual function + * @param t timepoint + * @param x Vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param w vector with helper variables + * @param dx Vector with the derivative states + **/ + virtual void fxdot(realtype *xdot, realtype t, const realtype *x, + const double *p, const double *k, const realtype *h, + const realtype *dx, const realtype *w) = 0; + + /** + * @brief model specific implementation of fdxdotdp + * @param dxdotdp partial derivative xdot wrt p + * @param t timepoint + * @param x Vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param ip parameter index + * @param dx Vector with the derivative states + * @param w vector with helper variables + * @param dwdp derivative of w wrt p + */ + virtual void fdxdotdp(realtype *dxdotdp, realtype t, const realtype *x, + const realtype *p, const realtype *k, + const realtype *h, int ip, const realtype *dx, + const realtype *w, const realtype *dwdp); + + /** + * @brief model specific implementation of fM + * @param M mass matrix + * @param t timepoint + * @param x Vector with the states + * @param p parameter vector + * @param k constants vector + */ + virtual void fM(realtype *M, const realtype t, const realtype *x, + const realtype *p, const realtype *k){}; +}; +} // namespace amici + +#endif // MODEL_H diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/model_ode.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/model_ode.h new file mode 100644 index 0000000..41aa2be --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/model_ode.h @@ -0,0 +1,462 @@ +#ifndef AMICI_MODEL_ODE_H +#define AMICI_MODEL_ODE_H + +#include "amici/model.h" + +#include <nvector/nvector_serial.h> + +#include <sundials/sundials_matrix.h> +#include <sunmatrix/sunmatrix_band.h> +#include <sunmatrix/sunmatrix_dense.h> +#include <sunmatrix/sunmatrix_sparse.h> + +#include <utility> +#include <vector> + +namespace amici { +extern msgIdAndTxtFp warnMsgIdAndTxt; + +class CVodeSolver; + +/** + * @brief The Model class represents an AMICI ODE model. + * + * The model does not contain any data, but represents the state + * of the model at a specific time t. The states must not always be + * in sync, but may be updated asynchroneously. + */ +class Model_ODE : public Model { + public: + /** default constructor */ + Model_ODE() = default; + + /** + * @brief Constructor with model dimensions + * @param nx_rdata number of state variables + * @param nxtrue_rdata number of state variables of the non-augmented 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 ny number of observables + * @param nytrue number of observables of the non-augmented model + * @param nz number of event observables + * @param nztrue number of event observables of the non-augmented model + * @param ne number of events + * @param nJ number of objective functions + * @param nw number of repeating elements + * @param ndwdx number of nonzero elements in the x derivative of the + * repeating elements + * @param ndwdp number of nonzero elements in the p derivative of the + * repeating elements + * @param ndxdotdw number of nonzero elements dxdotdw + * @param ndJydy number of nonzero elements dJydy + * @param nnz number of nonzero elements in Jacobian + * @param ubw upper matrix bandwidth in the Jacobian + * @param lbw lower matrix bandwidth in the Jacobian + * @param o2mode second order sensitivity mode + * @param p parameters + * @param k constants + * @param plist indexes wrt to which sensitivities are to be computed + * @param idlist indexes indicating algebraic components (DAE only) + * @param z2event mapping of event outputs to events + */ + 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 nz, const int nztrue, const int ne, const int nJ, + const int nw, const int ndwdx, const int ndwdp, + const int ndxdotdw, std::vector<int> ndJydy, const int nnz, + const int ubw, const int lbw, const SecondOrderMode o2mode, + std::vector<realtype> const &p, std::vector<realtype> const &k, + std::vector<int> const &plist, + std::vector<realtype> const &idlist, + std::vector<int> const &z2event) + : Model(nx_rdata, nxtrue_rdata, nx_solver, nxtrue_solver, ny, nytrue, + nz, nztrue, ne, nJ, nw, ndwdx, ndwdp, ndxdotdw, + std::move(ndJydy), nnz, ubw, lbw, o2mode, p, k, plist, idlist, + z2event) {} + + void fJ(realtype t, realtype cj, const AmiVector &x, const AmiVector &dx, + const AmiVector &xdot, SUNMatrix J) override; + + /** + * @brief Implementation of fJ at the N_Vector level + * + * This function provides an + * interface to the model specific routines for the solver + * implementation as well as the AmiVector level implementation + * @param t timepoint + * @param x Vector with the states + * @param xdot Vector with the right hand side + * @param J Matrix to which the Jacobian will be written + **/ + 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 + * @param t timepoint + * @param x Vector with the states + * @param xB Vector with the adjoint states + * @param xBdot Vector with the adjoint right hand side + * @param JB Matrix to which the Jacobian will be written + **/ + void fJB(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot, SUNMatrix JB); + + void fJSparse(realtype t, realtype cj, const AmiVector &x, + const AmiVector &dx, const AmiVector &xdot, + 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 + * @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 + * 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 + * @param xBdot Vector with the adjoint right hand side + * @param JB Matrix to which the Jacobian will be written + */ + 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 + * @param t timepoint + * @param JDiag Vector to which the Jacobian diagonal will be written + * @param x Vector with the states + **/ + void fJDiag(realtype t, N_Vector JDiag, N_Vector x); + + /** + * @brief diagonalized 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 + * @param x Vector with the states + * @param dx Vector with the derivative states + **/ + void fJDiag(realtype t, AmiVector &JDiag, realtype cj, const AmiVector &x, + const AmiVector &dx) override; + + void fJv(realtype t, const AmiVector &x, const AmiVector &dx, + const AmiVector &xdot, const AmiVector &v, AmiVector &nJv, + realtype cj) override; + + /** 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 + * @param Jv Vector to which the Jacobian vector product will be + * written + **/ + void fJv(N_Vector v, N_Vector Jv, realtype t, N_Vector x); + + /** + * @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 + * @param vB Vector with which the Jacobian is multiplied + * @param JvB Vector to which the Jacobian vector product will be written + **/ + void fJvB(N_Vector vB, N_Vector JvB, realtype t, N_Vector x, N_Vector xB); + + void froot(realtype t, const AmiVector &x, const AmiVector &dx, + gsl::span<realtype> root) override; + + /** + * @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 + * @param x Vector with the states + * @param root array with root function values + */ + void froot(realtype t, N_Vector x, gsl::span<realtype> root); + + 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 + * @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 + * @param t timepoint + * @param x Vector with the states + * @param xB Vector with the adjoint states + * @param xBdot Vector with the adjoint right hand side + */ + void fxBdot(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot); + + /** implementation of fqBdot at the N_Vector level + * @param t timepoint + * @param x Vector with the states + * @param xB Vector with the adjoint states + * @param qBdot Vector with the adjoint quadrature right hand side + */ + void fqBdot(realtype t, N_Vector x, N_Vector xB, N_Vector qBdot); + + /** 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); + + /** 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); + + void fdxdotdp(realtype t, const AmiVector &x, const AmiVector &dx) override; + + void fsxdot(realtype t, const AmiVector &x, const AmiVector &dx, int ip, + const AmiVector &sx, const AmiVector &sdx, + AmiVector &sxdot) override; + + /** + * @brief implementation of fsxdot at the N_Vector level + * @param t timepoint + * @param x Vector with the states + * @param ip parameter index + * @param sx Vector with the state sensitivities + * @param sxdot Vector with the sensitivity right hand side + */ + void fsxdot(realtype t, N_Vector x, int ip, N_Vector sx, N_Vector sxdot); + + std::unique_ptr<Solver> getSolver() override; + + protected: + /** model specific implementation for fJ + * @param J Matrix to which the Jacobian will be written + * @param t timepoint + * @param x Vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param w vector with helper variables + * @param dwdx derivative of w wrt x + **/ + virtual void fJ(realtype *J, realtype t, const realtype *x, + const realtype *p, const realtype *k, const realtype *h, + const realtype *w, const realtype *dwdx) = 0; + + /** model specific implementation for fJB + * @param JB Matrix to which the Jacobian will be written + * @param t timepoint + * @param x Vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param xB Vector with the adjoint states + * @param w vector with helper variables + * @param dwdx derivative of w wrt x + **/ + virtual void fJB(realtype *JB, realtype t, const realtype *x, + const realtype *p, const realtype *k, const realtype *h, + const realtype *xB, const realtype *w, + const realtype *dwdx); + + /** model specific implementation for fJSparse + * @param JSparse Matrix to which the Jacobian will be written + * @param t timepoint + * @param x Vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param w vector with helper variables + * @param dwdx derivative of w wrt x + **/ + virtual void fJSparse(SUNMatrixContent_Sparse JSparse, realtype t, + const realtype *x, const realtype *p, + const realtype *k, const realtype *h, + const realtype *w, const realtype *dwdx); + + /** 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 + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param w vector with helper variables + * @param dwdx derivative of w wrt x + **/ + virtual void fJSparse(realtype *JSparse, realtype t, const realtype *x, + const realtype *p, const realtype *k, + const realtype *h, const realtype *w, + const realtype *dwdx); + + /** + * @brief model specific implementation for fJSparse, column pointers + * @param indexptrs column pointers + **/ + virtual void fJSparse_colptrs(sunindextype *indexptrs); + + /** + * @brief Model specific implementation for fJSparse, row values + * @param indexvals row values + **/ + virtual void fJSparse_rowvals(sunindextype *indexvals); + + /** + * @brief Model specific implementation for fJSparseB + * @param JSparseB Matrix to which the Jacobian will be written + * @param t timepoint + * @param x Vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param xB Vector with the adjoint states + * @param w vector with helper variables + * @param dwdx derivative of w wrt x + **/ + virtual void fJSparseB(SUNMatrixContent_Sparse JSparseB, realtype t, + const realtype *x, const realtype *p, + const realtype *k, const realtype *h, + const realtype *xB, const realtype *w, + const realtype *dwdx); + + /** model specific implementation for fJSparseB + * @param JSparseB data array + * @param t timepoint + * @param x Vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param xB Vector with the adjoint states + * @param w vector with helper variables + * @param dwdx derivative of w wrt x + **/ + virtual void fJSparseB(realtype *JSparseB, realtype t, const realtype *x, + const realtype *p, const realtype *k, + const realtype *h, const realtype *xB, + const realtype *w, const realtype *dwdx); + + /** + * @brief Model specific implementation for fJSparse, column pointers + * @param indexptrs column pointers + **/ + virtual void fJSparseB_colptrs(sunindextype *indexptrs); + + /** + * @brief Model specific implementation for fJSparse, row values + * @param indexvals row values + **/ + virtual void fJSparseB_rowvals(sunindextype *indexvals); + + /** + * @brief Model specific implementation for fJDiag + * @param JDiag Matrix to which the Jacobian will be written + * @param t timepoint + * @param x Vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param w vector with helper variables + * @param dwdx derivative of w wrt x + **/ + virtual void fJDiag(realtype *JDiag, realtype t, const realtype *x, + const realtype *p, const realtype *k, const realtype *h, + const realtype *w, const realtype *dwdx); + + /** + * @brief model specific implementation for froot + * @param root values of the trigger function + * @param t timepoint + * @param x Vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + **/ + virtual void froot(realtype *root, realtype t, const realtype *x, + const realtype *p, const realtype *k, const realtype *h); + + /** model specific implementation for fxdot + * @param xdot residual function + * @param t timepoint + * @param x Vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param w vector with helper variables + **/ + virtual void fxdot(realtype *xdot, realtype t, const realtype *x, + const realtype *p, const realtype *k, const realtype *h, + const realtype *w) = 0; + + /** model specific implementation of fdxdotdp, with w chainrule + * @param dxdotdp partial derivative xdot wrt p + * @param t timepoint + * @param x Vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param ip parameter index + * @param w vector with helper variables + * @param dwdp derivative of w wrt p + */ + virtual void fdxdotdp(realtype *dxdotdp, realtype t, const realtype *x, + const realtype *p, const realtype *k, + const realtype *h, int ip, const realtype *w, + const realtype *dwdp); + + /** model specific implementation of fdxdotdp, without w chainrule + * @param dxdotdp partial derivative xdot wrt p + * @param t timepoint + * @param x Vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param ip parameter index + * @param w vector with helper variables + */ + virtual void fdxdotdp(realtype *dxdotdp, realtype t, const realtype *x, + const realtype *p, const realtype *k, + const realtype *h, int ip, const realtype *w); + + /** model specific implementation of fdxdotdw, data part + * @param dxdotdw partial derivative xdot wrt w + * @param t timepoint + * @param x Vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param w vector with helper variables + */ + virtual void fdxdotdw(realtype *dxdotdw, realtype t, const realtype *x, + const realtype *p, const realtype *k, + const realtype *h, const realtype *w); + + /** model specific implementation of fdxdotdw, colptrs part + * @param indexptrs column pointers + */ + virtual void fdxdotdw_colptrs(sunindextype *indexptrs); + + /** model specific implementation of fdxdotdw, colptrs part + * @param indexvals row values + */ + virtual void fdxdotdw_rowvals(sunindextype *indexvals); +}; + +} // namespace amici + +#endif // MODEL_H diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/newton_solver.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/newton_solver.h new file mode 100644 index 0000000..c0c1232 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/newton_solver.h @@ -0,0 +1,296 @@ +#ifndef amici_newton_solver_h +#define amici_newton_solver_h + +#include "amici/vector.h" +#include "amici/defines.h" +#include "amici/sundials_matrix_wrapper.h" +#include "amici/sundials_linsol_wrapper.h" + +#include <memory> + + + +namespace amici { + +class ReturnData; +class Model; +class AmiVector; + +/** + * @brief The NewtonSolver class sets up the linear solver for the Newton + * method. + */ + +class NewtonSolver { + + public: + /** + * 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 + */ + NewtonSolver(realtype *t, AmiVector *x, Model *model, ReturnData *rdata); + + /** + * 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 + * @return solver NewtonSolver according to the specified linsolType + */ + static std::unique_ptr<NewtonSolver> getSolver(realtype *t, AmiVector *x, + LinearSolver linsolType, + Model *model, + ReturnData *rdata, + int maxlinsteps, + int maxsteps, + double atol, double rtol); + + /** + * Computes the solution of one Newton iteration + * + * @param ntry integer newton_try integer start number of Newton solver + * (1 or 2) + * @param nnewt integer number of current Newton step + * @param delta containing the RHS of the linear system, will be + * overwritten by solution to the linear system + */ + void getStep(int ntry, int nnewt, AmiVector &delta); + + /** + * Computes steady state sensitivities + * + * @param sx pointer to state variable sensitivities + */ + void computeNewtonSensis(AmiVectorArray &sx); + + /** + * 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) + * @param nnewt integer number of current Newton step + */ + virtual void prepareLinearSystem(int ntry, int nnewt) = 0; + + /** + * 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 + */ + virtual void solveLinearSystem(AmiVector &rhs) = 0; + + virtual ~NewtonSolver() = default; + + /** maximum number of allowed linear steps per Newton step for steady state + * computation */ + int maxlinsteps = 0; + /** maximum number of allowed Newton steps for steady state computation */ + int maxsteps = 0; + /** absolute tolerance */ + double atol = 1e-16; + /** relative tolerance */ + double rtol = 1e-8; + + protected: + /** time variable */ + realtype *t; + /** pointer to the AMICI 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; + +}; + +/** + * @brief The NewtonSolverDense provides access to the dense linear solver for + * the Newton method. + */ + +class NewtonSolverDense : public NewtonSolver { + + public: + /** + * 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 + */ + + NewtonSolverDense(realtype *t, AmiVector *x, Model *model, ReturnData *rdata); + ~NewtonSolverDense() override; + + /** + * 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 + */ + void solveLinearSystem(AmiVector &rhs) override; + + /** + * 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) + * @param nnewt integer number of current Newton step + */ + void prepareLinearSystem(int ntry, int nnewt) override; + + private: + /** temporary storage of Jacobian */ + SUNMatrixWrapper Jtmp; + + /** dense linear solver */ + SUNLinearSolver linsol = nullptr; +}; + +/** + * @brief The NewtonSolverSparse provides access to the sparse linear solver for + * the Newton method. + */ + +class NewtonSolverSparse : public NewtonSolver { + + public: + /** + * 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 + */ + NewtonSolverSparse(realtype *t, AmiVector *x, Model *model, ReturnData *rdata); + ~NewtonSolverSparse() override; + + /** + * 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 + */ + void solveLinearSystem(AmiVector &rhs) override; + + /** + * 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) + * @param nnewt integer number of current Newton step + */ + void prepareLinearSystem(int ntry, int nnewt) override; + + private: + /** temporary storage of Jacobian */ + SUNMatrixWrapper Jtmp; + + /** sparse linear solver */ + SUNLinearSolver linsol = nullptr; +}; + +/** + * @brief The NewtonSolverIterative provides access to the iterative linear + * solver for the Newton method. + */ + +class NewtonSolverIterative : public NewtonSolver { + + public: + /** + * 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 + */ + NewtonSolverIterative(realtype *t, AmiVector *x, Model *model, ReturnData *rdata); + ~NewtonSolverIterative() override = default; + + /** + * Solves the linear system for the Newton step by passing it to + * linsolveSPBCG + * + * @param rhs containing the RHS of the linear system, will be + * overwritten by solution to the linear system + */ + void solveLinearSystem(AmiVector &rhs) override; + + /** + * Writes the Jacobian 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 prepareLinearSystem(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 + * chosen. + * + * @param ntry integer newton_try integer start number of Newton solver + * (1 or 2) + * @param nnewt integer number of current Newton step + * @param ns_delta Newton step + */ + void linsolveSPBCG(int ntry, int nnewt, AmiVector &ns_delta); + + private: + /** number of tries */ + int newton_try = 0; + /** number of iterations */ + int i_newton = 0; + /** ??? */ + AmiVector ns_p; + /** ??? */ + AmiVector ns_h; + /** ??? */ + AmiVector ns_t; + /** ??? */ + AmiVector ns_s; + /** ??? */ + AmiVector ns_r; + /** ??? */ + AmiVector ns_rt; + /** ??? */ + AmiVector ns_v; + /** ??? */ + AmiVector ns_Jv; + /** ??? */ + AmiVector ns_tmp; + /** ??? */ + AmiVector ns_Jdiag; +}; + + +} // namespace amici + +#endif // NEWTON_SOLVER diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/rdata.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/rdata.h new file mode 100644 index 0000000..999d453 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/rdata.h @@ -0,0 +1,362 @@ +#ifndef AMICI_RDATA_H +#define AMICI_RDATA_H + +#include "amici/defines.h" + +#include <vector> + +namespace amici { +class Model; +class ReturnData; +class Solver; +class ExpData; +} + +namespace boost { +namespace serialization { +template <class Archive> +void serialize(Archive &ar, amici::ReturnData &u, unsigned int version); +}} + +namespace amici { + +/** + * @brief Stores all data to be returned by amici::runAmiciSimulation. + * + * NOTE: multidimensional arrays are stored in row-major order + * (FORTRAN-style) + */ +class ReturnData { + public: + /** + * @brief default constructor + */ + ReturnData() = default; + + /** + * @brief ReturnData + * @param ts see amici::Model::ts + * @param np see amici::Model::np + * @param nk see amici::Model::nk + * @param nx see amici::Model::nx_rdata + * @param nx_solver see amici::Model::nx_solver + * @param nxtrue see amici::Model::nxtrue_rdata + * @param ny see amici::Model::ny + * @param nytrue see amici::Model::nytrue + * @param nz see amici::Model::nz + * @param nztrue see amici::Model::nztrue + * @param ne see amici::Model::ne + * @param nJ see amici::Model::nJ + * @param nplist see amici::Model::nplist + * @param nmaxevent see amici::Model::nmaxevent + * @param nt see amici::Model::nt + * @param newton_maxsteps see amici::Solver::newton_maxsteps + * @param pscale see amici::Model::pscale + * @param o2mode see amici::Model::o2mode + * @param sensi see amici::Solver::sensi + * @param sensi_meth see amici::Solver::sensi_meth + */ + ReturnData( + std::vector<realtype> 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, std::vector<ParameterScaling> pscale, + SecondOrderMode o2mode, SensitivityOrder sensi, SensitivityMethod sensi_meth); + + /** + * @brief constructor that uses information from model and solver to + * appropriately initialize fields + * @param solver solver instance + * @param model model instance + * bool + */ + ReturnData(Solver const& solver, const Model &model); + + ~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); + + /** + * Residual function + * @param it time index + * @param edata ExpData instance containing observable data + */ + void fres(int it, const ExpData &edata); + + /** + * Chi-squared function + * @param it time index + */ + void fchi2(int it); + + /** + * Residual sensitivity function + * @param it time index + * @param edata ExpData instance containing observable data + */ + void fsres(int it, const ExpData &edata); + + /** + * Fisher information matrix function + * @param it time index + */ + void fFIM(int it); + + /** timepoints (dimension: nt) */ + std::vector<realtype> ts; + + /** time derivative (dimension: nx) */ + std::vector<realtype> xdot; + + /** Jacobian of differential equation right hand side (dimension: nx x nx, + * row-major) */ + std::vector<realtype> J; + + /** event output (dimension: nmaxevent x nz, row-major) */ + std::vector<realtype> z; + + /** event output sigma standard deviation (dimension: nmaxevent x nz, + * row-major) */ + std::vector<realtype> sigmaz; + + /** parameter derivative of event output (dimension: nmaxevent x nz, + * row-major) */ + std::vector<realtype> sz; + + /** parameter derivative of event output standard deviation (dimension: + * nmaxevent x nz, row-major) */ + std::vector<realtype> ssigmaz; + + /** event trigger output (dimension: nmaxevent x nz, row-major)*/ + std::vector<realtype> rz; + + /** parameter derivative of event trigger output (dimension: nmaxevent x nz + * x nplist, row-major) */ + std::vector<realtype> srz; + + /** second order parameter derivative of event trigger output (dimension: + * nmaxevent x nztrue x nplist x nplist, row-major) */ + std::vector<realtype> s2rz; + + /** state (dimension: nt x nx, row-major) */ + std::vector<realtype> x; + + /** parameter derivative of state (dimension: nt x nplist x nx, + * row-major) */ + std::vector<realtype> sx; + + /** observable (dimension: nt x ny, row-major) */ + std::vector<realtype> y; + + /** observable standard deviation (dimension: nt x ny, row-major) */ + std::vector<realtype> sigmay; + + /** parameter derivative of observable (dimension: nt x nplist x ny, + * row-major) */ + std::vector<realtype> sy; + + /** parameter derivative of observable standard deviation (dimension: nt x + * nplist x ny, row-major) */ + std::vector<realtype> ssigmay; + + /** observable (dimension: nt*ny, row-major) */ + std::vector<realtype> res; + + /** parameter derivative of residual (dimension: nt*ny x nplist, + * row-major) */ + std::vector<realtype> sres; + + /** fisher information matrix (dimension: nplist x nplist, + * row-major) */ + std::vector<realtype> FIM; + + /** number of integration steps forward problem (dimension: nt) */ + std::vector<int> numsteps; + + /** number of integration steps backward problem (dimension: nt) */ + std::vector<int> numstepsB; + + /** number of right hand side evaluations forward problem (dimension: nt) */ + std::vector<int> numrhsevals; + + /** number of right hand side evaluations backwad problem (dimension: nt) */ + std::vector<int> numrhsevalsB; + + /** number of error test failures forward problem (dimension: nt) */ + std::vector<int> numerrtestfails; + + /** number of error test failures backwad problem (dimension: nt) */ + std::vector<int> numerrtestfailsB; + + /** number of linear solver convergence failures forward problem (dimension: + * nt) */ + std::vector<int> numnonlinsolvconvfails; + + /** number of linear solver convergence failures backwad problem (dimension: + * nt) */ + std::vector<int> numnonlinsolvconvfailsB; + + /** employed order forward problem (dimension: nt) */ + std::vector<int> order; + + /** computation time of forward solve [ms] */ + double cpu_time = 0.0; + + /** computation time of backward solve [ms] */ + double cpu_timeB = 0.0; + + /** flag indicating success of Newton solver */ + int newton_status = 0; + + /** computation time of the Newton solver [ms] */ + double newton_cpu_time = 0.0; + + /** number of Newton steps for steady state problem + [newton, simulation, newton] (length = 3) */ + std::vector<int> newton_numsteps; + + /** number of linear steps by Newton step for steady state problem. this + will only be filled for iterative solvers (length = newton_maxsteps * 2) */ + std::vector<int> newton_numlinsteps; + + /** time at which steadystate was reached in the simulation based approach */ + realtype t_steadystate = NAN; + + /** weighted root-mean-square of the rhs when steadystate + was reached*/ + realtype wrms_steadystate = NAN; + + /** weighted root-mean-square of the rhs when steadystate + was reached*/ + realtype wrms_sensi_steadystate = NAN; + + + /** initial state (dimension: nx) */ + std::vector<realtype> x0; + + /** preequilibration steady state found by Newton solver (dimension: nx) */ + std::vector<realtype> x_ss; + + /** initial sensitivities (dimension: nplist x nx, row-major) */ + std::vector<realtype> sx0; + + /** preequilibration sensitivities found by Newton solver (dimension: nplist x nx, row-major) */ + std::vector<realtype> sx_ss; + + /** loglikelihood value */ + realtype llh = 0.0; + + /** chi2 value */ + realtype chi2 = 0.0; + + /** parameter derivative of loglikelihood (dimension: nplist) */ + std::vector<realtype> sllh; + + /** second order parameter derivative of loglikelihood (dimension: (nJ-1) x + * nplist, row-major) */ + std::vector<realtype> s2llh; + + /** status code */ + int status = 0; + + /** total number of model parameters */ + int np{0}; + + /** number of fixed parameters */ + int nk{0}; + + /** number of states */ + int nx{0}; + + /** number of states with conservation laws applied */ + int nx_solver{0}; + + /** number of states in the unaugmented system */ + int nxtrue{0}; + + /** number of observables */ + int ny{0}; + + /** number of observables in the unaugmented system */ + int nytrue{0}; + + /** number of event outputs */ + int nz{0}; + + /** number of event outputs in the unaugmented system */ + int nztrue{0}; + + /** number of events */ + int ne{0}; + + /** dimension of the augmented objective function for 2nd order ASA */ + int nJ{0}; + + /** number of parameter for which sensitivities were requested */ + int nplist{0}; + + /** maximal number of occuring events (for every event type) */ + int nmaxevent{0}; + + /** number of considered timepoints */ + int nt{0}; + + /** maximal number of newton iterations for steady state calculation */ + int newton_maxsteps{0}; + + /** scaling of parameterization (lin,log,log10) */ + std::vector<ParameterScaling> pscale; + + /** flag indicating whether second order sensitivities were requested */ + SecondOrderMode o2mode{SecondOrderMode::none}; + + /** sensitivity order */ + SensitivityOrder sensi{SensitivityOrder::none}; + + /** sensitivity method */ + SensitivityMethod sensi_meth{SensitivityMethod::none}; + + /** + * @brief Serialize ReturnData (see boost::serialization::serialize) + * @param ar Archive to serialize to + * @param r Data to serialize + * @param version Version number + */ + template <class Archive> + friend void boost::serialization::serialize(Archive &ar, ReturnData &r, + unsigned int version); +}; + +} // namespace amici + +#endif /* _MY_RDATA */ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/returndata_matlab.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/returndata_matlab.h new file mode 100644 index 0000000..becf417 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/returndata_matlab.h @@ -0,0 +1,135 @@ +#ifndef RETURNDATA_MATLAB_H +#define RETURNDATA_MATLAB_H + +#include "amici/rdata.h" + +#include <vector> + +#include <mex.h> + +namespace amici { + +/** + * @brief generates matlab mxArray from a ReturnData object + * @param rdata ReturnDataObject + * @return rdatamatlab ReturnDataObject stored as matlab compatible data + */ +mxArray *getReturnDataMatlabFromAmiciCall(ReturnData const *rdata); + +/** + * @brief allocates and initialises solution mxArray with the corresponding + * fields + * @param rdata ReturnDataObject + * @return Solution mxArray + */ +mxArray *initMatlabReturnFields(ReturnData const *rdata); + +/** + * @brief allocates and initialises diagnosis mxArray with the corresponding + * fields + * @param rdata ReturnDataObject + * @return Diagnosis mxArray + */ +mxArray *initMatlabDiagnosisFields(ReturnData const *rdata); + +/** + * @brief initialise vector and attach to the field + * @param matlabStruct pointer of the field to which the vector will be + * attached + * @param fieldName Name of the field to which the vector will be attached + * @param fieldData Data wich will be stored in the field + */ +template <typename T> +void writeMatlabField0(mxArray *matlabStruct, const char *fieldName, + T fieldData); + +/** + * @brief initialise vector and attach to the field + * @param matlabStruct pointer of the field to which the vector will be + * attached + * @param fieldName Name of the field to which the vector will be attached + * @param fieldData Data wich will be stored in the field + * @param dim0 Number of elements in the vector + */ +template <typename T> +void writeMatlabField1(mxArray *matlabStruct, const char *fieldName, + std::vector<T> const &fieldData, const int dim0); + +/** + * @brief initialise matrix, attach to the field and write data + * @param matlabStruct Pointer to the matlab structure + * @param fieldName Name of the field to which the tensor will be attached + * @param fieldData Data wich will be stored in the field + * @param dim0 Number of rows in the tensor + * @param dim1 Number of columns in the tensor + * @param perm reordering of dimensions (i.e., transposition) + */ +template <typename T> +void writeMatlabField2(mxArray *matlabStruct, const char *fieldName, + std::vector<T> const &fieldData, int dim0, int dim1, + std::vector<int> perm); + +/** + * @brief initialise 3D tensor, attach to the field and write data + * @param matlabStruct Pointer to the matlab structure + * @param fieldName Name of the field to which the tensor will be attached + * @param fieldData Data wich will be stored in the field + * @param dim0 number of rows in the tensor + * @param dim1 number of columns in the tensor + * @param dim2 number of elements in the third dimension of the tensor + * @param perm reordering of dimensions + */ +template <typename T> +void writeMatlabField3(mxArray *matlabStruct, const char *fieldName, + std::vector<T> const &fieldData, int dim0, int dim1, + int dim2, std::vector<int> perm); + +/** + * @brief initialise 4D tensor, attach to the field and write data + * @param matlabStruct Pointer to the matlab structure + * @param fieldName Name of the field to which the tensor will be attached + * @param fieldData Data wich will be stored in the field + * @param dim0 number of rows in the tensor + * @param dim1 number of columns in the tensor + * @param dim2 number of elements in the third dimension of the tensor + * @param dim3 number of elements in the fourth dimension of the tensor + * @param perm reordering of dimensions + */ +template <typename T> +void writeMatlabField4(mxArray *matlabStruct, const char *fieldName, + std::vector<T> const &fieldData, int dim0, int dim1, + int dim2, int dim3, std::vector<int> perm); + +/** + * @brief initialises the field fieldName in matlabStruct with dimension dim + * @param matlabStruct Pointer to the matlab structure + * @param fieldName Name of the field to which the tensor will be attached + * @param dim vector of field dimensions + * + * @return pointer to field data + */ +double *initAndAttachArray(mxArray *matlabStruct, const char *fieldName, + std::vector<mwSize> dim); + +/** + * @brief checks whether fieldNames was properly allocated + * @param fieldNames array of field names + * @param fieldCount expected number of fields in fieldNames + */ +void checkFieldNames(const char **fieldNames, const int fieldCount); + +/** + * @brief template function that reorders elements in a std::vector + * + * @param input unordered vector + * @param order dimension permutation + * + * @return Reordered vector + */ +template <typename T> +std::vector<T> reorder(std::vector<T> const& input, + std::vector<int> const& order); + +} // namespace amici + +#endif // RETURNDATA_MATLAB_H diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/serialization.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/serialization.h new file mode 100644 index 0000000..3feb3db --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/serialization.h @@ -0,0 +1,323 @@ +#ifndef AMICI_SERIALIZATION_H +#define AMICI_SERIALIZATION_H + +#include "amici/rdata.h" +#include "amici/model.h" +#include "amici/solver.h" +#include "amici/solver_cvodes.h" + +#include <cassert> +#include <fstream> +#include <iostream> + +#include <boost/serialization/array.hpp> +#include <boost/serialization/vector.hpp> +#include <boost/archive/binary_iarchive.hpp> +#include <boost/archive/binary_oarchive.hpp> +#include <boost/archive/text_iarchive.hpp> +#include <boost/archive/text_oarchive.hpp> +#include <boost/iostreams/device/back_inserter.hpp> +#include <boost/iostreams/stream.hpp> + +/* Helper functions and forward declarations for boost::serialization */ +namespace boost { +namespace serialization { + +template <class Archive, typename T> +void archiveVector(Archive &ar, T **p, int size) { + if (Archive::is_loading::value) { + if(*p != nullptr) + delete[] *p; + ar &size; + *p = size ? new T[size] : nullptr; + } else { + size = *p == nullptr ? 0 : size; + ar &size; + } + ar &make_array<T>(*p, size); +} + +template <class Archive> +void serialize(Archive &ar, amici::Solver &u, const unsigned int version) { + ar &u.sensi; + ar &u.atol; + ar &u.rtol; + ar &u.atolB; + ar &u.rtolB; + ar &u.atol_fsa; + ar &u.rtol_fsa; + ar &u.quad_atol; + ar &u.quad_rtol; + ar &u.ss_atol; + ar &u.ss_rtol; + ar &u.ss_atol_sensi; + ar &u.ss_rtol_sensi; + ar &u.maxsteps; + ar &u.maxstepsB; + ar &u.newton_preeq; + ar &u.newton_maxsteps; + ar &u.newton_maxlinsteps; + ar &u.ism; + ar &u.sensi_meth; + ar &u.linsol; + ar &u.interpType; + ar &u.lmm; + ar &u.iter; + ar &u.stldet; + ar &u.ordering; + ar &u.cpu_time; + ar &u.cpu_timeB; +} + + +template <class Archive> +void serialize(Archive &ar, amici::CVodeSolver &u, const unsigned int version) { + ar & static_cast<amici::Solver&>(u); +} + +template <class Archive> +void serialize(Archive &ar, amici::Model &u, const unsigned int version) { + ar &u.nx_rdata; + ar &u.nxtrue_rdata; + ar &u.nx_solver; + ar &u.nxtrue_solver; + ar &u.ny; + ar &u.nytrue; + ar &u.nz; + ar &u.nztrue; + ar &u.ne; + ar &u.nw; + ar &u.ndwdx; + ar &u.ndwdp; + ar &u.ndxdotdw; + ar &u.nnz; + ar &u.nJ; + ar &u.ubw; + ar &u.lbw; + ar &u.o2mode; + ar &u.z2event; + ar &u.idlist; + ar &u.h; + ar &u.unscaledParameters; + ar &u.originalParameters; + ar &u.fixedParameters; + ar &u.plist_; + ar &u.x0data; + ar &u.sx0data; + ar &u.ts; + ar &u.nmaxevent; + ar &u.pscale; + ar &u.tstart; + ar &u.stateIsNonNegative; +} + + +template <class Archive> +void serialize(Archive &ar, amici::ReturnData &r, const unsigned int version) { + ar &r.np; + ar &r.nk; + ar &r.nx; + ar &r.nx_solver; + ar &r.nxtrue; + ar &r.ny; + ar &r.nytrue; + ar &r.nz; + ar &r.nztrue; + ar &r.ne; + ar &r.nJ; + ar &r.nplist; + ar &r.nmaxevent; + ar &r.nt; + ar &r.newton_maxsteps; + ar &r.pscale; + ar &r.o2mode; + ar &r.sensi; + ar &r.sensi_meth; + + ar &r.ts; + ar &r.xdot; + ar &r.J; + ar &r.z & r.sigmaz; + ar &r.sz &r.ssigmaz; + ar &r.rz; + ar &r.srz; + ar &r.s2rz; + ar &r.x; + ar &r.sx; + ar &r.y & r.sigmay; + ar &r.sy & r.ssigmay; + + ar &r.numsteps; + ar &r.numstepsB; + ar &r.numrhsevals; + ar &r.numrhsevalsB; + ar &r.numerrtestfails; + ar &r.numerrtestfailsB; + ar &r.numnonlinsolvconvfails; + ar &r.numnonlinsolvconvfailsB; + 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.x0; + ar &r.sx0; + ar &r.llh; + ar &r.chi2; + ar &r.sllh; + ar &r.s2llh; + ar &r.status; +} + + +} // namespace serialization +} // namespace boost + +namespace amici { + +template <typename T> +char *serializeToChar(T const& data, int *size) { + /** + * @brief Serialize object to char array + * + * @param data input object + * @param size maximum char length + * + * @return The object serialized as char + */ + try { + std::string serialized; + ::boost::iostreams::back_insert_device<std::string> inserter(serialized); + ::boost::iostreams::stream<::boost::iostreams::back_insert_device<std::string>> + s(inserter); + ::boost::archive::binary_oarchive oar(s); + oar << data; + s.flush(); + + char *charBuffer = new char[serialized.size()]; + memcpy(charBuffer, serialized.data(), serialized.size()); + + if (size) + *size = serialized.size(); + + return charBuffer; + } catch(boost::archive::archive_exception const& e) { + throw AmiException("Serialization to char failed: %s", e.what()); + } +} + + + +template <typename T> +T deserializeFromChar(const char *buffer, int size) { + /** + * @brief Deserialize object that has been serialized using serializeToChar + * + * @param buffer serialized object + * @param size length of buffer + * + * @return The deserialized object + */ + try { + ::boost::iostreams::basic_array_source<char> device(buffer, size); + ::boost::iostreams::stream<::boost::iostreams::basic_array_source<char>> s( + device); + ::boost::archive::binary_iarchive iar(s); + T data; + iar >> data; + + return data; + } catch(::boost::archive::archive_exception const& e) { + throw AmiException("Deserialization from char failed: %s", e.what()); + } +} + + +template <typename T> +std::string serializeToString(T const& data) { + /** + * @brief Serialize object to string + * + * @param data input object + * + * @return The object serialized as string + */ + try { + std::string serialized; + ::boost::iostreams::back_insert_device<std::string> inserter(serialized); + ::boost::iostreams::stream< + ::boost::iostreams::back_insert_device<std::string>> + s(inserter); + ::boost::archive::binary_oarchive oar(s); + + oar << data; + s.flush(); + + return serialized; + } catch(::boost::archive::archive_exception const& e) { + throw AmiException("Serialization to string failed: %s", e.what()); + } +} + +template <typename T> +std::vector<char> serializeToStdVec(T const& data) { + /** + * @brief Serialize object to std::vector<char> + * + * @param data input object + * + * @return The object serialized as std::vector<char> + */ + try{ + std::string serialized; + ::boost::iostreams::back_insert_device<std::string> inserter(serialized); + ::boost::iostreams::stream<::boost::iostreams::back_insert_device<std::string>> + s(inserter); + ::boost::archive::binary_oarchive oar(s); + + oar << data; + s.flush(); + + std::vector<char> buf(serialized.begin(), serialized.end()); + + return buf; + } catch(::boost::archive::archive_exception const& e) { + throw AmiException("Serialization to StdVec failed: %s", e.what()); + } +} + +template <typename T> +T deserializeFromString(std::string const& serialized) { + /** + * @brief Deserialize object that has been serialized using serializeToString + * + * @param serialized serialized object + * + * @return The deserialized object + */ + try{ + ::boost::iostreams::basic_array_source<char> device(serialized.data(), + serialized.size()); + ::boost::iostreams::stream<::boost::iostreams::basic_array_source<char>> s( + device); + ::boost::archive::binary_iarchive iar(s); + T deserialized; + + iar >> deserialized; + + return deserialized; + } catch(::boost::archive::archive_exception const& e) { + throw AmiException("Deserialization from StdVec failed: %s", e.what()); + } +} + + +} // namespace amici +#endif // AMICI_SERIALIZATION_H diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/solver.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/solver.h new file mode 100644 index 0000000..6cb7edc --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/solver.h @@ -0,0 +1,1477 @@ +#ifndef AMICI_SOLVER_H +#define AMICI_SOLVER_H + +#include "amici/defines.h" +#include "amici/sundials_linsol_wrapper.h" +#include "amici/symbolic_functions.h" +#include "amici/vector.h" + +#include <functional> +#include <memory> + +namespace amici { + +class ReturnData; +class ForwardProblem; +class BackwardProblem; +class Model; +class Solver; +} // namespace amici + +// for serialization friend in Solver +namespace boost { +namespace serialization { +template <class Archive> +void serialize(Archive &ar, amici::Solver &u, unsigned int version); +} +} // namespace boost::serialization + +namespace amici { + +/** + * The Solver class provides a generic interface to CVODES and IDAS solvers, + * individual realizations are realized in the CVodeSolver and the IDASolver + * class. All transient private/protected members (CVODES/IDAS memory, interface + * variables and status flags) are specified as mutable and not included in + * serialization or equality checks. No solver setting parameter should be + * marked mutable. + * + * NOTE: Any changes in data members here must be propagated to copy ctor, + * equality operator, serialization functions in serialization.h, and + * amici::hdf5::readSolverSettingsFromHDF5 in hdf5.cpp. + */ +class Solver { + public: + Solver() = default; + + /** + * @brief Solver copy constructor + * @param other + */ + Solver(const Solver &other); + + virtual ~Solver() = default; + + /** + * @brief Clone this instance + * @return The clone + */ + virtual Solver *clone() const = 0; + + /** + * @brief runs a forward simulation until the specified timepoint + * + * @param tout next timepooint + * @return status flag + */ + int run(realtype tout) const; + + /** + * @brief makes a single step in the simulation + * + * @param tout next timepooint + * @return status flag + */ + int step(realtype tout) const; + + /** + * @brief runs a backward simulation until the specified timepoint + * + * @param tout next timepooint + */ + void runB(realtype tout) const; + + /** + * @brief Initialises the ami memory object and applies specified options + * @param t0 initial timepoint + * @param model pointer to the model instance + * @param x0 initial states + * @param dx0 initial derivative states + * @param sx0 initial state sensitivities + * @param sdx0 initial derivative state sensitivities + */ + + void setup(realtype t0, Model *model, const AmiVector &x0, + const AmiVector &dx0, const AmiVectorArray &sx0, + const AmiVectorArray &sdx0) const; + + /** + * @brief Initialises the AMI memory object for the backwards problem + * @param which index of the backward problem, will be set by this routine + * @param tf final timepoint (initial timepoint for the bwd problem) + * @param model pointer to the model instance + * @param xB0 initial adjoint states + * @param dxB0 initial adjoint derivative states + * @param xQB0 initial adjoint quadratures + */ + + void setupB(int *which, realtype tf, Model *model, + const AmiVector &xB0, 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 + */ + void getDiagnosis(int it, ReturnData *rdata) const; + + /** + * @brief Extracts diagnosis information from solver memory block and + * writes them into the return data object for the backward problem + * + * @param it time-point index + * @param rdata pointer to the return data object + * @param which identifier of the backwards problem + */ + void getDiagnosisB(int it, ReturnData *rdata, int which) const; + + /** + * getRootInfo extracts information which event occured + * + * @param rootsfound array with flags indicating whether the respective + * event occured + */ + virtual void getRootInfo(int *rootsfound) const = 0; + + /** + * @brief Calculates consistent initial conditions, assumes initial + * states to be correct (DAE only) + * + * @param tout1 next timepoint to be computed (sets timescale) + */ + virtual void calcIC(realtype tout1) const = 0; + + /** + * @brief Calculates consistent initial conditions for the backwards + * problem, assumes initial states to be correct (DAE only) + * + * @param which identifier of the backwards problem + * @param tout1 next timepoint to be computed (sets timescale) + */ + virtual void calcICB(int which, realtype tout1) const = 0; + + /** + * @brief Solves the backward problem until a predefined timepoint + * (adjoint only) + * + * @param tBout timepoint until which simulation should be performed + * @param itaskB task identifier, can be CV_NORMAL or CV_ONE_STEP + */ + virtual void solveB(realtype tBout, int itaskB) const = 0; + + /** + * @brief Disable rootfinding + */ + virtual void turnOffRootFinding() const = 0; + + /** + * @brief Return current sensitivity method + * @return method enum + */ + SensitivityMethod getSensitivityMethod() const; + + /** + * @brief Set sensitivity method + * @param sensi_meth + */ + void setSensitivityMethod(SensitivityMethod sensi_meth); + + /** + * @brief Get maximum number of allowed Newton steps for steady state + * computation + * @return + */ + int getNewtonMaxSteps() const; + + /** + * @brief Set maximum number of allowed Newton steps for steady state + * computation + * @param newton_maxsteps + */ + void setNewtonMaxSteps(int newton_maxsteps); + + /** + * @brief Get if preequilibration of model via Newton solver is enabled + * @return + */ + bool getNewtonPreequilibration() const; + + /** + * @brief Enable/disable preequilibration of model via Newton solver + * @param newton_preeq + */ + void setNewtonPreequilibration(bool newton_preeq); + + /** + * @brief Get maximum number of allowed linear steps per Newton step for + * steady state computation + * @return + */ + int getNewtonMaxLinearSteps() const; + + /** + * @brief Set maximum number of allowed linear steps per Newton step for + * steady state computation + * @param newton_maxlinsteps + */ + void setNewtonMaxLinearSteps(int newton_maxlinsteps); + + /** + * @brief Get sensitvity order + * @return sensitivity order + */ + SensitivityOrder getSensitivityOrder() const; + + /** + * @brief Set the sensitvity order + * @param sensi sensitivity order + */ + void setSensitivityOrder(SensitivityOrder sensi); + + /** + * @brief Get the relative tolerances for the forward problem + * + * Same tolerance is used for the backward problem if not specified + * differently via setRelativeToleranceASA. + * + * @return relative tolerances + */ + double getRelativeTolerance() const; + + /** + * @brief Sets the relative tolerances for the forward problem + * + * Same tolerance is used for the backward problem if not specified + * differently via setRelativeToleranceASA. + * + * @param rtol relative tolerance (non-negative number) + */ + void setRelativeTolerance(double rtol); + + /** + * @brief Get the absolute tolerances for the forward problem + * + * Same tolerance is used for the backward problem if not specified + * differently via setAbsoluteToleranceASA. + * + * @return absolute tolerances + */ + double getAbsoluteTolerance() const; + + /** + * @brief Sets the absolute tolerances for the forward problem + * + * Same tolerance is used for the backward problem if not specified + * differently via setAbsoluteToleranceASA. + * + * @param atol absolute tolerance (non-negative number) + */ + void setAbsoluteTolerance(double atol); + + /** + * @brief Returns the relative tolerances for the forward sensitivity + * problem + * @return relative tolerances + */ + double getRelativeToleranceFSA() const; + + /** + * @brief Sets the relative tolerances for the forward sensitivity problem + * @param rtol relative tolerance (non-negative number) + */ + void setRelativeToleranceFSA(double rtol); + + /** + * @brief Returns the absolute tolerances for the forward sensitivity + * problem + * @return absolute tolerances + */ + double getAbsoluteToleranceFSA() const; + + /** + * @brief Sets the absolute tolerances for the forward sensitivity problem + * @param atol absolute tolerance (non-negative number) + */ + void setAbsoluteToleranceFSA(double atol); + + /** + * @brief Returns the relative tolerances for the adjoint sensitivity + * problem + * @return relative tolerances + */ + double getRelativeToleranceB() const; + + /** + * @brief Sets the relative tolerances for the adjoint sensitivity problem + * @param rtol relative tolerance (non-negative number) + */ + void setRelativeToleranceB(double rtol); + + /** + * @brief Returns the absolute tolerances for the backward problem for + * adjoint sensitivity analysis + * @return absolute tolerances + */ + double getAbsoluteToleranceB() const; + + /** + * @brief Sets the absolute tolerances for the backward problem for + * adjoint sensitivity analysis + * @param atol absolute tolerance (non-negative number) + */ + void setAbsoluteToleranceB(double atol); + + /** + * @brief Returns the relative tolerance for the quadrature problem + * @return relative tolerance + */ + double getRelativeToleranceQuadratures() const; + + /** + * @brief sets the relative tolerance for the quadrature problem + * @param rtol relative tolerance (non-negative number) + */ + void setRelativeToleranceQuadratures(double rtol); + + /** + * @brief returns the absolute tolerance for the quadrature problem + * @return absolute tolerance + */ + double getAbsoluteToleranceQuadratures() const; + + /** + * @brief sets the absolute tolerance for the quadrature problem + * @param atol absolute tolerance (non-negative number) + */ + void setAbsoluteToleranceQuadratures(double atol); + + /** + * @brief returns the relative tolerance for the steady state problem + * @return relative tolerance + */ + double getRelativeToleranceSteadyState() const; + + /** + * @brief sets the relative tolerance for the steady state problem + * @param rtol relative tolerance (non-negative number) + */ + void setRelativeToleranceSteadyState(double rtol); + + /** + * @brief returns the absolute tolerance for the steady state problem + * @return absolute tolerance + */ + double getAbsoluteToleranceSteadyState() const; + + /** + * @brief sets the absolute tolerance for the steady state problem + * @param atol absolute tolerance (non-negative number) + */ + void setAbsoluteToleranceSteadyState(double atol); + + /** + * @brief returns the relative tolerance for the sensitivities of the + * steady state problem + * @return relative tolerance + */ + double getRelativeToleranceSteadyStateSensi() const; + + /** + * @brief sets the relative tolerance for the sensitivities of the + * steady state problem + * @param rtol relative tolerance (non-negative number) + */ + void setRelativeToleranceSteadyStateSensi(double rtol); + + /** + * @brief returns the absolute tolerance for the sensitivities of the + * steady state problem + * @return absolute tolerance + */ + double getAbsoluteToleranceSteadyStateSensi() const; + + /** + * @brief sets the absolute tolerance for the sensitivities of the + * steady state problem + * @param atol absolute tolerance (non-negative number) + */ + void setAbsoluteToleranceSteadyStateSensi(double atol); + + /** + * @brief returns the maximum number of solver steps for the forward + * problem + * @return maximum number of solver steps + */ + long int getMaxSteps() const; + + /** + * @brief sets the maximum number of solver steps for the forward problem + * @param maxsteps maximum number of solver steps (non-negative number) + */ + void setMaxSteps(long int maxsteps); + + /** + * @brief returns the maximum number of solver steps for the backward + * problem + * @return maximum number of solver steps + */ + long int getMaxStepsBackwardProblem() const; + + /** + * @brief sets the maximum number of solver steps for the backward problem + * @param maxsteps maximum number of solver steps (non-negative number) + */ + void setMaxStepsBackwardProblem(long int maxsteps); + + /** + * @brief returns the linear system multistep method + * @return linear system multistep method + */ + LinearMultistepMethod getLinearMultistepMethod() const; + + /** + * @brief sets the linear system multistep method + * @param lmm linear system multistep method + */ + void setLinearMultistepMethod(LinearMultistepMethod lmm); + + /** + * @brief returns the nonlinear system solution method + * @return + */ + NonlinearSolverIteration getNonlinearSolverIteration() const; + + /** + * @brief sets the nonlinear system solution method + * @param iter nonlinear system solution method + */ + void setNonlinearSolverIteration(NonlinearSolverIteration iter); + + /** + * @brief getInterpolationType + * @return + */ + InterpolationType getInterpolationType() const; + + /** + * @brief sets the interpolation of the forward solution that is used for + * the backwards problem + * @param interpType interpolation type + */ + void setInterpolationType(InterpolationType interpType); + + /** + * @brief Gets KLU / SuperLUMT state ordering mode + * + * @return State-ordering as integer according to + * SUNLinSolKLU::StateOrdering or SUNLinSolSuperLUMT::StateOrdering + * (which differ). + */ + int getStateOrdering() const; + + /** + * @brief Sets KLU / SuperLUMT state ordering mode + * + * This only applies when linsol is set to LinearSolver::KLU or + * LinearSolver::SuperLUMT. Mind the difference between + * SUNLinSolKLU::StateOrdering and SUNLinSolSuperLUMT::StateOrdering. + * @param ordering state ordering + */ + void setStateOrdering(int ordering); + + /** + * @brief returns stability limit detection mode + * @return stldet can be amici.FALSE (deactivated) or amici.TRUE (activated) + */ + booleantype getStabilityLimitFlag() const; + + /** + * @brief set stability limit detection mode + * @param stldet can be amici.FALSE (deactivated) or amici.TRUE (activated) + */ + void setStabilityLimitFlag(booleantype stldet); + + /** + * @brief getLinearSolver + * @return + */ + LinearSolver getLinearSolver() const; + + /** + * @brief setLinearSolver + * @param linsol + */ + void setLinearSolver(LinearSolver linsol); + + /** + * @brief returns the internal sensitivity method + * @return internal sensitivity method + */ + InternalSensitivityMethod getInternalSensitivityMethod() const; + + /** + * @brief sets the internal sensitivity method + * @param ism internal sensitivity method + */ + void setInternalSensitivityMethod(InternalSensitivityMethod ism); + + /** + * @brief write solution from forward simulation + * @param t time + * @param x state + * @param dx derivative state + * @param sx state sensitivity + */ + void writeSolution(realtype *t, AmiVector &x, AmiVector &dx, + AmiVectorArray &sx) const; + + /** + * @brief write solution from forward simulation + * @param t time + * @param xB adjoint state + * @param dxB adjoint derivative state + * @param xQB adjoint quadrature + * @param which index of adjoint problem + */ + void writeSolutionB(realtype *t, AmiVector &xB, AmiVector &dxB, + AmiVector &xQB, int which) const; + + /** + * @brief Access state solution at time t + * @param t time + * @return x or interpolated solution dky + */ + const AmiVector &getState(realtype t) const; + + /** + * @brief Access derivative state solution at time t + * @param t time + * @return dx or interpolated solution dky + */ + const AmiVector &getDerivativeState(realtype t) const; + + /** + * @brief Access state sensitivity solution at time t + * @param t time + * @return (interpolated) solution sx + */ + const AmiVectorArray &getStateSensitivity(realtype t) const; + + /** + * @brief Access adjoint solution at time t + * @param which adjoint problem index + * @param t time + * @return (interpolated) solution xB + */ + const AmiVector &getAdjointState(int which, realtype t) const; + + /** + * @brief Access adjoint derivative solution at time t + * @param which adjoint problem index + * @param t time + * @return (interpolated) solution dxB + */ + const AmiVector &getAdjointDerivativeState(int which, + realtype t) const; + + /** + * @brief Access adjoint quadrature solution at time t + * @param which adjoint problem index + * @param t time + * @return (interpolated) solution xQB + */ + const AmiVector &getAdjointQuadrature(int which, realtype t) const; + + /** + * @brief Reinitializes the states in the solver after an event occurence + * + * @param t0 reinitialization timepoint + * @param yy0 inital state variables + * @param yp0 initial derivative state variables (DAE only) + */ + virtual void reInit(realtype t0, const AmiVector &yy0, + const AmiVector &yp0) const = 0; + + /** + * @brief Reinitializes the state sensitivites in the solver after an + * event occurence + * + * @param yyS0 new state sensitivity + * @param ypS0 new derivative state sensitivities (DAE only) + */ + virtual void sensReInit(const AmiVectorArray &yyS0, + const AmiVectorArray &ypS0) const = 0; + + /** + * @brief Reinitializes the adjoint states after an event occurence + * + * @param which identifier of the backwards problem + * @param tB0 reinitialization timepoint + * @param yyB0 new adjoint state + * @param ypB0 new adjoint derivative state + */ + virtual void reInitB(int which, realtype tB0, + const AmiVector &yyB0, const AmiVector &ypB0) const = 0; + + /** + * @brief Reinitialize the adjoint states after an event occurence + * + * @param which identifier of the backwards problem + * @param yQB0 new adjoint quadrature state + */ + virtual void quadReInitB(int which, const AmiVector &yQB0) const = 0; + + /** + * @brief current solver timepoint + * @return t + */ + realtype gett() const; + + /** + * @brief Reads out the cpu time needed for forward solve + * @return cpu_time + */ + realtype getCpuTime() const; + + /** + * @brief Reads out the cpu time needed for bavkward solve + * @return cpu_timeB + */ + realtype getCpuTimeB() const; + + /** + * @brief number of states with which the solver was initialized + * @return x.getLength() + */ + int nx() const; + + /** + * @brief number of parameters with which the solver was initialized + * @return sx.getLength() + */ + int nplist() const; + + /** + * @brief number of quadratures with which the solver was initialized + * @return xQB.getLength() + */ + int nquad() const; + + /** + * @brief Serialize Solver (see boost::serialization::serialize) + * @param ar Archive to serialize to + * @param r Data to serialize + * @param version Version number + */ + template <class Archive> + friend void boost::serialization::serialize(Archive &ar, Solver &r, + unsigned int version); + + /** + * @brief Check equality of data members excluding solver memory + * @param a + * @param b + * @return + */ + friend bool operator==(const Solver &a, const Solver &b); + + protected: + /** + * @brief Sets a timepoint at which the simulation will be stopped + * + * @param tstop timepoint until which simulation should be performed + */ + virtual void setStopTime(realtype tstop) const = 0; + + /** + * @brief Solves the forward problem until a predefined timepoint + * + * @param tout timepoint until which simulation should be performed + * @param itask task identifier, can be CV_NORMAL or CV_ONE_STEP + * @return status flag indicating success of execution + */ + virtual int solve(realtype tout, int itask) const = 0; + + /** + * @brief Solves the forward problem until a predefined timepoint + * (adjoint only) + * + * @param tout timepoint until which simulation should be performed + * @param itask task identifier, can be CV_NORMAL or CV_ONE_STEP + * @param ncheckPtr pointer to a number that counts the internal + * checkpoints + * @return status flag indicating success of execution + */ + virtual int solveF(realtype tout, int itask, + int *ncheckPtr) const = 0; + + /** + * @brief reInitPostProcessF postprocessing of the solver memory after a + * discontinuity in the forward problem + * @param tnext next timepoint (defines integration direction) + */ + virtual void reInitPostProcessF(realtype tnext) const = 0; + + /** + * @brief reInitPostProcessB postprocessing of the solver memory after a + * discontinuity in the backward problem + * @param tnext next timepoint (defines integration direction) + */ + virtual void reInitPostProcessB(realtype tnext) const = 0; + + /** + * @brief extracts the state sensitivity at the current timepoint from + * solver memory and writes it to the sx member variable + */ + virtual void getSens() const = 0; + + /** + * @brief extracts the adjoint state at the current timepoint from + * solver memory and writes it to the xB member variable + * @param which index of the backwards problem + */ + virtual void getB(int which) const = 0; + + /** + * @brief extracts the adjoint quadrature state at the current timepoint + * from solver memory and writes it to the xQB member variable + * @param which index of the backwards problem + */ + virtual void getQuadB(int which) 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 init(realtype t0, const AmiVector &x0, + const AmiVector &dx0) const = 0; + + /** + * @brief initialises the forward sensitivities + * @param sx0 initial states semsitivities + * @param sdx0 initial derivative states sensitivities + */ + virtual void sensInit1(const AmiVectorArray &sx0, + const AmiVectorArray &sdx0) const = 0; + + /** + * @brief Initialise the adjoint states at the specified final timepoint + * + * @param which identifier of the backwards problem + * @param tf final timepoint + * @param xB0 initial adjoint state + * @param dxB0 initial adjoint derivative state + */ + virtual void binit(int which, realtype tf, const AmiVector &xB0, + const AmiVector &dxB0) const = 0; + + /** + * @brief Initialise the quadrature states at the specified final timepoint + * + * @param which identifier of the backwards problem + * @param xQB0 intial adjoint quadrature state + */ + virtual void qbinit(int which, const AmiVector &xQB0) const = 0; + + /** + * @brief Initialises the rootfinding for events + * + * @param ne number of different events + */ + virtual void rootInit(int ne) const = 0; + + /** + * @brief Initalize non-linear solver for sensitivities + * @param model Model instance + */ + void initializeNonLinearSolverSens(const Model *model) const; + + /** + * @brief Set the dense Jacobian function + */ + virtual void setDenseJacFn() const = 0; + + /** + * @brief sets the sparse Jacobian function + */ + virtual void setSparseJacFn() const = 0; + + /** + * @brief sets the banded Jacobian function + */ + virtual void setBandJacFn() const = 0; + + /** + * @brief sets the Jacobian vector multiplication function + */ + virtual void setJacTimesVecFn() const = 0; + + /** + * @brief sets the dense Jacobian function + * + * @param which identifier of the backwards problem + */ + virtual void setDenseJacFnB(int which) const = 0; + + /** + * @brief sets the sparse Jacobian function + * + * @param which identifier of the backwards problem + */ + virtual void setSparseJacFnB(int which) const = 0; + + /** + * @brief sets the banded Jacobian function + * + * @param which identifier of the backwards problem + */ + virtual void setBandJacFnB(int which) const = 0; + + /** + * @brief sets the Jacobian vector multiplication function + * + * @param which identifier of the backwards problem + */ + virtual void setJacTimesVecFnB(int which) const = 0; + + /** + * @brief Create specifies solver method and initializes solver memory for + * the forward problem + */ + virtual void allocateSolver() const = 0; + + /** + * @brief sets scalar relative and absolute tolerances for the forward + * problem + * + * @param rtol relative tolerances + * @param atol absolute tolerances + */ + virtual void setSStolerances(double rtol, + double atol) const = 0; + + /** + * @brief activates sets scalar relative and absolute tolerances for the + * sensitivity variables + * + * @param rtol relative tolerances + * @param atol array of absolute tolerances for every sensitivy variable + */ + virtual void setSensSStolerances(double rtol, + const double *atol) const = 0; + + /** + * SetSensErrCon specifies whether error control is also enforced for + * sensitivities for the forward problem + * + * @param error_corr activation flag + */ + virtual void setSensErrCon(bool error_corr) const = 0; + + /** + * @brief Specifies whether error control is also enforced for the + * backward quadrature problem + * + * @param which identifier of the backwards problem + * @param flag activation flag + */ + virtual void setQuadErrConB(int which, bool flag) const = 0; + + /** + * @brief Attaches the error handler function (errMsgIdAndTxt) + * to the solver + * + */ + virtual void setErrHandlerFn() const = 0; + + /** + * @brief Attaches the user data instance (here this is a Model) to the + * forward problem + * + * @param model Model instance + */ + virtual void setUserData(Model *model) const = 0; + + /** + * @brief attaches the user data instance (here this is a Model) to the + * backward problem + * + * @param which identifier of the backwards problem + * @param model Model instance + */ + virtual void setUserDataB(int which, Model *model) const = 0; + + /** + * @brief specifies the maximum number of steps for the forward + * problem + * + * @param mxsteps number of steps + */ + virtual void setMaxNumSteps(long int mxsteps) const = 0; + + /** + * @brief specifies the maximum number of steps for the forward + * problem + * + * @param which identifier of the backwards problem + * @param mxstepsB number of steps + */ + virtual void setMaxNumStepsB(int which, long int mxstepsB) const = 0; + + /** + * @brief activates stability limit detection for the forward + * problem + * + * @param stldet flag for stability limit detection (TRUE or FALSE) + * + */ + virtual void setStabLimDet(int stldet) const = 0; + + /** + * @brief activates stability limit detection for the backward + * problem + * + * @param which identifier of the backwards problem + * @param stldet flag for stability limit detection (TRUE or FALSE) + * + */ + virtual void setStabLimDetB(int which, int stldet) const = 0; + + /** + * @brief specify algebraic/differential components (DAE only) + * + * @param model model specification + */ + virtual void setId(const Model *model) const = 0; + + /** + * @brief deactivates error control for algebraic components (DAE only) + * + * @param flag deactivation flag + */ + virtual void setSuppressAlg(bool flag) const = 0; + + /** + * @brief specifies the scaling and indexes for sensitivity + * computation + * + * @param p paramaters + * @param pbar parameter scaling constants + * @param plist parameter index list + */ + virtual void setSensParams(const realtype *p, const realtype *pbar, + const int *plist) const = 0; + + /** + * @brief interpolates the (derivative of the) solution at the requested + * timepoint + * + * @param t timepoint + * @param k derivative order + */ + virtual void getDky(realtype t, int k) const = 0; + + /** + * @brief interpolates the (derivative of the) solution at the requested + * timepoint + * + * @param t timepoint + * @param k derivative order + * @param which index of backward problem + */ + virtual void getDkyB(realtype t, int k, + int which) const = 0; + + /** + * @brief interpolates the (derivative of the) solution at the requested + * timepoint + * + * @param t timepoint + * @param k derivative order + */ + virtual void getSensDky(realtype t, int k) const = 0; + + /** + * @brief interpolates the (derivative of the) solution at the requested + * timepoint + * + * @param t timepoint + * @param k derivative order + * @param which index of backward problem + */ + virtual void getQuadDkyB(realtype t, int k, + int which) const = 0; + + /** + * @brief initializes the adjoint problem + * + */ + virtual void adjInit() const = 0; + + /** + * @brief Specifies solver method and initializes solver memory for the + * backward problem + * + * @param which identifier of the backwards problem + */ + virtual void allocateSolverB(int *which) const = 0; + + /** + * @brief sets relative and absolute tolerances for the backward + * problem + * + * @param which identifier of the backwards problem + * @param relTolB relative tolerances + * @param absTolB absolute tolerances + */ + virtual void setSStolerancesB(int which, realtype relTolB, + realtype absTolB) const = 0; + + /** + * @brief sets relative and absolute tolerances for the quadrature + * backward problem + * + * @param which identifier of the backwards problem + * @param reltolQB relative tolerances + * @param abstolQB absolute tolerances + */ + virtual void quadSStolerancesB(int which, realtype reltolQB, + realtype abstolQB) const = 0; + + /** + * @brief reports the number of solver steps + * + * @param ami_mem pointer to the solver memory instance (can be from + * forward or backward problem) + * @param numsteps output array + */ + virtual void getNumSteps(const void *ami_mem, long int *numsteps) const = 0; + + /** + * @brief reports the number of right hand evaluations + * + * @param ami_mem pointer to the solver memory instance (can be from + * forward or backward problem) + * @param numrhsevals output array + */ + virtual void getNumRhsEvals(const void *ami_mem, + long int *numrhsevals) const = 0; + + /** + * @brief reports the number of local error test failures + * + * @param ami_mem pointer to the solver memory instance (can be from + * forward or backward problem) + * @param numerrtestfails output array + */ + virtual void getNumErrTestFails(const void *ami_mem, + long int *numerrtestfails) const = 0; + + /** + * @brief reports the number of nonlinear convergence failures + * + * @param ami_mem pointer to the solver memory instance (can be from + * forward or backward problem) + * @param numnonlinsolvconvfails output array + */ + virtual void + getNumNonlinSolvConvFails(const void *ami_mem, + long int *numnonlinsolvconvfails) const = 0; + + /** + * @brief Reports the order of the integration method during the + * last internal step + * + * @param ami_mem pointer to the solver memory instance (can be from + * forward or backward problem) + * @param order output array + */ + virtual void getLastOrder(const void *ami_mem, int *order) const = 0; + + /** + * @brief Initializes and sets the linear solver for the forward problem + * + * @param model pointer to the model object + */ + void initializeLinearSolver(const Model *model) const; + + /** + * @brief Sets the non-linear solver + */ + void initializeNonLinearSolver() const; + + /** + * @brief Sets the linear solver for the forward problem + */ + virtual void setLinearSolver() const = 0; + + /** + * @brief Sets the linear solver for the backward problem + * @param which index of the backward problem + */ + virtual void setLinearSolverB(int which) const = 0; + + /** + * @brief Set the non-linear solver for the forward problem + */ + virtual void setNonLinearSolver() const = 0; + + /** + * @brief Set the non-linear solver for the backward problem + * @param which index of the backward problem + */ + virtual void setNonLinearSolverB(int which) const = 0; + + /** + * @brief Set the non-linear solver for sensitivities + */ + virtual void setNonLinearSolverSens() const = 0; + + /** + * @brief Initializes the linear solver for the backward problem + * + * @param model pointer to the model object + * @param which index of the backward problem + */ + + void initializeLinearSolverB(const Model *model, int which) const; + + /** + * @brief Initializes the non-linear solver for the backward problem + * @param which index of the backward problem + */ + void initializeNonLinearSolverB(int which) const; + + /** + * Accessor function to the model stored in the user data + * + * @return user data model + */ + virtual const Model *getModel() const = 0; + + /** + * @brief checks whether memory for the forward problem has been allocated + * + * @return proxy for solverMemory->(cv|ida)_MallocDone + */ + bool getInitDone() const; + + /** + * @brief checks whether memory for forward sensitivities has been allocated + * + * @return proxy for solverMemory->(cv|ida)_SensMallocDone + */ + bool getSensInitDone() const; + + /** + * @brief checks whether memory for forward interpolation has been allocated + * + * @return proxy for solverMemory->(cv|ida)_adjMallocDone + */ + bool getAdjInitDone() const; + + /** + * @brief checks whether memory for the backward problem has been allocated + * @param which adjoint problem index + * @return proxy for solverMemoryB->(cv|ida)_MallocDone + */ + bool getInitDoneB(int which) const; + + /** + * @brief checks whether memory for backward quadratures has been allocated + * @param which adjoint problem index + * @return proxy for solverMemoryB->(cv|ida)_QuadMallocDone + */ + bool getQuadInitDoneB(int which) const; + + /** + * @brief attaches a diagonal linear solver to the forward problem + */ + virtual void diag() const = 0; + + /** + * @brief attaches a diagonal linear solver to the backward problem + * + * @param which identifier of the backwards problem + */ + virtual void diagB(int which) const = 0; + + /** + * @brief resets solverMemory and solverMemoryB + * @param nx new number of state variables + * @param nplist new number of sensitivity parameters + * @param nquad new number of quadratures (only differs from nplist for + * higher order senisitivity computation) + */ + void resetMutableMemory(int nx, int nplist, int nquad) const; + + /** + * @brief Retrieves the solver memory instance for the backward problem + * + * @param which identifier of the backwards problem + * @param ami_mem pointer to the forward solver memory instance + */ + virtual void *getAdjBmem(void *ami_mem, int which) const = 0; + + /** + * @brief updates solver tolerances according to the currently specified + * member variables + */ + void applyTolerances() const; + + /** + * @brief updates FSA solver tolerances according to the currently + * specified member variables + */ + void applyTolerancesFSA() const; + + /** + * @brief updates ASA solver tolerances according to the currently + * specified member variables + * + * @param which identifier of the backwards problem + */ + void applyTolerancesASA(int which) const; + + /** + * @brief updates ASA quadrature solver tolerances according to the + * currently specified member variables + * + * @param which identifier of the backwards problem + */ + void applyQuadTolerancesASA(int which) const; + + /** + * @brief updates all senstivivity solver tolerances according to the + * currently specified member variables + */ + void applySensitivityTolerances() const; + + /** pointer to solver memory block */ + mutable std::unique_ptr<void, std::function<void(void *)>> solverMemory; + + /** pointer to solver memory block */ + mutable std::vector<std::unique_ptr<void, std::function<void(void *)>>> + solverMemoryB; + + /** internal sensitivity method flag used to select the sensitivity solution + * method. Only applies for Forward Sensitivities. */ + InternalSensitivityMethod ism = InternalSensitivityMethod::simultaneous; + + /** specifies the linear multistep method. + */ + LinearMultistepMethod lmm = LinearMultistepMethod::BDF; + + /** + * specifies the type of nonlinear solver iteration + */ + NonlinearSolverIteration iter = NonlinearSolverIteration::newton; + + /** interpolation type for the forward problem solution which + * is then used for the backwards problem. + */ + InterpolationType interpType = InterpolationType::hermite; + + /** maximum number of allowed integration steps */ + long int maxsteps = 10000; + + /** linear solver for the forward problem */ + mutable std::unique_ptr<SUNLinSolWrapper> linearSolver; + + /** linear solver for the backward problem */ + mutable std::unique_ptr<SUNLinSolWrapper> linearSolverB; + + /** non-linear solver for the forward problem */ + mutable std::unique_ptr<SUNNonLinSolWrapper> nonLinearSolver; + + /** non-linear solver for the backward problem */ + mutable std::unique_ptr<SUNNonLinSolWrapper> nonLinearSolverB; + + /** non-linear solver for the sensitivities */ + mutable std::unique_ptr<SUNNonLinSolWrapper> nonLinearSolverSens; + + /** flag indicating whether the forward solver has been called */ + mutable bool solverWasCalledF = false; + + /** flag indicating whether the backward solver has been called */ + mutable bool solverWasCalledB = false; + + /** + * @brief sets that memory for the forward problem has been allocated + */ + void setInitDone() const; + + /** + * @brief sets that memory for forward sensitivities has been allocated + */ + void setSensInitDone() const; + + /** + * @brief sets that memory for forward interpolation has been allocated + */ + void setAdjInitDone() const; + + /** + * @brief sets that memory for the backward problem has been allocated + * @param which adjoint problem index + */ + void setInitDoneB(int which) const; + + /** + * @brief sets that memory for backward quadratures has been allocated + * @param which adjoint problem index + */ + void setQuadInitDoneB(int which) const; + + /** state (dimension: nx_solver) */ + mutable AmiVector x = AmiVector(0); + + /** state interface variable (dimension: nx_solver) */ + mutable AmiVector dky = AmiVector(0); + + /** state derivative dummy (dimension: nx_solver) */ + mutable AmiVector dx = AmiVector(0); + + /** state sensititivities interface variable (dimension: nx_solver x nplist) + */ + mutable AmiVectorArray sx = AmiVectorArray(0, 0); + /** state derivative sensititivities dummy (dimension: nx_solver x nplist) + */ + mutable AmiVectorArray sdx = AmiVectorArray(0, 0); + + /** adjoint state interface variable (dimension: nx_solver) */ + mutable AmiVector xB = AmiVector(0); + + /** adjoint derivative dummy variable (dimension: nx_solver) */ + mutable AmiVector dxB = AmiVector(0); + + /** adjoint quadrature interface variable (dimension: nJ x nplist) */ + mutable AmiVector xQB = AmiVector(0); + + /** integration time of the forward problem */ + mutable realtype t; + + /** flag to force reInitPostProcessF before next call to solve */ + mutable bool forceReInitPostProcessF = false; + + /** flag to force reInitPostProcessB before next call to solveB */ + mutable bool forceReInitPostProcessB = false; + + private: + + /** method for sensitivity computation */ + SensitivityMethod sensi_meth = SensitivityMethod::forward; + + /** flag controlling stability limit detection */ + booleantype stldet = true; + + /** state ordering */ + int ordering = static_cast<int>(SUNLinSolKLU::StateOrdering::AMD); + + /** maximum number of allowed Newton steps for steady state computation */ + long int newton_maxsteps = 0; + + /** maximum number of allowed linear steps per Newton step for steady state + * computation */ + long int newton_maxlinsteps = 0; + + /** Preequilibration of model via Newton solver? */ + bool newton_preeq = false; + + /** linear solver specification */ + LinearSolver linsol = LinearSolver::KLU; + + /** absolute tolerances for integration */ + realtype atol = 1e-16; + + /** relative tolerances for integration */ + realtype rtol = 1e-8; + + /** absolute tolerances for forward sensitivity integration */ + realtype atol_fsa = NAN; + + /** relative tolerances for forward sensitivity integration */ + realtype rtol_fsa = NAN; + + /** absolute tolerances for adjoint sensitivity integration */ + realtype atolB = NAN; + + /** relative tolerances for adjoint sensitivity integration */ + realtype rtolB = NAN; + + /** absolute tolerances for backward quadratures */ + realtype quad_atol = 1e-12; + + /** relative tolerances for backward quadratures */ + realtype quad_rtol = 1e-8; + + /** absolute tolerances for steadystate computation */ + realtype ss_atol = NAN; + + /** relative tolerances for steadystate computation */ + realtype ss_rtol = NAN; + + /** absolute tolerances for steadystate computation */ + realtype ss_atol_sensi = NAN; + + /** relative tolerances for steadystate computation */ + realtype ss_rtol_sensi = NAN; + + /** CPU time, forward solve */ + mutable realtype cpu_time = 0.0; + + /** CPU time, backward solve */ + mutable realtype cpu_timeB = 0.0; + + /** maximum number of allowed integration steps for backward problem */ + long int maxstepsB = 0; + + /** flag indicating whether sensitivities are supposed to be computed */ + SensitivityOrder sensi = SensitivityOrder::none; + + /** flag indicating whether init was called */ + mutable bool initialized = false; + + /** flag indicating whether sensInit1 was called */ + mutable bool sensInitialized = false; + + /** flag indicating whether adjInit was called */ + mutable bool adjInitialized = false; + + /** vector of flags indicating whether binit was called for respective + which */ + mutable std::vector<bool> initializedB{false}; + + /** vector of flags indicating whether qbinit was called for respective + which */ + mutable std::vector<bool> initializedQB{false}; + + /** number of checkpoints in the forward problem */ + mutable int ncheckPtr = 0; +}; + +bool operator==(const Solver &a, const Solver &b); + +/** + * @brief Extracts diagnosis information from solver memory block and + * writes them into the return data object for the backward problem + * + * @param error_code error identifier + * @param module name of the module in which the error occured + * @param function name of the function in which the error occured @type + * char + * @param msg error message + * @param eh_data unused input + */ +void wrapErrHandlerFn(int error_code, const char *module, + const char *function, char *msg, void *eh_data); + +} // namespace amici + +#endif // AMICISOLVER_H diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/solver_cvodes.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/solver_cvodes.h new file mode 100644 index 0000000..ce2278c --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/solver_cvodes.h @@ -0,0 +1,209 @@ +#ifndef AMICI_SOLVER_CVODES_h +#define AMICI_SOLVER_CVODES_h + +#include "amici/defines.h" +#include "amici/solver.h" +#include "amici/vector.h" + +#include <sundials/sundials_matrix.h> + +namespace amici { +class ExpData; +class ReturnData; +class Model_ODE; +class CVodeSolver; +} // namespace amici + +// for serialization friend in Solver +namespace boost { +namespace serialization { +template <class Archive> +void serialize(Archive &ar, amici::CVodeSolver &u, unsigned int version); +} +} // namespace boost::serialization + +namespace amici { + +class CVodeSolver : public Solver { + public: + CVodeSolver() = default; + + ~CVodeSolver() override = default; + + /** + * @brief Clone this instance + * @return The clone + */ + Solver *clone() const override; + + void reInit(realtype t0, const AmiVector &yy0, + const AmiVector &yp0) const override; + + void sensReInit(const AmiVectorArray &yyS0, + const AmiVectorArray &ypS0) const override; + + void reInitB(int which, realtype tB0, + const AmiVector &yyB0, const AmiVector &ypB0) const override; + + void quadReInitB(int which, const AmiVector &yQB0) const override; + + int solve(realtype tout, int itask) const override; + + int solveF(realtype tout, int itask, + int *ncheckPtr) const override; + + void solveB(realtype tBout, int itaskB) const override; + + void getDky(realtype t, int k) const override; + + void getSensDky(realtype t, int k) const override; + + void getQuadDkyB(realtype t, int k, + int which) const override; + + void getDkyB(realtype t, int k, int which) const override; + + void getRootInfo(int *rootsfound) const override; + + void setStopTime(realtype tstop) const override; + + void turnOffRootFinding() const override; + + const Model *getModel() const override; + + using Solver::setLinearSolver; + + using Solver::setLinearSolverB; + + void setLinearSolver() const override; + + void setLinearSolverB(int which) const override; + + void setNonLinearSolver() const override; + + void setNonLinearSolverSens() const override; + + void setNonLinearSolverB(int which) const override; + + protected: + + void calcIC(realtype tout1) const override; + + void calcICB(int which, realtype tout1) const override; + + void getB(int which) const override; + + void getSens() const override; + + void getQuadB(int which) const override; + + void reInitPostProcessF(realtype tnext) const override; + + void reInitPostProcessB(realtype tnext) const override; + + void reInitPostProcess(void *ami_mem, realtype *t, AmiVector *yout, + realtype tout) const; + + void allocateSolver() const override; + + void setSStolerances(double rtol, double atol) const override; + + void setSensSStolerances(double rtol, + const double *atol) const override; + + void setSensErrCon(bool error_corr) const override; + + void setQuadErrConB(int which, bool flag) const override; + + void setErrHandlerFn() const override; + + void setUserData(Model *model) const override; + + void setUserDataB(int which, Model *model) const override; + + void setMaxNumSteps(long int mxsteps) const override; + + void setStabLimDet(int stldet) const override; + + void setStabLimDetB(int which, int stldet) const override; + + void setId(const Model *model) const override; + + void setSuppressAlg(bool flag) const override; + + void resetState(void *cv_mem, const_N_Vector y0) const; + + void setSensParams(const realtype *p, const realtype *pbar, + const int *plist) const override; + + void adjInit() const override; + + void allocateSolverB(int *which) const override; + + void setSStolerancesB(int which, realtype relTolB, + realtype absTolB) const override; + + void quadSStolerancesB(int which, realtype reltolQB, + realtype abstolQB) const override; + + void setMaxNumStepsB(int which, long int mxstepsB) const override; + + void diag() const override; + + void diagB(int which) const override; + + void getNumSteps(const void *ami_mem, long int *numsteps) const override; + + void getNumRhsEvals(const void *ami_mem, + long int *numrhsevals) const override; + + void getNumErrTestFails(const void *ami_mem, + long int *numerrtestfails) const override; + + void + getNumNonlinSolvConvFails(const void *ami_mem, + long int *numnonlinsolvconvfails) const override; + + void getLastOrder(const void *ami_ami_mem, int *order) const override; + + void *getAdjBmem(void *ami_mem, int which) const override; + + template <class Archive> + friend void boost::serialization::serialize(Archive &ar, CVodeSolver &r, + unsigned int version); + + friend bool operator==(const CVodeSolver &a, const CVodeSolver &b); + + void init(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, const AmiVector &xB0, + const AmiVector &dxB0) const override; + + void qbinit(int which, const AmiVector &xQB0) const override; + + void rootInit(int ne) const override; + + void setDenseJacFn() const override; + + void setSparseJacFn() const override; + + void setBandJacFn() const override; + + void setJacTimesVecFn() const override; + + void setDenseJacFnB(int which) const override; + + void setSparseJacFnB(int which) const override; + + void setBandJacFnB(int which) const override; + + void setJacTimesVecFnB(int which) const override; +}; + +} // namespace amici + +#endif /* CVodewrap_h */ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/solver_idas.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/solver_idas.h new file mode 100644 index 0000000..21648dd --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/solver_idas.h @@ -0,0 +1,196 @@ +#ifndef AMICI_SOLVER_IDAS_h +#define AMICI_SOLVER_IDAS_h + +#include "amici/solver.h" + +#include <sundials/sundials_matrix.h> + +namespace amici { +class ExpData; +class ReturnData; +class Model_DAE; +class IDASolver; +} // namespace amici + +// for serialization friend in Solver +namespace boost { +namespace serialization { +template <class Archive> +void serialize(Archive &ar, amici::IDASolver &u, unsigned int version); +} +} // namespace boost::serialization + +namespace amici { + +class IDASolver : public Solver { + public: + IDASolver() = default; + ~IDASolver() override = default; + + /** + * @brief Clone this instance + * @return The clone + */ + Solver *clone() const override; + + void reInitPostProcessF(realtype tnext) const override; + + void reInitPostProcessB(realtype tnext) const override; + + void reInit(realtype t0, const AmiVector &yy0, + const AmiVector &yp0) const override; + + void sensReInit(const AmiVectorArray &yyS0, + const AmiVectorArray &ypS0) const override; + + void reInitB(int which, realtype tB0, + const AmiVector &yyB0, const AmiVector &ypB0) const override; + + void quadReInitB(int which, const AmiVector &yQB0) const override; + + void quadSStolerancesB(int which, realtype reltolQB, + realtype abstolQB) const override; + + int solve(realtype tout, int itask) const override; + + int solveF(realtype tout, int itask, + int *ncheckPtr) const override; + + void solveB(realtype tBout, int itaskB) const override; + + void getRootInfo(int *rootsfound) const override; + + void getDky(realtype t, int k) const override; + + void getSens() const override; + + void getSensDky(realtype t, int k) const override; + + void getB(int which) const override; + + void getDkyB(realtype t, int k, int which) const override; + + void getQuadB(int which) const override; + + void getQuadDkyB(realtype t, int k, int which) const override; + + void calcIC(realtype tout1) const override; + + void calcICB(int which, realtype tout1) const override; + + void setStopTime(realtype tstop) const override; + + void turnOffRootFinding() const override; + + const Model *getModel() const override; + + void setLinearSolver() const override; + + void setLinearSolverB(int which) const override; + + void setNonLinearSolver() const override; + + void setNonLinearSolverSens() const override; + + void setNonLinearSolverB(int which) const override; + + protected: + void reInitPostProcess(void *ami_mem, realtype *t, AmiVector *yout, + AmiVector *ypout, realtype tout) const; + + void allocateSolver() const override; + + void setSStolerances(realtype rtol, + realtype atol) const override; + + void setSensSStolerances(realtype rtol, + const realtype *atol) const override; + + void setSensErrCon(bool error_corr) const override; + + void setQuadErrConB(int which, bool flag) const override; + + void setErrHandlerFn() const override; + + void setUserData(Model *model) const override; + + void setUserDataB(int which, Model *model) const override; + + void setMaxNumSteps(long int mxsteps) const override; + + void setStabLimDet(int stldet) const override; + + void setStabLimDetB(int which, int stldet) const override; + + void setId(const Model *model) const override; + + void setSuppressAlg(bool flag) const override; + + void resetState(void *ida_mem, const_N_Vector yy0, + const_N_Vector yp0) const; + + void setSensParams(const realtype *p, const realtype *pbar, + const int *plist) const override; + + void adjInit() const override; + + void allocateSolverB(int *which) const override; + + void setMaxNumStepsB(int which, + long int mxstepsB) const override; + + void setSStolerancesB(int which, realtype relTolB, + realtype absTolB) const override; + + void diag() const override; + + void diagB(int which) const override; + + void getNumSteps(const void *ami_mem, long int *numsteps) const override; + + void getNumRhsEvals(const void *ami_mem, + long int *numrhsevals) const override; + + void getNumErrTestFails(const void *ami_mem, + long int *numerrtestfails) const override; + + void + getNumNonlinSolvConvFails(const void *ami_mem, + long int *numnonlinsolvconvfails) const override; + + void getLastOrder(const void *ami_mem, int *order) const override; + + void *getAdjBmem(void *ami_mem, int which) const override; + + void init(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, + const AmiVector &xB0, const AmiVector &dxB0) const override; + + void qbinit(int which, const AmiVector &xQB0) const override; + + void rootInit(int ne) const override; + + void setDenseJacFn() const override; + + void setSparseJacFn() const override; + + void setBandJacFn() const override; + + void setJacTimesVecFn() const override; + + void setDenseJacFnB(int which) const override; + + void setSparseJacFnB(int which) const override; + + void setBandJacFnB(int which) const override; + + void setJacTimesVecFnB(int which) const override; +}; + +} // namespace amici + +#endif /* idawrap_h */ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/spline.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/spline.h new file mode 100644 index 0000000..60614bf --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/spline.h @@ -0,0 +1,18 @@ +#ifndef amici_spline_h +#define amici_spline_h +#include <math.h> + +namespace amici { + +int spline(int n, int end1, int end2, double slope1, double slope2, double x[], + double y[], double b[], double c[], double d[]); + +double seval(int n, double u, double x[], double y[], double b[], double c[], + double d[]); + +double sinteg(int n, double u, double x[], double y[], double b[], double c[], + double d[]); + +} // namespace amici + +#endif /* spline_h */ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/steadystateproblem.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/steadystateproblem.h new file mode 100644 index 0000000..0f6d36b --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/steadystateproblem.h @@ -0,0 +1,152 @@ +#ifndef AMICI_STEADYSTATEPROBLEM_H +#define AMICI_STEADYSTATEPROBLEM_H + +#include "amici/defines.h" +#include "amici/vector.h" +#include "amici/solver_cvodes.h" +#include <amici/newton_solver.h> + +#include <nvector/nvector_serial.h> + +#include <functional> +#include <memory> + +namespace amici { + +class ReturnData; +class Solver; +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); + + /** + * 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 + * @return root-mean-square norm + */ + realtype getWrmsNorm(AmiVector const &x, + AmiVector const &xdot, + realtype atol, + realtype rtol + ); + + /** + * Checks convergence for state and respective sensitivities + * + * @param solver Solver instance + * @param model instance + * @return boolean indicating convergence + */ + bool checkConvergence(const Solver *solver, + Model *model); + + /** + * 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 + * @param newtonSolver pointer to the NewtonSolver object @type + * NewtonSolver + * @param steadystate_try start status of Newton solver + */ + 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); + + /** + * 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 + */ + void getSteadystateSimulation(ReturnData *rdata, Solver *solver, + Model *model); + + /** + * initialize CVodeSolver instance for preequilibration simulation + * + * @param solver pointer to the AMICI solver object + * @param model pointer to the AMICI model object + * @return solver instance + */ + std::unique_ptr<Solver> createSteadystateSimSolver(const Solver *solver, + Model *model) const; + + /** + * @brief constructor + * @param solver pointer to Solver instance + * @param x0 initial state + */ + explicit SteadystateProblem(const Solver *solver, const AmiVector &x0); + + /** + * @brief routine that writes solutions of steadystate problem to target + vectors + * @param t final timepoint + * @param x steadystate state + * @param sx steadystate state sensitivity + */ + void writeSolution(realtype *t, AmiVector &x, AmiVectorArray &sx) const; + + + private: + /** time variable for simulation steadystate finding */ + realtype t; + /** newton step */ + AmiVector delta; + /** error weights */ + AmiVector ewt; + /** container for relative error calcuation? */ + AmiVector rel_x_newton; + /** container for absolute error calcuation? */ + AmiVector x_newton; + /** state vector */ + AmiVector x; + /** old state vector */ + AmiVector x_old; + /** differential state vector */ + AmiVector dx; + /** time derivative state vector */ + AmiVector xdot; + /** old time derivative state vector */ + AmiVector xdot_old; + /** state sensitivities */ + AmiVectorArray sx; + /** state differential sensitivities */ + AmiVectorArray sdx; + + /** weighted root-mean-square error */ + realtype wrms = NAN; + +}; + +} // namespace amici +#endif // STEADYSTATEPROBLEM_H diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/sundials_linsol_wrapper.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/sundials_linsol_wrapper.h new file mode 100644 index 0000000..a80a8d7 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/sundials_linsol_wrapper.h @@ -0,0 +1,859 @@ +#ifndef AMICI_SUNDIALS_LINSOL_WRAPPER_H +#define AMICI_SUNDIALS_LINSOL_WRAPPER_H + +#include "amici/exception.h" +#include "amici/sundials_matrix_wrapper.h" +#include "amici/vector.h" + +#include <sundials/sundials_config.h> +#include <sunlinsol/sunlinsol_band.h> +#include <sunlinsol/sunlinsol_dense.h> +#include <sunlinsol/sunlinsol_klu.h> +#include <sunlinsol/sunlinsol_pcg.h> +#include <sunlinsol/sunlinsol_spbcgs.h> +#include <sunlinsol/sunlinsol_spfgmr.h> +#include <sunlinsol/sunlinsol_spgmr.h> +#include <sunlinsol/sunlinsol_sptfqmr.h> +#ifdef SUNDIALS_SUPERLUMT +#include <sunlinsol/sunlinsol_superlumt.h> +#endif +#include <sunnonlinsol/sunnonlinsol_fixedpoint.h> +#include <sunnonlinsol/sunnonlinsol_newton.h> + +namespace amici { + +/** + * @brief A RAII wrapper for SUNLinearSolver structs. + * + * For details on member functions see documentation in + * sunlinsol/sundials_linearsolver.h. + */ +class SUNLinSolWrapper { + public: + SUNLinSolWrapper() = default; + + /** + * @brief Wrap existing SUNLinearSolver + * @param linsol + */ + explicit SUNLinSolWrapper(SUNLinearSolver linsol); + + virtual ~SUNLinSolWrapper(); + + /** + * @brief Copy constructor + * @param other + */ + SUNLinSolWrapper(const SUNLinSolWrapper &other) = delete; + + /** + * @brief Move constructor + * @param other + */ + SUNLinSolWrapper(SUNLinSolWrapper &&other) noexcept; + + /** + * @brief Copy assignment + * @param other + * @return + */ + SUNLinSolWrapper &operator=(const SUNLinSolWrapper &other) = delete; + + /** + * @brief Move assignment + * @param other + * @return + */ + SUNLinSolWrapper &operator=(SUNLinSolWrapper &&other) noexcept; + + /** + * @brief Returns the wrapped SUNLinSol. + * @return SUNLinearSolver + */ + SUNLinearSolver get() const; + + /** + * @brief Returns an identifier for the linear solver type. + * @return + */ + SUNLinearSolver_Type getType() const; + + /** + * @brief Performs any linear solver setup needed, based on an updated + * system matrix A. + * @param A + */ + void setup(SUNMatrix A) const; + + /** + * @brief Performs any linear solver setup needed, based on an updated + * system matrix A. + * @param A + */ + void setup(const SUNMatrixWrapper& A) const; + + /** + * @brief Solves a linear system A*x = b + * @param A + * @param x A template for cloning vectors needed within the solver. + * @param b + * @param tol Tolerance (weighted 2-norm), iterative solvers only + * @return error flag + */ + int Solve(SUNMatrix A, N_Vector x, N_Vector b, realtype tol) const; + + /** + * @brief Returns the last error flag encountered within the linear solver + * @return error flag + */ + long int getLastFlag() const; + + /** + * @brief Returns the integer and real workspace sizes for the linear solver + * @param lenrwLS output argument for size of real workspace + * @param leniwLS output argument for size of interger workspace + * @return workspace size + */ + int space(long int *lenrwLS, long int *leniwLS) const; + + /** + * @brief Get the matrix A (matrix solvers only). + * @return A + */ + virtual SUNMatrix getMatrix() const; + + protected: + /** + * @brief Performs linear solver initialization (assumes that all + * solver-specific options have been set). + * @return error code + */ + int initialize(); + + /** Wrapped solver */ + SUNLinearSolver solver = nullptr; +}; + + +/** + * @brief SUNDIALS band direct solver. + */ +class SUNLinSolBand : public SUNLinSolWrapper { + public: + /** + * @brief Create solver using existing matrix A without taking ownership of + * A. + * @param x A template for cloning vectors needed within the solver. + * @param A square matrix + */ + SUNLinSolBand(N_Vector x, SUNMatrix A); + + /** + * @brief Create new band solver and matrix A. + * @param x A template for cloning vectors needed within the solver. + * @param ubw upper bandwidth of band matrix A + * @param lbw lower bandwidth of band matrix A + */ + SUNLinSolBand(AmiVector const &x, int ubw, int lbw); + + SUNMatrix getMatrix() const override; + + private: + /** Matrix A for solver, only if created by here. */ + SUNMatrixWrapper A; +}; + + +/** + * @brief SUNDIALS dense direct solver. + */ +class SUNLinSolDense : public SUNLinSolWrapper { + public: + /** + * @brief Create dense solver + * @param x A template for cloning vectors needed within the solver. + */ + explicit SUNLinSolDense(AmiVector const &x); + + SUNMatrix getMatrix() const override; + + private: + /** Matrix A for solver, only if created by here. */ + SUNMatrixWrapper A; +}; + + +/** + * @brief SUNDIALS KLU sparse direct solver. + */ +class SUNLinSolKLU : public SUNLinSolWrapper { + public: + /** KLU state reordering (different from SuperLUMT ordering!) */ + enum class StateOrdering { + AMD, + COLAMD, + natural + }; + + /** + * @brief Create KLU solver with given matrix + * @param x A template for cloning vectors needed within the solver. + * @param A sparse matrix + */ + SUNLinSolKLU(N_Vector x, SUNMatrix A); + + /** + * @brief Create KLU solver and matrix to operate on + * @param x A template for cloning vectors needed within the solver. + * @param nnz Number of non-zeros in matrix A + * @param sparsetype Sparse matrix type (CSC_MAT, CSR_MAT) + * @param ordering + */ + SUNLinSolKLU(AmiVector const &x, int nnz, int sparsetype, + StateOrdering ordering); + + SUNMatrix getMatrix() const override; + + /** + * @brief Reinitializes memory and flags for a new factorization + * (symbolic and numeric) to be conducted at the next solver setup call. + * + * For more details see sunlinsol/sunlinsol_klu.h + * @param nnz Number of non-zeros + * @param reinit_type SUNKLU_REINIT_FULL or SUNKLU_REINIT_PARTIAL + */ + void reInit(int nnz, int reinit_type); + + /** + * @brief Sets the ordering used by KLU for reducing fill in the linear + * solve. + * @param ordering + */ + void setOrdering(StateOrdering ordering); + + private: + /** Sparse matrix A for solver, only if created by here. */ + SUNMatrixWrapper A; +}; + +#ifdef SUNDIALS_SUPERLUMT +/** + * @brief SUNDIALS SuperLUMT sparse direct solver. + */ +class SUNLinSolSuperLUMT : public SUNLinSolWrapper { + public: + /** SuperLUMT ordering (different from KLU ordering!) */ + enum class StateOrdering { + natural, + minDegATA, + minDegATPlusA, + COLAMD, + }; + + /** + * @brief Create SuperLUMT solver with given matrix + * @param x A template for cloning vectors needed within the solver. + * @param A sparse matrix + * @param numThreads Number of threads to be used by SuperLUMT + */ + SUNLinSolSuperLUMT(N_Vector x, SUNMatrix A, int numThreads); + + /** + * @brief Create SuperLUMT solver and matrix to operate on + * + * Will set number of threads according to environment variable + * AMICI_SUPERLUMT_NUM_THREADS. Will default to 1 thread if unset. + * + * @param x A template for cloning vectors needed within the solver. + * @param nnz Number of non-zeros in matrix A + * @param sparsetype Sparse matrix type (CSC_MAT, CSR_MAT) + * @param ordering + */ + SUNLinSolSuperLUMT(AmiVector const &x, int nnz, int sparsetype, + StateOrdering ordering); + + /** + * @brief Create SuperLUMT solver and matrix to operate on + * @param x A template for cloning vectors needed within the solver. + * @param nnz Number of non-zeros in matrix A + * @param sparsetype Sparse matrix type (CSC_MAT, CSR_MAT) + * @param ordering + * @param numThreads Number of threads to be used by SuperLUMT + */ + SUNLinSolSuperLUMT(AmiVector const &x, int nnz, int sparsetype, + StateOrdering ordering, int numThreads); + + SUNMatrix getMatrix() const override; + + /** + * @brief Sets the ordering used by SuperLUMT for reducing fill in the + * linear solve. + * @param ordering + */ + void setOrdering(StateOrdering ordering); + + private: + /** Sparse matrix A for solver, only if created by here. */ + SUNMatrixWrapper A; +}; + +#endif + +/** + * @brief SUNDIALS scaled preconditioned CG (Conjugate Gradient method) (PCG) + * solver. + */ +class SUNLinSolPCG : public SUNLinSolWrapper { + public: + /** + * @brief Create PCG solver. + * @param y + * @param pretype Preconditioner type (PREC_NONE, PREC_LEFT, PREC_RIGHT, + * PREC_BOTH) + * @param maxl Maximum number of solver iterations + */ + SUNLinSolPCG(N_Vector y, int pretype, int maxl); + + /** + * @brief Sets the function pointer for ATimes + * (see sundials/sundials_linearsolver.h). + * @param A_data + * @param ATimes + * @return + */ + int setATimes(void *A_data, ATimesFn ATimes); + + /** + * @brief Sets function pointers for PSetup and PSolve routines inside + * of iterative linear solver objects + * (see sundials/sundials_linearsolver.h). + * @param P_data + * @param Pset + * @param Psol + * @return + */ + int setPreconditioner(void *P_data, PSetupFn Pset, PSolveFn Psol); + + /** + * @brief Sets pointers to left/right scaling vectors for the linear + * system solve (see sundials/sundials_linearsolver.h). + * @param s + * @param nul + * @return + */ + int setScalingVectors(N_Vector s, N_Vector nul); + + /** + * @brief Returns the number of linear iterations performed in the last + * 'Solve' call + * @return Number of iterations + */ + int getNumIters() const; + + /** + * @brief Returns the final residual norm from the last 'Solve' call. + * @return residual norm + */ + realtype getResNorm() const; + + /** + * @brief Get preconditioned initial residual + * (see sundials/sundials_linearsolver.h). + * @return + */ + N_Vector getResid() const; +}; + + +/** + * @brief SUNDIALS scaled preconditioned Bi-CGStab (Bi-Conjugate Gradient + * Stable method) (SPBCGS) solver. + */ +class SUNLinSolSPBCGS : public SUNLinSolWrapper { + public: + /** + * @brief SUNLinSolSPBCGS + * @param x A template for cloning vectors needed within the solver. + * @param pretype Preconditioner type (PREC_NONE, PREC_LEFT, PREC_RIGHT, + * PREC_BOTH) + * @param maxl Maximum number of solver iterations + */ + explicit SUNLinSolSPBCGS(N_Vector x, int pretype = PREC_NONE, + int maxl = SUNSPBCGS_MAXL_DEFAULT); + + /** + * @brief SUNLinSolSPBCGS + * @param x A template for cloning vectors needed within the solver. + * @param pretype Preconditioner type (PREC_NONE, PREC_LEFT, PREC_RIGHT, + * PREC_BOTH) + * @param maxl Maximum number of solver iterations + */ + explicit SUNLinSolSPBCGS(AmiVector const &x, int pretype = PREC_NONE, + int maxl = SUNSPBCGS_MAXL_DEFAULT); + + /** + * @brief Sets the function pointer for ATimes + * (see sundials/sundials_linearsolver.h). + * @param A_data + * @param ATimes + * @return + */ + int setATimes(void *A_data, ATimesFn ATimes); + + /** + * @brief Sets function pointers for PSetup and PSolve routines inside + * of iterative linear solver objects + * (see sundials/sundials_linearsolver.h). + * @param P_data + * @param Pset + * @param Psol + * @return + */ + int setPreconditioner(void *P_data, PSetupFn Pset, PSolveFn Psol); + + /** + * @brief Sets pointers to left/right scaling vectors for the linear + * system solve (see sundials/sundials_linearsolver.h). + * @param s + * @param nul + * @return + */ + int setScalingVectors(N_Vector s, N_Vector nul); + + /** + * @brief Returns the number of linear iterations performed in the last + * 'Solve' call + * @return Number of iterations + */ + int getNumIters() const; + + /** + * @brief Returns the final residual norm from the last 'Solve' call. + * @return residual norm + */ + realtype getResNorm() const; + + /** + * @brief Get preconditioned initial residual + * (see sundials/sundials_linearsolver.h). + * @return + */ + N_Vector getResid() const; +}; + + +/** + * @brief SUNDIALS scaled preconditioned FGMRES (Flexible Generalized Minimal + * Residual method) (SPFGMR) solver. + */ +class SUNLinSolSPFGMR : public SUNLinSolWrapper { + public: + /** + * @brief SUNLinSolSPFGMR + * @param x A template for cloning vectors needed within the solver. + * @param pretype Preconditioner type (PREC_NONE, PREC_LEFT, PREC_RIGHT, + * PREC_BOTH) + * @param maxl Maximum number of solver iterations + */ + SUNLinSolSPFGMR(AmiVector const &x, int pretype, int maxl); + + /** + * @brief Sets the function pointer for ATimes + * (see sundials/sundials_linearsolver.h). + * @param A_data + * @param ATimes + * @return + */ + int setATimes(void *A_data, ATimesFn ATimes); + + /** + * @brief Sets function pointers for PSetup and PSolve routines inside + * of iterative linear solver objects + * (see sundials/sundials_linearsolver.h). + * @param P_data + * @param Pset + * @param Psol + * @return + */ + int setPreconditioner(void *P_data, PSetupFn Pset, PSolveFn Psol); + + /** + * @brief Sets pointers to left/right scaling vectors for the linear + * system solve (see sundials/sundials_linearsolver.h). + * @param s + * @param nul + * @return + */ + int setScalingVectors(N_Vector s, N_Vector nul); + + /** + * @brief Returns the number of linear iterations performed in the last + * 'Solve' call + * @return Number of iterations + */ + int getNumIters() const; + + /** + * @brief Returns the final residual norm from the last 'Solve' call. + * @return residual norm + */ + realtype getResNorm() const; + + /** + * @brief Get preconditioned initial residual + * (see sundials/sundials_linearsolver.h). + * @return + */ + N_Vector getResid() const; +}; + + +/** + * @brief SUNDIALS scaled preconditioned GMRES (Generalized Minimal Residual + * method) solver (SPGMR). + */ +class SUNLinSolSPGMR : public SUNLinSolWrapper { + public: + /** + * @brief Create SPGMR solver + * @param x A template for cloning vectors needed within the solver. + * @param pretype Preconditioner type (PREC_NONE, PREC_LEFT, PREC_RIGHT, + * PREC_BOTH) + * @param maxl Maximum number of solver iterations + */ + explicit SUNLinSolSPGMR(AmiVector const &x, int pretype = PREC_NONE, + int maxl = SUNSPGMR_MAXL_DEFAULT); + + /** + * @brief Sets the function pointer for ATimes + * (see sundials/sundials_linearsolver.h). + * @param A_data + * @param ATimes + * @return + */ + int setATimes(void *A_data, ATimesFn ATimes); + + /** + * @brief Sets function pointers for PSetup and PSolve routines inside + * of iterative linear solver objects + * (see sundials/sundials_linearsolver.h). + * @param P_data + * @param Pset + * @param Psol + * @return + */ + int setPreconditioner(void *P_data, PSetupFn Pset, PSolveFn Psol); + + /** + * @brief Sets pointers to left/right scaling vectors for the linear + * system solve (see sundials/sundials_linearsolver.h). + * @param s + * @param nul + * @return + */ + int setScalingVectors(N_Vector s, N_Vector nul); + + /** + * @brief Returns the number of linear iterations performed in the last + * 'Solve' call + * @return Number of iterations + */ + int getNumIters() const; + + /** + * @brief Returns the final residual norm from the last 'Solve' call. + * @return residual norm + */ + realtype getResNorm() const; + + /** + * @brief Get preconditioned initial residual + * (see sundials/sundials_linearsolver.h). + * @return + */ + N_Vector getResid() const; +}; + + +/** + * @brief SUNDIALS scaled preconditioned TFQMR (Transpose-Free Quasi-Minimal + * Residual method) (SPTFQMR) solver. + */ +class SUNLinSolSPTFQMR : public SUNLinSolWrapper { + public: + /** + * @brief Create SPTFQMR solver + * @param x A template for cloning vectors needed within the solver. + * @param pretype Preconditioner type (PREC_NONE, PREC_LEFT, PREC_RIGHT, + * PREC_BOTH) + * @param maxl Maximum number of solver iterations + */ + explicit SUNLinSolSPTFQMR(N_Vector x, int pretype = PREC_NONE, + int maxl = SUNSPTFQMR_MAXL_DEFAULT); + + /** + * @brief Create SPTFQMR solver + * @param x A template for cloning vectors needed within the solver. + * @param pretype Preconditioner type (PREC_NONE, PREC_LEFT, PREC_RIGHT, + * PREC_BOTH) + * @param maxl Maximum number of solver iterations + */ + explicit SUNLinSolSPTFQMR(AmiVector const &x, int pretype = PREC_NONE, + int maxl = SUNSPTFQMR_MAXL_DEFAULT); + + /** + * @brief Sets the function pointer for ATimes + * (see sundials/sundials_linearsolver.h). + * @param A_data + * @param ATimes + * @return + */ + int setATimes(void *A_data, ATimesFn ATimes); + + /** + * @brief Sets function pointers for PSetup and PSolve routines inside + * of iterative linear solver objects + * (see sundials/sundials_linearsolver.h). + * @param P_data + * @param Pset + * @param Psol + * @return + */ + int setPreconditioner(void *P_data, PSetupFn Pset, PSolveFn Psol); + + /** + * @brief Sets pointers to left/right scaling vectors for the linear + * system solve (see sundials/sundials_linearsolver.h). + * @param s + * @param nul + * @return + */ + int setScalingVectors(N_Vector s, N_Vector nul); + + /** + * @brief Returns the number of linear iterations performed in the last + * 'Solve' call + * @return Number of iterations + */ + int getNumIters() const; + + /** + * @brief Returns the final residual norm from the last 'Solve' call. + * @return residual norm + */ + realtype getResNorm() const; + + /** + * @brief Get preconditioned initial residual + * (see sundials/sundials_linearsolver.h). + * @return + */ + N_Vector getResid() const; +}; + + +/** + * @brief A RAII wrapper for SUNNonLinearSolver structs which solve the + * nonlinear system F (y) = 0 or G(y) = y. + */ +class SUNNonLinSolWrapper { + public: + /** + * @brief SUNNonLinSolWrapper from existing SUNNonlinearSolver + * @param sol + */ + explicit SUNNonLinSolWrapper(SUNNonlinearSolver sol); + + virtual ~SUNNonLinSolWrapper(); + + /** + * @brief Copy constructor + * @param other + */ + SUNNonLinSolWrapper(const SUNNonLinSolWrapper &other) = delete; + + /** + * @brief Move constructor + * @param other + */ + SUNNonLinSolWrapper(SUNNonLinSolWrapper &&other) noexcept; + + /** + * @brief Copy assignment + * @param other + * @return + */ + SUNNonLinSolWrapper &operator=(const SUNNonLinSolWrapper &other) = delete; + + /** + * @brief Move assignment + * @param other + * @return + */ + SUNNonLinSolWrapper &operator=(SUNNonLinSolWrapper &&other) noexcept; + + /** + * @brief Get the wrapped SUNNonlinearSolver + * @return SUNNonlinearSolver + */ + SUNNonlinearSolver get() const; + + /** + * @brief Get type ID of the solver + * @return + */ + SUNNonlinearSolver_Type getType() const; + + /** + * @brief Setup solver + * @param y the initial iteration passed to the nonlinear solver. + * @param mem the sundials integrator memory structure. + * @return + */ + int setup(N_Vector y, void *mem); + + /** + * @brief Solve the nonlinear system F (y) = 0 or G(y) = y. + * @param y0 the initial iterate for the nonlinear solve. This must remain + * unchanged throughout the solution process. + * @param y the solution to the nonlinear system + * @param w the solution error weight vector used for computing weighted + * error norms. + * @param tol the requested solution tolerance in the weighted root-mean- + * squared norm. + * @param callLSetup a flag indicating that the integrator recommends for + * the linear solver setup function to be called. + * @param mem the sundials integrator memory structure. + * @return + */ + int Solve(N_Vector y0, N_Vector y, N_Vector w, realtype tol, + booleantype callLSetup, void *mem); + + /** + * @brief Set function to evaluate the nonlinear residual function F(y) = 0 + * or the fixed point function G(y) = y + * @param SysFn + * @return + */ + int setSysFn(SUNNonlinSolSysFn SysFn); + + /** + * @brief Set linear solver setup function. + * @param SetupFn + * @return + */ + int setLSetupFn(SUNNonlinSolLSetupFn SetupFn); + + /** + * @brief Set linear solver solve function. + * @param SolveFn + * @return + */ + int setLSolveFn(SUNNonlinSolLSolveFn SolveFn); + + /** + * @brief Set function to test for convergence + * @param CTestFn + * @return + */ + int setConvTestFn(SUNNonlinSolConvTestFn CTestFn); + + /** + * @brief Set maximum number of non-linear iterations + * @param maxiters + * @return + */ + int setMaxIters(int maxiters); + + /** + * @brief getNumIters + * @return + */ + long int getNumIters() const; + + /** + * @brief getCurIter + * @return + */ + int getCurIter() const; + + /** + * @brief getNumConvFails + * @return + */ + long int getNumConvFails() const; + + protected: + /** + * @brief initialize + */ + void initialize(); + + /** the wrapper solver */ + SUNNonlinearSolver solver = nullptr; +}; + + +/** + * @brief SUNDIALS Newton non-linear solver to solve F (y) = 0. + */ +class SUNNonLinSolNewton : public SUNNonLinSolWrapper { + public: + /** + * @brief Create Newton solver + * @param x A template for cloning vectors needed within the solver. + */ + explicit SUNNonLinSolNewton(N_Vector x); + + /** + * @brief Create Newton solver for enabled sensitivity analysis + * @param count Number of vectors in the nonlinear solve. When integrating + * a system containing Ns sensitivities the value of count is: + * - Ns+1 if using a simultaneous corrector approach. + * - Ns if using a staggered corrector approach. + * @param x A template for cloning vectors needed within the solver. + */ + SUNNonLinSolNewton(int count, N_Vector x); + + /** + * @brief Get function to evaluate the nonlinear residual function F(y) = 0 + * @param SysFn + * @return + */ + int getSysFn(SUNNonlinSolSysFn *SysFn) const; +}; + + +/** + * @brief SUNDIALS Fixed point non-linear solver to solve G(y) = y. + */ +class SUNNonLinSolFixedPoint : public SUNNonLinSolWrapper { + public: + /** + * @brief Create fixed-point solver + * @param x template for cloning vectors needed within the solver. + * @param m number of acceleration vectors to use + */ + explicit SUNNonLinSolFixedPoint(const_N_Vector x, int m = 0); + + /** + * @brief Create fixed-point solver for use with sensitivity analysis + * @param count Number of vectors in the nonlinear solve. When integrating + * a system containing Ns sensitivities the value of count is: + * - Ns+1 if using a simultaneous corrector approach. + * - Ns if using a staggered corrector approach. + * @param x template for cloning vectors needed within the solver. + * @param m number of acceleration vectors to use + */ + SUNNonLinSolFixedPoint(int count, const_N_Vector x, int m = 0); + + /** + * @brief Get function to evaluate the fixed point function G(y) = y + * @param SysFn + * @return + */ + int getSysFn(SUNNonlinSolSysFn *SysFn) const; +}; + +} // namespace amici +#endif // AMICI_SUNDIALS_LINSOL_WRAPPER_H diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/sundials_matrix_wrapper.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/sundials_matrix_wrapper.h new file mode 100644 index 0000000..5975142 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/sundials_matrix_wrapper.h @@ -0,0 +1,191 @@ +#ifndef AMICI_SUNDIALS_MATRIX_WRAPPER_H +#define AMICI_SUNDIALS_MATRIX_WRAPPER_H + +#include <sunmatrix/sunmatrix_band.h> // SUNMatrix_Band +#include <sunmatrix/sunmatrix_dense.h> // SUNMatrix_Dense +#include <sunmatrix/sunmatrix_sparse.h> // SUNMatrix_Sparse + +#include <gsl/gsl-lite.hpp> + +#include <vector> + +#include "amici/vector.h" + +namespace amici { + +/** + * @brief A RAII wrapper for SUNMatrix structs. + * + * This can create dense, sparse, or banded matrices using the respective + * constructor. + */ +class SUNMatrixWrapper { + public: + SUNMatrixWrapper() = default; + + /** + * @brief Create sparse matrix. See SUNSparseMatrix in sunmatrix_sparse.h + * @param M Number of rows + * @param N Number of columns + * @param NNZ Number of nonzeros + * @param sparsetype Sparse type + */ + SUNMatrixWrapper(int M, int N, int NNZ, int sparsetype); + + /** + * @brief Create dense matrix. See SUNDenseMatrix in sunmatrix_dense.h + * @param M Number of rows + * @param N Number of columns + */ + SUNMatrixWrapper(int M, int N); + + /** + * @brief Create banded matrix. See SUNBandMatrix in sunmatrix_band.h + * @param M Number of rows and columns + * @param ubw Upper bandwidth + * @param lbw Lower bandwidth + */ + SUNMatrixWrapper(int M, int ubw, int lbw); + + /** + * @brief Create sparse matrix from dense or banded matrix. See + * SUNSparseFromDenseMatrix and SUNSparseFromBandMatrix in + * sunmatrix_sparse.h + * @param A Wrapper for dense matrix + * @param droptol tolerance for dropping entries + * @param sparsetype Sparse type + */ + SUNMatrixWrapper(const SUNMatrixWrapper &A, realtype droptol, + int sparsetype); + + /** + * @brief Wrap existing SUNMatrix + * @param mat + */ + explicit SUNMatrixWrapper(SUNMatrix mat); + + ~SUNMatrixWrapper(); + + /** + * @brief Copy constructor + * @param other + */ + SUNMatrixWrapper(const SUNMatrixWrapper &other); + + /** + * @brief Move constructor + * @param other + */ + SUNMatrixWrapper(SUNMatrixWrapper &&other); + + /** + * @brief Copy assignment + * @param other + * @return + */ + SUNMatrixWrapper &operator=(const SUNMatrixWrapper &other); + + /** + * @brief Move assignment + * @param other + * @return + */ + SUNMatrixWrapper &operator=(SUNMatrixWrapper &&other); + + /** + * @brief Access raw data + * @return raw data pointer + */ + realtype *data() const; + + /** + * @brief Get the wrapped SUNMatrix + * @return SlsMat + */ + SUNMatrix get() const; + + /** + * @brief Get the number of rows + * @return number + */ + sunindextype rows() const; + + /** + * @brief Get the number of columns + * @return number + */ + sunindextype columns() const; + + /** + * @brief Get the index values of a sparse matrix + * @return index array + */ + sunindextype *indexvals() const; + + /** + * @brief Get the index pointers of a sparse matrix + * @return index array + */ + sunindextype *indexptrs() const; + + /** + * @brief Get the type of sparse matrix + * @return index array + */ + int sparsetype() const; + + /** + * @brief reset data to zeroes + */ + void reset(); + + /** + * @brief N_Vector interface for multiply + * @param c output vector, may already contain values + * @param b multiplication vector + */ + void multiply(N_Vector c, const_N_Vector b) const; + + /** + * @brief Perform matrix vector multiplication c += A*b + * @param c output vector, may already contain values + * @param b multiplication vector + */ + void multiply(gsl::span<realtype> c, gsl::span<const realtype> b) const; + + /** + * @brief Set to 0.0 + */ + void zero(); + + private: + void update_ptrs(); + + SUNMatrix matrix = nullptr; + realtype *data_ptr = nullptr; + sunindextype *indexptrs_ptr = nullptr; + sunindextype *indexvals_ptr = nullptr; +}; + +} // namespace amici + +namespace gsl { +/** + * @brief Create span from SUNMatrix + * @param nv + * @return + */ +inline span<realtype> make_span(SUNMatrix m) +{ + switch (SUNMatGetID(m)) { + case SUNMATRIX_DENSE: + return span<realtype>(SM_DATA_D(m), SM_LDATA_D(m)); + case SUNMATRIX_SPARSE: + return span<realtype>(SM_DATA_S(m), SM_NNZ_S(m)); + default: + throw amici::AmiException("Unimplemented SUNMatrix type for make_span"); + } +} +} // namespace gsl + +#endif // AMICI_SUNDIALS_MATRIX_WRAPPER_H diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/symbolic_functions.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/symbolic_functions.h new file mode 100644 index 0000000..6d394c5 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/symbolic_functions.h @@ -0,0 +1,34 @@ +#ifndef amici_symbolic_functions_h +#define amici_symbolic_functions_h + +namespace amici { + +double log(double x); +double dirac(double x); +double heaviside(double x); + +double min(double a, double b, double c); +double Dmin(int id, double a, double b, double c); +double max(double a, double b, double c); +double Dmax(int id, double a, double b, double c); + +double pos_pow(double base, double exponent); + +int isNaN(double what); +int isInf(double what); +double getNaN(); + +/* sign */ +double sign(double x); + +/* splines */ + +double spline(double t, int num, ...); +double spline_pos(double t, int num, ...); +double Dspline(int id, double t, int num, ...); +double Dspline_pos(int id, double t, int num, ...); +double DDspline(int id1, int id2, double t, int num, ...); +double DDspline_pos(int id1, int id2, double t, int num, ...); +} // namespace amici + +#endif /* amici_symbolic_functions_h */ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/vector.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/vector.h new file mode 100644 index 0000000..44a327f --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/vector.h @@ -0,0 +1,313 @@ +#ifndef AMICI_VECTOR_H +#define AMICI_VECTOR_H + +#include <vector> +#include <type_traits> + +#include <amici/exception.h> + +#include <nvector/nvector_serial.h> + +#include <gsl/gsl-lite.hpp> + +namespace amici { + +/** Since const N_Vector is not what we want */ +using const_N_Vector = + std::add_const<typename std::remove_pointer<N_Vector>::type *>::type; + +/** AmiVector class provides a generic interface to the NVector_Serial struct */ +class AmiVector { + public: + /** + * @brief Default constructor + */ + AmiVector() = default; + + /** Creates an std::vector<realtype> and attaches the + * data pointer to a newly created N_Vector_Serial. + * 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 + * @param length number of elements in vector + */ + explicit AmiVector(const long int length) + : vec(static_cast<decltype(vec)::size_type>(length), 0.0), + nvec(N_VMake_Serial(length, vec.data())) {} + + /** Moves data from std::vector and constructs an nvec that points to the + * data + * @brief constructor from std::vector, + * @param rvec vector from which the data will be moved + */ + explicit AmiVector(std::vector<realtype> rvec) + : vec(std::move(rvec)), + nvec(N_VMake_Serial(static_cast<long int>(vec.size()), vec.data())) {} + + /** + * @brief copy constructor + * @param vold vector from which the data will be copied + */ + AmiVector(const AmiVector &vold) : vec(vold.vec) { + nvec = + N_VMake_Serial(static_cast<long int>(vold.vec.size()), vec.data()); + } + + /** + * @brief copy assignment operator + * @param other right hand side + * @return left hand side + */ + AmiVector &operator=(AmiVector const &other); + + /** + * @brief data accessor + * @return pointer to data array + */ + realtype *data(); + + /** + * @brief const data accessor + * @return const pointer to data array + */ + const realtype *data() const; + + /** + * @brief N_Vector accessor + * @return N_Vector + */ + N_Vector getNVector(); + + /** + * @brief N_Vector accessor + * @return N_Vector + */ + const_N_Vector getNVector() const; + + /** + * @brief Vector accessor + * @return Vector + */ + std::vector<realtype> const &getVector(); + + /** + * @brief returns the length of the vector + * @return length + */ + int getLength() const; + + /** + * @brief resets the Vector by filling with zero values + */ + void reset(); + + /** + * @brief changes the sign of data elements + */ + void minus(); + + /** + * @brief sets all data elements to a specific value + * @param val value for data elements + */ + void set(realtype val); + + /** + * @brief accessor to data elements of the vector + * @param pos index of element + * @return element + */ + realtype &operator[](int pos); + /** + * @brief accessor to data elements of the vector + * @param pos index of element + * @return element + */ + realtype &at(int pos); + + /** + * @brief accessor to data elements of the vector + * @param pos index of element + * @return element + */ + const realtype &at(int pos) const; + + /** + * @brief copies data from another AmiVector + * @param other data source + */ + void copy(const AmiVector &other); + + /** + * @brief destructor + */ + ~AmiVector(); + + private: + /** main data storage */ + std::vector<realtype> vec; + + /** N_Vector, will be synchronised such that it points to data in vec */ + N_Vector nvec = nullptr; + + /** + * @brief reconstructs nvec such that data pointer points to vec data array + */ + void synchroniseNVector(); +}; + +/** + * @brief AmiVectorArray class. + * + * Provides a generic interface to arrays of NVector_Serial structs + */ +class AmiVectorArray { + public: + /** + * @brief Default constructor + */ + AmiVectorArray() = default; + + /** + * Creates an std::vector<realype> and attaches the + * data pointer to a newly created N_VectorArray + * using CloneVectorArrayEmpty ensures that the N_Vector + * module does not try to deallocate the data vector + * when calling N_VDestroyVectorArray_Serial + * @brief empty constructor + * @param length_inner length of vectors + * @param length_outer number of vectors + */ + AmiVectorArray(long int length_inner, long int length_outer); + + /** + * @brief copy constructor + * @param vaold object to copy from + */ + AmiVectorArray(const AmiVectorArray &vaold); + + /** + * @brief copy assignment operator + * @param other right hand side + * @return left hand side + */ + AmiVectorArray &operator=(AmiVectorArray const &other); + + /** + * @brief accessor to data of AmiVector elements + * @param pos index of AmiVector + * @return pointer to data array + */ + realtype *data(int pos); + + /** + * @brief const accessor to data of AmiVector elements + * @param pos index of AmiVector + * @return const pointer to data array + */ + const realtype *data(int pos) const; + + /** + * @brief accessor to elements of AmiVector elements + * @param ipos inner index in AmiVector + * @param jpos outer index in AmiVectorArray + * @return element + */ + realtype &at(int ipos, int jpos); + + /** + * @brief const accessor to elements of AmiVector elements + * @param ipos inner index in AmiVector + * @param jpos outer index in AmiVectorArray + * @return element + */ + const realtype &at(int ipos, int jpos) const; + + /** + * @brief accessor to NVectorArray + * @return N_VectorArray + */ + N_Vector *getNVectorArray(); + + /** + * @brief accessor to NVector element + * @param pos index of corresponding AmiVector + * @return N_Vector + */ + N_Vector getNVector(int pos); + + /** + * @brief const accessor to NVector element + * @param pos index of corresponding AmiVector + * @return N_Vector + */ + const_N_Vector getNVector(int pos) const; + + /** + * @brief accessor to AmiVector elements + * @param pos index of AmiVector + * @return AmiVector + */ + AmiVector &operator[](int pos); + + /** + * @brief const accessor to AmiVector elements + * @param pos index of AmiVector + * @return const AmiVector + */ + const AmiVector &operator[](int pos) const; + + /** + * @brief length of AmiVectorArray + * @return length + */ + int getLength() const; + + /** + * @brief resets every AmiVector in AmiVectorArray + */ + void reset(); + + /** + * @brief flattens the AmiVectorArray to a vector in row-major format + * @param vec vector into which the AmiVectorArray will be flattened. Must + * have length equal to number of elements. + */ + void flatten_to_vector(std::vector<realtype> &vec) const; + + /** + * @brief copies data from another AmiVectorArray + * @param other data source + */ + void copy(const AmiVectorArray &other); + + ~AmiVectorArray() = default; + + private: + /** main data storage */ + std::vector<AmiVector> vec_array; + + /** + * N_Vector array, will be synchronised such that it points to + * respective elements in the vec_array + */ + std::vector<N_Vector> nvec_array; +}; + +} // namespace amici + + +namespace gsl { +/** + * @brief Create span from N_Vector + * @param nv + * @return + */ +inline span<realtype> make_span(N_Vector nv) +{ + return span<realtype>(N_VGetArrayPointer(nv), N_VGetLength_Serial(nv)); +} +} // namespace gsl + +#endif /* AMICI_VECTOR_H */ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/version.in.h b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/version.in.h new file mode 100644 index 0000000..c31230d --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/include/amici/version.in.h @@ -0,0 +1,6 @@ +#ifndef AMICI_VERSION_H +#define AMICI_VERSION_H + +#define AMICI_VERSION "@AMICI_VERSION@" + +#endif diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/matlab/auxiliary/CalcMD5/CalcMD5.c b/Requirements/AMICI-0.10.11_SS_eventFix/matlab/auxiliary/CalcMD5/CalcMD5.c new file mode 100644 index 0000000..d84dcfb --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/matlab/auxiliary/CalcMD5/CalcMD5.c @@ -0,0 +1,650 @@ +/* CalcMD5.c */ +/* 128 bit MD5 checksum: file, string, byte stream */ +/* This function calculates a 128 bit checksum for arrays or files. */ +/* Digest = CalcMD5(Data, [InClass], [OutClass]) */ +/* INPUT: */ +/* Data: Data array or file name. Either numerical or CHAR array. */ +/* Currently only files and arrays with up to 2^32 bytes (2.1GB) are */ +/* accepted. */ +/* InClass: String to declare the type of the 1st input. */ +/* Optional. Default: 'Char'. */ +/* 'File': [Data] is a file name as string. The digest is calculated */ +/* for this file. */ +/* 'Char': [Data] is a char array to calculate the digest for. Only the */ +/* ASCII part of the Matlab CHARs is used, such that the digest */ +/* is the same as if the Matlab string is written to a file as */ +/* UCHAR, e.g. with FWRITE. */ +/* 'Unicode': All bytes of the input [Data] are used to calculate the */ +/* digest. If [Data] has a numerical type, this method is */ +/* applied ever. */ +/* OutClass: String, format of the output. Just the first character matters. */ +/* Optional, default: 'hex'. */ +/* 'hex': [1 x 32] string as lowercase hexadecimal number. */ +/* 'HEX': [1 x 32] string as lowercase hexadecimal number. */ +/* 'Dec': [1 x 16] double vector with UINT8 values. */ +/* 'Base64': [1 x 22] string, encoded to base 64 (A:Z,a:z,0:9,+,/). */ +/* */ +/* OUTPUT: */ +/* Digest: A 128 bit number is replied in a format depending on [OutClass]. */ +/* */ +/* EXAMPLES: */ +/* Three methods to get the MD5 of a file: */ +/* 1. Direct file access (recommended): */ +/* MD5 = CalcMD5(which('CalcMD5.m'), 'File') */ +/* 2. Import the file to a CHAR array (binary mode for exact line breaks!): */ +/* FID = fopen(which('CalcMD5.m'), 'rb'); */ +/* S = fread(FID, inf, 'uchar=>char'); */ +/* fclose(FID); */ +/* MD5 = CalcMD5(S, 'char') */ +/* 3. Import file as a byte stream: */ +/* FID = fopen(which('CalcMD5.m'), 'rb'); */ +/* S = fread(FID, inf, 'uint8=>uint8'); */ +/* fclose(FID); */ +/* MD5 = CalcMD5(S, 'unicode'); // 'unicode' can be omitted here */ +/* */ +/* Test data: */ +/* CalcMD5(char(0:511), 'char', 'HEX') */ +/* => F5C8E3C31C044BAE0E65569560B54332 */ +/* CalcMD5(char(0:511), 'unicode') */ +/* => 3484769D4F7EBB88BBE942BB924834CD */ +/* */ +/* Compile with: */ +/* mex -O CalcMD5.c */ +/* On Linux the C99 comments must be considered (thanks Sebastiaan Breedveld): */ +/* mex -O CFLAGS="\$CFLAGS -std=C99" CalcMD5.c */ +/* */ +/* Tested: Matlab 6.5, 7.7, 7.8, WinXP, [UnitTest] */ +/* Compiler: BCC5.5, LCC2.4/3.8, OpenWatcom 1.8 */ +/* Author: Jan Simon, Heidelberg, (C) 2006-2010 J@n-Simon.De */ +/* License: BSD. This program is based on: */ +/* RFC 1321, MD5 Message-Digest Algorithm, April 1992 */ +/* RSA Data Security, Inc. MD5 Message Digest Algorithm */ +/* Modifications: */ +/* - Acceleration: Unrolled loops. Compacted macros FF, GG, HH, II. */ +/* - Mex-interface: Input and output from and to Matlab. */ +/* */ +/* See also: CalcCRC32. */ +/* */ +/* Michael Kleder has published a Java call to compute the MD5 and SHA sums: */ +/* http://www.mathworks.com/matlabcentral/fileexchange/8944 */ + +/********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** License to copy and use this software is granted provided that ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message ** + ** Digest Algorithm" in all material mentioning or referencing this ** + ** software or this function. ** + ** ** + ** License is also granted to make and use derivative works ** + ** provided that such works are identified as "derived from the RSA ** + ** Data Security, Inc. MD5 Message Digest Algorithm" in all ** + ** material mentioning or referencing the derived work. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + ********************************************************************** + */ + +/* +% $JRev: R5.00z V:025 Sum:/kHGslMmCpAS Date:17-Dec-2009 12:46:26 $ +% $File: CalcMD5\CalcMD5.c $ +% History: +% 011: 20-Oct-2006 20:50, [16 x 1] -> [1 x 16] replied as double. +% 012: 01-Nov-2006 23:10, BUGFIX: hex output for 'Hex' input now. +% 015: 02-Oct-2008 14:47, Base64 output. +% 017: 19-Oct-2008 22:33, Accept numerical arrays as byte stream. +% 023: 15-Dec-2009 16:53, BUGFIX: UINT32 has 32 bits on 64 bit systems now. +% Thanks to Sebastiaan Breedveld! +*/ + +/* Headers: */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include "mex.h" + +/* Assume 32 bit array dimensions for Matlab 6.5: */ +/* See option "compatibleArrayDims" for MEX in Matlab >= 7.7. */ +#ifndef mwSize +#define mwSize int +#define mwIndex int +#endif + +/* Types: */ +typedef unsigned char UCHAR; +typedef unsigned int UINT; +typedef unsigned char * POINTER; /* generic pointer */ +typedef UINT32_T UINT32; /* four byte word (defined in tmwtypes.h) */ + +typedef struct { + UINT32 state[4]; /* state (ABCD) */ + UINT32 count[2]; /* number of bits, modulo 64 (lsb first) */ + UCHAR buffer[64]; /* input buffer */ +} MD5_CTX; + +/* Prototypes: */ +void MD5Init (MD5_CTX *); +void MD5Update (MD5_CTX *, UCHAR *, UINT); +void MD5Final (UCHAR[16], MD5_CTX *); +void MD5Transform(UINT32[4], UCHAR[64]); +void MD5Encode (UCHAR *, UINT32 *, UINT); +void MD5Array (UCHAR *data, mwSize N, UCHAR digest[16]); +void MD5File (char *FileName, UCHAR digest[16]); +void MD5Char (mxChar *data, mwSize N, UCHAR digest[16]); +void ToHex (const UCHAR In[16], char *Out, int LowerCase); +void ToBase64 (const UCHAR In[16], char *Out); + +/* Constants for MD5Transform routine: */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static UCHAR PADDING[64] = { + 0x80, 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, 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 }; + +/* F, G, H and I are basic MD5 functions: */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits: */ +/* Rotation is separate from addition to prevent recomputation. */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4: */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) = ROTATE_LEFT((a) + F((b), (c), (d)) + (x) + (UINT32)(ac), (s)) + (b); } +#define GG(a, b, c, d, x, s, ac) { \ + (a) = ROTATE_LEFT((a) + G((b), (c), (d)) + (x) + (UINT32)(ac), (s)) + (b); } +#define HH(a, b, c, d, x, s, ac) { \ + (a) = ROTATE_LEFT((a) + H((b), (c), (d)) + (x) + (UINT32)(ac), (s)) + (b); } +#define II(a, b, c, d, x, s, ac) { \ + (a) = ROTATE_LEFT((a) + I((b), (c), (d)) + (x) + (UINT32)(ac), (s)) + (b); } + +/* Length of the file buffer (must be < 2^31 for INT conversion): */ +#define BUFFER_LEN 1024 +static UCHAR buffer[BUFFER_LEN]; + +/* MD5 initialization. Begins an MD5 operation, writing a new context. ========= */ +void MD5Init(MD5_CTX *context) +{ + /* Load magic initialization constants: */ + context->count[0] = 0; + context->count[1] = 0; + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* MD5 block update operation. Continues an MD5 message-digest operation, */ +/* processing another message block, and updating the context. */ +void MD5Update(MD5_CTX *context, UCHAR *input, UINT inputLen) +{ + UINT index, partLen; + int inputLenM63; + + /* Compute number of bytes mod 64: */ + index = (UINT)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits: */ + if ((context->count[0] += ((UINT32)inputLen << 3)) < ((UINT32)inputLen << 3)) { + context->count[1]++; + } + context->count[1] += ((UINT32)inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible: */ + if (inputLen >= partLen) { + int i; + memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen); + MD5Transform(context->state, context->buffer); + + inputLenM63 = inputLen - 63; + for (i = partLen; i < inputLenM63; i += 64) { + MD5Transform(context->state, &input[i]); + } + + /* Buffer remaining input: index = 0 */ + memcpy((POINTER)&context->buffer[0], (POINTER)&input[i], inputLen - i); + } else { + /* Buffer remaining input: i = 0 */ + memcpy((POINTER)&context->buffer[index], (POINTER)input, inputLen); + } + + return; +} + +/* Finalize MD5: =============================================================== */ +/* Ends an MD5 message-digest operation, writing the message digest and zeroing */ +/* the context. */ +void MD5Final(UCHAR digest[16], MD5_CTX *context) +{ + UCHAR bits[8]; + UINT index, padLen; + + /* Save number of bits: */ + MD5Encode(bits, context->count, 2); + + /* Pad out to 56 mod 64: */ + index = (UINT)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update(context, PADDING, padLen); + + /* Append length before padding: */ + MD5Update(context, bits, 8); + + /* Store state in digest: */ + MD5Encode(digest, context->state, 4); + + /* Zero sensitive information: */ + memset((POINTER)context, 0, sizeof(MD5_CTX)); +} + +/* MD5 basic transformation. Transforms state based on block: ================== */ +void MD5Transform(UINT32 state[4], UCHAR block[64]) +{ + UINT32 a = state[0], + b = state[1], + c = state[2], + d = state[3], + x[16]; + + /* Unroll the loop for speed: */ + /* UINT i, j; */ + /* for (i = 0, j = 0; j < 64; i++, j += 4) { */ + /* x[i] = ((UINT32)block[j]) | (((UINT32)block[j + 1]) << 8) | */ + /* (((UINT32)block[j + 2]) << 16) | (((UINT32)block[j + 3]) << 24); */ + /* } */ + x[0] = ( (UINT32)block[0]) | (((UINT32)block[1]) << 8) | + (((UINT32)block[2]) << 16) | (((UINT32)block[3]) << 24); + x[1] = ( (UINT32)block[4]) | (((UINT32)block[5]) << 8) | + (((UINT32)block[6]) << 16) | (((UINT32)block[7]) << 24); + x[2] = ( (UINT32)block[8]) | (((UINT32)block[9]) << 8) | + (((UINT32)block[10]) << 16) | (((UINT32)block[11]) << 24); + x[3] = ( (UINT32)block[12]) | (((UINT32)block[13]) << 8) | + (((UINT32)block[14]) << 16) | (((UINT32)block[15]) << 24); + x[4] = ( (UINT32)block[16]) | (((UINT32)block[17]) << 8) | + (((UINT32)block[18]) << 16) | (((UINT32)block[19]) << 24); + x[5] = ( (UINT32)block[20]) | (((UINT32)block[21]) << 8) | + (((UINT32)block[22]) << 16) | (((UINT32)block[23]) << 24); + x[6] = ( (UINT32)block[24]) | (((UINT32)block[25]) << 8) | + (((UINT32)block[26]) << 16) | (((UINT32)block[27]) << 24); + x[7] = ( (UINT32)block[28]) | (((UINT32)block[29]) << 8) | + (((UINT32)block[30]) << 16) | (((UINT32)block[31]) << 24); + x[8] = ( (UINT32)block[32]) | (((UINT32)block[33]) << 8) | + (((UINT32)block[34]) << 16) | (((UINT32)block[35]) << 24); + x[9] = ( (UINT32)block[36]) | (((UINT32)block[37]) << 8) | + (((UINT32)block[38]) << 16) | (((UINT32)block[39]) << 24); + x[10] = ( (UINT32)block[40]) | (((UINT32)block[41]) << 8) | + (((UINT32)block[42]) << 16) | (((UINT32)block[43]) << 24); + x[11] = ( (UINT32)block[44]) | (((UINT32)block[45]) << 8) | + (((UINT32)block[46]) << 16) | (((UINT32)block[47]) << 24); + x[12] = ( (UINT32)block[48]) | (((UINT32)block[49]) << 8) | + (((UINT32)block[50]) << 16) | (((UINT32)block[51]) << 24); + x[13] = ( (UINT32)block[52]) | (((UINT32)block[53]) << 8) | + (((UINT32)block[54]) << 16) | (((UINT32)block[55]) << 24); + x[14] = ( (UINT32)block[56]) | (((UINT32)block[57]) << 8) | + (((UINT32)block[58]) << 16) | (((UINT32)block[59]) << 24); + x[15] = ( (UINT32)block[60]) | (((UINT32)block[61]) << 8) | + (((UINT32)block[62]) << 16) | (((UINT32)block[63]) << 24); + + /* Round 1 */ + FF(a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF(d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF(c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF(b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF(a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF(d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF(c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF(b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF(a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF(d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG(a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG(d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG(a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG(a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG(c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + + GG(b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG(d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG(c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH(a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH(d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH(a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH(d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH(c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH(d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH(c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH(b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH(a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH(b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II(a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II(d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II(b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II(d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II(b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II(a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II(c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II(a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II(b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + memset((POINTER)x, 0, sizeof(x)); +} + +/* Encodes input (UINT32) into output (UCHAR) (length is divided by 4) ========= */ +void MD5Encode(UCHAR *output, UINT32 *input, UINT len) +{ + UINT j; + + for (j = 0; j < len; j++) { + *output++ = (UCHAR)( *input & 0xff); + *output++ = (UCHAR)((*input >> 8) & 0xff); + *output++ = (UCHAR)((*input >> 16) & 0xff); + *output++ = (UCHAR)((*input++ >> 24) & 0xff); + } +} + +/* Calcualte digest: =========================================================== */ +void MD5Char(mxChar *array, mwSize inputLen, UCHAR digest[16]) +{ + /* Process string: Matlab stores strings as mxChar, which are 2 bytes per */ + /* character. This function considers the first byte of each CHAR only, which */ + /* is equivalent to calculate the sum after a conversion to a ASCII UCHAR */ + /* string. */ + MD5_CTX context; + UINT Chunk; + UCHAR *bufferP, *bufferEnd = buffer + BUFFER_LEN, *arrayP; + + /* Limit length to 32 bit address, because I cannot test this function */ + /* with 64 bit arrays currently (under construction): */ + if (inputLen >> 31 != 0) { /* Detect sign-bit if mwSize is int */ + mexErrMsgTxt("*** CalcMD5[mex]: Input > 2^31 byte not handled yet."); + } + + arrayP = (UCHAR *) array; /* UCHAR *, not mxChar *!*/ + + MD5Init(&context); + + /* Copy chunks of input data - only the first byte of each mxChar: */ + Chunk = inputLen / BUFFER_LEN; + while (Chunk--) { + bufferP = buffer; + while (bufferP < bufferEnd) { + *bufferP++ = *arrayP; + arrayP += 2; + } + + MD5Update(&context, buffer, BUFFER_LEN); + } + + /* Last chunk: */ + Chunk = inputLen % BUFFER_LEN; + if (Chunk != 0) { + bufferEnd = buffer + Chunk; + bufferP = buffer; + while (bufferP < bufferEnd) { + *bufferP++ = *arrayP; + arrayP += 2; + } + + MD5Update(&context, buffer, Chunk); + } + + MD5Final(digest, &context); + + return; +} + +/* Array of any type as byte stream: =========================================== */ +void MD5Array(UCHAR *array, mwSize inputLen, UCHAR digest[16]) +{ + MD5_CTX context; + + /* Limit length to 32 bit address, because I cannot test this function */ + /* with 64 bit arrays currently (under construction): */ + if (inputLen >> 31 != 0) { /* Detect sign-bit if mwSize is signed int */ + mexErrMsgTxt("*** CalcMD5[mex]: Input > 2^31 byte not handled yet."); + } + + MD5Init(&context); + MD5Update(&context, array, (UINT) inputLen); + MD5Final(digest, &context); +} + +/* File as byte stream: ======================================================== */ +void MD5File(char *filename, UCHAR digest[16]) +{ + FILE *FID; + MD5_CTX context; + int len; + UINT32 allLen = 0; + + /* Open the file in binary mode: */ + if ((FID = fopen(filename, "rb")) == NULL) { + mexPrintf("*** Error for file: [%s]\n", filename); + mexErrMsgTxt("*** CalcMD5[mex]: Cannot open file."); + } + + MD5Init(&context); + while ((len = fread(buffer, 1, BUFFER_LEN, FID)) != 0) { + /* Limit length to 32 bit address, because I cannot test this function */ + /* with 64 bit arrays currently (under construction): */ + allLen += len; + if (allLen > 2147483647) { /* 2^31 */ + fclose(FID); + mexErrMsgTxt("*** CalcMD5[mex]: Cannot handle files > 2.1GB yet."); + } + + MD5Update(&context, buffer, (UINT) len); + } + MD5Final(digest, &context); + + fclose(FID); +} + +/* Output of 16 UCHARs as 32 character hexadecimals: =========================== */ +void ToHex(const UCHAR digest[16], char *output, int LowerCase) +{ + char *outputEnd; + + if (LowerCase) { + for (outputEnd = output + 32; output < outputEnd; output += 2) { + sprintf(output, "%02x", *(digest++)); + } + } else { /* Upper case: */ + for (outputEnd = output + 32; output < outputEnd; output += 2) { + sprintf(output, "%02X", *(digest++)); + } + } + + return; +} + +/* BASE64 encoded output: ====================================================== */ +void ToBase64(const UCHAR In[16], char *Out) +{ + /* The base64 encoded string is shorter than the hex string. */ + /* Needed length: ((len + 2) / 3 * 4) + 1, here fixed to 22+1 here (trailing */ + /* 0 included). */ + static const UCHAR B64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + int i; + char *p; + const UCHAR *s; + + p = Out; + s = In; + for (i = 0; i < 5; i++) { + *p++ = B64[(*s >> 2) & 0x3F]; + *p++ = B64[((*s & 0x3) << 4) | ((s[1] & 0xF0) >> 4)]; + *p++ = B64[((s[1] & 0xF) << 2) | ((s[2] & 0xC0) >> 6)]; + *p++ = B64[s[2] & 0x3F]; + s += 3; + } + + *p++ = B64[(*s >> 2) & 0x3F]; + *p++ = B64[((*s & 0x3) << 4)]; + *p = '\0'; + + return; +} + +/* Main function: ============================================================== */ +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + /* Mex interface: */ + /* - Define default values of optional arguments. */ + /* - Forward input data to different calculators according to the input type. */ + /* - Convert digest to output format. */ + + char *FileName, InType, hexOut[33], b64Out[23]; + UCHAR digest[16], *digestP, OutType = 'h'; + int isFile = false, isUnicode = false; + double *outP, *outEnd; + + /* Check number of inputs and outputs: */ + if (nrhs == 0 || nrhs > 3) { + mexErrMsgTxt("*** CalcMD5[mex]: 1 to 3 inputs required."); + } + if (nlhs > 1) { + mexErrMsgTxt("*** CalcMD5[mex]: Too many output arguments."); + } + + /* If 2nd input starts with 'f', treat string in 1st argument as file name: */ + if (nrhs >= 2 && mxGetNumberOfElements(prhs[1]) > 0) { + if (mxIsChar(prhs[1]) == 0) { + mexErrMsgTxt("*** CalcMD5[mex]: 2nd input must be a string."); + } + + InType = (char) tolower(*(POINTER) mxGetData(prhs[1])); + isFile = (InType == 'f'); + isUnicode = (InType == 'u'); + } /* Default otherwise! */ + + /* Output type - default: hex: */ + if (nrhs == 3 && !mxIsEmpty(prhs[2])) { + if (mxIsChar(prhs[2]) == 0) { + mexErrMsgTxt("*** CalcMD5[mex]: 3rd input must be a string."); + } + + OutType = *(POINTER) mxGetData(prhs[2]); /* Just 1st character */ + } + + /* Calculate check sum: */ + if (isFile) { + if ((FileName = mxArrayToString(prhs[0])) == NULL) { + mexErrMsgTxt("*** CalcMD5[mex]: Cannot get file name."); + } + MD5File(FileName, digest); + mxFree(FileName); + + } else if (mxIsNumeric(prhs[0]) || isUnicode) { + MD5Array((POINTER) mxGetData(prhs[0]), + mxGetNumberOfElements(prhs[0]) * mxGetElementSize(prhs[0]), + digest); + + } else if (mxIsChar(prhs[0])) { + MD5Char((mxChar *) mxGetData(prhs[0]), + mxGetNumberOfElements(prhs[0]), + digest); + + } else { + mexErrMsgTxt("*** CalcMD5[mex]: Input type not accepted."); + } + + /* Create output: */ + switch (OutType) { + case 'H': + case 'h': /* Hexadecimal upper/lower case: */ + ToHex(digest, hexOut, OutType == 'h'); + plhs[0] = mxCreateString(hexOut); + break; + + case 'D': + case 'd': /* DOUBLE with integer values: */ + plhs[0] = mxCreateDoubleMatrix(1, 16, mxREAL); + outP = mxGetPr(plhs[0]); + digestP = digest; + for (outEnd = outP + 16; outP < outEnd; outP++) { + *outP = (double) *digestP++; + } + break; + + case 'B': + case 'b': /* Base64: */ + /* strtobase64(b64Out, 26, digest, 16); // included in LCC3.8 */ + /* b64Out[24] = '\0'; */ + ToBase64(digest, b64Out); /* Locally implemented */ + plhs[0] = mxCreateString(b64Out); + break; + + default: + mexErrMsgTxt("*** CalcMD5[mex]: Unknown output type."); + } + + return; +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/src/model_header.ODE_template.h b/Requirements/AMICI-0.10.11_SS_eventFix/src/model_header.ODE_template.h new file mode 100644 index 0000000..bde8831 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/src/model_header.ODE_template.h @@ -0,0 +1,810 @@ +#ifndef _amici_TPL_MODELNAME_h +#define _amici_TPL_MODELNAME_h +#include <cmath> +#include <memory> + +#include "amici/model_ode.h" +#include "amici/solver_cvodes.h" + +#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 + */ +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, + const realtype *dwdx); +extern void JB_TPL_MODELNAME(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); +extern void JDiag_TPL_MODELNAME(realtype *JDiag, const realtype t, + const realtype *x, const realtype *p, + const realtype *k, const realtype *h, + const realtype *w, const realtype *dwdx); +TPL_JSPARSE_DEF +TPL_JSPARSE_COLPTRS_DEF +TPL_JSPARSE_ROWVALS_DEF +TPL_JSPARSEB_DEF +TPL_JSPARSEB_COLPTRS_DEF +TPL_JSPARSEB_ROWVALS_DEF +extern void Jy_TPL_MODELNAME(realtype *nllh, const int iy, const realtype *p, + const realtype *k, const realtype *y, + const realtype *sigmay, const realtype *my); +extern void dJydsigmay_TPL_MODELNAME(realtype *dJydsigmay, const int iy, + const realtype *p, const realtype *k, + const realtype *y, const realtype *sigmay, + const realtype *my); +TPL_DJYDY_DEF +TPL_DJYDY_COLPTRS_DEF +TPL_DJYDY_ROWVALS_DEF +TPL_DWDP_DEF +TPL_DWDX_DEF +TPL_DWDX_COLPTRS_DEF +TPL_DWDX_ROWVALS_DEF +TPL_DXDOTDW_DEF +TPL_DXDOTDW_COLPTRS_DEF +TPL_DXDOTDW_ROWVALS_DEF +TPL_DXDOTDP_DEF +extern void dydx_TPL_MODELNAME(realtype *dydx, const realtype t, + const realtype *x, const realtype *p, + const realtype *k, const realtype *h, + const realtype *w, const realtype *dwdx); +extern void dydp_TPL_MODELNAME(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 *dwp); +extern void dsigmaydp_TPL_MODELNAME(realtype *dsigmaydp, const realtype t, + const realtype *p, const realtype *k, + const int ip); +extern void sigmay_TPL_MODELNAME(realtype *sigmay, const realtype t, + const realtype *p, const realtype *k); +TPL_W_DEF +extern void x0_TPL_MODELNAME(realtype *x0, const realtype t, const realtype *p, + const realtype *k); +extern void x0_fixedParameters_TPL_MODELNAME(realtype *x0, const realtype t, + const realtype *p, + const realtype *k); +extern void sx0_TPL_MODELNAME(realtype *sx0, const realtype t, + const realtype *x0, const realtype *p, + const realtype *k, const int ip); +extern void sx0_fixedParameters_TPL_MODELNAME(realtype *sx0, const realtype t, + const realtype *x0, + const realtype *p, + const realtype *k, const int ip); +extern void xdot_TPL_MODELNAME(realtype *xdot, const realtype t, + const realtype *x, const realtype *p, + const realtype *k, const realtype *h, + const realtype *w); +extern void y_TPL_MODELNAME(realtype *y, const realtype t, const realtype *x, + const realtype *p, const realtype *k, + const realtype *h, const realtype *w); +TPL_X_RDATA_DEF +TPL_X_SOLVER_DEF +TPL_TOTAL_CL_DEF + +/** + * @brief AMICI-generated model subclass. + */ +class Model_TPL_MODELNAME : public amici::Model_ODE { + public: + /** + * @brief Default constructor. + */ + Model_TPL_MODELNAME() + : amici::Model_ODE( + TPL_NX_RDATA, // nx_rdata + TPL_NXTRUE_RDATA, // nxtrue_rdata + TPL_NX_SOLVER, // nx_solver + TPL_NXTRUE_SOLVER, // nxtrue_solver + TPL_NY, // ny + TPL_NYTRUE, // nytrue + TPL_NZ, // nz + TPL_NZTRUE, // nztrue + TPL_NEVENT, // nevent + TPL_NOBJECTIVE, // nobjective + TPL_NW, // nw + TPL_NDWDX, // ndwdx + TPL_NDWDP, // ndwdp + TPL_NDXDOTDW, // ndxdotdw + TPL_NDJYDY, // ndjydy + TPL_NNZ, // nnz + TPL_UBW, // ubw + TPL_LBW, // lbw + TPL_O2MODE, // o2mode + std::vector<realtype>{TPL_PARAMETERS}, // dynamic parameters + std::vector<realtype>{TPL_FIXED_PARAMETERS}, // fixedParameters + std::vector<int>{}, // plist + std::vector<realtype>(TPL_NX_SOLVER, 0.0), // idlist + std::vector<int>{} // z2event + ) {} + + /** + * @brief Clone this model instance. + * @return A deep copy of this instance. + */ + virtual amici::Model *clone() const override { + return new Model_TPL_MODELNAME(*this); + } + + /** model specific implementation for fJ + * @param J Matrix to which the Jacobian will be written + * @param t timepoint + * @param x Vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param w vector with helper variables + * @param dwdx derivative of w wrt x + **/ + virtual void fJ(realtype *J, const realtype t, const realtype *x, + const realtype *p, const realtype *k, const realtype *h, + const realtype *w, const realtype *dwdx) override { + J_TPL_MODELNAME(J, t, x, p, k, h, w, dwdx); + } + + /** model specific implementation for fJB + * @param JB Matrix to which the Jacobian will be written + * @param t timepoint + * @param x Vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param xB Vector with the adjoint states + * @param w vector with helper variables + * @param dwdx derivative of w wrt x + **/ + virtual void fJB(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) override { + JB_TPL_MODELNAME(JB, t, x, p, k, h, xB, w, dwdx); + } + + /** model specific implementation for fJDiag + * @param JDiag Matrix to which the Jacobian will be written + * @param t timepoint + * @param x Vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param w vector with helper variables + * @param dwdx derivative of w wrt x + **/ + virtual void fJDiag(realtype *JDiag, const realtype t, const realtype *x, + const realtype *p, const realtype *k, const realtype *h, + const realtype *w, const realtype *dwdx) override { + JDiag_TPL_MODELNAME(JDiag, t, x, p, k, h, w, dwdx); + } + + TPL_JSPARSE_IMPL + + TPL_JSPARSE_COLPTRS_IMPL + + TPL_JSPARSE_ROWVALS_IMPL + + TPL_JSPARSEB_IMPL + + TPL_JSPARSEB_COLPTRS_IMPL + + TPL_JSPARSEB_ROWVALS_IMPL + + /** model specific implementation of fJrz + * @param nllh regularization for event measurements z + * @param iz event output index + * @param p parameter vector + * @param k constant vector + * @param z model event output at timepoint + * @param sigmaz event measurement standard deviation at timepoint + **/ + virtual void fJrz(realtype *nllh, const int iz, const realtype *p, + const realtype *k, const realtype *rz, + const realtype *sigmaz) override {} + + /** model specific implementation of fJy + * @param nllh negative log-likelihood for measurements y + * @param iy output index + * @param p parameter vector + * @param k constant vector + * @param y model output at timepoint + * @param sigmay measurement standard deviation at timepoint + * @param my measurements at timepoint + **/ + virtual void fJy(realtype *nllh, const int iy, const realtype *p, + const realtype *k, const realtype *y, + const realtype *sigmay, const realtype *my) override { + Jy_TPL_MODELNAME(nllh, iy, p, k, y, sigmay, my); + } + + /** model specific implementation of fJz + * @param nllh negative log-likelihood for event measurements z + * @param iz event output index + * @param p parameter vector + * @param k constant vector + * @param z model event output at timepoint + * @param sigmaz event measurement standard deviation at timepoint + * @param mz event measurements at timepoint + **/ + virtual void fJz(realtype *nllh, const int iz, const realtype *p, + const realtype *k, const realtype *z, + const realtype *sigmaz, const realtype *mz) override {} + + /** model specific implementation of fdJrzdsigma + * @param dJrzdsigma Sensitivity of event penalization Jrz w.r.t. + * standard deviation sigmaz + * @param iz event output index + * @param p parameter vector + * @param k constant vector + * @param rz model root output at timepoint + * @param sigmaz event measurement standard deviation at timepoint + **/ + virtual void fdJrzdsigma(realtype *dJrzdsigma, const int iz, + const realtype *p, const realtype *k, + const realtype *rz, + const realtype *sigmaz) override {} + + /** model specific implementation of fdJrzdz + * @param dJrzdz partial derivative of event penalization Jrz + * @param iz event output index + * @param p parameter vector + * @param k constant vector + * @param rz model root output at timepoint + * @param sigmaz event measurement standard deviation at timepoint + **/ + virtual void fdJrzdz(realtype *dJrzdz, const int iz, const realtype *p, + const realtype *k, const realtype *rz, + const realtype *sigmaz) override {} + + /** model specific implementation of fdJydsigma + * @param dJydsigma Sensitivity of time-resolved measurement + * negative log-likelihood Jy w.r.t. standard deviation sigmay + * @param iy output index + * @param p parameter vector + * @param k constant vector + * @param y model output at timepoint + * @param sigmay measurement standard deviation at timepoint + * @param my measurement at timepoint + **/ + virtual void fdJydsigma(realtype *dJydsigma, const int iy, + const realtype *p, const realtype *k, + const realtype *y, const realtype *sigmay, + const realtype *my) override { + dJydsigmay_TPL_MODELNAME(dJydsigma, iy, p, k, y, sigmay, my); + } + + + /** model specific implementation of fdJzdsigma + * @param dJzdsigma Sensitivity of event measurement + * negative log-likelihood Jz w.r.t. standard deviation sigmaz + * @param iz event output index + * @param p parameter vector + * @param k constant vector + * @param z model event output at timepoint + * @param sigmaz event measurement standard deviation at timepoint + * @param mz event measurement at timepoint + **/ + virtual void fdJzdsigma(realtype *dJzdsigma, const int iz, + const realtype *p, const realtype *k, + const realtype *z, const realtype *sigmaz, + const realtype *mz) override {} + + /** model specific implementation of fdJzdz + * @param dJzdz partial derivative of event measurement negative + *log-likelihood Jz + * @param iz event output index + * @param p parameter vector + * @param k constant vector + * @param z model event output at timepoint + * @param sigmaz event measurement standard deviation at timepoint + * @param mz event measurement at timepoint + **/ + virtual void fdJzdz(realtype *dJzdz, const int iz, const realtype *p, + const realtype *k, const realtype *z, + const realtype *sigmaz, const realtype *mz) override {} + + /** model specific implementation of fdeltasx + * @param deltaqB sensitivity update + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + * @param ip sensitivity index + * @param ie event index + * @param xdot new model right hand side + * @param xdot_old previous model right hand side + * @param xB adjoint state + **/ + virtual void 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) override {} + + /** model specific implementation of fdeltasx + * @param deltasx sensitivity update + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + * @param w repeating elements vector + * @param ip sensitivity index + * @param ie event index + * @param xdot new model right hand side + * @param xdot_old previous model right hand side + * @param sx state sensitivity + * @param stau event-time sensitivity + **/ + virtual void 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) override {} + + /** model specific implementation of fdeltax + * @param deltax state update + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + * @param ie event index + * @param xdot new model right hand side + * @param xdot_old previous model right hand side + **/ + virtual void 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) override {} + + /** model specific implementation of fdeltaxB + * @param deltaxB adjoint state update + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + * @param ie event index + * @param xdot new model right hand side + * @param xdot_old previous model right hand side + * @param xB current adjoint state + **/ + virtual void 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) override {} + + /** model specific implementation of fdrzdp + * @param drzdp partial derivative of root output rz w.r.t. model parameters + *p + * @param ie event index + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + * @param ip parameter index w.r.t. which the derivative is requested + **/ + virtual void fdrzdp(realtype *drzdp, const int ie, const realtype t, + const realtype *x, const realtype *p, const realtype *k, + const realtype *h, const int ip) override {} + + /** model specific implementation of fdrzdx + * @param drzdx partial derivative of root output rz w.r.t. model states x + * @param ie event index + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + **/ + virtual void fdrzdx(realtype *drzdx, const int ie, const realtype t, + const realtype *x, const realtype *p, const realtype *k, + const realtype *h) override {} + + /** model specific implementation of fsigmay + * @param dsigmaydp partial derivative of standard deviation of measurements + * @param t current time + * @param p parameter vector + * @param k constant vector + * @param ip sensitivity index + **/ + virtual void fdsigmaydp(realtype *dsigmaydp, const realtype t, + const realtype *p, const realtype *k, + const int ip) override { + dsigmaydp_TPL_MODELNAME(dsigmaydp, t, p, k, ip); + } + + /** model specific implementation of fsigmaz + * @param dsigmazdp partial derivative of standard deviation of event + *measurements + * @param t current time + * @param p parameter vector + * @param k constant vector + * @param ip sensitivity index + **/ + virtual void fdsigmazdp(realtype *dsigmazdp, const realtype t, + const realtype *p, const realtype *k, + const int ip) override {} + + TPL_DJYDY_IMPL + TPL_DJYDY_COLPTRS_IMPL + TPL_DJYDY_ROWVALS_IMPL + + TPL_DWDP_IMPL + + TPL_DWDX_IMPL + + TPL_DXDOTDW_IMPL + + TPL_DXDOTDW_COLPTRS_IMPL + + TPL_DXDOTDW_ROWVALS_IMPL + + TPL_DXDOTDP_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 + **/ + virtual void fdydx(realtype *dydx, const realtype t, const realtype *x, + const realtype *p, const realtype *k, const realtype *h, + const realtype *w, const realtype *dwdx) override { + dydx_TPL_MODELNAME(dydx, t, x, p, k, h, w, dwdx); + } + + /** model specific implementation of fdydp + * @param dydp partial derivative of observables y w.r.t. model parameters p + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + * @param ip parameter index w.r.t. which the derivative is requested + **/ + virtual void 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) override { + dydp_TPL_MODELNAME(dydp, t, x, p, k, h, ip, w, dwdp); + } + + /** model specific implementation of fdzdp + * @param dzdp partial derivative of event-resolved output z w.r.t. model + *parameters p + * @param ie event index + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + * @param ip parameter index w.r.t. which the derivative is requested + **/ + virtual void fdzdp(realtype *dzdp, const int ie, const realtype t, + const realtype *x, const realtype *p, const realtype *k, + const realtype *h, const int ip) override {} + + /** model specific implementation of fdzdx + * @param dzdx partial derivative of event-resolved output z w.r.t. model + *states x + * @param ie event index + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + **/ + virtual void fdzdx(realtype *dzdx, const int ie, const realtype t, + const realtype *x, const realtype *p, const realtype *k, + const realtype *h) override {} + + /** model specific implementation for froot + * @param root values of the trigger function + * @param t timepoint + * @param x Vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + **/ + virtual void froot(realtype *root, const realtype t, const realtype *x, + const realtype *p, const realtype *k, + const realtype *h) override {} + + /** model specific implementation of frz + * @param rz value of root function at current timepoint (non-output events + *not included) + * @param ie event index + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + **/ + virtual void frz(realtype *rz, const int ie, const realtype t, + const realtype *x, const realtype *p, const realtype *k, + const realtype *h) override {} + + /** model specific implementation of fsigmay + * @param sigmay standard deviation of measurements + * @param t current time + * @param p parameter vector + * @param k constant vector + **/ + virtual void fsigmay(realtype *sigmay, const realtype t, const realtype *p, + const realtype *k) override { + sigmay_TPL_MODELNAME(sigmay, t, p, k); + } + + /** model specific implementation of fsigmaz + * @param sigmaz standard deviation of event measurements + * @param t current time + * @param p parameter vector + * @param k constant vector + **/ + virtual void fsigmaz(realtype *sigmaz, const realtype t, const realtype *p, + const realtype *k) override {} + + /** model specific implementation of fsrz + * @param srz Sensitivity of rz, total derivative + * @param ie event index + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param sx current state sensitivity + * @param h heavyside vector + * @param ip sensitivity index + **/ + virtual void 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) override {} + + /** model specific implementation of fstau + * @param stau total derivative of event timepoint + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + * @param sx current state sensitivity + * @param ip sensitivity index + * @param ie event index + **/ + virtual void 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) override {} + + /** model specific implementation of fsx0 + * @param sx0 initial state sensitivities + * @param t initial time + * @param x0 initial state + * @param p parameter vector + * @param k constant vector + * @param ip sensitivity index + **/ + virtual void fsx0(realtype *sx0, const realtype t, const realtype *x0, + const realtype *p, const realtype *k, + const int ip) override { + sx0_TPL_MODELNAME(sx0, t, x0, p, k, ip); + } + + /** model specific implementation of fsx0_fixedParameters + * @param sx0 initial state sensitivities + * @param t initial time + * @param x0 initial state + * @param p parameter vector + * @param k constant vector + * @param ip sensitivity index + **/ + virtual void fsx0_fixedParameters(realtype *sx0, const realtype t, + const realtype *x0, const realtype *p, + const realtype *k, + const int ip) override { + sx0_fixedParameters_TPL_MODELNAME(sx0, t, x0, p, k, ip); + } + + /** model specific implementation of fsz + * @param sz Sensitivity of rz, total derivative + * @param ie event index + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + * @param sx current state sensitivity + * @param ip sensitivity index + **/ + virtual void 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) override {} + + TPL_W_IMPL + + /** model specific implementation of fx0 + * @param x0 initial state + * @param t initial time + * @param p parameter vector + * @param k constant vector + **/ + virtual void fx0(realtype *x0, const realtype t, const realtype *p, + const realtype *k) override { + x0_TPL_MODELNAME(x0, t, p, k); + } + + /** model specific implementation of fx0_fixedParameters + * @param x0 initial state + * @param t initial time + * @param p parameter vector + * @param k constant vector + **/ + virtual void fx0_fixedParameters(realtype *x0, const realtype t, + const realtype *p, + const realtype *k) override { + x0_fixedParameters_TPL_MODELNAME(x0, t, p, k); + } + + /** model specific implementation for fxdot + * @param xdot residual function + * @param t timepoint + * @param x Vector with the states + * @param p parameter vector + * @param k constants vector + * @param h heavyside vector + * @param w vector with helper variables + **/ + virtual void fxdot(realtype *xdot, const realtype t, const realtype *x, + const realtype *p, const realtype *k, const realtype *h, + const realtype *w) override { + xdot_TPL_MODELNAME(xdot, t, x, p, k, h, w); + } + + /** model specific implementation of fy + * @param y model output at current timepoint + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + **/ + virtual void fy(realtype *y, const realtype t, const realtype *x, + const realtype *p, const realtype *k, const realtype *h, + const realtype *w) override { + y_TPL_MODELNAME(y, t, x, p, k, h, w); + } + + /** model specific implementation of fz + * @param z value of event output + * @param ie event index + * @param t current time + * @param x current state + * @param p parameter vector + * @param k constant vector + * @param h heavyside vector + **/ + virtual void fz(realtype *z, const int ie, const realtype t, + const realtype *x, const realtype *p, const realtype *k, + const realtype *h) override {} + + TPL_X_RDATA_IMPL + + TPL_X_SOLVER_IMPL + + TPL_TOTAL_CL_IMPL + + /** + * @brief Get names of the model parameters + * @return the names + */ + virtual std::vector<std::string> getParameterNames() const override { + return std::vector<std::string>{TPL_PARAMETER_NAMES_INITIALIZER_LIST}; + } + + /** + * @brief Get names of the model states + * @return the names + */ + virtual std::vector<std::string> getStateNames() const override { + return std::vector<std::string>{TPL_STATE_NAMES_INITIALIZER_LIST}; + } + + /** + * @brief Get names of the fixed model parameters + * @return the names + */ + virtual std::vector<std::string> getFixedParameterNames() const override { + return std::vector<std::string>{ + TPL_FIXED_PARAMETER_NAMES_INITIALIZER_LIST}; + } + + /** + * @brief Get names of the observables + * @return the names + */ + virtual std::vector<std::string> getObservableNames() const override { + return std::vector<std::string>{TPL_OBSERVABLE_NAMES_INITIALIZER_LIST}; + } + + /** + * @brief Get ids of the model parameters + * @return the ids + */ + virtual std::vector<std::string> getParameterIds() const override { + return std::vector<std::string>{TPL_PARAMETER_IDS_INITIALIZER_LIST}; + } + + /** + * @brief Get ids of the model states + * @return the ids + */ + virtual std::vector<std::string> getStateIds() const override { + return std::vector<std::string>{TPL_STATE_IDS_INITIALIZER_LIST}; + } + + /** + * @brief Get ids of the fixed model parameters + * @return the ids + */ + virtual std::vector<std::string> getFixedParameterIds() const override { + return std::vector<std::string>{ + TPL_FIXED_PARAMETER_IDS_INITIALIZER_LIST}; + } + + /** + * @brief Get ids of the observables + * @return the ids + */ + virtual std::vector<std::string> getObservableIds() const override { + return std::vector<std::string>{TPL_OBSERVABLE_IDS_INITIALIZER_LIST}; + } + + /** + * @brief function indicating whether reinitialization of states depending on + fixed parameters is permissible + * @return flag inidication whether reinitialization of states depending on + fixed parameters is permissible + */ + virtual bool isFixedParameterStateReinitializationAllowed() const override { + return TPL_REINIT_FIXPAR_INITCOND; + } + + /** + * @brief returns the amici version that was used to generate the model + * @return ver amici version string + */ + virtual const std::string getAmiciVersion() const override { + return "TPL_AMICI_VERSION_STRING"; + } + + /** + & @brief returns the amici version that was used to generate the model + * @return commit amici git commit hash + */ + virtual const std::string getAmiciCommit() const override { + return "TPL_AMICI_COMMIT_STRING"; + } + + virtual bool wasPythonGenerated() const override { + return true; + } +}; + +#endif /* _amici_TPL_MODELNAME_h */ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/src/wrapfunctions.ODE_template.h b/Requirements/AMICI-0.10.11_SS_eventFix/src/wrapfunctions.ODE_template.h new file mode 100644 index 0000000..b789f43 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/src/wrapfunctions.ODE_template.h @@ -0,0 +1,11 @@ +#ifndef _amici_wrapfunctions_h +#define _amici_wrapfunctions_h +#include "TPL_MODELNAME.h" + +/** + * @brief Wrapper function to instantiate the linked Amici model without knowing the name at compile time. + * @return + */ +std::unique_ptr<amici::Model> getModel(); + +#endif /* _amici_wrapfunctions_h */ diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/swig/stdvec2numpy.h b/Requirements/AMICI-0.10.11_SS_eventFix/swig/stdvec2numpy.h new file mode 100644 index 0000000..2a67a8f --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/swig/stdvec2numpy.h @@ -0,0 +1,128 @@ +namespace amici { + +/** + * @brief Convert 1D array to *non-owning* numpy ndarray. + * @param vec + * @param dim1 + * @return + */ +PyObject* stdVec2ndarray(std::vector<double>& vec, int dim1) { + if (vec.size() != (unsigned) dim1) throw std::runtime_error("Size mismatch in stdVec2ndarray"); + npy_intp dims[1] = { dim1 }; + PyObject * array = PyArray_SimpleNewFromData(1, dims, NPY_DOUBLE, vec.data()); + if (!array) throw std::runtime_error("Unknown failure in stdVec2ndarray");; + return array; +} + +/** + * @brief Convert row-major flattened 2D array to *non-owning* numpy ndarray. + * @param vec + * @param dim1 + * @param dim2 + * @return + */ +PyObject* stdVec2ndarray(std::vector<double>& vec, int dim1, int dim2) { + if (vec.size() != (unsigned) dim1 * dim2) throw std::runtime_error("Size mismatch in stdVec2ndarray"); + npy_intp dims[2] = { dim1, dim2 }; + PyObject * array = PyArray_SimpleNewFromData(2, dims, NPY_DOUBLE, vec.data()); + if (!array) throw std::runtime_error("Unknown failure in stdVec2ndarray");; + return array; +} + +/** + * @brief Convert row-major flattened 3D array to *non-owning* numpy ndarray. + * @param vec + * @param dim1 + * @param dim2 + * @param dim3 + * @return + */ +PyObject* stdVec2ndarray(std::vector<double>& vec, int dim1, int dim2, int dim3) { + if (vec.size() != (unsigned) dim1 * dim2 * dim3) throw std::runtime_error("Size mismatch in stdVec2ndarray"); + npy_intp dims[3] = { dim1, dim2, dim3 }; + PyObject * array = PyArray_SimpleNewFromData(3, dims, NPY_DOUBLE, vec.data()); + if (!array) throw std::runtime_error("Unknown failure in stdVec2ndarray");; + return array; +} + +/** + * @brief Convert row-major flattened 2D array to *non-owning* numpy ndarray. + * @param vec + * @param dim1 + * @param dim2 + * @param dim3 + * @param dim4 + * @return + */ +PyObject* stdVec2ndarray(std::vector<double>& vec, int dim1, int dim2, int dim3, int dim4) { + if (vec.size() != (unsigned) dim1 * dim2 * dim3 * dim4) throw std::runtime_error("Size mismatch in stdVec2ndarray"); + npy_intp dims[4] = { dim1, dim2, dim3, dim4 }; + PyObject * array = PyArray_SimpleNewFromData(4, dims, NPY_DOUBLE, vec.data()); + if (!array) throw std::runtime_error("Unknown failure in stdVec2ndarray");; + return array; +} + + +/** + * @brief Convert 1D array to *non-owning* numpy ndarray. + * @param vec + * @param dim1 + * @return + */ +PyObject* stdVec2ndarray(std::vector<int>& vec, int dim1) { + if (vec.size() != (unsigned) dim1) throw std::runtime_error("Size mismatch in stdVec2ndarray"); + npy_intp dims[1] = { dim1 }; + PyObject * array = PyArray_SimpleNewFromData(1, dims, NPY_INT, vec.data()); + if (!array) throw std::runtime_error("Unknown failure in stdVec2ndarray");; + return array; +} + +/** + * @brief Convert row-major flattened 2D array to *non-owning* numpy ndarray. + * @param vec + * @param dim1 + * @param dim2 + * @return + */ +PyObject* stdVec2ndarray(std::vector<int>& vec, int dim1, int dim2) { + if (vec.size() != (unsigned) dim1 * dim2) throw std::runtime_error("Size mismatch in stdVec2ndarray"); + npy_intp dims[2] = { dim1, dim2 }; + PyObject * array = PyArray_SimpleNewFromData(2, dims, NPY_INT, vec.data()); + if (!array) throw std::runtime_error("Unknown failure in stdVec2ndarray");; + return array; +} + +/** + * @brief Convert row-major flattened 3D array to *non-owning* numpy ndarray. + * @param vec + * @param dim1 + * @param dim2 + * @param dim3 + * @return + */ +PyObject* stdVec2ndarray(std::vector<int>& vec, int dim1, int dim2, int dim3) { + if (vec.size() != (unsigned) dim1 * dim2 * dim3) throw std::runtime_error("Size mismatch in stdVec2ndarray"); + npy_intp dims[3] = { dim1, dim2, dim3 }; + PyObject * array = PyArray_SimpleNewFromData(3, dims, NPY_INT, vec.data()); + if (!array) throw std::runtime_error("Unknown failure in stdVec2ndarray");; + return array; +} + +/** + * @brief Convert row-major flattened 2D array to *non-owning* numpy ndarray. + * @param vec + * @param dim1 + * @param dim2 + * @param dim3 + * @param dim4 + * @return + */ +PyObject* stdVec2ndarray(std::vector<int>& vec, int dim1, int dim2, int dim3, int dim4) { + if (vec.size() != (unsigned) dim1 * dim2 * dim3 * dim4) throw std::runtime_error("Size mismatch in stdVec2ndarray"); + npy_intp dims[4] = { dim1, dim2, dim3, dim4 }; + PyObject * array = PyArray_SimpleNewFromData(4, dims, NPY_INT, vec.data()); + if (!array) throw std::runtime_error("Unknown failure in stdVec2ndarray");; + return array; +} + +} diff --git a/Requirements/AMICI-0.10.11_SS_eventFix/tests/cpputest/testfunctions.h b/Requirements/AMICI-0.10.11_SS_eventFix/tests/cpputest/testfunctions.h new file mode 100644 index 0000000..ac07dd2 --- /dev/null +++ b/Requirements/AMICI-0.10.11_SS_eventFix/tests/cpputest/testfunctions.h @@ -0,0 +1,205 @@ +#ifndef TESTFUNCTIONS_H +#define TESTFUNCTIONS_H + +#include <amici/hdf5.h> +#include <amici/amici.h> + +#include <H5Cpp.h> + +#ifndef __APPLE__ +#include <iostream> +#endif +#include <string> +#include <sstream> // make std::ostringstream available (needs to come before TestHarness.h) +#include <CppUTest/TestHarness.h> +#include <CppUTestExt/MockSupport.h> + +namespace amici { + +class ReturnData; +class ExpData; + +#if !defined(NEW_OPTION_FILE) || !defined(HDFFILE) || !defined(HDFFILEWRITE) +# error "Must define NEW_OPTION_FILE HDFFILE HDFFILEWRITE" +#endif + +#define TEST_ATOL 1e-10 +#define TEST_RTOL 1e-05 + +/** + * @brief helper function to initialize default names/ids + * @param name name of variables + * @param length number of variables + * @return default names/ids + */ +std::vector<std::string> getVariableNames(const char* name, int length); + +/** + * @brief The Model_Test class is a model-unspecific implementation + of model designed for unit testing. + */ +class Model_Test : public Model { +public: + /** constructor with model dimensions + * @param nx number of state variables + * @param nxtrue number of state variables of the non-augmented model + * @param ny number of observables + * @param nytrue number of observables of the non-augmented model + * @param nz number of event observables + * @param nztrue number of event observables of the non-augmented model + * @param ne number of events + * @param nJ number of objective functions + * @param nw number of repeating elements + * @param ndwdx number of nonzero elements in the x derivative of the + * repeating elements + * @param ndwdp number of nonzero elements in the p derivative of the + * repeating elements + * @param nnz number of nonzero elements in Jacobian + * @param ubw upper matrix bandwidth in the Jacobian + * @param lbw lower matrix bandwidth in the Jacobian + * @param o2mode second order sensitivity mode + * @param p parameters + * @param k constants + * @param plist indexes wrt to which sensitivities are to be computed + * @param idlist indexes indicating algebraic components (DAE only) + * @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 SecondOrderMode o2mode, const std::vector<realtype> p, + const std::vector<realtype> k, const std::vector<int> plist, + const std::vector<realtype> idlist, const std::vector<int> z2event) + : Model(nx_rdata, nxtrue_rdata, nx_solver, nxtrue_solver, 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, + SecondOrderMode::none, std::vector<realtype>(), + std::vector<realtype>(), std::vector<int>(), + std::vector<realtype>(), std::vector<int>()) {} + + virtual Model *clone() const override { return new Model_Test(*this); } + + virtual std::unique_ptr<Solver> getSolver() override { + throw AmiException("not implemented"); + } + virtual void froot(const realtype t, const AmiVector &x, + const AmiVector &dx, gsl::span<realtype> root) override { + throw AmiException("not implemented"); + } + virtual void fxdot(const realtype t, const AmiVector &x, + const AmiVector &dx, AmiVector &xdot) override { + throw AmiException("not implemented"); + } + virtual void fsxdot(const realtype t, const AmiVector &x, + const AmiVector &dx, const int ip, const AmiVector &sx, + const AmiVector &sdx, AmiVector &sxdot) override { + throw AmiException("not implemented"); + } + virtual void fJ(const realtype t, const realtype cj, const AmiVector &x, + const AmiVector &dx, const AmiVector &xdot, SUNMatrix J) + override { + throw AmiException("not implemented"); + } + virtual void fJSparse(const realtype t, const realtype cj, + const AmiVector &x, const AmiVector &dx, + const AmiVector &xdot, SUNMatrix J) override { + throw AmiException("not implemented"); + } + virtual void fJDiag(const realtype t, AmiVector &Jdiag, + const realtype cj, const AmiVector &x, + const AmiVector &dx) override { + throw AmiException("not implemented"); + } + virtual void fdxdotdp(const realtype t, const AmiVector &x, + const AmiVector &dx) override { + throw AmiException("not implemented"); + } + virtual void fJv(const realtype t, const AmiVector &x, const AmiVector &dx, + const AmiVector &xdot,const AmiVector &v, AmiVector &nJv, + const realtype cj) override { + throw AmiException("not implemented"); + } + + virtual std::vector<std::string> getParameterNames() const override + { + return getVariableNames("p", np()); + } + + virtual std::vector<std::string> getStateNames() const override + { + return getVariableNames("x", nx_rdata); + } + + virtual std::vector<std::string> getFixedParameterNames() const override + { + return getVariableNames("k", nk()); + } + + virtual std::vector<std::string> getObservableNames() const override + { + return getVariableNames("y", ny); + } + + virtual std::vector<std::string> getParameterIds() const override + { + return getVariableNames("p", np()); + } + + virtual std::vector<std::string> getStateIds() const override + { + return getVariableNames("x", nx_rdata); + } + + virtual std::vector<std::string> getFixedParameterIds() const override + { + return getVariableNames("k", nk()); + } + + virtual std::vector<std::string> getObservableIds() const override + { + return getVariableNames("y", ny); + } + + +}; + +void simulateWithDefaultOptions(); + +void simulateVerifyWrite(const std::string& path); + +void simulateVerifyWrite(std::string path, double atol, double rtol); + +void simulateVerifyWrite(const std::string& hdffileOptions, const std::string& hdffileResults, + const std::string& hdffilewrite, const std::string& path, + double atol, double rtol); + +std::unique_ptr<ExpData> getTestExpData(const Model &model); + +bool withinTolerance(double expected, double actual, double atol, double rtol, int index, const char *name); + +void checkEqualArray(const double *expected, const double *actual, int length, double atol, double rtol, const char *name); + +void checkEqualArray(std::vector<double> const& expected, std::vector<double> const& actual, + double atol, double rtol, std::string const& name); + +// TODO: delete after transitioning to C++-written test results +void verifyReturnDataMatlab(const std::string &hdffile, const std::string &resultPath, const ReturnData *rdata, const Model *model, double atol, double rtol); + +// TODO: delete after transitioning to C++-written test results +void verifyReturnDataSensitivitiesMatlab(const H5::H5File &file_id, const std::string &resultPath, const ReturnData *rdata, const Model *model, double atol, double rtol); + +void verifyReturnData(const std::string &hdffile, const std::string &resultPath, const ReturnData *rdata, const Model *model, double atol, double rtol); + +void verifyReturnDataSensitivities(const H5::H5File &file_id, const std::string &resultPath, const ReturnData *rdata, const Model *model, double atol, double rtol); + +void printBacktrace(int depth); + +} // namespace amici + +#endif -- GitLab