comparison scripts/ode/ode45.m @ 20568:fcb792acab9b

Moving ode45, odeset, odeget, and levenshtein from odepkg to core. * libinterp/corefcn/levenshtein.cc: move function from odepkg into core * libinterp/corefcn/module.mk: include levenshtein.cc * scripts/ode: move ode45, odeset, odeget, and all dependencies from odepkg into core * scripts/module.mk: include them * doc/interpreter/diffeq.txi: add documentation for ode45, odeset, odeget * NEWS: announce functions included with this changeset * scripts/help/__unimplemented__.m: removed new functions
author jcorno <jacopo.corno@gmail.com>
date Thu, 24 Sep 2015 12:58:46 +0200
parents
children 3339c9bdfe6a
comparison
equal deleted inserted replaced
20567:2480bbcd1333 20568:fcb792acab9b
1 ## Copyright (C) 2006-2012, Thomas Treichl <treichl@users.sourceforge.net>
2 ## Copyright (C) 2013, Roberto Porcu' <roberto.porcu@polimi.it>
3 ## Copyright (C) 2014, Jacopo Corno <jacopo.corno@gmail.com>
4 ##
5 ## This file is part of Octave.
6 ##
7 ## Octave is free software; you can redistribute it and/or modify it
8 ## under the terms of the GNU General Public License as published by
9 ## the Free Software Foundation; either version 3 of the License, or (at
10 ## your option) any later version.
11 ##
12 ## Octave is distributed in the hope that it will be useful, but
13 ## WITHOUT ANY WARRANTY; without even the implied warranty of
14 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 ## General Public License for more details.
16 ##
17 ## You should have received a copy of the GNU General Public License
18 ## along with Octave; see the file COPYING. If not, see
19 ## <http://www.gnu.org/licenses/>.
20
21 ## -*- texinfo -*-
22 ## @deftypefn {Function File} {[@var{sol}] =} ode45 (@var{fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}])
23 ## @deftypefnx {Function File} {[@var{t}, @var{y}, [@var{xe}, @var{ye}, @var{ie}]] =} ode45 (@var{fun}, @var{slot}, @var{init}, [@var{opt}], [@var{par1}, @var{par2}, @dots{}])
24 ##
25 ## This function file can be used to solve a set of non--stiff ordinary
26 ## differential equations (non--stiff ODEs) with the well known explicit
27 ## Dormand-Prince method of order 4.
28 ##
29 ## This function can be called with two output arguments: @var{t} and @var{y}.
30 ## Variable @var{t} is a column vector and contains the time stamps, instead
31 ## @var{y} is a matrix in which each column refers to a different unknown of
32 ## the problem and the rows number is the same of @var{t} rows number so that each
33 ## row of @var{y} contains the values of all unknowns at the time value contained
34 ## in the corresponding row in @var{t}.
35 ##
36 ## The first input argument must be a function_handle or an inline function that
37 ## defines the set of ODE: @code{y' = f(t,y)}. As described above, this function
38 ## must take two input arguments, where the first is the time and the second
39 ## the unknowns, and must have just one output argument.
40 ##
41 ## The second input argument must contain time informations. Usually it should
42 ## be a vector with at least two elements which define the initial and the final
43 ## time instants; if the elements are more than two, then the solution will be
44 ## evaluated also at these intermediate time instants unless the integrate function
45 ## called is the @command{integrate_n_steps}. If there is only one time value,
46 ## then it will give an error unless the options structure has no empty fields
47 ## named @var{"TimeStepNumber"} and @var{"TimeStepSize"}. If the option
48 ## @var{"TimeStepSize"} is not empty, then the stepper called will be
49 ## @command{integrate_const}, if also @var{"TimeStepNumber"} is not empty it will
50 ## be called the integrate function @command{integrate_n_steps}, otherwise it will
51 ## be called @command{integrate_adaptive}. For this last possibility the user can
52 ## set the tolerance for the timestep computation by setting a value to the option
53 ## @var{"Tau"}, that as default value has @math{1.e-6}.
54 ##
55 ## The third input argument must contain the initial value for the unknown.
56 ## If this is a vector then the solution @var{y} will be a matrix in which each
57 ## column is the solution for the corresponding initial value in @var{init}.
58 ##
59 ## The fourth input argument is not mandatory and it should contain a structure
60 ## with valid ODE fields.
61 ##
62 ## For example, solve an anonymous implementation of the Van der Pol equation
63 ## @example
64 ## fvdp = @@(t,y) [y(2); (1 - y(1)^2) * y(2) - y(1)];
65 ## [T,Y] = ode45 (fvdp, [0 20], [2 0]);
66 ## @end example
67 ## @end deftypefn
68 ##
69
70 function [varargout] = ode45 (vfun, vslot, vinit, varargin)
71
72 vorder = 5; % runge_kutta_45_dorpri uses local extrapolation
73 vsolver = "ode45";
74
75 if (nargin == 0) ## Check number and types of all input arguments
76 help (vsolver);
77 error ("OdePkg:InvalidArgument", ...
78 "number of input arguments must be greater than zero");
79 endif
80
81 if (nargin < 3)
82 print_usage;
83 endif
84
85 if (nargin >= 4)
86 if (~isstruct (varargin{1}))
87 ## varargin{1:len} are parameters for vfun
88 vodeoptions = odeset;
89 vodeoptions.vfunarguments = varargin;
90 elseif (length (varargin) > 1)
91 ## varargin{1} is an OdePkg options structure vopt
92 vodeoptions = odepkg_structure_check (varargin{1}, "ode45");
93 vodeoptions.vfunarguments = {varargin{2:length(varargin)}};
94 else ## if (isstruct (varargin{1}))
95 vodeoptions = odepkg_structure_check (varargin{1}, "ode45");
96 vodeoptions.vfunarguments = {};
97 endif
98 else ## if (nargin == 3)
99 vodeoptions = odeset;
100 vodeoptions.vfunarguments = {};
101 endif
102
103 if (~isvector (vslot) || ~isnumeric (vslot))
104 error ("OdePkg:InvalidArgument", ...
105 "second input argument must be a valid vector");
106 endif
107
108 if (length (vslot) < 2 && ...
109 (isempty (vodeoptions.TimeStepSize) ...
110 || isempty (vodeoptions.TimeStepNumber)))
111 error ("OdePkg:InvalidArgument", ...
112 "second input argument must be a valid vector");
113 elseif (vslot(2) == vslot(1))
114 error ("OdePkg:InvalidArgument", ...
115 "second input argument must be a valid vector");
116 else
117 vodeoptions.vdirection = sign (vslot(2) - vslot(1));
118 endif
119 vslot = vslot(:);
120
121 if (~isvector (vinit) || ~isnumeric (vinit))
122 error ("OdePkg:InvalidArgument", ...
123 "third input argument must be a valid numerical value");
124 endif
125 vinit = vinit(:);
126
127 if ~(isa (vfun, "function_handle") || isa (vfun, "inline"))
128 error ("OdePkg:InvalidArgument", ...
129 "first input argument must be a valid function handle");
130 endif
131
132 ## Start preprocessing, have a look which options are set in
133 ## vodeoptions, check if an invalid or unused option is set
134 if (isempty (vodeoptions.TimeStepNumber) ...
135 && isempty (vodeoptions.TimeStepSize))
136 integrate_func = "adaptive";
137 vodeoptions.vstepsizefixed = false;
138 elseif (~isempty (vodeoptions.TimeStepNumber) ...
139 && ~isempty (vodeoptions.TimeStepSize))
140 integrate_func = "n_steps";
141 vodeoptions.vstepsizefixed = true;
142 if (sign (vodeoptions.TimeStepSize) != vodeoptions.vdirection)
143 warning ("OdePkg:InvalidArgument", ...
144 "option ''TimeStepSize'' has a wrong sign", ...
145 "it will be corrected automatically");
146 vodeoptions.TimeStepSize = (-1)*vodeoptions.TimeStepSize;
147 endif
148 elseif (isempty (vodeoptions.TimeStepNumber) && ~isempty (vodeoptions.TimeStepSize))
149 integrate_func = "const";
150 vodeoptions.vstepsizefixed = true;
151 if (sign (vodeoptions.TimeStepSize) != vodeoptions.vdirection)
152 warning ("OdePkg:InvalidArgument", ...
153 "option ''TimeStepSize'' has a wrong sign", ...
154 "it will be corrected automatically");
155 vodeoptions.TimeStepSize = (-1)*vodeoptions.TimeStepSize;
156 endif
157 else
158 warning ("OdePkg:InvalidArgument", ...
159 "assuming an adaptive integrate function");
160 integrate_func = "adaptive";
161 endif
162
163 ## Get the default options that can be set with "odeset" temporarily
164 vodetemp = odeset;
165
166 ## Implementation of the option RelTol has been finished. This option
167 ## can be set by the user to another value than default value.
168 if (isempty (vodeoptions.RelTol) && ~vodeoptions.vstepsizefixed)
169 vodeoptions.RelTol = 1e-3;
170 warning ("OdePkg:InvalidArgument", ...
171 "Option ''RelTol'' not set, new value %f is used", ...
172 vodeoptions.RelTol);
173 elseif (~isempty (vodeoptions.RelTol) && vodeoptions.vstepsizefixed)
174 warning ("OdePkg:InvalidArgument", ...
175 "Option ''RelTol'' will be ignored if fixed time stamps are given");
176 endif
177
178 ## Implementation of the option AbsTol has been finished. This option
179 ## can be set by the user to another value than default value.
180 if (isempty (vodeoptions.AbsTol) && ~vodeoptions.vstepsizefixed)
181 vodeoptions.AbsTol = 1e-6;
182 warning ("OdePkg:InvalidArgument", ...
183 "Option ''AbsTol'' not set, new value %f is used", ...
184 vodeoptions.AbsTol);
185 elseif (~isempty (vodeoptions.AbsTol) && vodeoptions.vstepsizefixed)
186 warning ("OdePkg:InvalidArgument", ...
187 "Option ''AbsTol'' will be ignored if fixed time stamps are given");
188 else
189 vodeoptions.AbsTol = vodeoptions.AbsTol(:); ## Create column vector
190 endif
191
192 ## Implementation of the option NormControl has been finished. This
193 ## option can be set by the user to another value than default value.
194 if (strcmp (vodeoptions.NormControl, "on"))
195 vodeoptions.vnormcontrol = true;
196 else
197 vodeoptions.vnormcontrol = false;
198 endif
199
200 ## Implementation of the option NonNegative has been finished. This
201 ## option can be set by the user to another value than default value.
202 if (~isempty (vodeoptions.NonNegative))
203 if (isempty (vodeoptions.Mass))
204 vodeoptions.vhavenonnegative = true;
205 else
206 vodeoptions.vhavenonnegative = false;
207 warning ("OdePkg:InvalidArgument", ...
208 "Option 'NonNegative' will be ignored if mass matrix is set");
209 endif
210 else
211 vodeoptions.vhavenonnegative = false;
212 endif
213
214 ## Implementation of the option OutputFcn has been finished. This
215 ## option can be set by the user to another value than default value.
216 if (isempty (vodeoptions.OutputFcn) && nargout == 0)
217 vodeoptions.OutputFcn = @odeplot;
218 vodeoptions.vhaveoutputfunction = true;
219 elseif (isempty (vodeoptions.OutputFcn))
220 vodeoptions.vhaveoutputfunction = false;
221 else
222 vodeoptions.vhaveoutputfunction = true;
223 endif
224
225 ## Implementation of the option OutputSel has been finished. This
226 ## option can be set by the user to another value than default value.
227 if (~isempty (vodeoptions.OutputSel))
228 vodeoptions.vhaveoutputselection = true;
229 else
230 vodeoptions.vhaveoutputselection = false;
231 endif
232
233 ## Implementation of the option OutputSave has been finished. This
234 ## option can be set by the user to another value than default value.
235 if (isempty (vodeoptions.OutputSave))
236 vodeoptions.OutputSave = 1;
237 endif
238
239 ## Implementation of the option Refine has been finished. This option
240 ## can be set by the user to another value than default value.
241 if (vodeoptions.Refine > 0)
242 vodeoptions.vhaverefine = true;
243 else
244 vodeoptions.vhaverefine = false;
245 endif
246
247 ## Implementation of the option Stats has been finished. This option
248 ## can be set by the user to another value than default value.
249
250 ## Implementation of the option InitialStep has been finished. This
251 ## option can be set by the user to another value than default value.
252 if (isempty (vodeoptions.InitialStep) && strcmp (integrate_func, "adaptive"))
253 vodeoptions.InitialStep = vodeoptions.vdirection* ...
254 starting_stepsize (vorder, vfun, vslot(1), vinit, vodeoptions.AbsTol, ...
255 vodeoptions.RelTol, vodeoptions.vnormcontrol);
256 warning ("OdePkg:InvalidArgument", ...
257 "option ''InitialStep'' not set, estimated value %f is used", ...
258 vodeoptions.InitialStep);
259 elseif(isempty (vodeoptions.InitialStep))
260 vodeoptions.InitialStep = odeget (vodeoptions, "TimeStepSize");
261 endif
262
263 ## Implementation of the option MaxStep has been finished. This option
264 ## can be set by the user to another value than default value.
265 if (isempty (vodeoptions.MaxStep) && ~vodeoptions.vstepsizefixed)
266 vodeoptions.MaxStep = abs (vslot(end) - vslot(1)) / 10;
267 warning ("OdePkg:InvalidArgument", ...
268 "Option ''MaxStep'' not set, new value %f is used", ...
269 vodeoptions.MaxStep);
270 endif
271
272 ## Implementation of the option Events has been finished. This option
273 ## can be set by the user to another value than default value.
274 if (~isempty (vodeoptions.Events))
275 vodeoptions.vhaveeventfunction = true;
276 else
277 vodeoptions.vhaveeventfunction = false;
278 endif
279
280 ## The options 'Jacobian', 'JPattern' and 'Vectorized' will be ignored
281 ## by this solver because this solver uses an explicit Runge-Kutta
282 ## method and therefore no Jacobian calculation is necessary
283 if (~isequal (vodeoptions.Jacobian, vodetemp.Jacobian))
284 warning ("OdePkg:InvalidArgument", ...
285 "option ''Jacobian'' will be ignored by this solver");
286 endif
287
288 if (~isequal (vodeoptions.JPattern, vodetemp.JPattern))
289 warning ("OdePkg:InvalidArgument", ...
290 "option ''JPattern'' will be ignored by this solver");
291 endif
292
293 if (~isequal (vodeoptions.Vectorized, vodetemp.Vectorized))
294 warning ("OdePkg:InvalidArgument", ...
295 "option ''Vectorized'' will be ignored by this solver");
296 endif
297
298 if (~isequal (vodeoptions.NewtonTol, vodetemp.NewtonTol))
299 warning ("OdePkg:InvalidArgument", ...
300 "option ''NewtonTol'' will be ignored by this solver");
301 endif
302
303 if (~isequal (vodeoptions.MaxNewtonIterations,vodetemp.MaxNewtonIterations))
304 warning ("OdePkg:InvalidArgument", ...
305 "option ''MaxNewtonIterations'' will be ignored by this solver");
306 endif
307
308 ## Implementation of the option Mass has been finished. This option
309 ## can be set by the user to another value than default value.
310 if (~isempty (vodeoptions.Mass) && isnumeric (vodeoptions.Mass))
311 vhavemasshandle = false;
312 vmass = vodeoptions.Mass; ## constant mass
313 elseif (isa (vodeoptions.Mass, "function_handle"))
314 vhavemasshandle = true; ## mass defined by a function handle
315 else ## no mass matrix - creating a diag-matrix of ones for mass
316 vhavemasshandle = false; ## vmass = diag (ones (length (vinit), 1), 0);
317 endif
318
319 ## Implementation of the option MStateDependence has been finished.
320 ## This option can be set by the user to another value than default
321 ## value.
322 if (strcmp (vodeoptions.MStateDependence, "none"))
323 vmassdependence = false;
324 else
325 vmassdependence = true;
326 endif
327
328 ## Other options that are not used by this solver. Print a warning
329 ## message to tell the user that the option(s) is/are ignored.
330 if (~isequal (vodeoptions.MvPattern, vodetemp.MvPattern))
331 warning ("OdePkg:InvalidArgument", ...
332 "option ''MvPattern'' will be ignored by this solver");
333 endif
334
335 if (~isequal (vodeoptions.MassSingular, vodetemp.MassSingular))
336 warning ("OdePkg:InvalidArgument", ...
337 "option ''MassSingular'' will be ignored by this solver");
338 endif
339
340 if (~isequal (vodeoptions.InitialSlope, vodetemp.InitialSlope))
341 warning ("OdePkg:InvalidArgument", ...
342 "option ''InitialSlope'' will be ignored by this solver");
343 endif
344
345 if (~isequal (vodeoptions.MaxOrder, vodetemp.MaxOrder))
346 warning ("OdePkg:InvalidArgument", ...
347 "option ''MaxOrder'' will be ignored by this solver");
348 endif
349
350 if (~isequal (vodeoptions.BDF, vodetemp.BDF))
351 warning ("OdePkg:InvalidArgument", ...
352 "option ''BDF'' will be ignored by this solver");
353 endif
354
355 ## Starting the initialisation of the core solver ode45
356 SubOpts = vodeoptions;
357
358 if (vhavemasshandle) ## Handle only the dynamic mass matrix,
359 if (vmassdependence) ## constant mass matrices have already
360 vmass = @(t,x) vodeoptions.Mass (t, x, vodeoptions.vfunarguments{:});
361 vfun = @(t,x) vmass (t, x, vodeoptions.vfunarguments{:}) ...
362 \ vfun (t, x, vodeoptions.vfunarguments{:});
363 else ## if (vmassdependence == false)
364 vmass = @(t) vodeoptions.Mass (t, vodeoptions.vfunarguments{:});
365 vfun = @(t,x) vmass (t, vodeoptions.vfunarguments{:}) ...
366 \ vfun (t, x, vodeoptions.vfunarguments{:});
367 endif
368 endif
369
370 switch integrate_func
371 case "adaptive"
372 solution = integrate_adaptive (@runge_kutta_45_dorpri, ...
373 vorder, vfun, vslot, vinit, SubOpts);
374 case "n_steps"
375 solution = integrate_n_steps (@runge_kutta_45_dorpri, ...
376 vfun, vslot(1), vinit, ...
377 vodeoptions.TimeStepSize, ...
378 vodeoptions.TimeStepNumber, SubOpts);
379 case "const"
380 solution = integrate_const (@runge_kutta_45_dorpri, ...
381 vfun, vslot, vinit, ...
382 vodeoptions.TimeStepSize, SubOpts);
383 endswitch
384
385 ## Postprocessing, do whatever when terminating integration algorithm
386 if (vodeoptions.vhaveoutputfunction) ## Cleanup plotter
387 feval (vodeoptions.OutputFcn, solution.t(end), ...
388 solution.x(end,:)', "done", vodeoptions.vfunarguments{:});
389 endif
390 if (vodeoptions.vhaveeventfunction) ## Cleanup event function handling
391 odepkg_event_handle (vodeoptions.Events, solution.t(end), ...
392 solution.x(end,:)', "done", vodeoptions.vfunarguments{:});
393 endif
394
395 ## Print additional information if option Stats is set
396 if (strcmp (vodeoptions.Stats, "on"))
397 vhavestats = true;
398 vnsteps = solution.vcntloop-2; ## vcntloop from 2..end
399 vnfailed = (solution.vcntcycles-1)-(solution.vcntloop-2)+1; ## vcntcycl from 1..end
400 vnfevals = 7*(solution.vcntcycles-1); ## number of ode evaluations
401 vndecomps = 0; ## number of LU decompositions
402 vnpds = 0; ## number of partial derivatives
403 vnlinsols = 0; ## no. of solutions of linear systems
404 ## Print cost statistics if no output argument is given
405 if (nargout == 0)
406 vmsg = fprintf (1, "Number of successful steps: %d\n", vnsteps);
407 vmsg = fprintf (1, "Number of failed attempts: %d\n", vnfailed);
408 vmsg = fprintf (1, "Number of function calls: %d\n", vnfevals);
409 endif
410 else
411 vhavestats = false;
412 endif
413
414 if (nargout == 1) ## Sort output variables, depends on nargout
415 varargout{1}.x = solution.t; ## Time stamps are saved in field x
416 varargout{1}.y = solution.x; ## Results are saved in field y
417 varargout{1}.solver = vsolver; ## Solver name is saved in field solver
418 if (vodeoptions.vhaveeventfunction)
419 varargout{1}.ie = solution.vevent{2}; ## Index info which event occured
420 varargout{1}.xe = solution.vevent{3}; ## Time info when an event occured
421 varargout{1}.ye = solution.vevent{4}; ## Results when an event occured
422 endif
423 if (vhavestats)
424 varargout{1}.stats = struct;
425 varargout{1}.stats.nsteps = vnsteps;
426 varargout{1}.stats.nfailed = vnfailed;
427 varargout{1}.stats.nfevals = vnfevals;
428 varargout{1}.stats.npds = vnpds;
429 varargout{1}.stats.ndecomps = vndecomps;
430 varargout{1}.stats.nlinsols = vnlinsols;
431 endif
432 elseif (nargout == 2)
433 varargout{1} = solution.t; ## Time stamps are first output argument
434 varargout{2} = solution.x; ## Results are second output argument
435 elseif (nargout == 5)
436 varargout{1} = solution.t; ## Same as (nargout == 2)
437 varargout{2} = solution.x; ## Same as (nargout == 2)
438 varargout{3} = []; ## LabMat doesn't accept lines like
439 varargout{4} = []; ## varargout{3} = varargout{4} = [];
440 varargout{5} = [];
441 if (vodeoptions.vhaveeventfunction)
442 varargout{3} = solution.vevent{3}; ## Time info when an event occured
443 varargout{4} = solution.vevent{4}; ## Results when an event occured
444 varargout{5} = solution.vevent{2}; ## Index info which event occured
445 endif
446 endif
447
448 endfunction
449
450 %! # We are using the "Van der Pol" implementation for all tests that
451 %! # are done for this function.
452 %! # For further tests we also define a reference solution (computed at high accuracy)
453 %!function [ydot] = fpol (vt, vy) ## The Van der Pol
454 %! ydot = [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)];
455 %!endfunction
456 %!function [vref] = fref () ## The computed reference sol
457 %! vref = [0.32331666704577, -1.83297456798624];
458 %!endfunction
459 %!function [vjac] = fjac (vt, vy, varargin) ## its Jacobian
460 %! vjac = [0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2];
461 %!function [vjac] = fjcc (vt, vy, varargin) ## sparse type
462 %! vjac = sparse ([0, 1; -1 - 2 * vy(1) * vy(2), 1 - vy(1)^2])
463 %!function [vval, vtrm, vdir] = feve (vt, vy, varargin)
464 %! vval = fpol (vt, vy, varargin); ## We use the derivatives
465 %! vtrm = zeros (2,1); ## that's why component 2
466 %! vdir = ones (2,1); ## seems to not be exact
467 %!function [vval, vtrm, vdir] = fevn (vt, vy, varargin)
468 %! vval = fpol (vt, vy, varargin); ## We use the derivatives
469 %! vtrm = ones (2,1); ## that's why component 2
470 %! vdir = ones (2,1); ## seems to not be exact
471 %!function [vmas] = fmas (vt, vy, varargin)
472 %! vmas = [1, 0; 0, 1]; ## Dummy mass matrix for tests
473 %!function [vmas] = fmsa (vt, vy, varargin)
474 %! vmas = sparse ([1, 0; 0, 1]); ## A sparse dummy matrix
475 %!function [vout] = fout (vt, vy, vflag, varargin)
476 %! if (regexp (char (vflag), 'init') == 1)
477 %! if (any (size (vt) ~= [2, 1])) error ('"fout" step "init"'); end
478 %! elseif (isempty (vflag))
479 %! if (any (size (vt) ~= [1, 1])) error ('"fout" step "calc"'); end
480 %! vout = false;
481 %! elseif (regexp (char (vflag), 'done') == 1)
482 %! if (any (size (vt) ~= [1, 1])) error ('"fout" step "done"'); end
483 %! else error ('"fout" invalid vflag');
484 %! end
485 %!
486 %! ## Turn off output of warning messages for all tests, turn them on
487 %! ## again if the last test is called
488 %!error ## ouput argument
489 %! warning ('off', 'OdePkg:InvalidArgument');
490 %! B = ode45 (1, [0 25], [3 15 1]);
491 %!error ## input argument number one
492 %! [vt, vy] = ode45 (1, [0 25], [3 15 1]);
493 %!error ## input argument number two
494 %! [vt, vy] = ode45 (@fpol, 1, [3 15 1]);
495 %!test ## two output arguments
496 %! [vt, vy] = ode45 (@fpol, [0 2], [2 0]);
497 %! assert ([vt(end), vy(end,:)], [2, fref], 1e-2);
498 %!test ## not too many steps
499 %! [vt, vy] = ode45 (@fpol, [0 2], [2 0]);
500 %! assert (size (vt) < 20);
501 %!test ## anonymous function instead of real function
502 %! fvdb = @(vt,vy) [vy(2); (1 - vy(1)^2) * vy(2) - vy(1)];
503 %! [vt, vy] = ode45 (fvdb, [0 2], [2 0]);
504 %! assert ([vt(end), vy(end,:)], [2, fref], 1e-2);
505 %!test ## extra input arguments passed through
506 %! [vt, vy] = ode45 (@fpol, [0 2], [2 0], 12, 13, 'KL');
507 %! assert ([vt(end), vy(end,:)], [2, fref], 1e-2);
508 %!test ## empty OdePkg structure *but* extra input arguments
509 %! vopt = odeset;
510 %! [vt, vy] = ode45 (@fpol, [0 2], [2 0], vopt, 12, 13, 'KL');
511 %! assert ([vt(end), vy(end,:)], [2, fref], 1e-2);
512 %!error ## strange OdePkg structure
513 %! vopt = struct ('foo', 1);
514 %! [vt, vy] = ode45 (@fpol, [0 2], [2 0], vopt);
515 %!test ## Solve vdp in fixed step sizes
516 %! vopt = odeset('TimeStepSize', 0.1);
517 %! [vt, vy] = ode45 (@fpol, [0,2], [2 0], vopt);
518 %! assert (vt(:), [0:0.1:2]', 1e-2);
519 %!test ## Solve another anonymous function below zero
520 %! vref = [0, 14.77810590694212];
521 %! [vt, vy] = ode45 (@(t,y) y, [-2 0], 2);
522 %! assert ([vt(end), vy(end,:)], vref, 1e-1);
523 %!test ## InitialStep option
524 %! vopt = odeset ('InitialStep', 1e-8);
525 %! [vt, vy] = ode45 (@fpol, [0 0.2], [2 0], vopt);
526 %! assert ([vt(2)-vt(1)], [1e-8], 1e-9);
527 %!test ## MaxStep option
528 %! vopt = odeset ('MaxStep', 1e-3);
529 %! vsol = ode45 (@fpol, [0 0.2], [2 0], vopt);
530 %! assert ([vsol.x(5)-vsol.x(4)], [1e-3], 1e-3);
531 %!test ## Solve with intermidiate step
532 %! vsol = ode45 (@fpol, [0 1 2], [2 0]);
533 %! assert (any((vsol.x-1) == 0));
534 %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3);
535 %!test ## Solve in backward direction starting at t=0
536 %! vref = [-1.205364552835178, 0.951542399860817];
537 %! vsol = ode45 (@fpol, [0 -2], [2 0]);
538 %! assert ([vsol.x(end), vsol.y(end,:)], [-2, vref], 1e-2);
539 %!test ## Solve in backward direction starting at t=2
540 %! vref = [-1.205364552835178, 0.951542399860817];
541 %! vsol = ode45 (@fpol, [2 -2], fref);
542 %! assert ([vsol.x(end), vsol.y(end,:)], [-2, vref], 1e-2);
543 %!test ## Solve in backward direction starting at t=2, with intermidiate step
544 %! vref = [-1.205364552835178, 0.951542399860817];
545 %! vsol = ode45 (@fpol, [2 0 -2], fref);
546 %! idx = find(vsol.x < 0, 1, 'first') - 1;
547 %! assert ([vsol.x(idx), vsol.y(idx,:)], [0 2 0], 1e-2);
548 %! assert ([vsol.x(end), vsol.y(end,:)], [-2, vref], 1e-2);
549 %!test ## Solve another anonymous function in backward direction
550 %! vref = [-1, 0.367879437558975];
551 %! vsol = ode45 (@(t,y) y, [0 -1], 1);
552 %! assert ([vsol.x(end), vsol.y(end,:)], vref, 1e-3);
553 %!test ## Solve another anonymous function below zero
554 %! vref = [0, 14.77810590694212];
555 %! vsol = ode45 (@(t,y) y, [-2 0], 2);
556 %! assert ([vsol.x(end), vsol.y(end,:)], vref, 1e-3);
557 %!test ## Solve in backward direction starting at t=0 with MaxStep option
558 %! vref = [-1.205364552835178, 0.951542399860817];
559 %! vopt = odeset ('MaxStep', 1e-3);
560 %! vsol = ode45 (@fpol, [0 -2], [2 0], vopt);
561 %! assert ([abs(vsol.x(8)-vsol.x(7))], [1e-3], 1e-3);
562 %! assert ([vsol.x(end), vsol.y(end,:)], [-2, vref], 1e-3);
563 %!test ## AbsTol option
564 %! vopt = odeset ('AbsTol', 1e-5);
565 %! vsol = ode45 (@fpol, [0 2], [2 0], vopt);
566 %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3);
567 %!test ## AbsTol and RelTol option
568 %! vopt = odeset ('AbsTol', 1e-8, 'RelTol', 1e-8);
569 %! vsol = ode45 (@fpol, [0 2], [2 0], vopt);
570 %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3);
571 %!test ## RelTol and NormControl option -- higher accuracy
572 %! vopt = odeset ('RelTol', 1e-8, 'NormControl', 'on');
573 %! vsol = ode45 (@fpol, [0 2], [2 0], vopt);
574 %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-5);
575 %!test ## Keeps initial values while integrating
576 %! vopt = odeset ('NonNegative', 2);
577 %! vsol = ode45 (@fpol, [0 2], [2 0], vopt);
578 %! assert ([vsol.x(end), vsol.y(end,:)], [2, 2, 0], 0.5);
579 %!test ## Details of OutputSel and Refine can't be tested
580 %! vopt = odeset ('OutputFcn', @fout, 'OutputSel', 1, 'Refine', 5);
581 %! vsol = ode45 (@fpol, [0 2], [2 0], vopt);
582 %!test ## Details of OutputSave can't be tested
583 %! vopt = odeset ('OutputSave', 1, 'OutputSel', 1);
584 %! vsla = ode45 (@fpol, [0 2], [2 0], vopt);
585 %! vopt = odeset ('OutputSave', 2);
586 %! vslb = ode45 (@fpol, [0 2], [2 0], vopt);
587 %! assert (length (vsla.x) + 1 >= 2 * length (vslb.x))
588 %!test ## Stats must add further elements in vsol
589 %! vopt = odeset ('Stats', 'on');
590 %! vsol = ode45 (@fpol, [0 2], [2 0], vopt);
591 %! assert (isfield (vsol, 'stats'));
592 %! assert (isfield (vsol.stats, 'nsteps'));
593 %!test ## Events option add further elements in vsol
594 %! vopt = odeset ('Events', @feve);
595 %! vsol = ode45 (@fpol, [0 10], [2 0], vopt);
596 %! assert (isfield (vsol, 'ie'));
597 %! assert (vsol.ie(1), 2);
598 %! assert (isfield (vsol, 'xe'));
599 %! assert (isfield (vsol, 'ye'));
600 %!test ## Events option, now stop integration
601 %! vopt = odeset ('Events', @fevn, 'NormControl', 'on');
602 %! vsol = ode45 (@fpol, [0 10], [2 0], vopt);
603 %! assert ([vsol.ie, vsol.xe, vsol.ye], ...
604 %! [2.0, 2.496110, -0.830550, -2.677589], 6e-1);
605 %!test ## Events option, five output arguments
606 %! vopt = odeset ('Events', @fevn, 'NormControl', 'on');
607 %! [vt, vy, vxe, vye, vie] = ode45 (@fpol, [0 10], [2 0], vopt);
608 %! assert ([vie, vxe, vye], ...
609 %! [2.0, 2.496110, -0.830550, -2.677589], 6e-1);
610 %!test ## Jacobian option
611 %! vopt = odeset ('Jacobian', @fjac);
612 %! vsol = ode45 (@fpol, [0 2], [2 0], vopt);
613 %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3);
614 %!test ## Jacobian option and sparse return value
615 %! vopt = odeset ('Jacobian', @fjcc);
616 %! vsol = ode45 (@fpol, [0 2], [2 0], vopt);
617 %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3);
618 %!
619 %! ## test for JPattern option is missing
620 %! ## test for Vectorized option is missing
621 %! ## test for NewtonTol option is missing
622 %! ## test for MaxNewtonIterations option is missing
623 %!
624 %!test ## Mass option as function
625 %! vopt = odeset ('Mass', @fmas);
626 %! vsol = ode45 (@fpol, [0 2], [2 0], vopt);
627 %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3);
628 %!test ## Mass option as matrix
629 %! vopt = odeset ('Mass', eye (2,2));
630 %! vsol = ode45 (@fpol, [0 2], [2 0], vopt);
631 %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3);
632 %!test ## Mass option as sparse matrix
633 %! vopt = odeset ('Mass', sparse (eye (2,2)));
634 %! vsol = ode45 (@fpol, [0 2], [2 0], vopt);
635 %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3);
636 %!test ## Mass option as function and sparse matrix
637 %! vopt = odeset ('Mass', @fmsa);
638 %! vsol = ode45 (@fpol, [0 2], [2 0], vopt);
639 %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3);
640 %!test ## Mass option as function and MStateDependence
641 %! vopt = odeset ('Mass', @fmas, 'MStateDependence', 'strong');
642 %! vsol = ode45 (@fpol, [0 2], [2 0], vopt);
643 %! assert ([vsol.x(end), vsol.y(end,:)], [2, fref], 1e-3);
644 %!test ## Set BDF option to something else than default
645 %! vopt = odeset ('BDF', 'on');
646 %! [vt, vy] = ode45 (@fpol, [0 2], [2 0], vopt);
647 %! assert ([vt(end), vy(end,:)], [2, fref], 1e-3);
648 %!
649 %! ## test for MvPattern option is missing
650 %! ## test for InitialSlope option is missing
651 %! ## test for MaxOrder option is missing
652 %!
653 %! warning ('on', 'OdePkg:InvalidArgument');
654
655 ## Local Variables: ***
656 ## mode: octave ***
657 ## End: ***