Mercurial > forge
changeset 3076:f36ed3946829 octave-forge
Updated and added two new interface functions for the solvers odex and radau.
author | treichl |
---|---|
date | Tue, 06 Feb 2007 20:14:25 +0000 |
parents | ef325faad634 |
children | 25501bc901f1 |
files | main/odepkg/src/odepkg_mexsolver_odex.c main/odepkg/src/odepkg_mexsolver_radau.c |
diffstat | 2 files changed, 1704 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/odepkg/src/odepkg_mexsolver_odex.c Tue Feb 06 20:14:25 2007 +0000 @@ -0,0 +1,805 @@ +/* +Copyright (C) 2007, Thomas Treichl <treichl@users.sourceforge.net> +OdePkg - Package for solving ordinary differential equations with octave + +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 2 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, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* To manually compile this file with debug messages + + mkoctfile --mex -Wall -W -Wshadow -D__ODEPKGDEBUG__ \ + odepkg_mexsolver_odex.c odepkgmex.c odepkgext.c hairer/odex.f + + or + + mex -v -D__ODEPKGDEBUG__ odepkg_mexsolver_odex.c odepkgext.c \ + odepkgmex.c hairer/odex.f + + a function check can be done via + + octave --quiet --eval "A = odeset (\"RelTol\", 1e-3, \"AbsTol\", 1e-4, \ + \"OutputFcn\", @odeprint, \"OutputSel\", [2, 1], \"Refine\", 3); \ + [C, B] = odepkg_mexsolver_odex (@odepkg_equations_vanderpol, \ + [0, 1], [2, 0], A, 12)" +*/ + +#include <config.h> /* Needed for the F77_FUNC definition etc. */ +#include <mex.h> /* Needed for all mex definitions */ +#include <f77-fcn.h> /* Needed for the use of Fortran routines */ +#include <stdio.h> /* Needed for the sprintf function etc.*/ +#include <string.h> /* Needed for the memcpy function etc.*/ +#include "odepkgmex.h" /* Needed for the mex extensions */ +#include "odepkgext.h" /* Needed for the odepkg interfaces */ + +/* These are the prototype definitions for the solver function, the + interpolation function that is used to achieve better results, the + Jacobian calculation function (if any), the mass calculation + function and the output function. These functions are very similar + to the functions from other solvers, therefore there is nor + explicit documentation for them in the manual. */ + +extern void F77_FUNC (odex, ODEX) (int *N, void *FCN, double *X, double *Y, + double *XEND, double *H, double *RTOL, double *ATOL, int *ITOL, void *SOL, int *IOUT, + double *WORK, int *LWORK, int *IWORK, int *LIWORK, double *RPAR, int *IPAR, + int *VRET); + +extern double F77_FUNC (contex, CONTEX) (int *I, double *S, double *CON, + int *NCON, int *ICOMP, int *ND); + +void F77_FUNC (ffcn, FFCN) (int *N, double *X, double *Y, double *F, + GCC_ATTR_UNUSED double *RPAR, GCC_ATTR_UNUSED int *IPAR) { + int vcnt = 0; + int vnum = 0; + char vmsg[64] = ""; + + mxArray *vtmp = NULL; + mxArray **vlhs = NULL; + mxArray **vrhs = NULL; + + /* Get number of varargin elements for allocating memory */ + fodepkgvar (2, "varargin", &vtmp); + vnum = mxGetNumberOfElements (vtmp); + + /* Allocate memory and set up variables lhs-arguments and rhs-arguments */ + vlhs = (mxArray **) mxMalloc (sizeof (mxArray *)); + vrhs = (mxArray **) mxMalloc ((2 + vnum) * sizeof (mxArray *)); + vrhs[0] = mxCreateDoubleScalar (*X); + + /* Copy the values that are given from the solver into the mxArray */ + vrhs[1] = mxCreateDoubleMatrix (*N, 1, mxREAL); + memcpy ((void *) mxGetPr (vrhs[1]), (void *) Y, *N * sizeof (double)); + + if (vnum > 0) /* Fill up vrhs[2..] */ + for (vcnt = 0; vcnt < vnum; vcnt++) + vrhs[vcnt+2] = mxGetCell (vtmp, vcnt); + + /* Evaluate the ode function in the octave workspace */ + fodepkgvar (2, "OdeFunction", &vtmp); + if (mexCallMATLAB (1, vlhs, vnum+2, vrhs, mxArrayToString (vtmp))) { + sprintf (vmsg, "Calling \"%s\" has failed", mxArrayToString (vtmp)); + mexErrMsgTxt (vmsg); + } + + /* Save the result of this time step in the variable f */ + memcpy ((void *) F, (void *) mxGetPr (vlhs[0]), *N * sizeof (double)); + mxFree (vlhs); /* Free the vlhs mxArray */ + mxFree (vrhs); /* Free the vrhs mxArray */ +} + +void F77_FUNC (fsol, FSOL) (int *NR, double *XOLD, double *X, double *Y, int *N, + double *CON, int *NCON, int *ICOMP, int *ND, GCC_ATTR_UNUSED double *RPAR, + GCC_ATTR_UNUSED int *IPAR, int *IRTRN) { + + bool vsuc = false; + double vdbt = 0.0; + unsigned int vref = 0; + unsigned int vcnt = 0; + int vnum = 0; + + double *vdob = NULL; + double *vdbl = NULL; + mxArray *vtmp = NULL; + mxArray *vtem = NULL; + mxArray *vtim = NULL; + mxArray *vrtm = NULL; + mxArray *vrvl = NULL; + + /* Convert the double *y into a selection of variables */ + fy2mxArray (*N, Y, &vtem); + vtim = mxCreateDoubleScalar (*X); + + /* Save the solution if this is not the initial first call */ + if (*NR > 1) fsolstore (1, &vtim, &vtem); + + /* Call output function if this is not the initial first call */ + fodepkgvar (2, "PlotFunction", &vtmp); + if (!mxIsEmpty (vtmp) && *NR > 1) { + fodepkgvar (2, "Refine", &vtmp); /* Check for "Refine" option */ + vdbl = mxGetPr (vtmp); + vref = (int)vdbl[0]; + + if (vref > 0) { /* If the Refine option is > 0 */ + vdob = (double *) mxMalloc (*N * sizeof (double)); + + for (vcnt = 0; vcnt < vref; vcnt++) { + vdbt = *XOLD + (double)(vcnt + 1) * ((*X - *XOLD) / (vref + 2)); + vrtm = mxCreateDoubleScalar (vdbt); + /* Time stamps for approximation: mexPrintf ("%f %f %f\n", *XOLD, vdbt, x); */ + + for (vnum = 1; vnum <= *N; vnum++) + vdob[vnum-1] = F77_FUNC (contex, CONTEX) (&vnum, &vdbt, CON, NCON, ICOMP, ND); + + fy2mxArray (*N, vdob, &vrvl); + /* Time stamps and approx. values: mexPrintf ("%f %f %f\n", vdbt, vdob[0], vdob[1]); */ + fodepkgplot (vrtm, vrvl, mxCreateString ("")); + } + mxFree (vdob); + } + vsuc = fodepkgplot (vtim, vtem, mxCreateString ("")); + if (vsuc == false) { + mexPrintf ("Integration has been stopped from output function at time t=%f\n", *X); + IRTRN[0] = - 1; /* Stop integration ? */ + } + } + + fodepkgvar (2, "EventFunction", &vtmp); + if (!mxIsEmpty (vtmp)) { + fodepkgevent (vtim, vtem, mxCreateString (""), &vtmp); + fodepkgvar (3, "EventSolution", NULL); /* Remove the last events results */ + fodepkgvar (1, "EventSolution", &vtmp); /* Set the new events results */ + + vtem = mxGetCell (vtmp, 0); /* Check if we have to stop solving */ + if (mxIsLogicalScalarTrue (vtem)) { + fsolstore (3, NULL, NULL); /* Remove the last solution entry */ + vtem = mxGetCell (vtmp, 3); /* Get last row of events solution */ + vtim = mxCreateDoubleScalar (*X); + vtmp = mxGetMatrixRow (vtem, mxGetM (vtem) - 1); + fsolstore (1, &vtim, &vtmp); /* Set last row of events solution */ + mexPrintf ("Integration has been stopped from event function at time t=%f\n", *X); + IRTRN[0] = -1; /* Tell the solver to stop solving */ + } + } +} + +void mexFunction (int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { + int vcnt = 0; + int vnum = 0; + double *vdbl = NULL; + char vmsg[64] = ""; + mxArray *vtmp = NULL; + mxArray *vtem = NULL; + + /* Variables that are needed to call the solver function */ + int N = 0; /* Dimension of differential equations */ + int ITOL = 0; /* Type of error tolerance handling */ + int LWORK = 0; /* Size of work vector will be set later */ + int LIWORK = 0; /* Size of iwork vector will be set later */ + int *IWORK = NULL; /* Memory of iwork vector will be allocated later */ + int IPAR = 0; /* Integer parameters will be unused */ + int VRET = 0; /* Return value of the solver function */ + double *SLOT = NULL; /* Time slot values tstart and tend */ + double *INIT = NULL; /* Initial values for differential equations */ + double *RTOL = NULL; /* Relative tolerances scalar or vector */ + double *ATOL = NULL; /* Absolute tolerances scalar or vector */ + double *WORK = NULL; /* Memory of work vector will be allocated later */ + double H = 0.0; /* Initial step size guess, odex will set this */ + double RPAR = 0; /* Real parameters will be unused */ + +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: ----- STARTING SOLVER INITIALISATION PROCEDURE\n"); +#endif + fodepkgvar (0, NULL, NULL); + + if (nrhs == 0) { /* Check number and types of all input arguments */ + vtmp = mxCreateString ("ode5d"); + if (mexCallMATLAB (0, NULL, 1, &vtmp, "help")) + mexErrMsgTxt ("Calling \"help\" has failed"); + mexErrMsgTxt ("Number of input arguments must be greater than zero"); + } + else if (nrhs < 3) { /* Check if number of input arguments >= 3 */ + mexUsgMsgTxt ("[t, y] = odepkg_mexsolver_odex (fun, slot, init, varargin)"); + } + else if (mxGetClassID (prhs[0]) != mxFUNCTION_CLASS) { + mexErrMsgTxt ("First input argument must be valid function handle"); + } + else if (!mxIsVector (prhs[1]) && (mxGetNumberOfElements (prhs[1]) < 2)) { /* vslot */ + mexErrMsgTxt ("Second input argument must be a valid vector"); + } + else if (!mxIsVector (prhs[2]) || !mxIsNumeric (prhs[2])) { /* vinit */ + mexErrMsgTxt ("Third input argument must be a valid vector"); + } + else if (nrhs >= 4) { + + if (!mxIsStruct (prhs[3])) { /* No option structure has been set in prhs[3] */ + vnum = nrhs - 3; vtmp = mxCreateCellArray (1, &vnum); + for (vcnt = 3; vcnt < nrhs; vcnt++) + mxSetCell (vtmp, vcnt-3, mxDuplicateArray (prhs[vcnt])); + fodepkgvar (1, "varargin", &vtmp); + if (mexCallMATLAB (1, &vtmp, 0, NULL, "odeset")) + mexErrMsgTxt ("Calling \"odeset\" has failed"); + fodepkgvar (1, "OdeOptions", &vtmp); + } + + else if (nrhs > 4) { /* An option structure and further arguments have been set */ + vnum = nrhs - 4; vtmp = mxCreateCellArray (1, &vnum); + for (vcnt = 4; vcnt < nrhs; vcnt++) + mxSetCell (vtmp, vcnt-4, mxDuplicateArray (prhs[vcnt])); + fodepkgvar (1, "varargin", &vtmp); + vtem = mxDuplicateArray (prhs[3]); + if (mexCallMATLAB (1, &vtmp, 1, &vtem, "odepkg_structure_check")) + mexErrMsgTxt ("Calling \"odepkg_structure_check\" has failed"); + fodepkgvar (1, "OdeOptions", &vtmp); + } + + else { /* Only an option-structure and no further arguments have been set */ + vnum = 0; vtmp = mxCreateCellArray (1, &vnum); + fodepkgvar (1, "varargin", &vtmp); + vtem = mxDuplicateArray (prhs[3]); + if (mexCallMATLAB (1, &vtmp, 1, &vtem, "odepkg_structure_check")) + mexErrMsgTxt ("Calling \"odepkg_structure_check\" has failed"); + fodepkgvar (1, "OdeOptions", &vtmp); + } + + } /* No valid function call has been found before - set the defaults */ + else { + vnum = 0; vtmp = mxCreateCellArray (1, &vnum); + fodepkgvar (1, "varargin", &vtmp); + if (mexCallMATLAB (1, &vtmp, 0, NULL, "odeset")) + mexErrMsgTxt ("Calling \"odeset\" has failed"); + fodepkgvar (1, "OdeOptions", &vtmp); + } + + /* Get the default options (Calling 'odeset' without arguments) */ + if (mexCallMATLAB (1, &vtmp, 0, NULL, "odeset")) + mexErrMsgTxt ("Calling \"odeset\" has failed"); + fodepkgvar (1, "DefaultOptions", &vtmp); + + /* Handle the prhs[0] element: The ode function that has to be solved */ + vtem = mxDuplicateArray (prhs[0]); + if (mexCallMATLAB (1, &vtmp, 1, &vtem, "func2str")) + mexErrMsgTxt ("Calling \"func2str\" has failed"); + fodepkgvar (1, "OdeFunction", &vtmp); + + /* Handle the prhs[1] element: Split the integration interval */ + if (mxGetM (prhs[1]) == 2 || mxGetN (prhs[1]) == 2) { + SLOT = mxMalloc (2 * sizeof (double)); + memcpy ((void *) SLOT, (void *) mxGetPr (prhs[1]), 2 * sizeof (double)); + } + else mexErrMsgTxt ("Second input argument of this solver must be of size 1x2 or 2x1"); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: Solving is done from tStart=%f to tStop=%f\n", + SLOT[0], SLOT[1]); +#endif + + /* Handle the prhs[2] element: Set the dimension and the initial values */ + if (mxIsRowVector (prhs[2])) N = (int) mxGetN (prhs[2]); + else N = (int) mxGetM (prhs[2]); + INIT = mxMalloc (N * sizeof (double)); + vtmp = mxCreateDoubleScalar (N); + fodepkgvar (1, "OdeDimension", &vtmp); + memcpy ((void *) INIT, (void *) mxGetPr (prhs[2]), N * sizeof (double)); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: Number of initial values is %d\n", N); + mexPrintf ("ODEPKGDEBUG: Last element of initial values is %f\n", INIT[N-1]); +#endif + + /* Initialize the WORK and LWORK vectors with zeros */ + LWORK = N*(9+5)+5*9+20+(2*9*(9+2)+5)*N; /* LWORK = N*(KM+5)+5*KM+20+(2*KM*(KM+2)+5)*NRDENS; */ + WORK = (double *) mxMalloc (LWORK * sizeof (double)); + for (vcnt = 0; vcnt < LWORK; vcnt++) WORK[vcnt] = 0.0; + LIWORK = 2*9+21+N; /* LIWORK = 2*KM+21+NRDENS; */ + IWORK = (int *) mxMalloc (LIWORK * sizeof (int)); + for (vcnt = 0; vcnt < LIWORK; vcnt++) IWORK[vcnt] = 0; + + /* Handle the OdeOptions structure field: RELTOL */ + fodepkgvar (2, "OdeOptions", &vtmp); + vtem = mxGetField (vtmp, 0, "RelTol"); + if (mxIsRowVector (vtem)) vcnt = (int) mxGetN (vtem); + else vcnt = (int) mxGetM (vtem); + RTOL = mxMalloc (vcnt * sizeof (double)); + memcpy ((void *) RTOL, (void *) mxGetPr (vtem), vcnt * sizeof (double)); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: Last element of relative error is %f\n", RTOL[vcnt-1]); +#endif + + /* Handle the OdeOptions structure field: ABSTOL */ + vtem = mxGetField (vtmp, 0, "AbsTol"); + if (mxIsRowVector (vtem)) vnum = (int) mxGetN (vtem); + else vnum = (int) mxGetM (vtem); + ATOL = mxMalloc (vnum * sizeof (double)); + memcpy ((void *) ATOL, (void *) mxGetPr (vtem), vnum * sizeof (double)); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: Last element of relative error is %f\n", ATOL[vnum-1]); +#endif + + /* Handle the OdeOptions structure field: RELTOL vs. ABSTOL vs. N */ + if (vcnt != vnum) + mexErrMsgTxt ("\"AbsTol\" and \"RelTol\" must have same size"); + else if (vcnt > 1) { + if (vcnt != N) + mexErrMsgTxt ("\"AbsTol\", \"RelTol\" and the dimension must have same size"); + ITOL = 1; + } + else ITOL = 0; +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: Type of dopri tolerance handling is %d\n", ITOL); +#endif + + /* Handle the OdeOptions structure field: NORMCONTROL */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (mxIsEqual (mxGetField (vtmp, 0, "NormControl"), mxCreateString ("on"))) IWORK[5] = 0; + else IWORK[5] = 1; + + /* Handle the OdeOptions structure field: OUTPUTFCN */ + fodepkgvar (2, "OdeOptions", &vtmp); + vtem = mxGetField (vtmp, 0, "OutputFcn"); + if (mxIsEmpty (vtem) && (nlhs == 0)) { + vtmp = mxCreateString ("odeplot"); + fodepkgvar (1, "PlotFunction", &vtmp); + } + else if (!mxIsEmpty (vtem)) { + if (mexCallMATLAB (1, &vtmp, 1, &vtem, "func2str")) + mexErrMsgTxt ("Calling \"func2str\" has failed"); + fodepkgvar (1, "PlotFunction", &vtmp); + } + else { + vtmp = mxCreateString (""); + fodepkgvar (1, "PlotFunction", &vtmp); + } +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: The output function was set to \"%s\"\n", + mxArrayToString (vtmp)); +#endif + + /* Handle the OdeOptions structure field: OUTPUTSEL */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + vtmp = mxGetField (vtmp, 0, "OutputSel"); + vtem = mxGetField (vtem, 0, "OutputSel"); + if (!mxIsEqual (vtmp, vtem)) { + vnum = (int) mxGetNumberOfElements (vtmp); + vdbl = mxGetPr (vtmp); + for (vcnt = 0; vcnt < vnum; vcnt++) + if ((int)(vdbl[vcnt]) > N) { + sprintf (vmsg, "Found invalid number element \"%d\" in option \"OuputSel\"", + (int)(vdbl[vcnt])); + mexErrMsgTxt (vmsg); + } + fodepkgvar (1, "OutputSelection", &vtmp); + } + else fodepkgvar (1, "OutputSelection", &vtmp); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: The outputsel option has successfully been set\n"); +#endif + + /* Handle the OdeOptions structure field: REFINE */ + fodepkgvar (2, "OdeOptions", &vtmp); + vtem = mxGetField (vtmp, 0, "Refine"); + fodepkgvar (1, "Refine", &vtem); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: The Refine option has been set\n"); +#endif + + /* Handle the OdeOptions structure field: STATS */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "Stats"), mxGetField (vtem, 0, "Stats"))) { + /* mexWarnMsgTxt ("Not yet implemented option \"Stats\" will be ignored"); */ + vtmp = mxCreateLogicalScalar (true); + fodepkgvar (1, "Stats", &vtmp); + } + else { + vtmp = mxCreateLogicalScalar (false); + fodepkgvar (1, "Stats", &vtmp); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: The Stats option has not been set\n"); +#endif + } + + /* Handle the OdeOptions structure field: INITIALSTEP */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "InitialStep"), mxGetField (vtem, 0, "InitialStep"))) + H = *mxGetPr (mxGetField (vtmp, 0, "InitialStep") ); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: The inital step size is %f\n", WORK[6]); +#endif + + /* Handle the OdeOptions structure field: MAXSTEP */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "MaxStep"), mxGetField (vtem, 0, "MaxStep"))) + WORK[1] = *mxGetPr (mxGetField (vtmp, 0, "MaxStep") ); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: The maximum step size is %f\n", WORK[5]); +#endif + + /* Handle the OdeOptions structure field: EVENTS */ + fodepkgvar (2, "OdeOptions", &vtmp); + vtem = mxGetField (vtmp, 0, "Events"); + fodepkgvar (1, "EventFunction", &vtem); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: The Events option has been set\n"); +#endif + + /* Handle the OdeOptions structure field: JACOBIAN */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "Jacobian"), mxGetField (vtem, 0, "Jacobian"))) + mexWarnMsgTxt ("Option \"Jacobian\" will be ignored by this solver"); +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: The Jacobian option has not been set\n"); +#endif + + /* Handle the OdeOptions structure field: JPATTERN */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "JPattern"), mxGetField (vtem, 0, "JPattern"))) + mexWarnMsgTxt ("Option \"JPattern\" will be ignored by this solver"); +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: The JPattern option has not been set\n"); +#endif + + /* Handle the OdeOptions structure field: VECTORIZED */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "Vectorized"), mxGetField (vtem, 0, "Vectorized"))) + mexWarnMsgTxt ("Option \"Vectorized\" will be ignored by this solver"); +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: The Vectorized option has not been set\n"); +#endif + + /* Handle the OdeOptions structure field: MASS */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "Mass"), mxGetField (vtem, 0, "Mass"))) + mexWarnMsgTxt ("Option \"Mass\" will be ignored by this solver"); +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: The Mass option has not been set\n"); +#endif + + /* Handle the OdeOptions structure field: MSTATEDEP */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "MStateDependence"), mxGetField (vtem, 0, "MStateDependence"))) + mexWarnMsgTxt ("Option \"MStateDependence\" will be ignored by this solver"); +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: The MStateDependence option has not been set\n"); +#endif + + /* Handle the OdeOptions structure field: MVPATTERN */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "MvPattern"), mxGetField (vtem, 0, "MvPattern"))) + mexWarnMsgTxt ("Option \"MvPattern\" will be ignored by this solver"); +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: The MvPattern option has not been set\n"); +#endif + + /* Handle the OdeOptions structure field: MASSSINGULAR */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "MassSingular"), mxGetField (vtem, 0, "MassSingular"))) + mexWarnMsgTxt ("Option \"MassSingular\" will be ignored by this solver"); +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: The MassSingular option has not been set\n"); +#endif + + /* Handle the OdeOptions structure field: INITIALSLOPE */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "InitialSlope"), mxGetField (vtem, 0, "InitialSlope"))) + mexWarnMsgTxt ("Option \"InitialSlope\" will be ignored by this solver"); +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: The InitialSlope option has not been set\n"); +#endif + + /* Handle the OdeOptions structure field: MAXORDER */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "MaxOrder"), mxGetField (vtem, 0, "MaxOrder"))) + mexWarnMsgTxt ("Option \"MaxOrder\" will be ignored by this solver"); +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: The MaxOrder option has not been set\n"); +#endif + + /* Handle the OdeOptions structure field: BDF */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "BDF"), mxGetField (vtem, 0, "BDF"))) + mexWarnMsgTxt ("Option \"BDF\" will be ignored by this solver"); +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: The BDF option has not been set\n"); +#endif + + /* Initialize the function: FODEPKGPLOT */ + fodepkgvar (2, "PlotFunction", &vtmp); + if (!mxIsEmpty (vtmp)) { + vtmp = mxDuplicateArray (prhs[1]); + fy2mxArray (N, INIT, &vtem); + if (!fodepkgplot (vtmp, vtem, mxCreateString ("init"))) { + fodepkgvar (2, "PlotFunction", &vtmp); + sprintf (vmsg, "Error at initialisation of output function \"%s\"", mxArrayToString (vtmp)); + mexErrMsgTxt (vmsg); + } +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: Initialisation of output function successfully completed\n"); +#endif + } + + /* Initialize the function: FODEPKGEVENT */ + fodepkgvar (2, "EventFunction", &vtmp); + if (!mxIsEmpty (vtmp)) { + vtmp = mxCreateDoubleScalar (SLOT[0]); + fy2mxArray (N, INIT, &vtem); + if (!fodepkgevent (vtmp, vtem, mxCreateString ("init"), NULL)) { + fodepkgvar (2, "EventFunction", &vtmp); + sprintf (vmsg, "Error at initialisation of event function \"%s\"", mxArrayToString (vtmp)); + mexErrMsgTxt (vmsg); + } +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: Initialisation of event function successfully completed\n"); +#endif + } + + /* Initialize the function: FSOLSTORE */ + vtmp = mxCreateDoubleScalar (SLOT[0]); + fy2mxArray (N, INIT, &vtem); + fsolstore (0, &vtmp, &vtem); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: Initialisation of fsolstore function successfully completed\n"); +#endif + +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: ----- STARTING SOLVER CALCULATION PROCEDURE\n"); +#endif + + /* IWORK[0] = 10^4; */ /* The maximal number of allowed steps */ + /* IWORK[1] = 0; */ /* Number of needed extrapolation columns */ + IWORK[2] = 5; /* Switch for step size sequence */ + /* IWORK[3] = 1000; */ /* Switch for stability check activation */ + /* IWORK[4] = 0; */ /* Switch for stability check activation */ + /* IWORK[5] = 0; */ /* Switch for error estimation, cf. NormControl */ + /* IWORK[6] = 0; */ /* Number for the degree of interpolation */ + IWORK[7] = N; /* Number of components for dense output */ + + /* FORTRAN SUBROUTINE ODEX(N, FCN, X, Y, XEND, H, RTOL, ATOL, ITOL, */ + /* SOLOUT, IOUT, WORK, LWORK, IWORK, LIWORK, RPAR, IPAR, IDID) */ + + vnum = 2; /* Needed to call output at every successful step */ + F77_FUNC (odex, ODEX) (&N, &F77_FUNC (ffcn, FFCN), &SLOT[0], + INIT, &SLOT[1], &H, RTOL, ATOL, &ITOL, &F77_FUNC (fsol, FSOL), + &vnum, WORK, &LWORK, IWORK, &LIWORK, &RPAR, &IPAR, &VRET); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: Solving has been finished, exit status %d\n", VRET); +#endif + + switch (VRET) { /* Only two possible return values do exist */ + case -1: /* Computation has not been successful */ + mexPrintf ("Computation has not been successful\n"); + break; + case 1: break; /* Computation has been successful */ + default: break; + } +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: ----- STARTING SOLVER POSTPROCESSING PROCEDURE\n"); +#endif + + /* Handle the OdeOptions structure field: STATS */ + fodepkgvar (2, "Stats", &vtmp); + if (mxIsLogicalScalarTrue (vtmp)) { + /* Print additional information on the screen */ + vnum = IWORK[16]; /* A dopri solver result */ + vtem = mxCreateDoubleScalar ((double) vnum); + fodepkgvar (1, "vfevals", &vtem); + mexPrintf ("Number of function calls: %d\n", vnum); + + vnum = IWORK[17]; /* A dopri solver result */ + vtem = mxCreateDoubleScalar ((double) vnum); + fodepkgvar (1, "vsuccess", &vtem); + mexPrintf ("Number of used steps: %d\n", vnum); + + vnum = IWORK[18]; /* A dopri solver result */ + vtem = mxCreateDoubleScalar ((double) vnum); + fodepkgvar (1, "vaccept", &vtem); + mexPrintf ("Number of accepted steps: %d\n", vnum); + + vnum = IWORK[19]; /* A dopri solver result */ + vtem = mxCreateDoubleScalar ((double) vnum); + fodepkgvar (1, "vreject", &vtem); + mexPrintf ("Number of rejected steps: %d\n", vnum); + } + + if (nlhs == 1) { /* Handle the PLHS array (1 output argument) */ + vnum = 1; + plhs[0] = mxCreateStructArray (1, &vnum, 0, NULL); + + fsolstore (2, &vtmp, &vtem); + + mxAddField (plhs[0], "x"); + vnum = mxGetFieldNumber (plhs[0], "x"); + mxSetFieldByNumber (plhs[0], 0, vnum, vtmp); + + mxAddField (plhs[0], "y"); + vnum = mxGetFieldNumber (plhs[0], "y"); + mxSetFieldByNumber (plhs[0], 0, vnum, mxTransposeMatrix (vtem)); + + mxAddField (plhs[0], "solver"); + vnum = mxGetFieldNumber (plhs[0], "solver"); + mxSetFieldByNumber (plhs[0], 0, vnum, mxCreateString ("ode5d")); + + fodepkgvar (2, "Stats", &vtmp); + if (mxIsLogicalScalarTrue (vtmp)) { + vnum = 1; /* Put additional information into structure */ + vtem = mxCreateStructArray (1, &vnum, 0, NULL); + + mxAddField (vtem, "success"); + vnum = mxGetFieldNumber (vtem, "success"); + fodepkgvar (2, "vsuccess", &vtmp); + mxSetFieldByNumber (vtem, 0, vnum, mxDuplicateArray (vtmp)); + + mxAddField (vtem, "failed"); + vnum = mxGetFieldNumber (vtem, "failed"); + fodepkgvar (2, "vreject", &vtmp); + mxSetFieldByNumber (vtem, 0, vnum, mxDuplicateArray (vtmp)); + + mxAddField (vtem, "fevals"); + vnum = mxGetFieldNumber (vtem, "fevals"); + fodepkgvar (2, "vfevals", &vtmp); + mxSetFieldByNumber (vtem, 0, vnum, mxDuplicateArray (vtmp)); + + mxAddField (vtem, "partial"); + vnum = mxGetFieldNumber (vtem, "partial"); + mxSetFieldByNumber (vtem, 0, vnum, mxCreateDoubleScalar (0.0)); + + mxAddField (vtem, "ludecom"); + vnum = mxGetFieldNumber (vtem, "ludecom"); + mxSetFieldByNumber (vtem, 0, vnum, mxCreateDoubleScalar (0.0)); + + mxAddField (vtem, "linsol"); + vnum = mxGetFieldNumber (vtem, "linsol"); + mxSetFieldByNumber (vtem, 0, vnum, mxCreateDoubleScalar (0.0)); + + mxAddField (plhs[0], "Stats"); + vnum = mxGetFieldNumber (plhs[0], "Stats"); + mxSetFieldByNumber (plhs[0], 0, vnum, vtem); + } + + fodepkgvar (2, "EventFunction", &vtmp); + if (!mxIsEmpty (vtmp)) { + /* Put additional information about events into structure */ + fodepkgvar (2, "EventSolution", &vtem); + + mxAddField (plhs[0], "ie"); + vnum = mxGetFieldNumber (plhs[0], "ie"); + vtmp = mxDuplicateArray (mxGetCell (vtem, 1)); + mxSetFieldByNumber (plhs[0], 0, vnum, vtmp); + + mxAddField (plhs[0], "xe"); + vnum = mxGetFieldNumber (plhs[0], "xe"); + vtmp = mxDuplicateArray (mxGetCell (vtem, 2)); + mxSetFieldByNumber (plhs[0], 0, vnum, vtmp); + + mxAddField (plhs[0], "ye"); + vnum = mxGetFieldNumber (plhs[0], "ye"); + vtmp = mxDuplicateArray (mxGetCell (vtem, 3)); + mxSetFieldByNumber (plhs[0], 0, vnum, vtmp); + } + } + + else if (nlhs == 2) { + /* Handle the PLHS array (2 output arguments) */ + fsolstore (2, &vtmp, &vtem); + plhs[0] = vtmp; + plhs[1] = mxTransposeMatrix (vtem); + } + + else if (nlhs == 5) { + /* Handle the PLHS array (5 output arguments) */ + fsolstore (2, &vtmp, &vtem); + plhs[0] = vtmp; + plhs[1] = mxTransposeMatrix (vtem); + + fodepkgvar (2, "EventFunction", &vtmp); + if (!mxIsEmpty (vtmp)) { + fodepkgvar (2, "EventSolution", &vtem); + plhs[2] = mxDuplicateArray (mxGetCell (vtem, 2)); + plhs[3] = mxDuplicateArray (mxGetCell (vtem, 3)); + plhs[4] = mxDuplicateArray (mxGetCell (vtem, 1)); + } + else { + plhs[2] = mxCreateDoubleMatrix (0, 0, mxREAL); + plhs[3] = mxCreateDoubleMatrix (0, 0, mxREAL); + plhs[4] = mxCreateDoubleMatrix (0, 0, mxREAL); + } + } + +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: ----- STARTING SOLVER CLEANUP PROCEDURE\n"); +#endif + + /* Cleanup all internals of: FODEPKGPLOT */ + fodepkgvar (2, "PlotFunction", &vtmp); + if (!mxIsEmpty (vtmp)) { + vtmp = mxDuplicateArray (prhs[1]); + fy2mxArray (N, INIT, &vtem); /* vtem = mxDuplicateArray (prhs[2]); */ + if (!fodepkgplot (vtmp, vtem, mxCreateString ("done"))) { + fodepkgvar (2, "PlotFunction", &vtmp); + sprintf (vmsg, "Error at finalisation of output function \"%s\"", mxArrayToString (vtmp)); + mexErrMsgTxt (vmsg); + } +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: Cleanup of output function successfully completed\n"); +#endif + } + + /* Cleanup all internals of: FODEPKGEVENT */ + fodepkgvar (2, "EventFunction", &vtmp); + if (!mxIsEmpty (vtmp)) { + vtmp = mxCreateDoubleScalar (SLOT[0]); + fy2mxArray (N, INIT, &vtem); + if (!fodepkgevent (vtmp, vtem, mxCreateString ("done"), NULL)) { + fodepkgvar (2, "EventFunction", &vtmp); + sprintf (vmsg, "Error at initialisation of event function \"%s\"", mxArrayToString (vtmp)); + mexErrMsgTxt (vmsg); + } +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: Cleanup of event function successfully completed\n"); +#endif + } + + /* Free and destroy the mxAllocated arrays */ +/* mxFree (SLOT); */ +/* mxFree (INIT); */ +/* mxFree (RTOL); */ +/* mxFree (ATOL); */ +/* mxDestroyArray (vtmp); */ +/* mxDestroyArray (vtem); */ +/* fodepkgvar (9, NULL, NULL); */ + + /* Cleanup all internals of: FSOLSTORE */ + fsolstore (4, NULL, NULL); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: Cleanup of fsolstore function successfully completed\n"); +#endif + + /* Cleanup all internals of: FODEPKGVAR */ + fodepkgvar (4, NULL, NULL); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: Cleanup of fodepkgvar function successfully completed\n"); +#endif + +} + +/* +Local Variables: *** +mode: C *** +End: *** +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/odepkg/src/odepkg_mexsolver_radau.c Tue Feb 06 20:14:25 2007 +0000 @@ -0,0 +1,899 @@ +/* +Copyright (C) 2007, Thomas Treichl <treichl@users.sourceforge.net> +OdePkg - Package for solving ordinary differential equations with octave + +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 2 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, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* To manually compile this file with debug messages + + mkoctfile --mex -Wall -W -Wshadow -D__ODEPKGDEBUG__ \ + odepkg_mexsolver_radau.c odepkgmex.c odepkgext.c hairer/radau.f + + or + + mex -v -D__ODEPKGDEBUG__ odepkg_mexsolver_radau.c odepkgext.c \ + odepkgmex.c hairer/radau.f + + a function check can be done via + + octave --quiet --eval "A = odeset (\"RelTol\", 1e-3, \"AbsTol\", 1e-4, \ + \"OutputFcn\", @odeprint, \"OutputSel\", [2, 1], \"Refine\", 3); \ + [C, B] = odepkg_mexsolver_radau (@odepkg_equations_vanderpol, \ + [0, 1], [2, 0], A, 12)" +*/ + +#include <config.h> /* Needed for the F77_FUNC definition etc. */ +#include <mex.h> /* Needed for all mex definitions */ +#include <f77-fcn.h> /* Needed for the use of Fortran routines */ +#include <stdio.h> /* Needed for the sprintf function etc.*/ +#include <string.h> /* Needed for the memcpy function etc.*/ +#include "odepkgmex.h" /* Needed for the mex extensions */ +#include "odepkgext.h" /* Needed for the odepkg interfaces */ + +/* These are the prototype definitions for the solver function, the + interpolation function that is used to achieve better results, the + Jacobian calculation function (if any), the mass calculation + function and the output function. These functions are very similar + to the functions from other solvers, therefore there is nor + explicit documentation for them in the manual. */ + +extern void F77_FUNC (radau, RADAU) (int *N, void *FCN, double *X, double *Y, + double *XEND, double *H, double *RTOL, double *ATOL, int *ITOL, + void *JAC, int *IJAC, int *MLJAC, int *MUJAC, + void *MAS , int *IMAS, int *MLMAS, int *MUMAS, + void *SOL, int *IOUT, double *WORK, int *LWORK, int *IWORK, int *LIWORK, + double *RPAR, int *IPAR, int *VRET); + +extern double F77_FUNC (contra, CONTRA) (int *I, double *S, double *CONT, int *LRC); + +void F77_FUNC (ffcn, FFCN) (int *N, double *X, double *Y, double *F, + GCC_ATTR_UNUSED double *RPAR, GCC_ATTR_UNUSED int *IPAR) { + int vcnt = 0; + int vnum = 0; + char vmsg[64] = ""; + + mxArray *vtmp = NULL; + mxArray **vlhs = NULL; + mxArray **vrhs = NULL; + + /* Get number of varargin elements for allocating memory */ + fodepkgvar (2, "varargin", &vtmp); + vnum = mxGetNumberOfElements (vtmp); + + /* Allocate memory and set up variables lhs-arguments and rhs-arguments */ + vlhs = (mxArray **) mxMalloc (sizeof (mxArray *)); + vrhs = (mxArray **) mxMalloc ((2 + vnum) * sizeof (mxArray *)); + vrhs[0] = mxCreateDoubleScalar (*X); + + /* Copy the values that are given from the solver into the mxArray */ + vrhs[1] = mxCreateDoubleMatrix (*N, 1, mxREAL); + memcpy ((void *) mxGetPr (vrhs[1]), (void *) Y, *N * sizeof (double)); + + if (vnum > 0) /* Fill up vrhs[2..] */ + for (vcnt = 0; vcnt < vnum; vcnt++) + vrhs[vcnt+2] = mxGetCell (vtmp, vcnt); + + /* Evaluate the ode function in the octave workspace */ + fodepkgvar (2, "OdeFunction", &vtmp); + if (mexCallMATLAB (1, vlhs, vnum+2, vrhs, mxArrayToString (vtmp))) { + sprintf (vmsg, "Calling \"%s\" has failed", mxArrayToString (vtmp)); + mexErrMsgTxt (vmsg); + } + + /* Save the result of this time step in the variable f */ + memcpy ((void *) F, (void *) mxGetPr (vlhs[0]), *N * sizeof (double)); + mxFree (vlhs); /* Free the vlhs mxArray */ + mxFree (vrhs); /* Free the vrhs mxArray */ +} + +void F77_FUNC (fjac, FJAC) (int *N, double *X, double *Y, double *DFY, int *LDFY, + GCC_ATTR_UNUSED double *RPAR, GCC_ATTR_UNUSED int *IPAR) { + + int vcnt = 0; + int vnum = 0; + char vmsg[64] = ""; + + mxArray *vjac = NULL; + mxArray *vtmp = NULL; + mxArray **vlhs = NULL; + mxArray **vrhs = NULL; + + fodepkgvar (2, "Jacobian", &vjac); + if (mxIsChar (vjac)) { /* Found the name of the Jacobian function */ + /* Get number of varargin elements for allocating memory */ + fodepkgvar (2, "varargin", &vtmp); + vnum = mxGetNumberOfElements (vtmp); + + /* Allocate memory and set up variables lhs-arguments and rhs-arguments */ + vlhs = (mxArray **) mxMalloc (sizeof (mxArray *)); + vrhs = (mxArray **) mxMalloc ((2 + vnum) * sizeof (mxArray *)); + vrhs[0] = mxCreateDoubleScalar (*X); + + /* Copy the values that are given from the solver into the mxArray */ + vrhs[1] = mxCreateDoubleMatrix (*N, 1, mxREAL); + memcpy ((void *) mxGetPr (vrhs[1]), (void *) Y, *N * sizeof (double)); + + if (vnum > 0) /* Fill up vrhs[2..] */ + for (vcnt = 0; vcnt < vnum; vcnt++) + vrhs[vcnt+2] = mxGetCell (vtmp, vcnt); + + /* Evaluate the ode function in the octave workspace */ + if (mexCallMATLAB (1, vlhs, vnum+2, vrhs, mxArrayToString (vjac))) { + sprintf (vmsg, "Calling \"%s\" has failed", mxArrayToString (vjac)); + mexErrMsgTxt (vmsg); + } + + /* Transpose the matrix, because Fortran stores elements column-wise */ + vtmp = mxTransposeMatrix (vlhs[0]); + /* vtmp = mxDuplicateArray (vlhs[0]); */ + vnum = mxGetM (vtmp) * mxGetN (vtmp); + + /* Save the result of this time step in the variable f */ + memcpy ((void *) DFY, (void *) mxGetPr (vtmp), vnum * sizeof (double)); + /* mexCallMATLAB (0, NULL, 1, &vtmp, "disp"); */ + mxFree (vlhs); /* Free the vlhs mxArray */ + mxFree (vrhs); /* Free the vrhs mxArray */ + } + else { /* Found constant matrix of the Jacobian */ + mexPrintf ("Implement and test this"); + } +} + +void F77_FUNC (fmas, FMAS) (int *N, double *AM, int *LMAS, + double *RPAR, int *IPAR) { + + mexPrintf ("Calc the mas"); +} + +void F77_FUNC (fsol, FSOL) (int *NR, double *XOLD, double *X, double *Y, + double *CONT, int *LRC, int *N, GCC_ATTR_UNUSED double *RPAR, + GCC_ATTR_UNUSED int *IPAR, int *IRTRN) { + + bool vsuc = false; + double vdbt = 0.0; + unsigned int vref = 0; + unsigned int vcnt = 0; + int vnum = 0; + + double *vdob = NULL; + double *vdbl = NULL; + mxArray *vtmp = NULL; + mxArray *vtem = NULL; + mxArray *vtim = NULL; + mxArray *vrtm = NULL; + mxArray *vrvl = NULL; + + /* Convert the double *y into a selection of variables */ + fy2mxArray (*N, Y, &vtem); + vtim = mxCreateDoubleScalar (*X); + + /* Save the solution if this is not the initial first call */ + if (*NR > 1) fsolstore (1, &vtim, &vtem); + + /* Call output function if this is not the initial first call */ + fodepkgvar (2, "PlotFunction", &vtmp); + if (!mxIsEmpty (vtmp) && *NR > 1) { + fodepkgvar (2, "Refine", &vtmp); /* Check for "Refine" option */ + vdbl = mxGetPr (vtmp); + vref = (int)vdbl[0]; + + if (vref > 0) { /* If the Refine option is > 0 */ + vdob = (double *) mxMalloc (*N * sizeof (double)); + + for (vcnt = 0; vcnt < vref; vcnt++) { + vdbt = *XOLD + (double)(vcnt + 1) * ((*X - *XOLD) / (vref + 2)); + vrtm = mxCreateDoubleScalar (vdbt); + /* Time stamps for approximation: mexPrintf ("%f %f %f\n", *XOLD, vdbt, x); */ + + for (vnum = 1; vnum <= *N; vnum++) + vdob[vnum-1] = F77_FUNC (contra, CONTRA) (&vnum, &vdbt, CONT, LRC); + + fy2mxArray (*N, vdob, &vrvl); + /* Time stamps and approx. values: mexPrintf ("%f %f %f\n", vdbt, vdob[0], vdob[1]); */ + fodepkgplot (vrtm, vrvl, mxCreateString ("")); + } + mxFree (vdob); + } + vsuc = fodepkgplot (vtim, vtem, mxCreateString ("")); + if (vsuc == false) { + mexPrintf ("Integration has been stopped from output function at time t=%f\n", *X); + IRTRN[0] = - 1; /* Stop integration ? */ + } + } + + fodepkgvar (2, "EventFunction", &vtmp); + if (!mxIsEmpty (vtmp)) { + fodepkgevent (vtim, vtem, mxCreateString (""), &vtmp); + fodepkgvar (3, "EventSolution", NULL); /* Remove the last events results */ + fodepkgvar (1, "EventSolution", &vtmp); /* Set the new events results */ + + vtem = mxGetCell (vtmp, 0); /* Check if we have to stop solving */ + if (mxIsLogicalScalarTrue (vtem)) { + fsolstore (3, NULL, NULL); /* Remove the last solution entry */ + vtem = mxGetCell (vtmp, 3); /* Get last row of events solution */ + vtim = mxCreateDoubleScalar (*X); + vtmp = mxGetMatrixRow (vtem, mxGetM (vtem) - 1); + fsolstore (1, &vtim, &vtmp); /* Set last row of events solution */ + mexPrintf ("Integration has been stopped from event function at time t=%f\n", *X); + IRTRN[0] = -1; /* Tell the solver to stop solving */ + } + } +} + +void mexFunction (int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { + int vcnt = 0; + int vnum = 0; + double *vdbl = NULL; + char vmsg[64] = ""; + mxArray *vtmp = NULL; + mxArray *vtem = NULL; + + /* Variables that are needed to call the solver function */ + int N = 0; /* Dimension of differential equations */ + int ITOL = 0; /* Type of error tolerance handling */ + int LWORK = 0; /* Size of work vector will be set later */ + int LIWORK = 0; /* Size of iwork vector will be set later */ + int *IWORK = NULL; /* Memory of iwork vector will be allocated later */ + int IPAR = 0; /* Integer parameters will be unused */ + int VRET = 0; /* Return value of the solver function */ + int IJAC = 0; /* Switch for calculation of the Jacobian */ + int MLJAC = 0; /* Switch for banded structure of the Jac */ + int MUJAC = 0; /* Upper bandwidth of the Jacobian */ + int IMAS = 0; /* Switch for calculation of the mass matrix */ + int MLMAS = 0; /* Switch for banded structure of the mass */ + int MUMAS = 0; /* Upper bandwidth of the mass matrix */ + double *SLOT = NULL; /* Time slot values tstart and tend */ + double *INIT = NULL; /* Initial values for differential equations */ + double *RTOL = NULL; /* Relative tolerances scalar or vector */ + double *ATOL = NULL; /* Absolute tolerances scalar or vector */ + double *WORK = NULL; /* Memory of work vector will be allocated later */ + double H = 0.0; /* Initial step size guess, radau will set this */ + double RPAR = 0; /* Real parameters will be unused */ + +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: ----- STARTING SOLVER INITIALISATION PROCEDURE\n"); +#endif + fodepkgvar (0, NULL, NULL); + + if (nrhs == 0) { /* Check number and types of all input arguments */ + vtmp = mxCreateString ("oderd"); + if (mexCallMATLAB (0, NULL, 1, &vtmp, "help")) + mexErrMsgTxt ("Calling \"help\" has failed"); + mexErrMsgTxt ("Number of input arguments must be greater than zero"); + } + else if (nrhs < 3) { /* Check if number of input arguments >= 3 */ + mexUsgMsgTxt ("[t, y] = odepkg_mexsolver_radau (fun, slot, init, varargin)"); + } + else if (mxGetClassID (prhs[0]) != mxFUNCTION_CLASS) { + mexErrMsgTxt ("First input argument must be valid function handle"); + } + else if (!mxIsVector (prhs[1]) && (mxGetNumberOfElements (prhs[1]) < 2)) { /* vslot */ + mexErrMsgTxt ("Second input argument must be a valid vector"); + } + else if (!mxIsVector (prhs[2]) || !mxIsNumeric (prhs[2])) { /* vinit */ + mexErrMsgTxt ("Third input argument must be a valid vector"); + } + else if (nrhs >= 4) { + + if (!mxIsStruct (prhs[3])) { /* No option structure has been set in prhs[3] */ + vnum = nrhs - 3; vtmp = mxCreateCellArray (1, &vnum); + for (vcnt = 3; vcnt < nrhs; vcnt++) + mxSetCell (vtmp, vcnt-3, mxDuplicateArray (prhs[vcnt])); + fodepkgvar (1, "varargin", &vtmp); + if (mexCallMATLAB (1, &vtmp, 0, NULL, "odeset")) + mexErrMsgTxt ("Calling \"odeset\" has failed"); + fodepkgvar (1, "OdeOptions", &vtmp); + } + + else if (nrhs > 4) { /* An option structure and further arguments have been set */ + vnum = nrhs - 4; vtmp = mxCreateCellArray (1, &vnum); + for (vcnt = 4; vcnt < nrhs; vcnt++) + mxSetCell (vtmp, vcnt-4, mxDuplicateArray (prhs[vcnt])); + fodepkgvar (1, "varargin", &vtmp); + vtem = mxDuplicateArray (prhs[3]); + if (mexCallMATLAB (1, &vtmp, 1, &vtem, "odepkg_structure_check")) + mexErrMsgTxt ("Calling \"odepkg_structure_check\" has failed"); + fodepkgvar (1, "OdeOptions", &vtmp); + } + + else { /* Only an option-structure and no further arguments have been set */ + vnum = 0; vtmp = mxCreateCellArray (1, &vnum); + fodepkgvar (1, "varargin", &vtmp); + vtem = mxDuplicateArray (prhs[3]); + if (mexCallMATLAB (1, &vtmp, 1, &vtem, "odepkg_structure_check")) + mexErrMsgTxt ("Calling \"odepkg_structure_check\" has failed"); + fodepkgvar (1, "OdeOptions", &vtmp); + } + + } /* No valid function call has been found before - set the defaults */ + else { + vnum = 0; vtmp = mxCreateCellArray (1, &vnum); + fodepkgvar (1, "varargin", &vtmp); + if (mexCallMATLAB (1, &vtmp, 0, NULL, "odeset")) + mexErrMsgTxt ("Calling \"odeset\" has failed"); + fodepkgvar (1, "OdeOptions", &vtmp); + } + + /* Get the default options (Calling 'odeset' without arguments) */ + if (mexCallMATLAB (1, &vtmp, 0, NULL, "odeset")) + mexErrMsgTxt ("Calling \"odeset\" has failed"); + fodepkgvar (1, "DefaultOptions", &vtmp); + + /* Handle the prhs[0] element: The ode function that has to be solved */ + vtem = mxDuplicateArray (prhs[0]); + if (mexCallMATLAB (1, &vtmp, 1, &vtem, "func2str")) + mexErrMsgTxt ("Calling \"func2str\" has failed"); + fodepkgvar (1, "OdeFunction", &vtmp); + + /* Handle the prhs[1] element: Split the integration interval */ + if (mxGetM (prhs[1]) == 2 || mxGetN (prhs[1]) == 2) { + SLOT = mxMalloc (2 * sizeof (double)); + memcpy ((void *) SLOT, (void *) mxGetPr (prhs[1]), 2 * sizeof (double)); + } + else mexErrMsgTxt ("Second input argument of this solver must be of size 1x2 or 2x1"); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: Solving is done from tStart=%f to tStop=%f\n", + SLOT[0], SLOT[1]); +#endif + + /* Handle the prhs[2] element: Set the dimension and the initial values */ + if (mxIsRowVector (prhs[2])) N = (int) mxGetN (prhs[2]); + else N = (int) mxGetM (prhs[2]); + INIT = mxMalloc (N * sizeof (double)); + vtmp = mxCreateDoubleScalar (N); + fodepkgvar (1, "OdeDimension", &vtmp); + memcpy ((void *) INIT, (void *) mxGetPr (prhs[2]), N * sizeof (double)); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: Number of initial values is %d\n", N); + mexPrintf ("ODEPKGDEBUG: Last element of initial values is %f\n", INIT[N-1]); +#endif + + /* Initialize the WORK and LWORK vectors with zeros */ + LWORK = N*(N+N+7*N+3*7+3)+20; /* LWORK = N*(LJAC+LMAS+NSMAX*LE+3*NSMAX+3)+20; */ + WORK = (double *) mxMalloc (LWORK * sizeof (double)); + for (vcnt = 0; vcnt < LWORK; vcnt++) WORK[vcnt] = 0.0; + LIWORK = (2+(7-1)/2)*N+20; /* LIWORK = (2+(NSMAX-1)/2)*N+20; */ + IWORK = (int *) mxMalloc (LIWORK * sizeof (int)); + for (vcnt = 0; vcnt < LIWORK; vcnt++) IWORK[vcnt] = 0; + + /* Handle the OdeOptions structure field: RELTOL */ + fodepkgvar (2, "OdeOptions", &vtmp); + vtem = mxGetField (vtmp, 0, "RelTol"); + if (mxIsRowVector (vtem)) vcnt = (int) mxGetN (vtem); + else vcnt = (int) mxGetM (vtem); + RTOL = mxMalloc (vcnt * sizeof (double)); + memcpy ((void *) RTOL, (void *) mxGetPr (vtem), vcnt * sizeof (double)); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: Last element of relative error is %f\n", RTOL[vcnt-1]); +#endif + + /* Handle the OdeOptions structure field: ABSTOL */ + vtem = mxGetField (vtmp, 0, "AbsTol"); + if (mxIsRowVector (vtem)) vnum = (int) mxGetN (vtem); + else vnum = (int) mxGetM (vtem); + ATOL = mxMalloc (vnum * sizeof (double)); + memcpy ((void *) ATOL, (void *) mxGetPr (vtem), vnum * sizeof (double)); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: Last element of relative error is %f\n", ATOL[vnum-1]); +#endif + + /* Handle the OdeOptions structure field: RELTOL vs. ABSTOL vs. N */ + if (vcnt != vnum) + mexErrMsgTxt ("\"AbsTol\" and \"RelTol\" must have same size"); + else if (vcnt > 1) { + if (vcnt != N) + mexErrMsgTxt ("\"AbsTol\", \"RelTol\" and the dimension must have same size"); + ITOL = 1; + } + else ITOL = 0; +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: Type of dopri tolerance handling is %d\n", ITOL); +#endif + + /* Handle the OdeOptions structure field: NORMCONTROL */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "NormControl"), + mxGetField (vtem, 0, "NormControl") ) ) + mexWarnMsgTxt ("Option \"NormControl\" will be ignored by this solver"); + + /* Handle the OdeOptions structure field: OUTPUTFCN */ + fodepkgvar (2, "OdeOptions", &vtmp); + vtem = mxGetField (vtmp, 0, "OutputFcn"); + if (mxIsEmpty (vtem) && (nlhs == 0)) { + vtmp = mxCreateString ("odeplot"); + fodepkgvar (1, "PlotFunction", &vtmp); + } + else if (!mxIsEmpty (vtem)) { + if (mexCallMATLAB (1, &vtmp, 1, &vtem, "func2str")) + mexErrMsgTxt ("Calling \"func2str\" has failed"); + fodepkgvar (1, "PlotFunction", &vtmp); + } + else { + vtmp = mxCreateString (""); + fodepkgvar (1, "PlotFunction", &vtmp); + } +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: The output function was set to \"%s\"\n", + mxArrayToString (vtmp)); +#endif + + /* Handle the OdeOptions structure field: OUTPUTSEL */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + vtmp = mxGetField (vtmp, 0, "OutputSel"); + vtem = mxGetField (vtem, 0, "OutputSel"); + if (!mxIsEqual (vtmp, vtem)) { + vnum = (int) mxGetNumberOfElements (vtmp); + vdbl = mxGetPr (vtmp); + for (vcnt = 0; vcnt < vnum; vcnt++) + if ((int)(vdbl[vcnt]) > N) { + sprintf (vmsg, "Found invalid number element \"%d\" in option \"OuputSel\"", + (int)(vdbl[vcnt])); + mexErrMsgTxt (vmsg); + } + fodepkgvar (1, "OutputSelection", &vtmp); + } + else fodepkgvar (1, "OutputSelection", &vtmp); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: The outputsel option has successfully been set\n"); +#endif + + /* Handle the OdeOptions structure field: REFINE */ + fodepkgvar (2, "OdeOptions", &vtmp); + vtem = mxGetField (vtmp, 0, "Refine"); + fodepkgvar (1, "Refine", &vtem); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: The Refine option has been set\n"); +#endif + + /* Handle the OdeOptions structure field: STATS */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "Stats"), mxGetField (vtem, 0, "Stats"))) { + /* mexWarnMsgTxt ("Not yet implemented option \"Stats\" will be ignored"); */ + vtmp = mxCreateLogicalScalar (true); + fodepkgvar (1, "Stats", &vtmp); + } + else { + vtmp = mxCreateLogicalScalar (false); + fodepkgvar (1, "Stats", &vtmp); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: The Stats option has not been set\n"); +#endif + } + + /* Handle the OdeOptions structure field: INITIALSTEP */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "InitialStep"), mxGetField (vtem, 0, "InitialStep"))) + H = *mxGetPr (mxGetField (vtmp, 0, "InitialStep") ); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: The inital step size is %f\n", WORK[6]); +#endif + + /* Handle the OdeOptions structure field: MAXSTEP */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "MaxStep"), mxGetField (vtem, 0, "MaxStep"))) + WORK[6] = *mxGetPr (mxGetField (vtmp, 0, "MaxStep") ); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: The maximum step size is %f\n", WORK[5]); +#endif + + /* Handle the OdeOptions structure field: EVENTS */ + fodepkgvar (2, "OdeOptions", &vtmp); + vtem = mxGetField (vtmp, 0, "Events"); + fodepkgvar (1, "EventFunction", &vtem); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: The Events option has been set\n"); +#endif + + /* Handle the OdeOptions structure field: JACOBIAN */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "Jacobian"), mxGetField (vtem, 0, "Jacobian"))) { + IJAC = 1; /* Tell the solver that we have a Jacobian matrix */ + vtem = mxGetField (vtmp, 0, "Jacobian"); + if (mxGetClassID (vtem) == mxFUNCTION_CLASS) { /* function handle */ + if (mexCallMATLAB (1, &vtmp, 1, &vtem, "func2str")) + mexErrMsgTxt ("Calling \"func2str\" has failed"); + fodepkgvar (1, "Jacobian", &vtmp); + } + else fodepkgvar (1, "Jacobian", &vtem); /* matrix */ + } +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: The Jacobian option has not been set\n"); +#endif + + /* Handle the OdeOptions structure field: JPATTERN */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "JPattern"), mxGetField (vtem, 0, "JPattern"))) + mexWarnMsgTxt ("Option \"JPattern\" will be ignored by this solver"); +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: The JPattern option has not been set\n"); +#endif + + /* Handle the OdeOptions structure field: VECTORIZED */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "Vectorized"), mxGetField (vtem, 0, "Vectorized"))) + mexWarnMsgTxt ("Option \"Vectorized\" will be ignored by this solver"); +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: The Vectorized option has not been set\n"); +#endif + + /* Handle the OdeOptions structure field: MASS */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "Mass"), mxGetField (vtem, 0, "Mass"))) + mexWarnMsgTxt ("Option \"Mass\" will be ignored by this solver"); +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: The Mass option has not been set\n"); +#endif + + /* Handle the OdeOptions structure field: MSTATEDEP */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "MStateDependence"), mxGetField (vtem, 0, "MStateDependence"))) + mexWarnMsgTxt ("Option \"MStateDependence\" will be ignored by this solver"); +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: The MStateDependence option has not been set\n"); +#endif + + /* Handle the OdeOptions structure field: MVPATTERN */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "MvPattern"), mxGetField (vtem, 0, "MvPattern"))) + mexWarnMsgTxt ("Option \"MvPattern\" will be ignored by this solver"); +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: The MvPattern option has not been set\n"); +#endif + + /* Handle the OdeOptions structure field: MASSSINGULAR */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "MassSingular"), mxGetField (vtem, 0, "MassSingular"))) + mexWarnMsgTxt ("Option \"MassSingular\" will be ignored by this solver"); +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: The MassSingular option has not been set\n"); +#endif + + /* Handle the OdeOptions structure field: INITIALSLOPE */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "InitialSlope"), mxGetField (vtem, 0, "InitialSlope"))) + mexWarnMsgTxt ("Option \"InitialSlope\" will be ignored by this solver"); +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: The InitialSlope option has not been set\n"); +#endif + + /* Handle the OdeOptions structure field: MAXORDER */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "MaxOrder"), mxGetField (vtem, 0, "MaxOrder"))) + mexWarnMsgTxt ("Option \"MaxOrder\" will be ignored by this solver"); +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: The MaxOrder option has not been set\n"); +#endif + + /* Handle the OdeOptions structure field: BDF */ + fodepkgvar (2, "OdeOptions", &vtmp); + fodepkgvar (2, "DefaultOptions", &vtem); + if (!mxIsEqual (mxGetField (vtmp, 0, "BDF"), mxGetField (vtem, 0, "BDF"))) + mexWarnMsgTxt ("Option \"BDF\" will be ignored by this solver"); +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: The BDF option has not been set\n"); +#endif + + /* Initialize the function: FODEPKGPLOT */ + fodepkgvar (2, "PlotFunction", &vtmp); + if (!mxIsEmpty (vtmp)) { + vtmp = mxDuplicateArray (prhs[1]); + fy2mxArray (N, INIT, &vtem); + if (!fodepkgplot (vtmp, vtem, mxCreateString ("init"))) { + fodepkgvar (2, "PlotFunction", &vtmp); + sprintf (vmsg, "Error at initialisation of output function \"%s\"", mxArrayToString (vtmp)); + mexErrMsgTxt (vmsg); + } +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: Initialisation of output function successfully completed\n"); +#endif + } + + /* Initialize the function: FODEPKGEVENT */ + fodepkgvar (2, "EventFunction", &vtmp); + if (!mxIsEmpty (vtmp)) { + vtmp = mxCreateDoubleScalar (SLOT[0]); + fy2mxArray (N, INIT, &vtem); + if (!fodepkgevent (vtmp, vtem, mxCreateString ("init"), NULL)) { + fodepkgvar (2, "EventFunction", &vtmp); + sprintf (vmsg, "Error at initialisation of event function \"%s\"", mxArrayToString (vtmp)); + mexErrMsgTxt (vmsg); + } +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: Initialisation of event function successfully completed\n"); +#endif + } + + /* Initialize the function: FSOLSTORE */ + vtmp = mxCreateDoubleScalar (SLOT[0]); + fy2mxArray (N, INIT, &vtem); + fsolstore (0, &vtmp, &vtem); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: Initialisation of fsolstore function successfully completed\n"); +#endif + +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: ----- STARTING SOLVER CALCULATION PROCEDURE\n"); +#endif + + IWORK[00] = 0; /* Switch for transformation of Jacobian into Hessenberg form */ + /* IWORK[01] = 0; */ /* Maximal number of allowed steps */ + /* IWORK[02] = 7; */ /* Maximal number of newton iterations (default value = 7) */ + /* IWORK[03] = 0; */ /* Take extrapolated collocation solution at startup */ + /* IWORK[04] = N; */ /* Dimension of the index 1 variables */ + /* IWORK[05] = 0; */ /* Dimension of the index 2 variables */ + /* IWORK[06] = 0; */ /* Dimension of the index 3 variables */ + /* IWORK[07] = 0; */ /* Switch for step size strategy */ + /* IWORK[08] = 0; */ /* Value for the M1 variable */ + /* IWORK[09] = 0; */ /* Value for the M2 variable */ + /* IWORK[10] = 0; */ /* Minimal number of stages NS */ + /* IWORK[11] = 0; */ /* Maximal number of stages NS */ + /* IWORK[12] = 0; */ /* Number of NS for the first step */ + + /* FORTRAN SUBROUTINE RADAU(N,FCN,X,Y,XEND,H,RTOL,ATOL,ITOL,JAC,IJAC,MLJAC,MUJAC, */ + /* MAS,IMAS,MLMAS,MUMAS,SOLOUT,IOUT,WORK,LWORK,IWORK,LIWORK,RPAR,IPAR,IDID) */ + + vnum = 2; /* Needed to call output at every successful step */ + F77_FUNC (radau, RADAU) (&N, &F77_FUNC (ffcn, FFCN), &SLOT[0], + INIT, &SLOT[1], &H, RTOL, ATOL, &ITOL, + &F77_FUNC (fjac, FJAC), &IJAC, &MLJAC, &MUJAC, + &F77_FUNC (fmas, FMAS), &IMAS, &MLMAS, &MUMAS, + &F77_FUNC (fsol, FSOL), &vnum, WORK, &LWORK, + IWORK, &LIWORK, &RPAR, &IPAR, &VRET); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: Solving has been finished, exit status %d\n", VRET); +#endif + + switch (VRET) { + case -4: + mexPrintf ("The computation has been stopped because the problem is probably stiff\n"); + break; + case -3: + mexPrintf ("The step size grew too small, reduce InitialStep and/or MaxStep\n"); + break; + case -2: + mexPrintf ("Maximal number of allowed steps has been reached\n"); + break; + case -1: + mexPrintf ("Input is not consistent\n"); + break; + case 0: break; /* Not treated */ + case 1: break; /* Computation has been successful */ + case 2: break; /* Computation has been successful, stopped by fsolout */ + default: break; + } +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: ----- STARTING SOLVER POSTPROCESSING PROCEDURE\n"); +#endif + + /* Handle the OdeOptions structure field: STATS */ + fodepkgvar (2, "Stats", &vtmp); + if (mxIsLogicalScalarTrue (vtmp)) { + /* Print additional information on the screen */ + vnum = IWORK[16]; /* A dopri solver result */ + vtem = mxCreateDoubleScalar ((double) vnum); + fodepkgvar (1, "vfevals", &vtem); + mexPrintf ("Number of function calls: %d\n", vnum); + + vnum = IWORK[17]; /* A dopri solver result */ + vtem = mxCreateDoubleScalar ((double) vnum); + fodepkgvar (1, "vsuccess", &vtem); + mexPrintf ("Number of used steps: %d\n", vnum); + + vnum = IWORK[18]; /* A dopri solver result */ + vtem = mxCreateDoubleScalar ((double) vnum); + fodepkgvar (1, "vaccept", &vtem); + mexPrintf ("Number of accepted steps: %d\n", vnum); + + vnum = IWORK[19]; /* A dopri solver result */ + vtem = mxCreateDoubleScalar ((double) vnum); + fodepkgvar (1, "vreject", &vtem); + mexPrintf ("Number of rejected steps: %d\n", vnum); + } + + if (nlhs == 1) { /* Handle the PLHS array (1 output argument) */ + vnum = 1; + plhs[0] = mxCreateStructArray (1, &vnum, 0, NULL); + + fsolstore (2, &vtmp, &vtem); + + mxAddField (plhs[0], "x"); + vnum = mxGetFieldNumber (plhs[0], "x"); + mxSetFieldByNumber (plhs[0], 0, vnum, vtmp); + + mxAddField (plhs[0], "y"); + vnum = mxGetFieldNumber (plhs[0], "y"); + mxSetFieldByNumber (plhs[0], 0, vnum, mxTransposeMatrix (vtem)); + + mxAddField (plhs[0], "solver"); + vnum = mxGetFieldNumber (plhs[0], "solver"); + mxSetFieldByNumber (plhs[0], 0, vnum, mxCreateString ("oderd")); + + fodepkgvar (2, "Stats", &vtmp); + if (mxIsLogicalScalarTrue (vtmp)) { + vnum = 1; /* Put additional information into structure */ + vtem = mxCreateStructArray (1, &vnum, 0, NULL); + + mxAddField (vtem, "success"); + vnum = mxGetFieldNumber (vtem, "success"); + fodepkgvar (2, "vsuccess", &vtmp); + mxSetFieldByNumber (vtem, 0, vnum, mxDuplicateArray (vtmp)); + + mxAddField (vtem, "failed"); + vnum = mxGetFieldNumber (vtem, "failed"); + fodepkgvar (2, "vreject", &vtmp); + mxSetFieldByNumber (vtem, 0, vnum, mxDuplicateArray (vtmp)); + + mxAddField (vtem, "fevals"); + vnum = mxGetFieldNumber (vtem, "fevals"); + fodepkgvar (2, "vfevals", &vtmp); + mxSetFieldByNumber (vtem, 0, vnum, mxDuplicateArray (vtmp)); + + mxAddField (vtem, "partial"); + vnum = mxGetFieldNumber (vtem, "partial"); + mxSetFieldByNumber (vtem, 0, vnum, mxCreateDoubleScalar (0.0)); + + mxAddField (vtem, "ludecom"); + vnum = mxGetFieldNumber (vtem, "ludecom"); + mxSetFieldByNumber (vtem, 0, vnum, mxCreateDoubleScalar (0.0)); + + mxAddField (vtem, "linsol"); + vnum = mxGetFieldNumber (vtem, "linsol"); + mxSetFieldByNumber (vtem, 0, vnum, mxCreateDoubleScalar (0.0)); + + mxAddField (plhs[0], "Stats"); + vnum = mxGetFieldNumber (plhs[0], "Stats"); + mxSetFieldByNumber (plhs[0], 0, vnum, vtem); + } + + fodepkgvar (2, "EventFunction", &vtmp); + if (!mxIsEmpty (vtmp)) { + /* Put additional information about events into structure */ + fodepkgvar (2, "EventSolution", &vtem); + + mxAddField (plhs[0], "ie"); + vnum = mxGetFieldNumber (plhs[0], "ie"); + vtmp = mxDuplicateArray (mxGetCell (vtem, 1)); + mxSetFieldByNumber (plhs[0], 0, vnum, vtmp); + + mxAddField (plhs[0], "xe"); + vnum = mxGetFieldNumber (plhs[0], "xe"); + vtmp = mxDuplicateArray (mxGetCell (vtem, 2)); + mxSetFieldByNumber (plhs[0], 0, vnum, vtmp); + + mxAddField (plhs[0], "ye"); + vnum = mxGetFieldNumber (plhs[0], "ye"); + vtmp = mxDuplicateArray (mxGetCell (vtem, 3)); + mxSetFieldByNumber (plhs[0], 0, vnum, vtmp); + } + } + + else if (nlhs == 2) { + /* Handle the PLHS array (2 output arguments) */ + fsolstore (2, &vtmp, &vtem); + plhs[0] = vtmp; + plhs[1] = mxTransposeMatrix (vtem); + } + + else if (nlhs == 5) { + /* Handle the PLHS array (5 output arguments) */ + fsolstore (2, &vtmp, &vtem); + plhs[0] = vtmp; + plhs[1] = mxTransposeMatrix (vtem); + + fodepkgvar (2, "EventFunction", &vtmp); + if (!mxIsEmpty (vtmp)) { + fodepkgvar (2, "EventSolution", &vtem); + plhs[2] = mxDuplicateArray (mxGetCell (vtem, 2)); + plhs[3] = mxDuplicateArray (mxGetCell (vtem, 3)); + plhs[4] = mxDuplicateArray (mxGetCell (vtem, 1)); + } + else { + plhs[2] = mxCreateDoubleMatrix (0, 0, mxREAL); + plhs[3] = mxCreateDoubleMatrix (0, 0, mxREAL); + plhs[4] = mxCreateDoubleMatrix (0, 0, mxREAL); + } + } + +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: ----- STARTING SOLVER CLEANUP PROCEDURE\n"); +#endif + + /* Cleanup all internals of: FODEPKGPLOT */ + fodepkgvar (2, "PlotFunction", &vtmp); + if (!mxIsEmpty (vtmp)) { + vtmp = mxDuplicateArray (prhs[1]); + fy2mxArray (N, INIT, &vtem); /* vtem = mxDuplicateArray (prhs[2]); */ + if (!fodepkgplot (vtmp, vtem, mxCreateString ("done"))) { + fodepkgvar (2, "PlotFunction", &vtmp); + sprintf (vmsg, "Error at finalisation of output function \"%s\"", mxArrayToString (vtmp)); + mexErrMsgTxt (vmsg); + } +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: Cleanup of output function successfully completed\n"); +#endif + } + + /* Cleanup all internals of: FODEPKGEVENT */ + fodepkgvar (2, "EventFunction", &vtmp); + if (!mxIsEmpty (vtmp)) { + vtmp = mxCreateDoubleScalar (SLOT[0]); + fy2mxArray (N, INIT, &vtem); + if (!fodepkgevent (vtmp, vtem, mxCreateString ("done"), NULL)) { + fodepkgvar (2, "EventFunction", &vtmp); + sprintf (vmsg, "Error at initialisation of event function \"%s\"", mxArrayToString (vtmp)); + mexErrMsgTxt (vmsg); + } +#ifdef __ODEPKGDEBUG__ + else + mexPrintf ("ODEPKGDEBUG: Cleanup of event function successfully completed\n"); +#endif + } + + /* Free and destroy the mxAllocated arrays */ +/* mxFree (SLOT); */ +/* mxFree (INIT); */ +/* mxFree (RTOL); */ +/* mxFree (ATOL); */ +/* mxDestroyArray (vtmp); */ +/* mxDestroyArray (vtem); */ +/* fodepkgvar (9, NULL, NULL); */ + + /* Cleanup all internals of: FSOLSTORE */ + fsolstore (4, NULL, NULL); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: Cleanup of fsolstore function successfully completed\n"); +#endif + + /* Cleanup all internals of: FODEPKGVAR */ + fodepkgvar (4, NULL, NULL); +#ifdef __ODEPKGDEBUG__ + mexPrintf ("ODEPKGDEBUG: Cleanup of fodepkgvar function successfully completed\n"); +#endif + +} + +/* +Local Variables: *** +mode: C *** +End: *** +*/