<?xml version="1.0" encoding="UTF-8"?>
<!--
* Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
* Copyright (C) 2022 - UTC - Stéphane MOTTELET
*
* This file is hereby licensed under the terms of the GNU GPL v3.0,
* For more information, see the COPYING file which you should have received
* along with this program.
*
-->
<refentry xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svg="http://www.w3.org/2000/svg" xmlns:ns5="http://www.w3.org/1999/xhtml" xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:db="http://docbook.org/ns/docbook" xmlns:scilab="http://www.scilab.org" xml:id="idas" xml:lang="en" xmlns:m="http://www.w3.org/1998/Math/MathML">
    <refnamediv>
        <refname>Sensitivity (DAE)</refname>
        <refpurpose>Forward Sensitivity computation with ida</refpurpose>
    </refnamediv>
    <refsynopsisdiv>
        <title>Syntax</title>
        <synopsis>
            [t,y,info] = ida(res, tspan, y0, yp0, sensPar = pvalue, options)
            sol = ida( ... , sensPar = pvalue, options)
        </synopsis>
    </refsynopsisdiv>
    <refsection role="parameters">
        <title>Arguments</title>
        <informaltable border='0'>
          <tbody>
            <tr>
              <td><term>pvalue</term></td>
              <td>    
                  <para>a real double array: the value of parameters with respect to which sensitivity is computed</para>
                </td>
            </tr>
            <tr>
                <td><term>options</term></td>
                <td>
                    <para>a sequence of optional named arguments (see the <link linkend="sundials_options">solvers options</link>) and below for sensitivity
                    specific options.</para>
                </td>
            </tr>
            <tr>
                <td><term>t</term></td>
                <td>
                    <para>vector of time points used by the solver.</para>
                </td>
            </tr>
            <tr>
                <td><term>y</term></td>
                <td>
                    <para>array of solution at time values in <term>t</term></para>
                </td>
            </tr>
            <tr>
                <td><term>info</term></td>
                <td>
                    <para>MList of <literal>_odeSolution</literal> type with solver information, 
                    user events information (if applicable), statistics and sensitivity of the solution at solver time points.</para>
                </td>
            </tr>
            <tr>
                <td><term>sol</term></td>
                <td>
                    <para>MList of <literal>_odeSolution</literal> type</para>
                </td>
            </tr>
        </tbody>
    </informaltable>
    </refsection>

    <refsection role="description">
        <title>Description</title>

        <para>While integrating a DAE where residual F(t,y,y',p) depends on a vector p of parameters, ida can compute simultaneously the
            solution vectors y, y' at given time points and also <latex style="inline">S={\partial y}/{\partial p</latex>, <latex style="inline">S'={\partial y'}/{\partial p</latex> the derivatives of y and y' with 
            respect to p, i.e. the sensitivity matrix and its time derivative. 
            This amounts to augment the original DAE with the sensitivity residual, which is obtained by formal derivation of the original DAE residual
            with respect to p:
            </para>
            <para>
                <latex style="display">
                    \begin{array}{rcl}0 &amp; = &amp; F(t,y,y',p),\\
                    0 &amp; = &amp; \frac{\partial F}{\partial y}S + \frac{\partial F}{\partial y'}S'+ \frac{\partial F}{\partial p},\\
                    y(t_0) &amp; = &amp;y_0(p),\\
                    y'(t_0) &amp; = &amp;yp_0(p),\\
                    S(t_0) &amp; = &amp; \frac{\partial y_0(p)}{\partial p},\\
                    S'(t_0) &amp; = &amp; \frac{\partial yp_0(p)}{\partial p},
                    \end{array}
                </latex>
            </para>
            <para>
                The sensitivity matrix is typically used when solving identification parameter problems, for example nonlinear regression, and it can serve both
                aspects of the problem solution, i.e. qualitative and quantitative: studying the sensitivity on the time span can help to state identifiability 
                of the parameters whereas computing the sensitivity at precise time points of measurements allows to compute the gradient of the squared norm of
                the observation residual. 
            </para>
            <para>
                When the residual of the DAE is
                explicitely known then the exact sensitivity equation residual can be provided (see the <code>sensRes</code> below), but ida can also
                approximate it by approximating directional derivatives by finite difference quotients. However, better precision is always obtained with 
                exact derivatives. In the example below we compute the sensitivity equation residual by the complex step method, which is exact up to
                machine precision.
            </para>
            <para>
                The sensitivity computation is triggered by using the <code>sensPar</code> option:
            </para>
            <para>
                <programlisting role="no-scilab-exec">
                    <![CDATA[[t,y,info] = ida(res, tspan, y0, yp0, sensPar = pvalue)
                    sol = ida(res, tspan, y0, yp0, sensPar = pvalue]]>
                </programlisting>
            </para>
            <para>
                where the sensitivity of the solution and its derivative are retrieved in the "s" and "sp" fields of either the <term>info</term> or <term>sol</term> output argument. 
                When the residual of the DAE is yielded by a Scilab function, the prototype of <literal>res</literal> must include a formal
                input argument after the usual (t,y,yp) triplet (denoted p below), which will contain the parameter values. Additionnal user parameters
                must be given as explained in the <link linkend="sundials_user_functions">User functions</link> help page :
            </para> 
            <para>
                <programlisting role="no-scilab-exec"><![CDATA[dydt = res(t, y, yp, p, ...)]]></programlisting>
            </para>
            <para>
                When the residual of the DAE is yielded by a DLL entry point, as only one array of double values can be passed,
                complimentary user parameters must be passed together with sensitivity parameters in the same vector. The actual sensitivity
                parameters can be precised by using the <code>sensParIndex</code> (see below).
            </para>
            <para>
               The sensitivity related output arguments <term>s,sp</term> and <term>se</term> (when events occur) can be recovered in 
                the solution output as complimentary fields.  Note that the yielded <term>info.s,info.sp</term> arrays have dimensions (length(y0), length(p), length(t)) but singleton dimension is squeezed when
                p is a scalar. 
            </para>
    </refsection>

    <refsection role="example">
        <title>Example</title>
        <para>Here we compute the sensitivity of the solution of the SIR epidemiologic system (written as a DAE) with respect to parameter β and γ. Option <code>yS0</code> and <code>ypS0</code> allow to give
        the initial values of the sensitivity and of its derivative. When <code>y0</code> does not depend on the parameters then <code>yS0</code> is the null matrix and does not need to be given,
        but <code>ypS0</code> has always to be given. In the code below this value is computed together with <code>yp0</code> thanks to the <code>calcIC</code> option, once the algebraic state <code>y_3</code> has been
        indicated by using the <code>yIsAlgebric</code> option.
        </para>
        <para>
            <programlisting><![CDATA[
                function dydt = rsir(t,y,yp,p)
                    β = p(1);
                    γ = p(2);
                    dydt = [-β*y(1)*y(2)-yp(1)
                             β*y(1)*y(2)-γ*y(2)-yp(2)  
                             y(1)+y(2)+y(3)-1];
                end
                y20 = 1e-6;
                β = 0.2;
                γ = 0.05;
                p = [β;γ];
                y0 = [1-y20; y20; 0];
                yp0 = zeros(y0);

                function sensres=rS_complex(t,y,yp,yS,ypS,p)
                    np = length(p);
                    sensres = zeros(length(y),np);
                    d = 1e-200;
                    id = %i*d;
                    E = eye(np,np)
                    for i=1:length(p)
                        sensres(:,i) = imag(rsir(t,y+id*yS(:,i),yp+id*ypS(:,i),p+id*E(:,i)))/d;
                    end
                endfunction

                [t,y,info] = ida(rsir, [0 200], y0, yp0, ...
                    sensPar = [β;γ], ...
                    sensRes = rS_complex, ...
                    yIsAlgebraic=3,...
                    calcIc="y0yp0")
    
                clf
                plot(t',squeeze(info.s(:,2,:))')
                legend("$\Large\partial "+["y_1","y_2","y_3"]+"/\partial\gamma"+"$")                ]]>
            </programlisting>
            <scilab:image>
                function dydt = rsir(t,y,yp,p)
                    β = p(1);
                    γ = p(2);
                    dydt = [-β*y(1)*y(2)-yp(1)
                             β*y(1)*y(2)-γ*y(2)-yp(2)  
                             y(1)+y(2)+y(3)-1];
                end
                y20 = 1e-6;
                β = 0.2;
                γ = 0.05;
                p = [β;γ];
                y0 = [1-y20; y20; 0];
                yp0 = [-β*y0(1)*y0(2); β*y0(1)*y0(2)-γ*y0(2); γ*y0(2)];

                function sensres=rS_complex(t,y,yp,yS,ypS,p)
                    np = length(p);
                    sensres = zeros(length(y),np);
                    d = 1e-200;
                    id = %i*d;
                    E = eye(np,np)
                    for i=1:length(p)
                        sensres(:,i) = imag(rsir(t,y+id*yS(:,i),yp+id*ypS(:,i),p+id*E(:,i)))/d;
                    end
                endfunction

                [t,y,info] = ida(rsir, [0 200], y0, yp0, ...
                    sensPar = [β;γ], ...
                    sensRes = rS_complex, ...
                    yIsAlgebraic=3,...
                    calcIc="y0yp0")
    
                clf
                plot(t',squeeze(info.s(:,2,:))')
                legend("$\Large\partial "+["y_1","y_2","y_3"]+"/\partial\gamma"+"$") 
            </scilab:image>
        </para>
    </refsection>
    
    <refsection role="example">
        <title>Options</title>
        <para>
            <informaltable border='1'>
                <tbody>
                    <tr>
                        <td>sensPar</td>
                        <td>    
                            <para>a double array with the values of parameters w.r.t. which sensitivity is to be computed.</para>
                        </td>
                    </tr>
                    <tr>
                        <td>sensParIndex</td>
                        <td>    
                            <para>an array of integers between 1 and <code>length(sensPar)</code>. It allows to define a subset
                            of the parameter components w.r.t. which sensitivity is to be computed.
                           </para>
                        </td>
                    </tr>
                    <tr>
                        <td>yS0,ypS0</td>
                        <td>    
                            <para>The initial condition of the sensitivity function and of its derivtive, i.e. <latex>\partial y0(p)/\partial p</latex>.
                            If sensParIndex options is used then the number of colums of yS0 must be compatible, i.e.
                            <code>size(yS0,2) == length(sensParIndex)</code>. The default value of <code>yS0</code> is a null matrix (the initial condition
                            does not depend on the parameters).</para>
                        </td>
                    </tr>
                    <tr>
                        <td>sensRes</td>
                        <td>    
                            <para>
                            a function, a string or a list, the residual of the sensitivity equation. When the right hand side of the DAE is known explicitely and 
                            computation of its derivative is tractable (e.g. by symbolic differentiation or by any automatic procedure, including complex step), giving the
                            true residual improves the precision and the computation time. When sensRes is a Scilab function, its prototype must be
                        </para>
                        <para>
                            <programlisting role="no-scilab-exec"><![CDATA[dsdt = sensRes(t, y, yp, s, sp, p, ...)]]></programlisting>
                        </para>
                        </td>
                    </tr>
                    <tr>
                        <td>sensErrCon</td>
                        <td>    
                            <para>By default, sensErrCon is set to %f. If sensErrCon=%t then both state variables and sensitivity variables are included in the error tests.</para>
                        </td>
                    </tr>
                    <tr>
                        <td>sensCorrStep</td>
                        <td>    
                            <para>"simultaneous" (the default) or "staggered": when sensCorrStep="simultaneous", the state and sensitivity variables are corrected at the same time. 
                                If sensCorrStep="staggered", the correction step for the sensitivity variables takes place at the same time for all sensitivity equations, but only
                                after the correction of the state variables has converged and the state variables have passed the local error test.</para>
                        </td>
                    </tr>
                    <tr>
                        <td>typicalPar</td>
                        <td>    
                            <para>This option serves as positive scaling factors when the right-hand side of the sensitivity is computed by cvode using internal finite difference-quotients.
                                 The results will be more accurate if an order of magnitude information is provided. Typically, if no component vanishes, the value of sensPar can be used.</para>
                        </td>
                    </tr>
                </tbody>
            </informaltable>
        </para>
    </refsection>
    
    <refsection role="see also">
        <title>See also</title>
        <simplelist type="inline">
            <member>
                <link linkend="arkode">arkode</link>
            </member>
            <member>
                <link linkend="cvode">cvode</link>
            </member>
            <member>
                <link linkend="ida">ida</link>
            </member>
            <member>
                <link linkend="cvodes">ODE Sensitivity</link>
            </member>
            <member>
                <link linkend="sundials_user_functions">User functions</link>
            </member>
            <member>
                <link linkend="sundials_options">Options (ODE and DAE solvers)</link>
            </member>
            <member>
                <link linkend="SUN_Clink">SUN_Clink</link>
            </member>
        </simplelist>
    </refsection>

</refentry>
