diff --git a/.gitignore b/.gitignore
index ba0543c6d4b3bb81636ea9cc193c3092c8aed9da..fdedf6c8524d3b62c92b1ce0c9d13f29cac454f4 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 0000000000000000000000000000000000000000..70d90070a83874c5d3e7fcfac9892055819a5ab7
--- /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 0000000000000000000000000000000000000000..68c1e9e8fdd271d73c001e021ceb5db088ba6d7f
--- /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 0000000000000000000000000000000000000000..d918845aa5d654334bb48b31004d14cc3f3f81d7
--- /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 0000000000000000000000000000000000000000..62a05913ee782b23ffd8f61aeaaabde4b31d5287
--- /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 0000000000000000000000000000000000000000..5241fb15003485e9088af173c181acb5132ed50e
--- /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 0000000000000000000000000000000000000000..a72851fcf469a757382ea1030801ed3096977690
--- /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 0000000000000000000000000000000000000000..67305273ec54b8db218192c6477504ed27491b5f
--- /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 0000000000000000000000000000000000000000..89fdc9b7cd23464fea131101bf04eea8a835ca67
--- /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 0000000000000000000000000000000000000000..2be486e01142638d9f8ab2fdf7c526f61e470f7d
--- /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 0000000000000000000000000000000000000000..f144722cd9a103a7e7e275f1ce194251e8f1f933
--- /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 0000000000000000000000000000000000000000..67c03f7a4c284ea8a4eb85b69d142ae351dccce8
--- /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 0000000000000000000000000000000000000000..f6a5e9a5403efd477927f5212e59b3c1a8d9ee78
--- /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 0000000000000000000000000000000000000000..b9a9079a03e71d4c9efcca9e1ea64bc2c9adb662
--- /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 0000000000000000000000000000000000000000..e58aaf55522ebc71a44e1ca1ba953aa69b3c89d6
--- /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 0000000000000000000000000000000000000000..453e970e409278abc0ecef665430cd4f92fe3a07
--- /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 0000000000000000000000000000000000000000..062651f496760c082f33491b8976c130c6f0b6f9
--- /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 0000000000000000000000000000000000000000..7f199aea66cfc0055d452cecea8638beda722dcd
--- /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 0000000000000000000000000000000000000000..516c95c9ad0ae8f0b645eeac7dd50a241c314c7d
--- /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 0000000000000000000000000000000000000000..e5aea7b7b940db28c8859ab3ef10cdeeb69e7def
--- /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 0000000000000000000000000000000000000000..a8139c300c0f0f9fd53a1caa7517b02ad7c1ae51
--- /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 0000000000000000000000000000000000000000..609abcaa4db1e801e940d3442d1f45cb48348adf
--- /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 0000000000000000000000000000000000000000..c36de946a18e47325bc25bf59de3a2d3618e708e
--- /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 0000000000000000000000000000000000000000..fc0426dd63734b7d6c57b1a47ec9c67ffc63369c
--- /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 0000000000000000000000000000000000000000..45dcf75d889f16525f493ab8d2ebe4289f5975db
--- /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 0000000000000000000000000000000000000000..8219981d5b438f88619b2e8b671df75c06afaa9e
--- /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 0000000000000000000000000000000000000000..0e15735801a57b24d6e6610ed8e1d6dbd9dc009c
--- /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 0000000000000000000000000000000000000000..3f44b261609803f03b15eace549baac205b4c3f3
--- /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 0000000000000000000000000000000000000000..b0bdb294b5b00a112cf5bbc7b4105f4c8fd7be01
--- /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 0000000000000000000000000000000000000000..36ec3e28f402977ee1df03aeb1e8c58ed6216845
--- /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, &timestamp,
+                    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 0000000000000000000000000000000000000000..0fd909a2cc3dac0e363675e8fa7deea93ec94bdc
--- /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 0000000000000000000000000000000000000000..8dd0b620542f0545c7efd97caa70fa88944dc73c
--- /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 0000000000000000000000000000000000000000..1c127d05e59ed5246154fe82806fb5ea6f4e2a6c
--- /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 0000000000000000000000000000000000000000..87dbdd5b37ac3d226aebe738e1eac68d4561a401
--- /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 0000000000000000000000000000000000000000..21898e01724881a5ca5b421753a6c18f21c1c013
--- /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 0000000000000000000000000000000000000000..92407c8080b872ca11a844ea446b7694080afc96
--- /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 0000000000000000000000000000000000000000..2be61209e4df59cba6621baa4dd11ab1bbab5c33
--- /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 0000000000000000000000000000000000000000..753f9651ede2d6769715a01b05848c28c399b8bd
--- /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 0000000000000000000000000000000000000000..ac8d63691e66530e89e23b7d42defd16fe1dea28
--- /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 0000000000000000000000000000000000000000..b385fc7ac9b70c8886fdaaa025498bc3e6883ad4
--- /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 0000000000000000000000000000000000000000..c1c57541bc293386382fe71ff2acd76010317040
--- /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 0000000000000000000000000000000000000000..5ac59bff3f8e734a56f4f81c93344d574b22b2e9
--- /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 0000000000000000000000000000000000000000..6b0b495b2f336c93da525789f9ed709f1ef9cd8e
--- /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 0000000000000000000000000000000000000000..eef93ee489ec38101455876002256f554000dc55
--- /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 0000000000000000000000000000000000000000..96547e6863d529fb38ae71fb312df4e3deb21f2d
--- /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 0000000000000000000000000000000000000000..67eb1fdafc8949511ff14138b2bb35953916d3e3
--- /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 0000000000000000000000000000000000000000..4af03e11eb2d4d03ca07885435c380761dc8f8d1
--- /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 0000000000000000000000000000000000000000..aa399c36ecf16ad2ed2ceab2b427a2e81a305bc7
--- /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 0000000000000000000000000000000000000000..a1da203d89f49479421b2b6e165fa4f21782b277
--- /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 0000000000000000000000000000000000000000..02fa3697ecac23e2749dc818a913c57377f978e7
--- /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 0000000000000000000000000000000000000000..657a9a73be44849718c456f4a606019c92c77eac
--- /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 0000000000000000000000000000000000000000..fbe95930896e7aa101795d29bdd3cc0becf7fd29
--- /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 0000000000000000000000000000000000000000..f6be92f23548d70d21dfbb141dab3e140b536d68
--- /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 0000000000000000000000000000000000000000..64ef2cb9b728d7f76ec07c31c66ae4bc19f237dc
--- /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 0000000000000000000000000000000000000000..af79e269d9c2e0cff8613214b3f93ca95891beb5
--- /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 0000000000000000000000000000000000000000..57cf05ca4b4c08db0f3b5d5c281386e2765c7bfe
--- /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 0000000000000000000000000000000000000000..8d56c389b5f467386648ffc87aece784f5f72ef1
--- /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 0000000000000000000000000000000000000000..7530d40fb7281a9da5f651a77253e3b07b6439e7
--- /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 0000000000000000000000000000000000000000..b6b22950155b7b5c0f30dd7cc1640a2a4d1c5dd0
--- /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 0000000000000000000000000000000000000000..ccf064476a79e2adabae03fc2106e481bfcaf411
--- /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 0000000000000000000000000000000000000000..2da483b06d69e5e345b087b3050e59f27df35505
--- /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 0000000000000000000000000000000000000000..f3d63c89e1a8de5fec96bdb603fc9ed150bf7ef3
--- /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 0000000000000000000000000000000000000000..e762a435c19fe7e6017fda7791eec7c6104aa3bd
--- /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 0000000000000000000000000000000000000000..f19f8a3cefb6675e7e3610927458c6e106989cc9
--- /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 0000000000000000000000000000000000000000..6042fcdfc18ac3b87bdb96b948bf9833498249c7
--- /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 0000000000000000000000000000000000000000..2fe81c19ca048da86dfd00c0c137835be105d383
--- /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 0000000000000000000000000000000000000000..bee5473455360c4be32aa2939a04689e8ea409ea
--- /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 0000000000000000000000000000000000000000..ba2b77ee1489b4ef95fd8a128fc477bc8fd38c43
--- /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 0000000000000000000000000000000000000000..dc9d288ecc7900b0399acd528e965f34da5d0a7e
--- /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 0000000000000000000000000000000000000000..8f5590053e2d3d62bceaccd4b8b2cae25264beb4
--- /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 0000000000000000000000000000000000000000..b009828a7b7dd08e3d756ffc765081bc763f0ed8
--- /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 0000000000000000000000000000000000000000..8a410e717be7c438c688779365277598ab6b48b0
--- /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 0000000000000000000000000000000000000000..cd4f3bdcd9b54bb26c4d9e88915ab6419c91cd90
--- /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 0000000000000000000000000000000000000000..20b4000e6205e489138d52ef2e785f029290e30b
--- /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 0000000000000000000000000000000000000000..c3a78b40d517fb5f219dd50faaa22ca99d017142
--- /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 0000000000000000000000000000000000000000..d391a0836dbe01226909d874e1f7d4f3ae8f73da
--- /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 0000000000000000000000000000000000000000..02539bebd1e42ef27181f19e291d1ec33bdcb6e8
--- /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 0000000000000000000000000000000000000000..479612006847d91d1af6686512bc371355e89279
--- /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 0000000000000000000000000000000000000000..d23a140956ece4629dafda3d0f4241abcc667554
--- /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 0000000000000000000000000000000000000000..a3ce98f4671729d92f72eed7160b20783ca98d0d
--- /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 0000000000000000000000000000000000000000..c1f10f7083a58319990f979df1178ccb514484a6
--- /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 0000000000000000000000000000000000000000..c09781499590323e367e2a9029dc59e055cf0530
--- /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 0000000000000000000000000000000000000000..c1c1872e449524381525924dc1afb6f0dda108ff
--- /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 0000000000000000000000000000000000000000..8f532a23f1d38f01364e35e15291dabe604b0851
--- /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 0000000000000000000000000000000000000000..0307546bd2d07b05dc9a20bdfb8ce5caf80ea4c0
--- /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 0000000000000000000000000000000000000000..b491539feafe54474e9fa564d402fc1121ef7d6a
--- /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 0000000000000000000000000000000000000000..6d1bc2dbefaaec9075f00e65c3c7a8db5827994b
--- /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 0000000000000000000000000000000000000000..5107f0353f9d462142fece2b07ab12430ab274ab
--- /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 0000000000000000000000000000000000000000..b332eb3da48d9758e4763702aca5caed1df41a4f
--- /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 0000000000000000000000000000000000000000..6d1bc2dbefaaec9075f00e65c3c7a8db5827994b
--- /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 0000000000000000000000000000000000000000..a72851fcf469a757382ea1030801ed3096977690
--- /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 0000000000000000000000000000000000000000..c36de946a18e47325bc25bf59de3a2d3618e708e
--- /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 0000000000000000000000000000000000000000..21898e01724881a5ca5b421753a6c18f21c1c013
--- /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 0000000000000000000000000000000000000000..fbe95930896e7aa101795d29bdd3cc0becf7fd29
--- /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 0000000000000000000000000000000000000000..2da483b06d69e5e345b087b3050e59f27df35505
--- /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 0000000000000000000000000000000000000000..00a10fe12be70839e51334d907b5433bc43e5890
--- /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 0000000000000000000000000000000000000000..e622b016540ca13ef1d66f7f07ba7b6a6ae0e252
--- /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 0000000000000000000000000000000000000000..ebcb38c90b3fdf4c2ba1ca0325d05796d31d785b
--- /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 0000000000000000000000000000000000000000..1594cf614ad38af531b49de2b5484cf4c7304590
--- /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 0000000000000000000000000000000000000000..d4432e9165e377cdd0fb4f4f6135b3fdef93ccb2
--- /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 0000000000000000000000000000000000000000..8b907cec2e9aaa2ba3ec695779fa9f7ebbb74a1b
--- /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 0000000000000000000000000000000000000000..d4f4dee66867de74018a8705847619e4373f2cae
--- /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 0000000000000000000000000000000000000000..f339d741c078a6e39c75d5a8fe658baa637e9c01
--- /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 0000000000000000000000000000000000000000..8cbac5c1baf7cbe4ee49a0ea55277d739f198d62
--- /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 0000000000000000000000000000000000000000..fde224291b9e77ec8083f0f75614a28f19b48590
--- /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 0000000000000000000000000000000000000000..48f7c824e2245855930e3e9325744f0aed0adca0
--- /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 0000000000000000000000000000000000000000..a75b0ab460d67cb7e5293a08b6acf98a0aa18365
--- /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 0000000000000000000000000000000000000000..7d606184bef0cbc359d424305686fdbfafc2244a
--- /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 0000000000000000000000000000000000000000..2575e84e0cd72a66088db3ec2e4117e15ff1be4b
--- /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 0000000000000000000000000000000000000000..95aa8e127c7583ea30cfef3bacb9ff2d5e981a45
--- /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 0000000000000000000000000000000000000000..94d1d786ae4aeb4508e7d411802dbe8999ac6c46
--- /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 0000000000000000000000000000000000000000..0d4e044a72fa0883a7efb92fab59aef6d7cc8f0b
--- /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 0000000000000000000000000000000000000000..194fb0808d5f96af885032b8778f3281ee313726
--- /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 0000000000000000000000000000000000000000..aec8709a27d25fd0f8bfdfddea2b1d0b469792e7
--- /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 0000000000000000000000000000000000000000..13dea8db4b28ed46b2d719ee899fca0f720d773b
--- /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 0000000000000000000000000000000000000000..b98e3416b83514c9b1f92efa213630e87048cd38
--- /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 0000000000000000000000000000000000000000..cef57b0c4fc6ba541f4a4ffd915413b7992f33e9
--- /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 0000000000000000000000000000000000000000..fb8e9f0f80739e2298dd9b37b20554a9d3f33395
--- /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 0000000000000000000000000000000000000000..da3bc7123da482cd0975aaf855fa8e305a682c05
--- /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 0000000000000000000000000000000000000000..bdfa9efc114fe19bb0b96f48481472f07312e063
--- /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 0000000000000000000000000000000000000000..0c99d1c02f916e8564f970ff766b3143081e189f
--- /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 0000000000000000000000000000000000000000..25455836a8a8c38b6329a294c500ed158ea6e82c
--- /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 0000000000000000000000000000000000000000..3255b2d7bb6b6bb56992aa7cda499d5aa38ec720
--- /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 0000000000000000000000000000000000000000..2ec98da78f16200e8d256b76716afb16550e495c
--- /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 0000000000000000000000000000000000000000..af33c8d614bc049fc2333a55b7fe2f036512349f
--- /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 0000000000000000000000000000000000000000..3e956c0686d2e018f8f11d94234c8ab38a98ebd5
--- /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 0000000000000000000000000000000000000000..74df9ed9db8749afd1ba763b3176da38169a0319
--- /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 0000000000000000000000000000000000000000..eed5c19178bd41d5b245ac175d38f123a2244e62
--- /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 0000000000000000000000000000000000000000..e7ef52ed154de15b453dbf5e3833aa60509f436c
--- /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 0000000000000000000000000000000000000000..fa8a372a0581d01319c1f440c6d9a7127716a7b7
--- /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 0000000000000000000000000000000000000000..bbc6910ad49ba87ee39304d5856c6b2bd592387c
--- /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 0000000000000000000000000000000000000000..c7e1ce7bb442fbfce8de62ad0ddde4beff78f845
--- /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 0000000000000000000000000000000000000000..27a8ea4e5990dfa3df565a7b3bade9858d108cbd
--- /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 0000000000000000000000000000000000000000..a20731d632f557b2bb3c78d1974ef5c924c77cef
--- /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 0000000000000000000000000000000000000000..c78989cdfd6d3ea0fbb1c653ca7fee96ac73f5de
--- /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 0000000000000000000000000000000000000000..b51b8e6341519efbf5b20c528bbf52c47af2b739
--- /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 0000000000000000000000000000000000000000..4915ea1688551eca72ce309a456e808cbc8a2ccb
--- /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 0000000000000000000000000000000000000000..00d2c8a7881a67ddae10108630bd5ec5a6ccb880
--- /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 0000000000000000000000000000000000000000..250b57caded771a95d8dd6758f98b85529a21f66
--- /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 0000000000000000000000000000000000000000..eaa87a8579179426e5b3b38f1e568abe7e972d11
--- /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 0000000000000000000000000000000000000000..992a9913ab0d94ec98b508e0ba57bdb569a457f7
--- /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 0000000000000000000000000000000000000000..8f7e11aa99d15525d579a6b1f510026bb86da2fe
--- /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 0000000000000000000000000000000000000000..0fc029fa1830cef7da118c49eab37c195eb52d34
--- /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 0000000000000000000000000000000000000000..22d8e4d736c1d93e221e72b4ba87cbe48b005ad9
--- /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 0000000000000000000000000000000000000000..10bcffc263b7af71133787a02324a0b0ad76535a
--- /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 0000000000000000000000000000000000000000..9ffcdc3016e2337f8a07fbf8e7585697f014209d
--- /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 0000000000000000000000000000000000000000..c549d29165a5aeaad9c430fedb7ee5a018134645
--- /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 0000000000000000000000000000000000000000..21a35407f885264dd25f04264bf67f47c561875f
--- /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 0000000000000000000000000000000000000000..7dee165cf68b06e6c120add3e5b54fa5441668bd
--- /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 0000000000000000000000000000000000000000..da4be77913b7103906cbc668ed15097fdce994d9
--- /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 0000000000000000000000000000000000000000..a1946f0be9ad12989d76b784e3caa343af140ede
--- /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 0000000000000000000000000000000000000000..8d5ab4dc33c12caac966b1708758a02402ca535b
--- /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 0000000000000000000000000000000000000000..fecca9a561351c9536773a4376a73748afb90172
--- /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 0000000000000000000000000000000000000000..886fecb9c7cfba6de7d42468170e70f0d3230f42
--- /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 0000000000000000000000000000000000000000..3d290972e7166330f45b4bef3061173fbb2ecb91
--- /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 0000000000000000000000000000000000000000..ab25391e76ee2899ebb788cdc7e41ee2356d2fea
--- /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 0000000000000000000000000000000000000000..2ac25c7ae41478bd1e12ad3a5d6cb979b3d7be99
--- /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 0000000000000000000000000000000000000000..bf80bcd6a1c7284a77f40a82d0db7ca25b50be08
--- /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 0000000000000000000000000000000000000000..ea034d65e2a52bc103864a5361a24995e4a49984
--- /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 0000000000000000000000000000000000000000..0930136c18f2c1337eb4c4aaefee2ac850a99e63
--- /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 0000000000000000000000000000000000000000..810dad67ebca098214f574f04eabbb8efa89f50e
--- /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 0000000000000000000000000000000000000000..728ded66c52daa950607fa72e64a61e6efc281c9
--- /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 0000000000000000000000000000000000000000..2918c690694be85942684a74325aedcbecc3ee0d
--- /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 0000000000000000000000000000000000000000..bcffb58f76f30f5d420b03f60d3f066fca477f1b
--- /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 0000000000000000000000000000000000000000..c6a57a4c594afc99ec850e17722526b259113a37
--- /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 0000000000000000000000000000000000000000..e4a79a387c05fdfc7aaa1326ca1010780ea94b4f
--- /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 0000000000000000000000000000000000000000..53e0fc2b6f911ab64acd3969a958989bf576f98b
--- /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 0000000000000000000000000000000000000000..f2bcea873f41432ac131f1345f31b8904c1786c8
--- /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 0000000000000000000000000000000000000000..27177764122e58d912b529f3c8a5417af6933c10
--- /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 0000000000000000000000000000000000000000..bba7c074c24e558033f0816b30bff91d15b3b4f3
--- /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 0000000000000000000000000000000000000000..e5574053ad479e400bea5a5a9621de459fc805a6
--- /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 0000000000000000000000000000000000000000..a4acb16fbc9d838dce0b5be739bd4e73d8a72e81
--- /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 0000000000000000000000000000000000000000..a2161cd100c88210f4a507649a19193f8c06fa26
--- /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 0000000000000000000000000000000000000000..dca22db6f767396b53fe4db3f09bdf8c11d39421
--- /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 0000000000000000000000000000000000000000..71aed4c14e731af704c0d022b7bbc53066baf12a
--- /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 0000000000000000000000000000000000000000..cdc35d4abce3f7978880ac9f457812355952b146
--- /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 0000000000000000000000000000000000000000..17343fba6a6b4621b230968871f61d3313e40948
--- /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 0000000000000000000000000000000000000000..282b5af9d5bea6048bf2a46673b42559c6f42d8f
--- /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 0000000000000000000000000000000000000000..98cc92b5f598e2d519d79b553733401736289de7
--- /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 0000000000000000000000000000000000000000..9c7925293d5b6e2e4593baac5628d6941249a6b9
--- /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 0000000000000000000000000000000000000000..57c1b46054fb1d045bbbe33e64b91204c2763b90
--- /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 0000000000000000000000000000000000000000..962976b9e962b6cd9e8f245d4ef56b39194ff741
--- /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 0000000000000000000000000000000000000000..ea0727dceed60756c6b6286d7885dc72da7cf8b2
--- /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 0000000000000000000000000000000000000000..de40e560c26e1b9279556d855e31f51fd89b1828
--- /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 0000000000000000000000000000000000000000..aea60aafabcbd46e48e0090c9c26c828f102eb63
--- /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 0000000000000000000000000000000000000000..e75c42b02bda52ec7a7b4a37dd679a4820ed31a4
--- /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 0000000000000000000000000000000000000000..3db653c1c0480eaf488b818e921cef101f2c21da
--- /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 0000000000000000000000000000000000000000..65916ba2550f28785a73beb60021960d367d1ab8
--- /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 0000000000000000000000000000000000000000..84619ffb5d4b93a0cac636943b97fb730d16a198
--- /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 0000000000000000000000000000000000000000..4e48bced407330ab8455d913f36bf6c4188bce5f
--- /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 0000000000000000000000000000000000000000..583ab80febba8c317811e07cf60181fb5e2c0c24
--- /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 0000000000000000000000000000000000000000..789edd558af64d102430d7e6476e9789277c64ce
--- /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 0000000000000000000000000000000000000000..1d4462792c48dbaf9460e84400a4ac9ff4263232
--- /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 0000000000000000000000000000000000000000..5382b2d7ecc10ab27cef7b031c9d06a2fee5b72d
--- /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 0000000000000000000000000000000000000000..e1e6f4074f8998d53f14c2e88e5354f37258b397
--- /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 0000000000000000000000000000000000000000..ff203a466f97ec340c16fdf6a62b4a389ea507ec
--- /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 0000000000000000000000000000000000000000..e364617275251582b9dccbc0d90f9972e7cab40f
--- /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 0000000000000000000000000000000000000000..8d1c36a6612df91ca6ba30cada4368ec5a59a7ce
--- /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 0000000000000000000000000000000000000000..ccb3856edd24206193fad20cc3030c5db5f9f37f
--- /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 0000000000000000000000000000000000000000..7bd1021cc6872d06a12cf65b0807abf7d8d130dc
--- /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 0000000000000000000000000000000000000000..8642ce8cd9d257b33c1657f6c86ef6efa956e4bc
--- /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 0000000000000000000000000000000000000000..06f1e837794e82e6144f02c43db28c5a03755e97
--- /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 0000000000000000000000000000000000000000..017ef4169062ca815d37beb2967c5631aea56d5e
--- /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 0000000000000000000000000000000000000000..750beadb53311026b5c4347bc9965fd1f166e68b
--- /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 0000000000000000000000000000000000000000..cb868cac55550a1dbb5c26618a84256065b98cf9
--- /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 0000000000000000000000000000000000000000..f0bf5383276b533f8d180bcf99b3a89e1e1eaa71
--- /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 0000000000000000000000000000000000000000..fc9a6ac3b1d1935de3130f0ebe5fd58233439962
--- /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 0000000000000000000000000000000000000000..8c2a46640d1f09dae5ef3bfc6418414adc2f54ab
--- /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 0000000000000000000000000000000000000000..6508c22bc730028e15c23ee926643fd3f8a536d2
--- /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 0000000000000000000000000000000000000000..568f6f1a76d2881e2f1b1b441acb5667c11eddc0
--- /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 0000000000000000000000000000000000000000..a66838dfa0fde9a65d8f3e1ceed51769071545eb
--- /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 0000000000000000000000000000000000000000..5b405a1264a0bfa4c6a08b4638e4cde7b11f4881
--- /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 0000000000000000000000000000000000000000..cced0b6d3fb2220391e3ba064aee1f2b1c55f59b
--- /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 0000000000000000000000000000000000000000..8131c14e34928c3fd0f4d22dd1fd565ce3e1fe99
--- /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 0000000000000000000000000000000000000000..69b61701b8566d0cca05ed18197bb34be8170ab8
--- /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 0000000000000000000000000000000000000000..09a83003d44a2391418db8bb5b4c27d791b53c26
--- /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 0000000000000000000000000000000000000000..0247b735e14d930d830162dd125ad6281a57a39e
--- /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 0000000000000000000000000000000000000000..38bdd50e4a08584ba0117c20d3f0f9c0f09cf176
--- /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 0000000000000000000000000000000000000000..9bf7c0d9ced05ed4d5bcfaf59c58e106b4d13c9c
--- /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 0000000000000000000000000000000000000000..65dd522987d1f91e9b8d6ae7ef5fe3c9d19f5e2e
--- /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 0000000000000000000000000000000000000000..fbb7aac82623d75ec107489f3a393fc058d77221
--- /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 0000000000000000000000000000000000000000..2781725cab9fc2b2adbea5079a9eb4f00206bf91
--- /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 0000000000000000000000000000000000000000..d55189541fc2dd9c0d84e8aa75a590ee128473bf
--- /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 0000000000000000000000000000000000000000..7aea9b691a8a80ab3bfd0552af05545745db1d0f
--- /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 0000000000000000000000000000000000000000..4dc039593c11d9467ae2d8f8e1acf17acacd67de
--- /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 0000000000000000000000000000000000000000..e7fa37e46ea394f2cb0ef742f9574b2f2b64b184
--- /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 0000000000000000000000000000000000000000..a4b07d5007cc30878ac03715732489ea4d2f5041
--- /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 0000000000000000000000000000000000000000..3f78949c0c44023ea945610c49d15f3e327b1bab
--- /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 0000000000000000000000000000000000000000..2a2a8a2236d5753230ff8c3a8bb03a34787be40e
--- /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 0000000000000000000000000000000000000000..e7b9d98416f9d1f625f5f6bd731726d79bcf4aad
--- /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 0000000000000000000000000000000000000000..36fc016e25f9a90b369e1a062c01e434f9628f49
--- /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 0000000000000000000000000000000000000000..1097f91cc70bb9511d7b891992c3c5bdb0e8478f
--- /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 0000000000000000000000000000000000000000..be0f6f9a2871812d8fd339989bb19ac66720f846
--- /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 0000000000000000000000000000000000000000..02eb14f2f5ea62ad39475dd3fe2756861d87d4c3
--- /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 0000000000000000000000000000000000000000..32da99557625286b1c56e9104bf53201d9b2eac4
--- /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 0000000000000000000000000000000000000000..b44235a328790548f156d8f335d3d0ae40bc3a50
--- /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 0000000000000000000000000000000000000000..a6f1f91e04fba44f6a031b679dd45c3d3c77d9a0
--- /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 0000000000000000000000000000000000000000..8be21248096a7c2dc512d952434428ffa384d776
--- /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 0000000000000000000000000000000000000000..6075c52a414ca918f0b4463d683b8041a69ebdb7
--- /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 0000000000000000000000000000000000000000..1bdc4aa13a5549e9a52c58ce76b95ae772010772
--- /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 0000000000000000000000000000000000000000..41194b0e479778447d435b268400b14188d7509a
--- /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 0000000000000000000000000000000000000000..be463b1f50846e546a7379f51e54bf8456a34da6
--- /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 0000000000000000000000000000000000000000..5ddd70129abb028e6b626ebd8018bce0eff0d31a
--- /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 0000000000000000000000000000000000000000..4bb58d34ae59689942e4faee89fcfbf7b68ab8e3
--- /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 0000000000000000000000000000000000000000..72b355500d69a696b8b2f0dac73bfa3cc483f2fa
--- /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 0000000000000000000000000000000000000000..2d1333adafb67692a577a875a6f4f8fb19292593
--- /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 0000000000000000000000000000000000000000..44f6946477191d873e10982fa9fb533c2f93080c
--- /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 0000000000000000000000000000000000000000..42881de75a82e16793ad4291b38492b2430da8a3
--- /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 0000000000000000000000000000000000000000..48d4c027d8d5007dda7b5fdd2e894f9c1b6bcfff
--- /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 0000000000000000000000000000000000000000..cc716bec75f34fd82d706fa2d441d617bb771159
--- /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 0000000000000000000000000000000000000000..f20ac3fb689ffc7f4f4b2f5756554a55581ab4cb
--- /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 0000000000000000000000000000000000000000..9c28e50a8d8916c76db582bcd291d41f0ee05aca
--- /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 0000000000000000000000000000000000000000..c4f9ffb2cfd11e8583ec6ccaca6287c3d5273c11
--- /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 0000000000000000000000000000000000000000..855a0772b8a3a783aa5022747b5b1143b4907302
--- /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 0000000000000000000000000000000000000000..382fa0bafa29465ce393b8af8e773fd012e36b39
--- /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 0000000000000000000000000000000000000000..849e575b81e42fe84a8743023d0fbe0b8d7ff155
--- /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 0000000000000000000000000000000000000000..695fc760a1c49a38b46d9a56079bc297798551e5
--- /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 0000000000000000000000000000000000000000..7f47253750dd813d98ea0ee1acdc8a4a13c41cc4
--- /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 0000000000000000000000000000000000000000..e3c6a2a8b0ca613b5a231b338baaa30eca14ed15
--- /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 0000000000000000000000000000000000000000..cecf847a0c31ce33fc4a0457c9c8d2a332d862f4
--- /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 0000000000000000000000000000000000000000..02ae44ebc62d64f80dd37f48cfef85eabbbbc3c7
--- /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 0000000000000000000000000000000000000000..be8ac27ef2d07b32f2f63f0682c51011f0ad9254
--- /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 0000000000000000000000000000000000000000..6f232327031c0b345ff4f09059de8ec4af866de5
--- /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 0000000000000000000000000000000000000000..824fe0befd9617a01d9b6fee88c5d289ef737ea7
--- /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 0000000000000000000000000000000000000000..ca67675005e7c89c7f67f15bb73069ba7fcc266b
--- /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 0000000000000000000000000000000000000000..b16119ef1857fbbbd63f39a8d7a2bfca2817ba21
--- /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 0000000000000000000000000000000000000000..b03404bfb2a22f00624647270ad5e4e39a116584
--- /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 0000000000000000000000000000000000000000..2f99da0500c5bc1dfc5bc4b0459420cd062fecbb
--- /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 0000000000000000000000000000000000000000..d92f192edfc045f96c8e8795a3f624bf6a84a99a
--- /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 0000000000000000000000000000000000000000..33dacc1ccd6a0e08ec12e506d4456e93bf41ac33
--- /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 0000000000000000000000000000000000000000..ed51e23e71d5152769895f8ddd57bac3bfb30bae
--- /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 0000000000000000000000000000000000000000..167b2eb40001ef16a63c3bd07d8ebf85efb37a89
--- /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 0000000000000000000000000000000000000000..025f3e9030c56a255c60409ce6427a340f0d7d40
--- /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 0000000000000000000000000000000000000000..844754cf8eb929484fa6cd38f5fccd34dc4e8471
--- /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 0000000000000000000000000000000000000000..de1b147f4d97bce08caa3f4609945f98aa0327d9
--- /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 0000000000000000000000000000000000000000..65ac4fee6ef15684528bab8ec427ab6c043e5f97
--- /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 0000000000000000000000000000000000000000..e6ad5893284072b9b3bb72fc400f39d749249043
--- /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 0000000000000000000000000000000000000000..cc3ca62b5deaac76d4cfd11ac075868eb5c1bbd7
--- /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 0000000000000000000000000000000000000000..799f7cb5334feaa8353b586dbc2d2c0e92f60ae2
--- /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 0000000000000000000000000000000000000000..3f172ac915c674e8ccf051e46654608b2e34f66c
--- /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 0000000000000000000000000000000000000000..233ab038e4656910d107984356f6c73bde762147
--- /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 0000000000000000000000000000000000000000..cb40f8ebfa1d9419ae8b0b781fb0547810f97ef9
--- /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 0000000000000000000000000000000000000000..0a5c9aca8758b1bc41ddfab15767a6698ed8c0f2
--- /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 0000000000000000000000000000000000000000..14a92278b3accaa071d10aa3f7d3fe90276fd845
--- /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 0000000000000000000000000000000000000000..6275530653806aa303a1b44cb87d62e514971175
--- /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 0000000000000000000000000000000000000000..54437f947d250039db698c06ff1ec605c092b841
--- /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 0000000000000000000000000000000000000000..8df40304012223fca1323e983371e2e0b3242796
--- /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 0000000000000000000000000000000000000000..aeed096d58dc2db5ab4d2486eede1a625ad592c9
--- /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 0000000000000000000000000000000000000000..0ce3a9a591a7850a63192ef0ef14b9733371dccf
--- /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 0000000000000000000000000000000000000000..0bdec85cdca12a0684ea0b90db9afad75c5d4245
--- /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 0000000000000000000000000000000000000000..b545c100ed28a91414e5a9a6744321c11a0194af
--- /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 0000000000000000000000000000000000000000..dc5001f43cea451ba57ae862edca6e219d6deb0a
--- /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 0000000000000000000000000000000000000000..57a6584c84e0b375bb86d13ca06e8c87e0510f64
--- /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 0000000000000000000000000000000000000000..6832f6a56cfb6bf8d039b2bec6d60871f07d0a8c
--- /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 0000000000000000000000000000000000000000..11203aba83e018e35ec9599cb9cd505d257de120
--- /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 0000000000000000000000000000000000000000..dcfdadc37e13c1063f023c5245837a0c5d58954b
--- /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 0000000000000000000000000000000000000000..35cd0dde93a6120eab313913aaf838c98569841b
--- /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 0000000000000000000000000000000000000000..ee87d7f10ee88128b9c2b757f5e470c010a9414b
--- /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 0000000000000000000000000000000000000000..8db385b56905429a953de1d53b7e62b8d87bd59e
--- /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 0000000000000000000000000000000000000000..0b50d7d69ef8dcfb1f5fc992b6b90fdcd90ffd1c
--- /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 0000000000000000000000000000000000000000..2cce74b75cffba3f0897d58cbf46671761e3b681
--- /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 0000000000000000000000000000000000000000..7d1d39dbebaff08b84d1651dc8588ae05f8590fd
--- /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 0000000000000000000000000000000000000000..afd74eb35972a333720b214f75f46a19bfd2ba07
--- /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 0000000000000000000000000000000000000000..c950af8a07c63a6b917de8baab0d47e7d5c55720
--- /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 0000000000000000000000000000000000000000..1cb11cef2cb8d1da00464ec520042c73be9f1bed
--- /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 0000000000000000000000000000000000000000..e904803302fb29e31be1984ca799aaa32ee37ee8
--- /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 0000000000000000000000000000000000000000..5ba46dd78f54c5adb0a99297e23094649911e1d1
--- /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 0000000000000000000000000000000000000000..305639c7fca8e9b7c2b5e45ec456ddfdb07c89f7
--- /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 0000000000000000000000000000000000000000..93b1458535d190675cd52342ad90dffbe81a7277
--- /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 0000000000000000000000000000000000000000..5c1868f83fd60d59adf76bc7f68b15bbe12d2b5a
--- /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 0000000000000000000000000000000000000000..566605ed768b36b05f5060dc649195b6c9afe537
--- /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 0000000000000000000000000000000000000000..c4ee8d42ab456dea625e4333a91ff503a7438cf3
--- /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 0000000000000000000000000000000000000000..f64464bc68254e14e2f5af2243af154f6428a553
--- /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 0000000000000000000000000000000000000000..55132140b04cef65ca204575a93151c7b53291f1
--- /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 0000000000000000000000000000000000000000..32bc0cb4d80ac47c2392179d74d352e82d2f6cc5
--- /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 0000000000000000000000000000000000000000..b328cd9c79a9e213aaa05348ca91ba9978360c8a
--- /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 0000000000000000000000000000000000000000..7770b400eb5300e86712ffeee73ef971b89993d6
--- /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 0000000000000000000000000000000000000000..ca32f7385f21a335732e79bae23bbbc9c3847556
--- /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 0000000000000000000000000000000000000000..45e409b34724d784aeccacea5bf2b5fd254701ad
--- /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 0000000000000000000000000000000000000000..ee1bf7c933dbea49a9095969e2db6b4aae25bcdb
--- /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 0000000000000000000000000000000000000000..0284d96bb3636a3afb3d9fa20732d7b4997f3327
--- /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 0000000000000000000000000000000000000000..c3285114ef4f877cc3705f7e3ac812d73bec4ff5
--- /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 0000000000000000000000000000000000000000..7423676d50ab37ee9e1678eb5207ec787e87c8c0
--- /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 0000000000000000000000000000000000000000..e7572668908eb8a86318e176ffa825df151b5707
--- /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 0000000000000000000000000000000000000000..3cb3dc94cdede901c87308ee87243832b0ed1081
--- /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 0000000000000000000000000000000000000000..831c859d2b2f1d431a4eb9078607bc2b065c7015
--- /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 0000000000000000000000000000000000000000..ce6fc5a412f854080ecdda40cec5f358cc0723b0
--- /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 0000000000000000000000000000000000000000..0efd6bf8453f61e396a115baffd85c1edfa26edd
--- /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 0000000000000000000000000000000000000000..26d20b1f54b1bb2efab9e12dabc5d95e2e9fa97b
--- /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 0000000000000000000000000000000000000000..b68f90e5a02862b0c1f83eea93ef44542a55fce5
--- /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 0000000000000000000000000000000000000000..2ed5b464214761571a5807af316a33a8d06fdfe7
--- /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 0000000000000000000000000000000000000000..fb04965959d76268f13ca5b74d40c76a01ccb741
--- /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 0000000000000000000000000000000000000000..b63031352e3d499e438b7440710b603f85977d06
--- /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 0000000000000000000000000000000000000000..7d8d600d6cfb371b8e621a98fe127d2723b7fd72
--- /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 0000000000000000000000000000000000000000..6c6d997aec44bdd2a3edfb76c462de2784fa92b9
--- /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 0000000000000000000000000000000000000000..6390ffdc39aeedd5d0601f00cd0681f331cffe81
--- /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 0000000000000000000000000000000000000000..33352cfd38fabf7e38409a9f3df47b1d1e00d227
--- /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 0000000000000000000000000000000000000000..6daf153a13246e91745d02201a54866b95446da7
--- /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 0000000000000000000000000000000000000000..26ca4d40be03f3cd38c74884406f24423e29eb50
--- /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 0000000000000000000000000000000000000000..80af78f4f4e82e551b156ddf896763548ef6a553
--- /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 0000000000000000000000000000000000000000..a9ad2e95650ea058bf097389356365c3cd06b1ef
--- /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 0000000000000000000000000000000000000000..9c6d5323d1cc3b64e6b44582f93a0aa981b3b9c4
--- /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 0000000000000000000000000000000000000000..5e4a3e9a7666b80ad095196874076381b6f5fa8e
--- /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 0000000000000000000000000000000000000000..2d04fa67b0777e4f0da3cb4ab4be44112a13a230
--- /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 0000000000000000000000000000000000000000..ff4b883d7683e473abd6d5e5614c99d8608cf67f
--- /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 0000000000000000000000000000000000000000..5a5138fb9d4a28a73669057a4a4e41977451a55e
--- /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 0000000000000000000000000000000000000000..8f5f611ee2e8957b28bbf47512791275e2fad85a
--- /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 0000000000000000000000000000000000000000..bbf540da50f473540c9f370bec476d770f2d9aaa
--- /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 0000000000000000000000000000000000000000..9e3ce8209a2f7647912e20c5c9ca1c00a85adad5
--- /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 0000000000000000000000000000000000000000..b54f6cb448c3be90576d7467bb8c56249cc35efa
--- /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 0000000000000000000000000000000000000000..aa354de97ceb690b16042ca1db9e1097287a4a52
--- /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 0000000000000000000000000000000000000000..e278029e4d42ed87b23567c532af795b09a50406
--- /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 0000000000000000000000000000000000000000..9e044471cf3dd3ae1427a86439592c3d293e59ff
--- /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 0000000000000000000000000000000000000000..b8812f5c8b02e23934677d662f71962ba5ed38b6
--- /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 0000000000000000000000000000000000000000..3e3db9d8711ff5a058ebb7aeea48c19f424059ae
--- /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 0000000000000000000000000000000000000000..441b08e4619b5f9266b09fea5dd4e4ecc095dd39
--- /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 0000000000000000000000000000000000000000..87b758562d32f4669d99acef55ff9e81d87509ed
--- /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 0000000000000000000000000000000000000000..9a2112b4cdf2970ed7e03bff51f416625b7cb834
--- /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 0000000000000000000000000000000000000000..9ca099918643e73b5e9ed39b51d6b1a83c2fce69
--- /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 0000000000000000000000000000000000000000..0fd2f608526216d6c711b121ec1b1211115393eb
--- /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 0000000000000000000000000000000000000000..70883fd8ffbc04f19a8bff2f9200f0e2feec4aec
--- /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   = &sum;
+    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   = &sum;
+    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   = &sum;
+    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   = &sum;
+    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   = &sum;
+    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 0000000000000000000000000000000000000000..12516fc552d8d19c1893fd8336629b8fd66e8088
--- /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 0000000000000000000000000000000000000000..8ee03b5721679208e0a32dfdc6dbbfb9cfa9d3b6
--- /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 0000000000000000000000000000000000000000..25f72c9e60bea36a154ff24f7163e8c747e205ad
--- /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 0000000000000000000000000000000000000000..1495a5747746fc75d49599968cbda19b6664fb44
--- /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 0000000000000000000000000000000000000000..debaf7f5a6d16d3889017d76a601debdfa5e4bda
--- /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 0000000000000000000000000000000000000000..6d2dab64a10cc242b31264394077e16aafbcdf86
--- /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 0000000000000000000000000000000000000000..da71f3b16481b354282d2e197e6df76996827f7a
--- /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 0000000000000000000000000000000000000000..b2895bbffc4f82c5d18d9b97580301a2932aa07e
--- /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 0000000000000000000000000000000000000000..bca60cdac6fba3bab76668db7825a10bc6f2db09
--- /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 0000000000000000000000000000000000000000..e4702c389b67ce5ec9676999b327f8a75aae85ea
--- /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 0000000000000000000000000000000000000000..05823af67e3fa6e0f2e26fa9015eec55e4a8b81f
--- /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 0000000000000000000000000000000000000000..1a6dc8e7055f0ba0b500b35498a4f98a1bd276c2
--- /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 0000000000000000000000000000000000000000..9227bae56e9f362d3dadc60fd92ff9fc3e58aea3
--- /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 0000000000000000000000000000000000000000..b16f40172b16ed8f462f823333402b3413d64e80
--- /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 0000000000000000000000000000000000000000..affadd2666a2052a17dc5b0b976e64b5f366782b
--- /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 0000000000000000000000000000000000000000..eeeeb1dddb2ed566f2674fd955988d493118ae55
--- /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 0000000000000000000000000000000000000000..6a32bbec51d135ea894540b4544a4e1eb2a138b6
--- /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 0000000000000000000000000000000000000000..c8419ea68057be3856da71a1a381793bf5a57e21
--- /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 0000000000000000000000000000000000000000..fd778511979fb2031e73ee2cadefc69469ce1d76
--- /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 0000000000000000000000000000000000000000..7d330ce6368dc87fb8ff668edb2d14839c16ebc1
--- /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 0000000000000000000000000000000000000000..5192f43088009164fe75078bd1906cbf1aadfdeb
--- /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 0000000000000000000000000000000000000000..13170c45db424382a803d12f04cd51755d5c814c
--- /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 0000000000000000000000000000000000000000..c32cee61c81c12189619cbf8bcfbe921289d35f4
--- /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 0000000000000000000000000000000000000000..53853288ab849b20ce90dfe2e9cb30758aa82d97
--- /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 0000000000000000000000000000000000000000..2330b1d709e6cefd1cdf0a310cfda37a06a74104
--- /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 0000000000000000000000000000000000000000..872bdbad677b460029166391027000901f3d5de3
--- /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 0000000000000000000000000000000000000000..073bc936b29d7a002d192dc59e2aa845906a074f
--- /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 0000000000000000000000000000000000000000..b63ff1e4062987fbe3b8953f46e9c994c0c3105e
--- /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 0000000000000000000000000000000000000000..b80ca5c2b3056b82dc2a559b25587f3a9f0657ad
--- /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 0000000000000000000000000000000000000000..8038fe1ea9a5b70d52b1664a7aba13aeaf20e6a8
--- /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 0000000000000000000000000000000000000000..c54b9da2cd44d75213f9a42a1f90d854ce801a9a
--- /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 0000000000000000000000000000000000000000..ef8383d6f8804d4bde640081677757a2d11d637d
--- /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 0000000000000000000000000000000000000000..7c890461c8c19ee460ddbb2e4bb1ffa8cd3c8201
--- /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 0000000000000000000000000000000000000000..eaed35e1d34c4f30cac5069a729128887620c025
--- /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 0000000000000000000000000000000000000000..d97a7f53483e8a93f3d32a63fa92d8b3bb47ed97
--- /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 0000000000000000000000000000000000000000..e3f47073203301d5bdae686a4abccb60c3ad2bb7
--- /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 0000000000000000000000000000000000000000..03b049926bf706c800e2f0f3a8637ac81161339d
--- /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 0000000000000000000000000000000000000000..5a7da10d49560c99ae154701b0657e2269ec2a7a
--- /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 0000000000000000000000000000000000000000..80e5226cc63908762d5b14976b63a689f48f599a
--- /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 0000000000000000000000000000000000000000..8987e29ed70ceae6bb6ed64f76a91197b2c8d9c5
--- /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 0000000000000000000000000000000000000000..4cd668b54a38540979836cab71a0b895646d9e97
--- /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 0000000000000000000000000000000000000000..d6eb3290fec8b9349a3f2ac015e40b77f4dd1b9f
--- /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 0000000000000000000000000000000000000000..add542fb552cb7f06a6f30171cdbd42b76e9851d
--- /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 0000000000000000000000000000000000000000..e5b25f20fab004819295b3e6da6c98db8c747bf4
--- /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 0000000000000000000000000000000000000000..51da6ebfcd23f5582f7d50f6ab904191a512aaad
--- /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 0000000000000000000000000000000000000000..5e9c2379d054692e590c9cf6ab9b950cd6b7fd9d
--- /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 0000000000000000000000000000000000000000..be3a82f96dfd823809867acac65283ccbae22411
--- /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 0000000000000000000000000000000000000000..533ca7ff2a55ae4268d26592b4500b8a3883173d
--- /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 0000000000000000000000000000000000000000..f858704868167981e0b4c13c4dfc8654b32d1ce6
--- /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 0000000000000000000000000000000000000000..7e3aa4b1d6718f28437954dedef602c8344d5f70
--- /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 0000000000000000000000000000000000000000..e66b159376b528de08fd034981234e8c7e575c67
--- /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 0000000000000000000000000000000000000000..711ba5c95a6235031e1e2c98b65f931d8e722359
--- /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 0000000000000000000000000000000000000000..c3935763355daa28c00a993429f3c3d5b0fac8ee
--- /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 0000000000000000000000000000000000000000..8aa3ca2141d84830bf78a4b6f74c8df037c5d8fd
--- /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 0000000000000000000000000000000000000000..5f2b010e09ae7a1703088b5cf9244eacccbb06ad
--- /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 0000000000000000000000000000000000000000..b9276c32a6edd276cf9f93d4c0934ae83a812bac
--- /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 0000000000000000000000000000000000000000..267f8a38432cbf41efe89771cf98b598f6cbea3b
--- /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 0000000000000000000000000000000000000000..219fb5c20a81bfd63f159e1ba547d9e88878f9fe
--- /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 0000000000000000000000000000000000000000..cf952b4c4cf8b94ad0fac59dcc4285b96b0f8d65
--- /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 0000000000000000000000000000000000000000..6494e01c9392be16fdec3fb1907bfe919b3377bc
--- /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 0000000000000000000000000000000000000000..c9cb09218ba078f70a06615f0b4ad5debcc4ee04
--- /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 0000000000000000000000000000000000000000..1fbcde6b985aa1ccfc1e70a63f3e6f634d263cb1
--- /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 0000000000000000000000000000000000000000..ee34771c554472001d5cdeefef435c5e934bbefd
--- /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 0000000000000000000000000000000000000000..baecfe157d58cfb65fe3916dbd5a8c240f1cc8e4
--- /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 0000000000000000000000000000000000000000..8373f000ed46ad0dc31cfe589be729fe45802b76
--- /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 0000000000000000000000000000000000000000..a27719e5e383a8f15e5b04ad79ecf8353d466c52
--- /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 0000000000000000000000000000000000000000..dfa9909311740c3be0505c5011e3ecbc0fca908f
--- /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 0000000000000000000000000000000000000000..289a525fb218322de06da783aa9715adf87eb7a4
--- /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 0000000000000000000000000000000000000000..677f6ede190c96c8bf0141134de61da5236a8aee
--- /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 0000000000000000000000000000000000000000..c6cadc3f97c78ee679c1414356bfabd9965f7e1c
--- /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 0000000000000000000000000000000000000000..c6aee270ee8c940531637a04385d66729f216eed
--- /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 0000000000000000000000000000000000000000..fcf4a3663febfe016c2b0185c665008e29f1482f
--- /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 0000000000000000000000000000000000000000..6aed56ba43a9daca747b24c867bcea362c28aea4
--- /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 0000000000000000000000000000000000000000..7482578645461d69068c23650005c6ecdc15e8d3
--- /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 0000000000000000000000000000000000000000..400b57d973839b59cf2456e19f278500a3fe5413
--- /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 0000000000000000000000000000000000000000..5417304692b01f637acd126021ad92e00ecf4304
--- /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 0000000000000000000000000000000000000000..1235141401ca4adbe631b034d5184b7389806b77
--- /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 0000000000000000000000000000000000000000..49f27f890569bfed54a0a061770925f426c3dc3d
--- /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 0000000000000000000000000000000000000000..edb6b7825e140641303c4bfc151f0f35e525786b
--- /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 0000000000000000000000000000000000000000..8b6a20cead629dc8004e69c601b6a9903729476e
--- /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 0000000000000000000000000000000000000000..542abb971cc8227d157d5ed33f32e71e3eedf948
--- /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 0000000000000000000000000000000000000000..3d19eb88887248cfd270e8cbf19e50a608603da2
--- /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 0000000000000000000000000000000000000000..41aa2be377a6f473466f317a049c2c6c04975819
--- /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 0000000000000000000000000000000000000000..c0c1232b31b97388d69066cbd785a5cae3c9fe8d
--- /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 0000000000000000000000000000000000000000..999d453d3aa2477bd3e5a535fb372510a81b9966
--- /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 0000000000000000000000000000000000000000..becf4179657a3a62b3e24c5729c912bfe951baff
--- /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 0000000000000000000000000000000000000000..3feb3db7a8022c12f2c33ecd6ca7985dadfcc3cd
--- /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 0000000000000000000000000000000000000000..6cb7edc68236751540ee37acf265e98ee3fc9e1e
--- /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 0000000000000000000000000000000000000000..ce2278c3d87733710dc03585fb5f8c262bde33c0
--- /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 0000000000000000000000000000000000000000..21648ddd88f5ec981d88563e89a6dda3b97a2579
--- /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 0000000000000000000000000000000000000000..60614bfe3633ce72d87e2783a13871b3a9465c5b
--- /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 0000000000000000000000000000000000000000..0f6d36b9b43dbeb3ba0dcc6f11d70546440c83b0
--- /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 0000000000000000000000000000000000000000..a80a8d79b9c9b7af43696a574c10e7ae99ea8ca7
--- /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 0000000000000000000000000000000000000000..59751425c5548ad93dccb970a26fe9eaabfc0b6e
--- /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 0000000000000000000000000000000000000000..6d394c5088f4c8687a9bf1761f912b4e4463d2bd
--- /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 0000000000000000000000000000000000000000..44a327f059d1273ff0a66273de3c94a9c0ae1d17
--- /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 0000000000000000000000000000000000000000..c31230ddf620fbe97d0c765d5c2cf780d0b085a7
--- /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 0000000000000000000000000000000000000000..d84dcfb8110e67a54c91d49282d695abef6f6678
--- /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 0000000000000000000000000000000000000000..bde8831f892eb0515b98f9560b7f88a179a5984f
--- /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 0000000000000000000000000000000000000000..b789f43603b7d7dbd1266e4bd85007976a02fb44
--- /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 0000000000000000000000000000000000000000..2a67a8f4786939fc35da8e716e5b3c1881607ab2
--- /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 0000000000000000000000000000000000000000..ac07dd2a0ec7343df2b9a5e8f2cdcb602eeaed88
--- /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