rbmatlab 0.10.01
general/+Postprocess/+StochasticAssessment/Assessment.m
00001 classdef Assessment < handle
00002   % a class used to compute reduced several reduced simulations over a huge
00003   % parameter sample extracting useful information
00004   %
00005   % The class generates one or two dimensional cell arrays of these data fields
00006   % storing information for a variation of some attributes of the reduced
00007   % model, which can be freely chosen by specification of #plot_fields .
00008 
00009   properties(Access=public)
00010     % is a vector of field names with at most 2 elements over which the error
00011     % landscape is computed or a cell with empty entries.
00012     %
00013     % A reasonable choice would be '{ \'N\', \'M\' }'. The error landscape is
00014     % plotted over a variation of these fields specified by samples.
00015     % In case of an empty cell entry, 'N' and 'M' are coupled by the fixed
00016     % ratio #M_by_N_ratio and samples should be a vector of coupling constant
00017     % between 0 and 1. See also: update_rmodel()
00018     %
00019     % @default = '{[]}'
00020     plot_fields = {[]};
00021 
00022     % is a cell array of scalar row vectors. The scalar values are 'plot_field'
00023     % values for which the error is computed and tested.
00024     %
00025     % @default = '{[0.1:0.1:1]}'
00026     samples = {(0.1:0.1:1)};
00027 
00028     % an parameter sampling object of type ParameterSampling.Interface
00029     %
00030     % @default is a random sampling with 10 elements and seed 654321;
00031     %
00032     % See also: init_random_sampling()
00033     M_test;
00034 
00035     % is a cell array of description texts for the plot fields.  If this field
00036     % is not set it is set to 'plot_fields'.
00037     plot_field_descr = {};
00038 
00039 
00040     % character string specifying this test run. The string should be unique
00041     % for every parameter combination.
00042     %
00043     % @default rmodel.name + '_stoachastic_assessment';
00044     run_name;
00045 
00046     % boolean value determining whether error estimates shall be computed
00047     compute_estimates  = false;
00048 
00049     % boolean value determining whether the "true" error `\|u_h(\mu) -
00050     % u_{\text{red}}(\mu)\|_{{\cal W}_h}` shall be computed
00051     compute_errors     = false;
00052 
00053     % boolean value determining whether the condition numbers of the system
00054     % matrices shall be computed
00055     compute_conditions = false;
00056 
00057     % boolean value indicating whether the refinement steps of the reduced
00058     % basis generation by Greedy.TrainingSetAdaptation shall be taken into account
00059     %
00060     % This option is only useful if
00061     %   -# #M_test is set to the training sample of the parameter space
00062     %     generation and
00063     %   -# the #plot_fields include the basis dimensions
00064     % In this case the parameter sampling used during basis generation for the
00065     % given basis dimension is selected.
00066     follow_refinement_steps = false;
00067 
00068     % if M and N are couple this value specifies the constant for the coupling.
00069     %
00070     % A value of zero means `M_{\max} / N_{\max}`
00071     M_by_N_ratio = 1;
00072 
00073     % the underlying reduced model of type IReducedModel
00074     rmodel;
00075 
00076     % an object of type CacheableObject storing the reduced model and the
00077     % detailed data
00078     cache_object;
00079 
00080   end
00081 
00082   properties(Dependent)
00083     % the "real" collection of vectors used for the #plot_fields variation
00084     %
00085     % See also: #samples
00086     rsamples;
00087 
00088     % the underlying detailed data of type Greedy.DataTree.Detailed.INode
00089     %
00090     % @todo make this cached...
00091     detailed_data;
00092   end
00093 
00094   methods
00095 
00096     function dd = get.detailed_data(this)
00097       dd = this.cache_object.obj.detailed_data;
00098     end
00099 
00100     function rsamples = get.rsamples(this)
00101       if length(this.samples) == 2
00102         rsamples = combvec(this.samples{1},this.samples{2});
00103       else
00104         rsamples = this.samples{1};
00105       end
00106     end
00107 
00108     function sta = Assessment(matfile, rmodel, mu_set_size, seed)
00109       % function sta = Assessment(matfile, rmodel, mu_set_size, seed)
00110       % constructor
00111       %
00112       % Parameters:
00113       %   matfile:     name of result file where a IReducedModel object and a
00114       %                Greedy.DataTree.Detailed.INode object must be stored.
00115       %   mu_set_size: Optional argument determining the number of random
00116       %                parameters in the validation sample. (Default = 10)
00117       %   seed:        a random seed used for initialization of
00118       %                ParameterSampling.Random object for the #M_test parameter
00119       %                sample set. (Default = 654321)
00120 
00121       if nargin == 1 && isa(matfile, 'Postprocess.StochasticAssessment.Assessment')
00122         cp = matfile;
00123         m = metaclass(cp);
00124         fns = m.Properties(cellfun(@(x) ~isequal(x.SetAccess, 'none') && ~x.Dependent, m.Properties));
00125         fns = cellfun(@(x) x.Name, fns, 'UniformOutput', false);
00126         fns = setdiff(fns, {'cache_object'});
00127         for i = 1:length(fns);
00128           sta.(fns{i}) = cp.(fns{i});
00129         end
00130         sta.cache_object = CacheableObject(cp.cache_object.matfile, 'detailed_data');
00131         sta.rmodel       = copy(cp.rmodel);
00132       else
00133         sta.rmodel       = copy(rmodel);
00134         sta.cache_object = CacheableObject(matfile, 'detailed_data');
00135         if nargin <= 2
00136           mu_set_size = 10;
00137         end
00138         if nargin <= 3
00139           seed = 654321;
00140         end
00141         init_random_sampling(sta, mu_set_size, seed);
00142 
00143         if isempty(sta.plot_field_descr)
00144           sta.plot_field_descr = sta.plot_fields;
00145         else
00146           assert(length(sta.plot_field_descr) == length(sta.plot_fields));
00147         end
00148 
00149         sta.run_name = [rmodel.detailed_model.name, '_stochastic_assessment'];
00150       end
00151     end
00152 
00153     function output=compute(this)
00154       % function compute(this)
00155       % stochastic estimation of error between reduced and detailed simulation over a
00156       % test sample of `\mu` vectors
00157       %
00158       % This function stochastically estimates the error between reduced and detailed
00159       % simulations for given `\mu`-vectors and various reduced and collateral basis
00160       % sizes. The results are visualized in a surface plot for problems with CRB.
00161       %
00162       % If required by the users, averaged time measurements for the reduced and the
00163       % detailed simulations are computed, too.
00164       %
00165       % Return values:
00166       %   output: an Output object
00167 
00168       %if isequal(params.mode, 'error_ei')
00169       %  model.detailed_simulation = model.detailed_ei_simulation;
00170       %end
00171 
00172       %if isequal(params.mode, 'error_ei_rb_proj')
00173       %  model.detailed_simulation = model.detailed_ei_rb_proj_simulation;
00174       %end
00175 
00176       reduced_data = gen_reduced_data(this.rmodel, this.detailed_data);
00177 
00178       if this.compute_estimates
00179         assert(this.rmodel.Mstrich > 0);
00180         assert(this.rmodel.enable_error_estimator);
00181       else
00182         assert(~this.rmodel.enable_error_estimator);
00183         assert(this.rmodel.Mstrich == 0);
00184       end
00185 
00186       basis_gen = this.detailed_data.bg_algorithm;
00187       while ~isa(basis_gen, 'Greedy.Algorithm')
00188         switch(class(basis_gen))
00189           case 'Greedy.Combined'
00190             basis_gen = get_rb_basis_generator(basis_gen);
00191           case 'Greedy.TrainingSetAdaptation'
00192             basis_gen = basis_gen.child;
00193           otherwise
00194             error('nonono');
00195         end
00196       end
00197       generator = basis_gen.detailed_gen;
00198 
00199       if ~generator.is_valid
00200         generator = SnapshotsGenerator.Trajectories(this.rmodel.detailed_model);
00201       end
00202 
00203       % default value (only need for mode == 'check' when no 'mu_set_size' is given)
00204 
00205       savefile = [this.run_name];
00206       tmpfile  = [savefile,'_tmp.mat'];
00207       savefile = [savefile,'.mat'];
00208 
00209       rps_size = length(this.rsamples);
00210 
00211       complete_out = cell(1, rps_size);
00212 
00213       if this.compute_conditions
00214         rd_conds = cell(1, rps_size);
00215       else
00216         rd_conds = {};
00217       end
00218 
00219       for comb = 1:rps_size
00220 
00221         pf_val=this.rsamples(:,comb);
00222 
00223         for i=1:length(pf_val)
00224           update_rmodel(this, this.plot_fields{i}, pf_val(i));
00225         end
00226         temp_rd = extract_reduced_data_subset(this.rmodel, reduced_data);
00227 
00228         if this.compute_conditions
00229           rd_conds{comb} = get_conds(temp_rd);
00230         end
00231 
00232         disp(['Processing combination ', num2str(comb), '/', num2str(rps_size)]);
00233 
00234         M = this.get_test_space_sample;
00235         generator.prepare(this.rmodel.detailed_model, this.detailed_data.model_data, M);
00236         mu_size = size(M,1);
00237 
00238         part_out = struct('max_Delta'    , cell(1, mu_size), ...
00239                           'max_Delta_ind', cell(1, mu_size), ...
00240                           'max_err'      , cell(1, mu_size), ...
00241                           'max_err_ind'  , cell(1, mu_size), ...
00242                           'rtime'        , cell(1, mu_size), ...
00243                           'rrtime'       , cell(1, mu_size), ...
00244                           'dtime'        , cell(1, mu_size), ...
00245                           'rconds'       , cell(1, mu_size), ...
00246                           'dconds'       , cell(1, mu_size));
00247         %for mu_ind = 1:mu_size
00248         parfor mu_ind = 1:mu_size
00249           tthis        = this;
00250           trm          = this.rmodel;
00251           tdm          = trm.detailed_model;
00252           trd          = temp_rd;
00253           tgen         = generator;
00254 
00255           disp(['processing parameter vector ',num2str(mu_ind),...
00256             '/',num2str(size(M,1))]);
00257 
00258           set_mu(trm, M(mu_ind,:));
00259           set_mu(tdm, M(mu_ind,:));
00260 
00261           compute_out      = compute_impl(tthis, tgen, trm, trd);
00262 
00263           part_out(mu_ind) = compute_out;
00264         end
00265 
00266         complete_out{comb} = part_out;
00267 %        disp(['saving temporary workspace in ', tmpfile]);
00268 %        rmodel       = this.rmodel;
00269 %        detailed_data = this.detailed_data;
00270 %        save(fullfile(rbmatlabtemp,tmpfile), 'complete_out', 'part_out', 'this', 'rmodel', 'detailed_data', 'reduced_data');
00271 
00272       end
00273 
00274       if length(this.samples) == 2
00275         ns1 = length(this.samples{1});
00276         ns2 = rps_size / ns1;
00277         complete_out = reshape(complete_out, ns1, ns2);
00278         if this.compute_conditions
00279           rd_conds = reshape(rd_conds, ns1, ns2);
00280         end
00281       end
00282 
00283       output = Postprocess.StochasticAssessment.Output(complete_out, this);
00284       output.rd_conds = rd_conds;
00285 
00286       save(fullfile(rbmatlabresult, savefile));
00287 
00288     end
00289 
00290     function init_random_sampling(this, mu_set_size, seed)
00291       % function init_random_sampling(this, mu_set_size, seed)
00292       % generates the initial random sample set #M_test
00293       %
00294       % Parameters:
00295       %   mu_set_size: @copydoc ParameterSampling.Random.nparameters
00296       %   seed       : @copydoc ParameterSampling.Random.seed
00297 
00298       detailed_model = this.rmodel.detailed_model;
00299       this.M_test = ParameterSampling.Random(mu_set_size, seed);
00300       if this.M_test.init_required()
00301         init_sample(this.M_test, detailed_model);
00302       end
00303     end
00304 
00305     function other = copy(this)
00306       % function other = copy(this)
00307       % deep copy of this object
00308       %
00309       % Return values:
00310       %   other:  copied Assessment object
00311       other = Postprocess.StochasticAssessment.Assessment(this);
00312     end
00313 
00314     function equal_distribution_samples(this, min, max, sample_size)
00315       % function equal_distribution_samples(min, max, sample_size)
00316       % adapts the #samples attribute such that they are equally distributed in
00317       % a given range.
00318       %
00319       % Parameters:
00320       %   min:         is a vector of minimum values of 'plot_fields' variables.
00321       %   max:         is a vector for maximum values of 'plot_fields'
00322       %                variables.
00323       %   sample_size: specifies the number of sample values between 'min' and
00324       %                'max' for which the error is computed and plotted. The
00325       %                default value is 'max-min'.
00326 
00327       if nargin == 2
00328         sample_size = max-min;
00329       end
00330 
00331 
00332       assert(all(max > min));
00333 
00334       this.samples = cell(1,length(max));
00335       for i = 1:length(max)
00336         this.samples{i} = min(i) + ...
00337           round((0:sample_size(i)-1) .* ...
00338           (max(i)-min(i))./(sample_size(i)-1));
00339       end
00340     end
00341 
00342     function update_rmodel(this, plot_field, new_value)
00343       % function update_rmodel(this, plot_field, new_value)
00344       % updates the reduced model, i.e. applies the changes defined by the
00345       % #plot_fields attribute
00346       %
00347       % Parameters:
00348       %   plot_field:  an entry in #plot_fields, if it is empty, a coupling of
00349       %                'N' and 'M' is assured.
00350       %   new_value:   the new value it should be set to.
00351 
00352       if ~isempty(plot_field)
00353         this.rmodel.(plot_field) = new_value;
00354       else
00355         couple_N_and_M_by_c(this, new_value);
00356       end
00357 
00358       rmodel = this.rmodel;
00359       disp(['N = ', num2str(rmodel.N), ' M = ', num2str(rmodel.M), ' Mstrich = ', num2str(rmodel.Mstrich)]);
00360     end
00361 
00362 
00363   end
00364 
00365 
00366   methods(Static)
00367 
00368     function [rb_sim_data, tictoc] = rb_simulation_tictoc(varargin)
00369       % function [rb_sim_data, tictoc] = rb_simulation_tictoc(varargin)
00370       % a wrapper around the IReducedModel.rb_simulation() measuring the
00371       % execution time
00372       %
00373       % Return values:
00374       %   rb_sim_data:  the reduced simulation data
00375       %   tictoc:       execution time
00376       [rb_sim_data, tictoc] = tictoc_wrapper(@rb_simulation, varargin{:});
00377     end
00378 
00379 
00380   end
00381 
00382   methods(Access=private)
00383 
00384     function output =  compute_impl(this, generator, rmodel, reduced_data)
00385 
00386       fprintf('[');
00387 
00388       model_data = this.detailed_data.model_data;
00389 
00390       max_Delta     = NaN;
00391       max_Delta_ind = 0;
00392       max_err       = NaN;
00393       max_err_ind   = 0;
00394       dtime         = NaN;
00395       rtime         = NaN;
00396       rrtime        = NaN;
00397       rconds        = [];
00398       dconds        = [];
00399       rmodel.compute_conditions = this.compute_conditions;
00400       try
00401         [rb_sim_data,tictoc] = this.rb_simulation_tictoc(rmodel, reduced_data);
00402 
00403         fprintf('N');
00404         if this.compute_estimates
00405           Delta = rb_sim_data.Delta;
00406           [max_Delta, max_Delta_ind] = max(Delta);
00407         else
00408           max_Delta     = Inf;
00409         end
00410 
00411         if this.compute_conditions
00412           rconds = rb_sim_data.conds;
00413         else
00414           % condition computations may make time measurements bogus.
00415           rtime                = tictoc;
00416         end
00417 
00418         if this.compute_errors
00419           dmodel = rmodel.detailed_model;
00420           if this.compute_conditions
00421             fields = {'conds'};
00422             dmodel.compute_conditions = true;
00423           else
00424             fields = [];
00425           end
00426           [U_H, dtic_toc, opts] = generate(generator, dmodel, model_data, fields);
00427           fprintf('H');
00428           if this.compute_conditions
00429             dconds = opts.conds;
00430           else
00431             % condition computations may make time measurements bogus.
00432             dtime = dtic_toc;
00433           end
00434 
00435           tic;
00436           rb_sim_data = rb_reconstruction(rmodel, this.detailed_data, rb_sim_data);
00437           rrtime = toc;
00438           fprintf('R');
00439 
00440           errors      = dmodel.l2_error_sequence_algorithm(U_H, rb_sim_data.U, ...
00441             model_data);
00442           [max_err,max_err_ind] = max(errors);
00443         else
00444           max_err     = Inf;
00445         end
00446 
00447       catch ME
00448         warning(['catched an error: ', ME.message]);
00449         disp('setting error to NaN');
00450       end
00451       fprintf(']');
00452       output.max_Delta     = max_Delta;
00453       output.max_Delta_ind = max_Delta_ind;
00454       output.max_err       = max_err;
00455       output.max_err_ind   = max_err_ind;
00456       output.rtime         = rtime;
00457       output.rrtime        = rrtime;
00458       output.dtime         = dtime;
00459       output.rconds        = rconds;
00460       output.dconds        = dconds;
00461     end
00462 
00463 
00464     function couple_N_and_M_by_c(this, c)
00465       % function model = couple_N_and_M_by_c(model, c)
00466       % modifies the reduced basis size fields of 'model' by a single variable.
00467       %
00468       % Parameters:
00469       %  c:  sets the reduced basis sizes to
00470       %      `(N,M) = c (N_{\mbox{max}}, c_{MbyN} N_{\mbox{max}})`. For time-adaptive
00471       %      schemes with several collateral reduced basis spaces, the following
00472       %      formula is applied: `(N,M^k) = c (N_{\mbox{max}}), c_{MbyN}
00473       %      \frac{M^k_{\mbox{max}}}{\mbox{max}_{k=0,...,K} M^k_{\mbox{max}}}
00474       %      N_{\mbox{max}}.`
00475 
00476       Nmax      = get_rb_size(this.detailed_data, this.rmodel);
00477       Mmax      = get_ei_size(this.detailed_data, this.rmodel);
00478       maxMmax   = max(Mmax)-this.rmodel.Mstrich;
00479       this.rmodel.N = max(round(c*Nmax),1);
00480       if this.M_by_N_ratio == 0
00481         M_by_N_r = maxMmax / Nmax;
00482       elseif this.M_by_N_ratio == -1
00483         leaf_dd = get_active_leaf(this.detailed_data, this.rmodel);
00484         assert(isa(leaf_dd, 'Greedy.DataTree.Detailed.PODEI'));
00485         ext_ind        = this.rmodel.N;
00486         ext_counts = get_field(leaf_dd, 'ei_ext_count');
00487         ei_ext_steps = get_field(leaf_dd, 'ei_ext_steps');
00488         rb_real_ext_steps = get_field(leaf_dd, 'rb_real_ext_steps');
00489         if isempty(ext_counts)
00490           n_ei_exts  = length(ei_ext_steps);
00491           ext_counts = ones(size(ei_ext_steps))*maxMmax/n_ei_exts;
00492         end
00493         Mcomp = round(sum((ei_ext_steps <= rb_real_ext_steps(ext_ind)).*ext_counts));
00494         this.rmodel.M = min(maxMmax, max(Mcomp, 1));
00495         return
00496       else
00497         M_by_N_r = this.M_by_N_ratio;
00498       end
00499       this.rmodel.M = arrayfun(@(x) min(x, max(round(c*x/maxMmax*M_by_N_r*Nmax),1)), maxMmax);
00500     end
00501 
00502     function M = get_test_space_sample(this)
00503       if this.follow_refinement_steps
00504         info = active_info(this.detailed_data);
00505         ref_level = get_ref_level(info, this.rmodel);
00506         M = get_sample_at_ref_level(this.M_test, ref_level);
00507       else
00508         M = this.M_test.sample;
00509       end
00510     end
00511 
00512   end
00513 end
 All Classes Namespaces Files Functions Variables