Mercurial > octave-nkf
comparison scripts/ode/private/integrate_adaptive.m @ 20584:eb9e2d187ed2
maint: Use Octave coding conventions in scripts/ode/private dir.
* AbsRel_Norm.m, fuzzy_compare.m, hermite_quartic_interpolation.m,
integrate_adaptive.m, integrate_const.m, integrate_n_steps.m, kahan.m,
ode_struct_value_check.m, odepkg_event_handle.m, odepkg_structure_check.m,
runge_kutta_45_dorpri.m, starting_stepsize.m:
Wrap long lines to < 80 chars.
Use double quotes rather than single quotes where possible.
Use ';' at end of keywords "return;" and "break;"
Use '##" for stand-alone comments and '#' for end-of-line comments.
Use two spaces after period before starting new sentence.
Use '!' instead of '~' for logical negation.
Use specific form of end (endif, endfor, etc.).
Don't use line continuation marker '...' unless necessary.
author | Rik <rik@octave.org> |
---|---|
date | Sun, 04 Oct 2015 22:18:54 -0700 |
parents | 25623ef2ff4f |
children | b7ac1e94266e |
comparison
equal
deleted
inserted
replaced
20583:d746695bf494 | 20584:eb9e2d187ed2 |
---|---|
59 ## | 59 ## |
60 ## @seealso{integrate_const, integrate_n_steps} | 60 ## @seealso{integrate_const, integrate_n_steps} |
61 | 61 |
62 function solution = integrate_adaptive (stepper, order, func, tspan, x0, options) | 62 function solution = integrate_adaptive (stepper, order, func, tspan, x0, options) |
63 | 63 |
64 solution = struct; | 64 solution = struct (); |
65 | 65 |
66 ## first values for time and solution | 66 ## first values for time and solution |
67 t = tspan(1); | 67 t = tspan(1); |
68 x = x0(:); | 68 x = x0(:); |
69 | 69 |
76 if (sign (dt) != vdirection) | 76 if (sign (dt) != vdirection) |
77 dt = -dt; | 77 dt = -dt; |
78 endif | 78 endif |
79 dt = vdirection * min (abs (dt), options.MaxStep); | 79 dt = vdirection * min (abs (dt), options.MaxStep); |
80 | 80 |
81 ## set parameters | 81 ## Set parameters |
82 k = length (tspan); | 82 k = length (tspan); |
83 counter = 2; | 83 counter = 2; |
84 comp = 0.0; | 84 comp = 0.0; |
85 tk = tspan(1); | 85 tk = tspan(1); |
86 options.comp = comp; | 86 options.comp = comp; |
87 | 87 |
88 ## factor multiplying the stepsize guess | 88 ## Factor multiplying the stepsize guess |
89 facmin = 0.8; | 89 facmin = 0.8; |
90 fac = 0.38^(1/(order+1)); ## formula taken from Hairer | 90 fac = 0.38^(1/(order+1)); # formula taken from Hairer |
91 t_caught = false; | 91 t_caught = false; |
92 | 92 |
93 | 93 |
94 ## Initialize the OutputFcn | 94 ## Initialize the OutputFcn |
95 if (options.vhaveoutputfunction) | 95 if (options.vhaveoutputfunction) |
120 k_vals = []; | 120 k_vals = []; |
121 | 121 |
122 while (counter <= k) | 122 while (counter <= k) |
123 facmax = 1.5; | 123 facmax = 1.5; |
124 | 124 |
125 ## compute integration step from t to t+dt | 125 ## Compute integration step from t to t+dt |
126 if (isempty (k_vals)) | 126 if (isempty (k_vals)) |
127 [s, y, y_est, new_k_vals] = stepper (func, z(end), u(:,end), | 127 [s, y, y_est, new_k_vals] = stepper (func, z(end), u(:,end), |
128 dt, options); | 128 dt, options); |
129 else | 129 else |
130 [s, y, y_est, new_k_vals] = stepper (func, z(end), u(:,end), | 130 [s, y, y_est, new_k_vals] = stepper (func, z(end), u(:,end), |
142 endif | 142 endif |
143 | 143 |
144 err = AbsRel_Norm (y(:,end), u(:,end), options.AbsTol, options.RelTol, | 144 err = AbsRel_Norm (y(:,end), u(:,end), options.AbsTol, options.RelTol, |
145 options.vnormcontrol, y_est(:,end)); | 145 options.vnormcontrol, y_est(:,end)); |
146 | 146 |
147 ## solution accepted only if the error is less or equal to 1.0 | 147 ## Solution accepted only if the error is less or equal to 1.0 |
148 if (err <= 1) | 148 if (err <= 1) |
149 | 149 |
150 [tk, comp] = kahan (tk, comp, dt); | 150 [tk, comp] = kahan (tk, comp, dt); |
151 options.comp = comp; | 151 options.comp = comp; |
152 s(end) = tk; | 152 s(end) = tk; |
160 if ((z(end) == tspan(counter)) | 160 if ((z(end) == tspan(counter)) |
161 || (abs (z(end) - tspan(counter)) / | 161 || (abs (z(end) - tspan(counter)) / |
162 (max (abs (z(end)), abs (tspan(counter)))) < 8*eps) ) | 162 (max (abs (z(end)), abs (tspan(counter)))) < 8*eps) ) |
163 counter++; | 163 counter++; |
164 | 164 |
165 ## if there is an element in time vector at which the solution is required | 165 ## if there is an element in time vector at which the solution is |
166 ## the program must compute this solution before going on with next steps | 166 ## required the program must compute this solution before going on with |
167 ## next steps | |
167 elseif (vdirection * z(end) > vdirection * tspan(counter)) | 168 elseif (vdirection * z(end) > vdirection * tspan(counter)) |
168 | 169 |
169 ## initialize counter for the following cycle | 170 ## initialize counter for the following cycle |
170 i = 2; | 171 i = 2; |
171 while (i <= length (z)) | 172 while (i <= length (z)) |
231 ## f_half = feval (func, t+1/2*dt, u_half, | 232 ## f_half = feval (func, t+1/2*dt, u_half, |
232 ## options.vfunarguments{:}); | 233 ## options.vfunarguments{:}); |
233 ## u_interp = | 234 ## u_interp = |
234 ## hermite_quintic_interpolation ([z(i-1) z(i)], | 235 ## hermite_quintic_interpolation ([z(i-1) z(i)], |
235 ## [u(:,i-1) u_half u(:,i)], | 236 ## [u(:,i-1) u_half u(:,i)], |
236 ## [k_vals(:,1) f_half k_vals(:,end)], | 237 ## [k_vals(:,1) f_half ... |
238 ## k_vals(:,end)], | |
237 ## tspan(counter)); | 239 ## tspan(counter)); |
238 otherwise | 240 otherwise |
239 warning ("High order interpolation not yet implemented: ", | 241 warning ("High order interpolation not yet implemented: ", |
240 "using cubic iterpolation instead"); | 242 "using cubic interpolation instead"); |
241 der(:,1) = feval (func, z(i-1) , u(:,i-1), | 243 der(:,1) = feval (func, z(i-1) , u(:,i-1), |
242 options.vfunarguments{:}); | 244 options.vfunarguments{:}); |
243 der(:,2) = feval (func, z(i) , u(:,i), | 245 der(:,2) = feval (func, z(i) , u(:,i), |
244 options.vfunarguments{:}); | 246 options.vfunarguments{:}); |
245 u_interp = ... | 247 u_interp = ... |
279 endif | 281 endif |
280 solution.vcntloop = solution.vcntloop + 1; | 282 solution.vcntloop = solution.vcntloop + 1; |
281 vcntiter = 0; | 283 vcntiter = 0; |
282 | 284 |
283 ## Call plot only if a valid result has been found, therefore this | 285 ## Call plot only if a valid result has been found, therefore this |
284 ## code fragment has moved here. Stop integration if plot function | 286 ## code fragment has moved here. Stop integration if plot function |
285 ## returns false | 287 ## returns false |
286 if (options.vhaveoutputfunction) | 288 if (options.vhaveoutputfunction) |
287 for vcnt = 0:options.Refine # Approximation between told and t | 289 for vcnt = 0:options.Refine # Approximation between told and t |
288 if (options.vhaverefine) # Do interpolation | 290 if (options.vhaverefine) # Do interpolation |
289 vapproxtime = (vcnt + 1) / (options.Refine + 2); | 291 vapproxtime = (vcnt + 1) / (options.Refine + 2); |
298 vapproxvals = vapproxvals(options.OutputSel); | 300 vapproxvals = vapproxvals(options.OutputSel); |
299 endif | 301 endif |
300 vpltret = feval (options.OutputFcn, vapproxtime, | 302 vpltret = feval (options.OutputFcn, vapproxtime, |
301 vapproxvals, [], options.vfunarguments{:}); | 303 vapproxvals, [], options.vfunarguments{:}); |
302 if (vpltret) # Leave refinement loop | 304 if (vpltret) # Leave refinement loop |
303 break | 305 break; |
304 endif | 306 endif |
305 endfor | 307 endfor |
306 if (vpltret) # Leave main loop | 308 if (vpltret) # Leave main loop |
307 solution.vunhandledtermination = false; | 309 solution.vunhandledtermination = false; |
308 break | 310 break; |
309 endif | 311 endif |
310 endif | 312 endif |
311 | 313 |
312 ## Call event only if a valid result has been found, therefore this | 314 ## Call event only if a valid result has been found, therefore this |
313 ## code fragment has moved here. Stop integration if veventbreak is | 315 ## code fragment has moved here. Stop integration if veventbreak is |
314 ## true | 316 ## true |
315 if (options.vhaveeventfunction) | 317 if (options.vhaveeventfunction) |
316 solution.vevent = odepkg_event_handle (options.Events, t(end), | 318 solution.vevent = odepkg_event_handle (options.Events, t(end), |
317 x(:,end), [], options.vfunarguments{:}); | 319 x(:,end), [], |
320 options.vfunarguments{:}); | |
318 if (! isempty (solution.vevent{1}) | 321 if (! isempty (solution.vevent{1}) |
319 && solution.vevent{1} == 1) | 322 && solution.vevent{1} == 1) |
320 t(solution.vcntloop-1,:) = solution.vevent{3}(end,:); | 323 t(solution.vcntloop-1,:) = solution.vevent{3}(end,:); |
321 x(:,solution.vcntloop-1) = solution.vevent{4}(end,:)'; | 324 x(:,solution.vcntloop-1) = solution.vevent{4}(end,:)'; |
322 solution.vunhandledtermination = false; | 325 solution.vunhandledtermination = false; |
323 break | 326 break; |
324 endif | 327 endif |
325 endif | 328 endif |
326 | 329 |
327 else | 330 else |
328 | 331 |
335 dt = dt * min (facmax, | 338 dt = dt * min (facmax, |
336 max (facmin, fac * (1 / err)^(1 / (order + 1)))); | 339 max (facmin, fac * (1 / err)^(1 / (order + 1)))); |
337 dt = vdirection * min (abs (dt), options.MaxStep); | 340 dt = vdirection * min (abs (dt), options.MaxStep); |
338 | 341 |
339 ## Update counters that count the number of iteration cycles | 342 ## Update counters that count the number of iteration cycles |
340 solution.vcntcycles = solution.vcntcycles + 1; # Needed for cost statistics | 343 solution.vcntcycles += 1; # Needed for cost statistics |
341 vcntiter = vcntiter + 1; # Needed to find iteration problems | 344 vcntiter += 1; # Needed to find iteration problems |
342 | 345 |
343 ## Stop solving because in the last 1000 steps no successful valid | 346 ## Stop solving because in the last 1000 steps no successful valid |
344 ## value has been found | 347 ## value has been found |
345 if (vcntiter >= 5000) | 348 if (vcntiter >= 5000) |
346 error (["Solving has not been successful. The iterative", | 349 error (["Solving has not been successful. The iterative", |
347 " integration loop exited at time t = %f before endpoint at", | 350 " integration loop exited at time t = %f before endpoint at", |
348 " tend = %f was reached. This happened because the iterative", | 351 " tend = %f was reached. This happened because the iterative", |
349 " integration loop does not find a valid solution at this time", | 352 " integration loop does not find a valid solution at this time", |
350 " stamp. Try to reduce the value of ''InitialStep'' and/or", | 353 " stamp. Try to reduce the value of 'InitialStep' and/or", |
351 " ''MaxStep'' with the command ''odeset''.\n"], | 354 " 'MaxStep' with the command 'odeset'.\n"], |
352 s(end), tspan(end)); | 355 s(end), tspan(end)); |
353 endif | 356 endif |
354 | 357 |
355 ## if this is the last iteration, save the length of last interval | 358 ## if this is the last iteration, save the length of last interval |
356 if (counter > k) | 359 if (counter > k) |
360 | 363 |
361 ## Check if integration of the ode has been successful | 364 ## Check if integration of the ode has been successful |
362 if (vdirection * z(end) < vdirection * tspan(end)) | 365 if (vdirection * z(end) < vdirection * tspan(end)) |
363 if (solution.vunhandledtermination == true) | 366 if (solution.vunhandledtermination == true) |
364 error ("OdePkg:InvalidArgument", | 367 error ("OdePkg:InvalidArgument", |
365 ["Solving has not been successful. The iterative", | 368 ["Solving has not been successful. The iterative", |
366 " integration loop exited at time t = %f", | 369 " integration loop exited at time t = %f", |
367 " before endpoint at tend = %f was reached. This may", | 370 " before endpoint at tend = %f was reached. This may", |
368 " happen if the stepsize grows smaller than defined in", | 371 " happen if the stepsize grows smaller than defined in", |
369 " vminstepsize. Try to reduce the value of ''InitialStep''", | 372 " vminstepsize. Try to reduce the value of 'InitialStep'", |
370 " and/or ''MaxStep'' with the command ''odeset''.\n"], | 373 " and/or 'MaxStep' with the command 'odeset'.\n"], |
371 z(end), tspan(end)); | 374 z(end), tspan(end)); |
372 else | 375 else |
373 warning ("OdePkg:InvalidArgument", | 376 warning ("OdePkg:InvalidArgument", |
374 ["Solver has been stopped by a call of ''break'' in the main", | 377 ["Solver has been stopped by a call of 'break' in the main", |
375 " iteration loop at time t = %f before endpoint at tend = %f ", | 378 " iteration loop at time t = %f before endpoint at tend = %f ", |
376 " was reached. This may happen because the @odeplot function", | 379 " was reached. This may happen because the @odeplot function", |
377 " returned ''true'' or the @event function returned", | 380 " returned 'true' or the @event function returned", |
378 " ''true''.\n"], | 381 " 'true'.\n"], |
379 z(end), tspan(end)); | 382 z(end), tspan(end)); |
380 endif | 383 endif |
381 endif | 384 endif |
382 | 385 |
383 ## Compute how many values are out of time inerval | 386 ## Compute how many values are out of time inerval |
387 ## Remove not-requested values of time and solution | 390 ## Remove not-requested values of time and solution |
388 solution.t = t(1:end-f); | 391 solution.t = t(1:end-f); |
389 solution.x = x(:,1:end-f)'; | 392 solution.x = x(:,1:end-f)'; |
390 | 393 |
391 endfunction | 394 endfunction |
395 |