1 classdef PODEI < Greedy.Plugin.Interface
3 % the reduced basis space and/or the collateral reduced basis space(s).
5 % As an error indicator it uses the error indicator of the reduced numerical
6 % scheme, with the ambition to
"optimize" all spaces
for best output in the
7 %
final solutions `u_{\text{red}}(\mu)`.
9 properties(Constant, Hidden=
true)
11 % cell array of field names whose values shall be copied to the generated
12 % Greedy.DataTree.Detailed.PODEILeafNode instance.
14 'Mmax_small',
'error_differences_for_extension', ...
15 'M_by_N_ratio',
'bad_extension_on_explosion', ...
16 'maximum_temporary_error_growth_factor',
'discard_last_rb_after_bad_extension', ...
17 'skip_rb_after_bad_extension',
'skip_ei_after_bad_extension' ...
48 % number of collateral reduced of the initial collateral reduced basis.
50 % In order to use the estimator of a nonlinear evolution equation
for a
51 % basis extension with a greedy search in the parameter space, a collateral
52 % reduced basis space
for all existing operators needs to be present. For
53 %
this reason at the beginning of the basis generation algorithm, a
54 % collateral reduced bases of size at most
'Mmax_small' is generated
57 %
boolean flag indicating to use largest error difference over time steps
58 % in order to select snapshot
for collateral reduced basis extension.
60 % In order to extend the collateral reduced basis spaces, we need to select
61 % one snapshot indexed by `k_{\max}` from the sequence of possible vectors
62 % `v_h(t^{k},\mu_{\max}) \in {\cal W}_h`. If
this flag is
set to
'true',
63 % `k_{\max} = \arg \max_{k=1,\ldots,K} \eta^k(\mu_{\max}) -
64 % \eta^{k-1}(\mu_{\max})`.
66 % Otherwise `k_{\max}` is determind as the time step of the maximum error
68 error_differences_for_extension = false;
70 % forced ratio between the sizes of the colletaral and the regular reduced
73 % If the ratio is too low before a basis extension, only the collateral
74 % reduced basis space is extended.
76 % Its purpose is to make the collateral reduced basis space more refined
77 % than the reduced basis space. This is necessary as the best possible
78 % error for the basis generation of the reduced basis space @em depends on
79 % the quality of the collateral reduced basis space.
82 %
boolean flag indicating whether in an @em explosion is a bad extension.
84 % See also: indicate_bad_basis_extension() for details.
85 bad_extension_on_explosion = false;
87 % maximum factor between the current maximum indicator and the smallest
88 % maximum error indicator during previous extensions
90 % See indicate_bad_basis_extension() for details.
91 maximum_temporary_error_growth_factor = 0;
93 %
boolean flag specifying whether the last generated reduced basis vector
94 % should be discarded after a bad extension is indicated by
95 % indicate_bad_basis_extension().
97 % See indicate_bad_basis_extension() and basis_extension() for details.
98 discard_last_rb_after_bad_extension = true;
100 %
boolean flag specifying whether the current reduced basis extension
101 % should be skipped after a bad extension is indicated by
102 % indicate_bad_basis_extension().
104 % See indicate_bad_basis_extension() and basis_extension() for details.
105 skip_rb_after_bad_extension = true;
107 %
boolean flag specifying whether the current collateral reduced basis
108 % extension should be skipped after a bad extension is indicated by
109 % indicate_bad_basis_extension().
111 % See indicate_bad_basis_extension() and basis_extension() for details.
112 skip_ei_after_bad_extension = false;
116 % @copybrief Greedy::
Interfacegenerated_basis_type
118 % This is set to 'eirb'.
120 % @sa Greedy::
Interfacegenerated_basis_type
121 generated_basis_type = 'eirb';
124 properties(Access = public)
125 %
object of type Greedy.Plugin::
PODCommon used for extension of the reduced basis space.
128 %
object of type Greedy.Plugin::
EICommon used for extension of the collateral reduced
129 % basis space(s) and providing an error estimator
132 %
object of type Greedy::
Algorithm used for initial creation of
133 % collateral reduced basis space(s)
135 % See
#Mmax_small for details
140 function crbeie =
PODEI(rb_extension, ei_extension, ei_init_greedy, Mmax_small)
141 %
function crbeie =
PODEI(rb_extension, ei_extension, ei_init_greedy, Mmax_small)
142 % constructor
for a combined extension algorithm
for reduced and
143 % collateral reduced basis spaces.
147 % extend the reduced basis space and providing an error
150 % extend the collateral reduced basis space(s).
152 % initial creation of collateral reduced basis space(s)
154 assert(isa(rb_extension, 'Greedy.Plugin.
PODCommon'));
155 assert(isa(ei_extension, 'Greedy.Plugin.
EICommon'));
156 crbeie = crbeie@Greedy.Plugin.
Interface(rb_extension.generator);
157 crbeie.rb_ext = rb_extension;
158 crbeie.ei_ext = ei_extension;
159 crbeie.ei_init_greedy = ei_init_greedy;
160 crbeie.Mmax_small = Mmax_small;
163 function needs_prepare = get.needs_preparation(this)
164 needs_prepare = this.rb_ext.needs_preparation;
167 function ret = get.indicator_mode(this)
168 ret = this.rb_ext.indicator_mode;
171 function ret = get.use_l2_error(this)
172 ret = this.rb_ext.use_l2_error;
175 function ret = get.relative_error(this)
176 ret = this.rb_ext.relative_error;
179 function this=set.indicator_mode(this, value)
180 this.ei_ext.indicator_mode=value;
181 this.rb_ext.indicator_mode=value;
184 function this=set.use_l2_error(this, value)
185 this.ei_ext.use_l2_error=value;
186 this.rb_ext.use_l2_error=value;
189 function this=set.relative_error(this, value)
190 this.ei_ext.relative_error=value;
191 this.rb_ext.relative_error=value;
194 function detailed_data = init_basis(this, rmodel, model_data, M_train)
195 % function detailed_data = init_basis(this, rmodel, model_data, M_train)
196 % @copybrief Greedy.Plugin::
Interfaceinit_basis()
198 % @copydetails Greedy.Plugin::
Interfaceinit_basis()
204 % detailed_data:
object of type Greedy.DataTree.Detailed.PODEILeafNode
207 % -
# starts Greedy.Algorithm.gen_detailed_data() on the
208 % #ei_init_greedy member in order to compute initial collateral
209 % reduced basis space(s)
210 % -# creates a history Greedy.DataTree.Detailed.INode.snapshot() afterwards
211 % -# calls Greedy.Plugin.PODCommon.init_basis() on the 'rb_ext' instance
212 detailed_data = Greedy.DataTree.Detailed.PODEILeafNode(model_data, true);
213 set_fields(detailed_data,
this, Greedy.Plugin.PODEI.info_fields);
215 assert(rmodel.crb_enabled);
217 if isfield(rmodel.bg_descr,
'stop_Mmax')
218 Mmax_backup = rmodel.bg_descr.stop_Mmax;
222 this.ei_init_greedy.detailed_extension.stop_Mmax = this.Mmax_small;
223 detailed_data.ei = gen_detailed_data(this.ei_init_greedy, rmodel, model_data, []);
224 snapshot(detailed_data.ei, 'ei_init_basis', ...
225 sprintf(['Initialization of empirical interpolation basis on a coarse parameter grid\n',...
226 'and small epsilon tolerance or maximum basis size']),...
228 % clear all stop flags, because they might lead to wrong behavior
230 detailed_data.ei.stop_flags = {};
232 if ~isempty(Mmax_backup)
233 rmodel.bg_descr.stop_Mmax = Mmax_backup;
234 detailed_data.ei.fields.stop_Mmax = Mmax_backup;
237 % update the value for M! Now we need to subtract the Mstrich value
238 if isa(rmodel.M, 'DataTree.INode')
239 if isa(reduced_data.M, 'DataTree.INode')
240 rmodel.M = create_scalar_tree(reduced_data.M, @(x) get(x,1) - rmodel.Mstrich);
242 assert(rmodel.Mstrich == 0 || rmodel.M > rmodel.Mstrich);
243 rmodel.M = reduced_data.M - rmodel.Mstrich;
247 tree_descr = get_leaf_description(detailed_data.ei);
248 for leaf_descr = tree_descr
249 leaf = get(detailed_data.ei, leaf_descr.basepath);
250 set_field(
leaf, 'target_error_external', true);
253 detailed_data.rb = init_basis(this.rb_ext, rmodel, model_data, M_train);
256 function prepare_reduced_data(this, rmodel, detailed_data)
257 % function prepare_reduced_data(this, rmodel, detailed_data)
258 % @copybrief Greedy.Plugin::
Interfaceprepare_reduced_data()
260 % @copydetails Greedy.Plugin::
Interfaceprepare_reduced_data()
262 prepare_reduced_data(this.rb_ext, rmodel, detailed_data);
263 % if this.ei_ext.needs_preparation
264 % prepare_reduced_data(this.ei_ext, rmodel, detailed_data);
268 function [max_errs, max_err_seq, max_mu_index] = error_indicators(this, rmodel, detailed_data, parameter_set, reuse_reduced_data)
269 % function [max_errs, max_err_seq, max_mu_index] = error_indicators(this, rmodel, detailed_data, parameter_set, reuse_reduced_data)
270 % @copybrief Greedy.Plugin::
Interfaceerror_indicators()
272 % @copydetails Greedy.Plugin::
Interfaceerror_indicators()
276 % detailed_data: an
object of type Greedy.DataTree.Detailed.PODEILeafNode
278 % This function calls the Greedy.Plugin::
Interfaceerror_indicators() method of the
281 reuse_reduced_data = [];
283 [max_errs, max_err_seq, max_mu_index] = error_indicators(this.rb_ext, rmodel, detailed_data, parameter_set, reuse_reduced_data);
286 function errs = compute_error(
this, rmodel, reduced_data, detailed_data)
287 %
function errs = compute_error(
this, rmodel, detailed_data)
297 % the
#rb_ext member.
298 errs = compute_error(this.rb_ext, rmodel, reduced_data, detailed_data);
301 function Uapprox = generate_reduced(
this, rmodel, reduced_data, detailed_data, U)
302 %
function Uapprox = generate_reduced(
this, rmodel, reduced_data, detailed_data, U)
313 Uapprox = generate_reduced(this.rb_ext, rmodel, reduced_data, detailed_data);
316 function [breakloop, reason] = pre_check_for_end(
this, rmodel, detailed_data)
317 %
function [breakloop, reason] = pre_check_for_end(
this, rmodel, detailed_data)
325 % This
function only indicates a basis extension stop
if both parts are
328 max_err_sequence = get_field(detailed_data,
'max_err_sequence');
329 ext_step = length(max_err_sequence);
331 [breakloop_rb, reason_rb] = pre_check_for_end(this.rb_ext, rmodel, detailed_data.rb);
332 [breakloop_ei, reason_ei] = pre_check_for_end(this.ei_ext, rmodel, detailed_data.ei);
334 breakloop = breakloop_rb & breakloop_ei;
336 % special
case:
EI skipped
for two small residual, and RB could not be
337 % extended => no strategy to
get away...
338 ei_skip_small_residual = get_field(detailed_data.ei,
'ei_skipped_for_too_small_residual', 0);
339 if breakloop_rb && ~breakloop_ei ...
340 && ei_skip_small_residual(end) == ext_step-1
342 set_stop_flag(detailed_data.ei,
'stopping_on_too_small_residual');
343 reason_ei =
'EI extension skipped because of too small residual.';
345 reason = [reason_rb, ' ', reason_ei];
348 function detailed_data = basis_extension(
this, rmodel, detailed_data, max_err_seq, mu)
349 %
function detailed_data = basis_extension(
this, rmodel, detailed_data, max_err_seq, mu)
354 % This
function first extends the collateral reduced basis space unless
355 % -# Greedy.Plugin.EI.pre_check_for_end() returned 'false'
356 % -# the last extension was "bad" as indicated by
357 % indicate_bad_basis_extension() and #skip_ei_after_bad_extension is
359 % -# the extension fails (e.g. because of
360 % Greedy.Plugin::
EIminimum_residual)
362 % Afterwards, this function extends the reduced basis space unless
363 % -# Greedy.Plugin.PODCommon.pre_check_for_end() returned 'false'
364 % -# the last extension was "bad" as indicated by
365 % indicate_bad_basis_extension() and #skip_rb_after_bad_extension of
366 % #discard_last_rb_after_bad_extension are enabled
367 % -# the 'M/N'-ratio condition as described in #M_by_N_ratio failed
368 % -# reduced simulations returned 'NaN' error indicators
370 % In the second case and with enabled
371 % #discard_last_rb_after_bad_extension option the last generated reduced
372 % basis is discarded if
373 % -# since the last discard at least two extensions have been
377 % rmodel: an object of type IReducedModel
378 % detailed_data: an object of type Greedy.DataTree.Detailed.PODEILeafNode
381 % detailed_data: an object of type Greedy.DataTree.Detailed.PODEILeafNode
384 max_extension_errs = get_field(detailed_data, 'max_extension_errs', 0);
385 last_extension_bad = indicate_bad_basis_extension(
this, detailed_data);
387 % extension step number
388 ext_step = length(max_extension_errs);
390 % check whether the ei extension is ready
391 [ei_breakloop, ei_reason] = pre_check_for_end(this.ei_ext, rmodel, detailed_data.ei);
393 Msize = get_ei_size(detailed_data.ei);
395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
396 %
EI extension checks start %
397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
399 % only update basis spaces
if end check is negative
400 ei_ext_steps = get_field(detailed_data,
'ei_ext_steps', 0);
402 if rmodel.verbose > 1
403 disp(
'[1]> Skipping EI extension step, because pre_check_for_end() returned true');
405 if rmodel.verbose > 5
406 disp([
'[5]> ', ei_reason]);
408 append_field(detailed_data.ei,
'ei_skipped_for_check_end', ext_step);
410 %
do not update basis space
if last extension was bad and skipping is requested
411 elseif last_extension_bad && get_field(detailed_data,
'skip_ei_after_bad_extension') ...
412 && ei_ext_steps(end) == ext_step - 1
415 disp('[1]> Skipping
EI extension step after bad extension');
417 append_field(
'ei_skipped_for_bad_extension', ext_step);
420 % compute error indicator
for snapshot selection
421 if get_field(detailed_data,
'error_differences_for_extension') && ~any(isnan(max_err_seq));
422 ei_errs = max_err_seq(2:end) - max_err_seq(1:end-1);
425 prepare_reduced_data(this.ei_ext, rmodel, detailed_data.ei);
427 ei_errs = compute_error(this.ei_ext, rmodel, [], detailed_data.ei);
430 %%%%%%%%%%%%%%%%%%%%%% extend
EI basis %%%%%%%%%%%%%%%%%%%%%
431 append_field(detailed_data,
'ei_errs', ei_errs);
432 append_field(detailed_data,
'ei_max_err', max(ei_errs));
434 this.ei_ext.target_error_external = 1;
435 detailed_data.ei = basis_extension(this.ei_ext, rmodel, detailed_data.ei, ei_errs, mu);
436 newMsize = get_ei_size(detailed_data.ei);
438 % skip ei
if residual is too small
440 append_field(detailed_data,
'ei_skipped_for_too_small_residual', ext_step);
442 if rmodel.verbose > 1
443 disp(
'[1]> Skipping EI extension because of too small residual.');
447 append_field(detailed_data,
'ei_ext_count', newMsize - Msize);
448 % update the info structure
450 append_field(detailed_data,
'ei_ext_steps', ext_step);
454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
455 %
EI extension checks end %
456 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
459 % reduced basis extension
460 Nsize = get_rb_size(detailed_data);
461 M_by_N = Msize / Nsize;
463 [rb_breakloop, rb_reason] = pre_check_for_end(this.rb_ext, rmodel, detailed_data.rb);
466 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
467 % RB extension checks start %
468 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
469 rb_ext_steps = get_field(detailed_data,
'rb_ext_steps');
470 rb_discarded_for_bad_extension = get_field(detailed_data,
'rb_discarded_for_bad_extension', []);
472 if rmodel.verbose > 1
473 disp(
'[1]> Skipping RB extension step, because pre_check_for_end() returned true');
475 if rmodel.verbose > 5
476 disp([
'[5]> ',rb_reason]);
478 append_field(detailed_data,
'rb_skipped_for_check_end', ext_step);
480 % on error increase only update the rb space
481 if last_extension_bad
482 if get_field(detailed_data,
'discard_last_rb_after_bad_extension') ...
483 && rb_ext_steps(end) == ext_step -1 ...
484 && length(rb_ext_steps) > 2 ...
485 && (isempty(rb_discarded_for_bad_extension) ...
486 || rb_ext_steps(end-1) > rb_discarded_for_bad_extension(end))
488 append_field(detailed_data, 'rb_discarded_for_bad_extension', ext_step);
489 delete_rb(detailed_data, Nsize);
490 if rmodel.verbose > 1
491 disp(
'[1]> Discarding last RB vector after bad extension step');
493 elseif this.skip_rb_after_bad_extension
494 append_field(detailed_data,
'rb_skipped_for_bad_extension', ext_step);
495 if rmodel.verbose > 1
496 disp(
'[1]> Skipping RB extension after bad extension step');
499 % only update rb basis space
if the M_by_N_ratio is fulfilled
500 elseif ~ei_breakloop && M_by_N < get_field(detailed_data,
'M_by_N_ratio')
501 append_field(detailed_data, 'rb_skipped_for_M_by_N_ratio_restriction', ext_step);
504 disp('[1]> Skipping RB extension because of M_by_N_ratio');
506 % if reduced simulations failed we have a big problem! :(
507 elseif any(isnan(max_err_seq))
508 append_field(detailed_data, 'rb_skipped_for_failed_simulation', ext_step);
510 error('Can''t extend either
EI nor RB reduced basis space');
513 % otherwise: Do a normal basis extension
515 detailed_data = basis_extension(this.rb_ext, rmodel, detailed_data, max_err_seq, mu);
516 append_field(detailed_data, 'rb_ext_steps', ext_step);
519 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
520 % RB extension checks end %
521 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
525 function detailed_data = finalize(this, rmodel, detailed_data)
526 % function detailed_data = finalize(this, rmodel, detailed_data)
527 % @copybrief Greedy.Plugin::
Interfacefinalize()
529 % @copydetails Greedy.Plugin::
Interfacefinalize()
533 % detailed_data: an
object of type Greedy.DataTree.Detailed.PODEILeafNode
536 % detailed_data: an
object of type Greedy.DataTree.Detailed.PODEILeafNode
539 % -
# the finalize() method of the #ei_ext member and
540 % -# the finalize() method of the #rb_ext member
542 detailed_data.ei = finalize(this.ei_ext, rmodel, detailed_data.ei);
543 detailed_data.rb = finalize(this.rb_ext, rmodel, detailed_data.rb);
548 methods(Access=
public)
550 function isbad = indicate_bad_basis_extension(this, detailed_data)
551 % function isbad = indicate_bad_basis_extension(this, detailed_data)
552 % indicates whether the last basis extension was bad
554 % The last basis extension is bad if the maximum error indicator is
555 % larger than in the step before.
557 % Furthermore, we test if the maximum error indicator is `f` times larger
558 % than the minimum error indicated at any extension step before. In this
559 % case we say, the event @em explosion has occured.
561 % If
#maximum_temporary_error_growth_factor equals '0', the explosion
564 % The explosion test can affect the the assessment of a @em bad @em
565 % extension in the following way dependent on the option
566 % #bad_extension_on_explosion:
567 % - If #bad_extension_on_explosion is set to true, an @em explosion is
568 % also an indicator for a bad extension.
569 % - If #bad_extension_on_explosion is set to false, for an @em
570 % explosion true is returned.
572 % The latter option assumes that an explosion of the error indicates that
573 % lately introduced complexity by more accurate empirical interpolation
574 % operators is not captured by the current reduced basis yet.
576 % In the @em explosion test the factor `f` is defined by
577 % ``f = c_{\text{max\_temp\_err\_growth}} \cdot \frac{1}{n_{\text{no\_rb\_ext}}}``
578 % with a constant `c_{\text{max\_temp\_err\_growth}}` given by
579 % #maximum_temporary_error_growth_factor and a weighting factor
580 % determined by the number of extension steps withouth reduced
581 % basis extension `n_{\text{no\_rb\_ext}}`.
584 % isbad: a
boolean value indicating whether the last extension was bad.
586 max_extension_errs = get_field(detailed_data,
'max_err_sequence');
588 ext_step = length(max_extension_errs);
590 isbad = (length(max_extension_errs) > 1 && (max_extension_errs(end) > max_extension_errs(end-1)));
592 max_temp_error_growth_factor = get_field(detailed_data,
'maximum_temporary_error_growth_factor');
593 rb_ext_steps = get_field(detailed_data,
'rb_ext_steps', 0);
594 if max_temp_error_growth_factor > 0
595 is_explosion = length(max_extension_errs) > 1 && max_extension_errs(end) < ...
596 max_temp_error_growth_factor/(ext_step - rb_ext_steps(end)) ...
597 * min(max_extension_errs);
598 if get_field(detailed_data,
'bad_extension_on_explosion')
599 isbad = isbad | is_explosion;
601 isbad = isbad & is_explosion;