1function [x, it, converged] = da_fpi(iterfun, x0, options)
2% [X,IT,CONVERGED] = DA_FPI(ITERFUN, X0, OPTIONS)
4% Generic damped successive-substitution driver
for decomposition-
5% aggregation (DA) fixed-point iterations. Each call to ITERFUN performs
6% one DA sweep: solve
the isolated submodels given
the current coupling
7% iterate X, exchange flows or rates, and
return the updated iterate.
9% ITERFUN: function handle [XNEW, XREF] = ITERFUN(X, IT) evaluating one DA
10% sweep from iterate X at iteration
count IT. XREF
is the baseline
11%
for the convergence test;
return XREF = X
for a standard
12% successive-substitution test, or a mid-sweep checkpoint when
the
13% method compares against a renormalized iterate.
14% X0: initial iterate (any numeric array).
15% OPTIONS: solver options
struct; uses iter_max and iter_tol, plus
the
16% optional fields config.da_damping in (0,1] (
default 1, i.e.
17% undamped), config.da_norm (function handle mapping
the iterate
18% difference to a scalar,
default @(d) max(abs(d(:))); a two-
19% argument handle
is called as da_norm(xnew, xref) instead, e.g.
20%
for relative-difference tests), config.da_miniter (
default 1):
21% convergence
is not tested before
this sweep
count, and
22% config.da_nanstop (
default false): when
true, a NaN convergence
23% measure terminates
the iteration, replicating legacy
while-loop
24% drivers whose
"continue while delta > tol" test exits on NaN;
25% when
false a NaN measure keeps iterating, as in legacy
26%
"break if delta < tol" drivers.
28% Returns
the final iterate X,
the number IT of sweeps executed, and a
29% CONVERGED flag (
false if the iteration stopped at iter_max).
31% Copyright (c) 2012-2026, Imperial College London
35normfun = @(d) max(abs(d(:)));
38if isfield(options,
'config')
39 if isfield(options.config, 'da_damping') && ~isempty(options.config.da_damping)
40 omega = options.config.da_damping;
42 if isfield(options.config, 'da_norm') && ~isempty(options.config.da_norm)
43 normfun = options.config.da_norm;
45 if isfield(options.config, 'da_nanstop') && ~isempty(options.config.da_nanstop)
46 nanstop = options.config.da_nanstop;
48 if isfield(options.config, 'da_miniter') && ~isempty(options.config.da_miniter)
49 miniter = options.config.da_miniter;
52twoargnorm = nargin(normfun) == 2;
57for it = 1:options.iter_max
58 [xnew, xref] = iterfun(x, it);
60 xnew = (1 - omega) * xref + omega * xnew;
63 delta = normfun(xnew, xref);
65 delta = normfun(xnew - xref);
69 if delta < options.iter_tol
72 elseif nanstop && isnan(delta)