2 % Interface
for the storage and generation of detailed data that can be used to
3 % build reduced basis functions.
5 % Via the generate() method, detailed data for exactly one parameter can vector be
6 % generated and is returned. Usually, this data needs to be postprocessed
7 % afterwards. E.g. in case of reduced basis generation for evolution equations,
8 % a
Cached instance could produce a detailed solution trajectory for
9 % the specified parameter and by applying a POD algorithm on this trajectory a
10 % single basis vector is extracted for basis extension.
12 % The generate method uses caching facilities to prevent data generation twice.
14 % Furthermore, the class provides methods to prepare and store solutions
15 % before-hand. This can be used in to compare reduced and detailed
16 % approximations for the entire training or validation set 'M'.
19 % unique name created from the IDs as given to the constructor.
23 properties(GetAccess = public, SetAccess = private)
24 id; %
string identifier for this generator
26 enable_caching = true; %
boolean flag indicating whether caching is enabled.
28 model_name = 'default'; % name
id of DetailedModel
32 %
boolean value indicating whether the cached data shall be automatically
33 % deleted if its inconsistent with the given 'dmodel'.
36 % seconds to wait before cached data is deleted automatically in case of
37 % inconsistent models.
42 % checks whether the basis generator points to a valid directory
46 properties(Access = private)
48 % number of files read from cache (only needed for debugging)
53 properties(Access = private, Dependent)
54 % path to all the cached data for the model for which this generator is
58 % path where the cached functions shall be stored.
61 % full path to settingsfile where model data is stored for consistency
70 function modelpath = get.modelpath(this)
71 modelpath = fullfile(rbmatlabtemp, 'cache', this.model_name);
74 function filepath = get.filepath(this)
75 filepath = fullfile(this.modelpath, this.idname);
78 function settingsfile = get.settingsfile(this)
79 settingsfile = fullfile(this.filepath, 'settings.mat');
82 function ok = get.is_valid(this)
83 ok = exist(this.settingsfile, 'file');
86 function dg =
Cached(dmodel,
id, force_delete, enable_caching)
87 % function dg =
Cached(dmodel,
id, force_delete)
88 % constructor for the detailed generator
91 %
id: an identifier
string or a cell array of identifier
93 % force_delete:
boolean value indicating whether the cached data shall
94 % be automatically deleted if its inconsistent with the
95 % given 'dmodel'. (Default = 'true')
96 % enable_caching:
boolean value indicating whether the generated data
97 % shall be stored in a cache. (Default = 'true')
100 if nargin >= 3 && ~isempty(force_delete)
101 dg.force_delete = force_delete;
103 if nargin >= 4 && ~isempty(enable_caching)
104 dg.enable_caching = enable_caching;
106 dg.model_name = dmodel.descr.name;
108 % When NEWDIR exists, MKDIR returns SUCCESS = 1, but with WARNING!
109 if ~exist(fullfile(rbmatlabtemp, 'cache', dmodel.descr.name, dg.idname), 'dir')
110 success = mkdir(rbmatlabtemp, fullfile('cache', dmodel.descr.name, dg.idname));
116 error(['error in generating the caching savepath: ', dg.filepath]);
120 if exist(dg.settingsfile, 'file')
121 tmp = load(dg.settingsfile);
123 assert_model_is_consistent(dg, dmodel, tmp.dmodel);
125 if ~dmodel.debug && dg.force_delete
126 disp(exception.message);
127 disp('==================================================================');
128 disp('========================== WARNING: ==============================');
129 disp('dmodel.force_delete is set to true. The data in the savepath' );
130 disp(['will be deleted in ', num2str(dg.countdown), ' seconds. ']);
131 disp('Press Ctrl-C if you want to keep the precompute files.');
132 disp('==================================================================');
133 for i=dg.countdown:-1:1
134 disp(['Deleting in directory in ', num2str(i), ' seconds.']);
137 clear_cachedirectory(dg);
139 error(exception.message);
145 save(dg.settingsfile, 'dmodel');
148 function idname = get.idname(this)
150 idname = sprintf('%s_', this.
id{:});
156 function clear_cachedirectory(
this)
157 % clears the directory containing the cached mat-files
159 delete(fullfile(this.filepath, '*.mat'));
160 if exist(this.settingsfile,
'file')
161 delete(this.settingsfile);
165 function assert_model_is_consistent(this, dmodel, comparemodel)
166 % function assert_model_is_consistent(this, dmodel, comparemodel)
167 % throws an inconsistency error if the the current
IDetailedModel object
168 % and the one stored on the harddrive differ.
171 iseq = (dmodel == comparemodel);
173 throw(MException('RBMatlab:Storage:InconsistentData', ...
174 ['parameters of precomputed data and current',...
175 ' simulation are inconsistent! Please delete files in path ', ...
176 this.filepath, ' and restart!']));
181 function [detailed_sample, tictoc, opt_fields] = generate(this, dmodel, detailed_data, fields)
182 % function detailed_sample = generate(this, model, detailed_data[, fields])
183 % generates a detailed data sample for a specific parameter using
186 % Internally this method calls the engine method generate_impl() if the
187 % result cannot be read from the harddrive cache.
190 % fields: cell array of structure field names which shall also be
191 % stored in the cache in the 'opt_fields' structure. If not
192 % given only the 'detailed_sample' is generated.
195 % detailed_sample: This is usually a matrix with DOF vector columns
196 % holding the generated snapshots.
197 % tictoc: time needed to compute the snapshots.
198 % opt_fields: optional fields to be cached.
206 if this.enable_caching
207 hash = this.hashcode(dmodel);
208 filename = fullfile(this.filepath, ['dsample', hash, '.mat']);
210 if exist(filename, 'file')
211 tmp = load(filename);
214 if ~isfield(tmp, 'opt_fields')
217 for i =1:length(fields)
218 if ~isfield(tmp.opt_fields, fields{i})
223 opt_fields = tmp.opt_fields;
226 detailed_sample = tmp.detailed_sample;
230 this.nocachereads = this.nocachereads+1;
231 if mod(this.nocachereads, 10) == 0
232 disp([
'This is the tenth cache read and we are in debug mode.', ...
233 'Comparing with real simulation...']);
234 comp = generate_impl(
this, dmodel, detailed_data);
235 if any(size(comp) ~= size(detailed_sample))...
236 || any(comp ~= detailed_sample)
237 disp('computations do not correspond with the cached result!!!');
238 disp('Please check the hash function of whether the data directory')
239 disp([' ', this.filepath]);
240 disp('needs to be deleted');
249 disp('cache file not found because opt_fields are missing...');
255 [detailed_sample, opt_fields] = generate_impl(this, dmodel, detailed_data, fields);
256 tictoc = toc(tstart);
258 if this.enable_caching
259 hash = this.hashcode(dmodel);
260 filename = fullfile(this.filepath, ['dsample', hash, '.mat']);
262 save(filename, 'detailed_sample', 'tictoc', 'opt_fields');
267 function prepare(this, dmodel, detailed_data, M)
268 % function prepare_data(this, dmodel, detailed_data)
269 % precompute detailed data for all parameters given by \a M.
272 % M: matrix storing the parameters for which the generation shall be
273 % prepared. The matrix size equal `dim(\cal M) \times M_p`, where `M_p`
274 % denotes the number of parameter vectors. (Default = [])
276 num_cpus = 2*dmodel.num_cpus;
278 tmp_fp = this.filepath;
280 for mout = 0:floor((npar-1)/num_cpus)
281 dsample_c = cell(1, npar);
282 tictoc_c = cell(1, npar);
284 %parfor muind = (mout*num_cpus+1):min(npar, (mout+1)*num_cpus)
285 for muind = (mout*num_cpus+1):min(npar, (mout+1)*num_cpus)
288 set_mu( tmp_dmodel, tmp_M(muind,:) );
291 hash = tmp_this.hashcode(tmp_dmodel);
292 filename = fullfile(tmp_fp, ['dsample', hash, '.mat']);
293 if ~exist(filename, 'file')
294 disp(['Processing parameter vector ', num2str(muind),'/',num2str(npar),...
295 ' in
Cached ', tmp_this.idname, '...']);
297 dsample_c{muind} = generate_impl(
this, tmp_dmodel, detailed_data);
298 tictoc_c{muind} = toc(tstart);
300 disp([
'File exists: Skipping parameter vector ', num2str(muind),
'/',num2str(npar),...
301 ' in Cached ', tmp_this.idname,
'...']);
304 if this.enable_caching
305 for muind = (mout*num_cpus+1):min(npar, (mout+1)*num_cpus)
306 detailed_sample = dsample_c{muind};
307 tictoc = tictoc_c{muind};
309 set_mu( dmodel, M(muind,:) );
310 hash = this.hashcode(dmodel);
311 filename = fullfile(tmp_fp, [
'dsample', hash,
'.mat']);
312 if ~exist(filename,
'file')
313 save(filename, 'detailed_sample', 'tictoc')
318 end % end of function prepare_data
320 function dmodel = get_underlying_model(this)
321 % function dmodel = get_underlying_model(this)
322 % returns the detailed model stored on the harddrive with which the
323 % snaphshots were generated.
324 if exist(this.settingsfile, 'file')
325 tmp = load(this.settingsfile);
328 dmodel = ['settingsfile for extension ', this.
id, ' does not exist!'];
335 methods (Abstract, Access=protected)
336 % generates a sample trajectory or detailed simulation item from which a
337 % new basis function can be generated.
340 % fields: cell array of structure field names which shall also be
341 % stored in the cache in the 'opt_fields' structure. If not
342 % given only the 'U' is generated.
345 % U: a matrix with DOF vector columns holding the generated
347 % opt_fields: optional fields to be cached.
348 [U, opt_fields] = generate_impl(this, dmodel, detailed_data, fields);
352 methods (Static, Access=protected)
353 % function hashcode = hashcode(basis_generation)
354 % this is a very simple hash code, generating an md5 hash out of the
355 % current parameter vector.
357 % The default implementation of this function simply computes an MD5 hash
358 % out of the parameter vector;
359 function hashcode = hashcode(dmodel)
362 hashcode = hash(mu, 'MD5');