1function [T, Y] = lsoda_solve(odefun, tspan, y0, options)
2% LSODA_SOLVE Solve ODE system
using LSODA (
auto stiff/nonstiff switching)
4% [T, Y] = lsoda_solve(odefun, tspan, y0)
5% [T, Y] = lsoda_solve(odefun, tspan, y0, options)
7% Solves the ODE system dy/dt = odefun(t,y) from tspan(1) to tspan(end).
8% LSODA automatically switches between nonstiff (Adams) and stiff (BDF)
9% methods based on the problem behavior.
12% odefun - Function handle @(t,y) returning column vector dy/dt
13% tspan - Time span [t0 tf] or vector of output times [t0 t1 ... tf]
14% y0 - Initial conditions (column vector)
15% options - (optional) struct with fields:
16% .RelTol - Relative tolerance (scalar or vector, default 1e-6)
17% .AbsTol - Absolute tolerance (scalar or vector, default 1e-9)
18% .MaxStep - Maximum internal steps per interval (default 5000)
19% .MaxOrdNonStiff - Max order for Adams method (1-12, default 12)
20% .MaxOrdStiff - Max order for BDF method (1-5, default 5)
23% T - Column vector of output times
24% Y - Solution matrix (length(T) x length(y0))
27% f = @(t,y) [-0.04*y(1) + 1e4*y(2)*y(3);
28% 0.04*y(1) - 1e4*y(2)*y(3) - 3e7*y(2)^2;
30% [T, Y] = lsoda_solve(f, [0 4e10], [1; 0; 0]);
32% Based on LSODA by L.R. Petzold and A.C. Hindmarsh (LLNL).
33% C implementation from liblsoda (MIT License).
35 % Ensure y0
is a column vector
38 % Handle tspan: if only [t0 tf], pass directly to MEX for adaptive
39 % stepping (itask=2 mode collects all internal solver steps).
40 % If >2 elements, integrate to each prescribed output time (itask=1).
51 mxordn = 0; % 0 = use library default (12)
52 mxords = 0; % 0 = use library default (5)
54 if nargin >= 4 && ~isempty(options)
55 if isfield(options, 'RelTol'), rtol = options.RelTol; end
56 if isfield(options, 'AbsTol'), atol = options.AbsTol; end
57 if isfield(options, 'MaxStep'), mxstep = options.MaxStep; end
58 if isfield(options, 'MaxOrdNonStiff'), mxordn = options.MaxOrdNonStiff; end
59 if isfield(options, 'MaxOrdStiff'), mxords = options.MaxOrdStiff; end
63 thisDir = fileparts(mfilename('fullpath'));
64 mexName = ['lsoda_mex.' mexext];
65 if ~exist(fullfile(thisDir, mexName), 'file')
66 fprintf('lsoda_mex not found, building...\n');
77 % Call the MEX function
78 [T, Y] = lsoda_mex(odefun, tspan, y0, rtol, atol, mxstep, mxordn, mxords);