rbmatlab  1.16.09
 All Classes Namespaces Files Functions Variables Modules Pages
Cached.m
1 classdef Cached < handle
2 % Interface for the storage and generation of detailed data that can be used to
3 % build reduced basis functions.
4 %
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.
11 %
12 % The generate method uses caching facilities to prevent data generation twice.
13 %
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'.
17 
18  properties(Dependent)
19  % unique name created from the IDs as given to the constructor.
20  idname;
21  end
22 
23  properties(GetAccess = public, SetAccess = private)
24  id; % string identifier for this generator
25 
26  enable_caching = true; % boolean flag indicating whether caching is enabled.
27 
28  model_name = 'default'; % name id of DetailedModel
29  end
30 
31  properties
32  % boolean value indicating whether the cached data shall be automatically
33  % deleted if its inconsistent with the given 'dmodel'.
34  force_delete = true;
35 
36  % seconds to wait before cached data is deleted automatically in case of
37  % inconsistent models.
38  countdown = 5;
39  end
40 
41  properties(Dependent)
42  % checks whether the basis generator points to a valid directory
43  is_valid;
44  end
45 
46  properties(Access = private)
47 
48  % number of files read from cache (only needed for debugging)
49  nocachereads = 0;
50 
51  end
52 
53  properties(Access = private, Dependent)
54  % path to all the cached data for the model for which this generator is
55  % constructed.
56  modelpath;
57 
58  % path where the cached functions shall be stored.
59  filepath;
60 
61  % full path to settingsfile where model data is stored for consistency
62  % checks.
63  settingsfile;
64 
65  end
66 
67 
68  methods
69 
70  function modelpath = get.modelpath(this)
71  modelpath = fullfile(rbmatlabtemp, 'cache', this.model_name);
72  end
73 
74  function filepath = get.filepath(this)
75  filepath = fullfile(this.modelpath, this.idname);
76  end
77 
78  function settingsfile = get.settingsfile(this)
79  settingsfile = fullfile(this.filepath, 'settings.mat');
80  end
81 
82  function ok = get.is_valid(this)
83  ok = exist(this.settingsfile, 'file');
84  end
85 
86  function dg = Cached(dmodel, id, force_delete, enable_caching)
87  % function dg = Cached(dmodel, id, force_delete)
88  % constructor for the detailed generator
89  %
90  % Parameters:
91  % id: an identifier string or a cell array of identifier
92  % strings.
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')
98  %
99  dg.id = id;
100  if nargin >= 3 && ~isempty(force_delete)
101  dg.force_delete = force_delete;
102  end
103  if nargin >= 4 && ~isempty(enable_caching)
104  dg.enable_caching = enable_caching;
105  end
106  dg.model_name = dmodel.descr.name;
107 
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));
111  else
112  success = true;
113  end
114 
115  if ~success
116  error(['error in generating the caching savepath: ', dg.filepath]);
117  end
118 
119  if dg.enable_caching
120  if exist(dg.settingsfile, 'file')
121  tmp = load(dg.settingsfile);
122  try
123  assert_model_is_consistent(dg, dmodel, tmp.dmodel);
124  catch exception
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.']);
135  pause(1);
136  end
137  clear_cachedirectory(dg);
138  else
139  error(exception.message);
140  end
141  end
142  end
143  end
144 
145  save(dg.settingsfile, 'dmodel');
146  end
147 
148  function idname = get.idname(this)
149  if iscell(this.id)
150  idname = sprintf('%s_', this.id{:});
151  else
152  idname = this.id;
153  end
154  end
155 
156  function clear_cachedirectory(this)
157  % clears the directory containing the cached mat-files
158 
159  delete(fullfile(this.filepath, '*.mat'));
160  if exist(this.settingsfile, 'file')
161  delete(this.settingsfile);
162  end
163  end
164 
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.
169  %
170 
171  iseq = (dmodel == comparemodel);
172  if ~iseq
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!']));
177  end
178 
179  end
180 
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
184  % caching facilities
185  %
186  % Internally this method calls the engine method generate_impl() if the
187  % result cannot be read from the harddrive cache.
188  %
189  % Parameters:
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.
193  %
194  % Return values:
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.
199 
200  if nargin <= 3
201  fields = [];
202  end
203 
204  opt_fields = [];
205 
206  if this.enable_caching
207  hash = this.hashcode(dmodel);
208  filename = fullfile(this.filepath, ['dsample', hash, '.mat']);
209 
210  if exist(filename, 'file')
211  tmp = load(filename);
212  cache_hit = true;
213  if ~isempty(fields)
214  if ~isfield(tmp, 'opt_fields')
215  cache_hit = false;
216  else
217  for i =1:length(fields)
218  if ~isfield(tmp.opt_fields, fields{i})
219  cache_hit = false;
220  break;
221  end
222  end
223  opt_fields = tmp.opt_fields;
224  end
225  end
226  detailed_sample = tmp.detailed_sample;
227  tictoc = tmp.tictoc;
228 
229  if dmodel.debug
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');
241  keyboard;
242  end
243  end
244  end
245 
246  if cache_hit
247  return;
248  else
249  disp('cache file not found because opt_fields are missing...');
250  end
251  end
252  end
253 
254  tstart = tic;
255  [detailed_sample, opt_fields] = generate_impl(this, dmodel, detailed_data, fields);
256  tictoc = toc(tstart);
257 
258  if this.enable_caching
259  hash = this.hashcode(dmodel);
260  filename = fullfile(this.filepath, ['dsample', hash, '.mat']);
261 
262  save(filename, 'detailed_sample', 'tictoc', 'opt_fields');
263  end
264 
265  end
266 
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.
270  %
271  % parameter:
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 = [])
275 
276  num_cpus = 2*dmodel.num_cpus;
277 
278  tmp_fp = this.filepath;
279  npar = size(M, 1);
280  for mout = 0:floor((npar-1)/num_cpus)
281  dsample_c = cell(1, npar);
282  tictoc_c = cell(1, npar);
283 
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)
286  tmp_M = M;
287  tmp_dmodel = dmodel;
288  set_mu( tmp_dmodel, tmp_M(muind,:) );
289  tmp_this = this;
290 
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, '...']);
296  tstart = tic;
297  dsample_c{muind} = generate_impl(this, tmp_dmodel, detailed_data);
298  tictoc_c{muind} = toc(tstart);
299  else
300  disp(['File exists: Skipping parameter vector ', num2str(muind),'/',num2str(npar),...
301  ' in Cached ', tmp_this.idname, '...']);
302  end
303  end
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};
308 
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')
314  end
315  end
316  end
317  end
318  end % end of function prepare_data
319 
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);
326  dmodel = tmp.dmodel;
327  else
328  dmodel = ['settingsfile for extension ', this.id, ' does not exist!'];
329  end
330  end
331 
333  end
334 
335  methods (Abstract, Access=protected)
336  % generates a sample trajectory or detailed simulation item from which a
337  % new basis function can be generated.
338  %
339  % Parameters:
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.
343  %
344  % Return values:
345  % U: a matrix with DOF vector columns holding the generated
346  % snapshots.
347  % opt_fields: optional fields to be cached.
348  [U, opt_fields] = generate_impl(this, dmodel, detailed_data, fields);
349 
350  end
351 
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.
356  %
357  % The default implementation of this function simply computes an MD5 hash
358  % out of the parameter vector;
359  function hashcode = hashcode(dmodel)
360 
361  mu = get_mu(dmodel);
362  hashcode = hash(mu, 'MD5');
363  end
364 
365  end
366 
367 end
Interface for the storage and generation of detailed data that can be used to build reduced basis fun...
Definition: Cached.m:18
debug
an integer defining the debugging level controlling error output and extra tests during basis generat...
This is the interface for a detailed model providing methods to compute high dimensional simulation s...