## Copyright (C) 2009 Carlo de Falco <carlo DOT defalco AT gmail DOT com>
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; If not, see <http://www.gnu.org/licenses/>.

## -*- texinfo -*-
## @deftypefn {Function File} {@var{data} =} osc_transient_init (@var{data})  
## Prepare the time-stepping kernel to run a transient simulation.
##
## @end deftypefn

## Author: Carlo de Falco <carlo DOT defalco AT gmail DOT com>

function data = osc_transient_init(data)

  switch data.tst
         
    case "daspk"
      
      Nx = data.Nx;
      ## FIXME: initial data could be set in a more clever way..
      data.a0 = data.b0 = data.c0 = zeros(Nx,1);
      
      ## FIXME: apparently daspk chokes on
      ## negative potential???
      data.d0 = data.V * (data.x - data.x(1)) / data.L / data.sc(4);
      data.d0 -= min(data.d0); 
      data.x0 = [data.a0; data.b0; data.c0; data.d0(2:end-1)];
      data.xdot0 = 0*data.x0;

      ## FIXME: user should be able to override default settings
      daspk_options("compute consistent initial condition", 1);

      alg_vars= [zeros(data.Nx,1); 
		 zeros(data.Nx,1); 
		 zeros(data.Nx,1); 
		 ones(data.Nx-2,1)];
      
      daspk_options("algebraic variables", alg_vars);
      daspk_options("maximum order", 3);
      daspk_options("maximum step size", max (diff (linspace(data.tslot(1), data.tslot(2), data.Nt).')));
      daspk_options("enforce inequality constraints",3);
      daspk_options("inequality constraint types", 1-alg_vars);
      daspk_options("exclude algebraic variables from error test", 0);
      daspk_options("compute consistent initial condition", 1);
      daspk_options("relative tolerance", 1e-6);
      daspk_options("absolute tolerance", 1e-6);
      fun{1} = @(y, ydot, t) ...
	  __osc_residual_tpl__ ( data, y, ydot, t );

      fun{2} = @(y, ydot, t, c) ...
	  __osc_jacobian_tpl__ (data, y, ydot, t ) + ...
	  c * __osc_mass_tpl__ (data);

      data.t   = linspace(data.tslot(1), data.tslot(2), data.Nt).';

      data.fun = fun;
      
    case "ode15i"

      Nx = data.Nx;
      ## FIXME: initial data could be set in a more clever way..
      data.a0 = data.b0 = data.c0 = zeros(Nx,1);
      ## FIXME: apparently daspk chokes on
      ## negative potential???
      data.d0 = data.V * (data.x - data.x(1)) / data.L / data.sc(4);
      data.d0 -= min(data.d0); 
      data.x0 = [data.a0; data.b0; data.c0; data.d0(2:end-1)];
      data.xdot0 = 0*data.x0;
      data.t   = linspace(data.tslot(1), data.tslot(2), data.Nt).';
      data.odeopt = odeset ('abstol', 1e-5, 'reltol', 1e-5,
                            'InitialStep', data.t(2) - data.t(1),
                            'MaxStep', max (diff (data.t)));
      
      fun = @(t, y, ydot) ...
	     __osc_residual_tpl__ ( data, y, ydot, t );

      jac = @(t, y, ydot) ...
	     jacode15i (t, y, ydot, data);

      data.t   = linspace(data.tslot(1), data.tslot(2), data.Nt).';

      data.fun = fun;
      data.odeopt = odeset (data.odeopt, "Jacobian", jac);
    otherwise
      error("unsupported solver")
  endswitch

endfunction

function [dfdx, dfdxdot] = jacode15i (t, y, ydot, data)
  dfdx =  __osc_jacobian_tpl__ (data, y, ydot, t );
  if nargout > 1
    dfdxdot = __osc_mass_tpl__ (data);
  endif
endfunction
