queso-0.51.1
InfiniteDimensionalMCMCSampler.C
Go to the documentation of this file.
1 //--------------------------------------------------------------------------
2 //
3 // QUESO - a library to support the Quantification of Uncertainty
4 // for Estimation, Simulation and Optimization
5 //
6 // Copyright (C) 2008,2009,2010,2011,2012,2013 The PECOS Development Team
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the Version 2.1 GNU Lesser General
10 // Public License as published by the Free Software Foundation.
11 //
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // Lesser General Public License for more details.
16 //
17 // You should have received a copy of the GNU Lesser General Public
18 // License along with this library; if not, write to the Free Software
19 // Foundation, Inc. 51 Franklin Street, Fifth Floor,
20 // Boston, MA 02110-1301 USA
21 //
22 //-----------------------------------------------------------------------el-
23 
24 #include <queso/Defines.h>
25 
26 #ifdef QUESO_HAVE_HDF5
27 
28 #include <cmath>
29 #include <algorithm>
30 #include <boost/math/constants/constants.hpp>
31 
32 // QUESO includes
33 #include <queso/Miscellaneous.h>
34 #include <queso/InfiniteDimensionalMeasureBase.h>
35 
36 #include <queso/InfiniteDimensionalLikelihoodBase.h>
37 #include <queso/InfiniteDimensionalMCMCSampler.h>
38 #include <queso/InfiniteDimensionalMCMCSamplerOptions.h>
39 
40 namespace QUESO {
41 
42 InfiniteDimensionalMCMCSampler::InfiniteDimensionalMCMCSampler(
43  const BaseEnvironment& env,
44  InfiniteDimensionalMeasureBase & prior,
45  InfiniteDimensionalLikelihoodBase & llhd,
46  InfiniteDimensionalMCMCSamplerOptions * ov)
47  : prior(prior),
48  llhd(llhd),
49  m_env(env),
50  current_physical_state(prior.draw()),
51  proposed_physical_state(prior.draw()),
52  current_physical_mean(prior.draw()),
53  current_physical_var(prior.draw()),
54  _delta(prior.draw()),
55  _M2(prior.draw())
56 {
57  if (ov != NULL) {
58  this->m_ov = ov;
59  }
60 
61 #ifdef QUESO_MEMORY_DEBUGGING
62  std::cout << "Entering InfiniteDimensionalMCMCSampler class" << std::endl;
63 #endif
64  if (m_env.subDisplayFile()) {
65  *m_env.subDisplayFile() << "Entering InfiniteDimensionalMCMCSampler::constructor()"
66  << ": prefix = " << this->m_ov->m_prefix
67  << ", m_env.optionsInputFileName() = " << this->m_env.optionsInputFileName()
68  << std::endl;
69  }
70 
71  if (m_env.optionsInputFileName() != "") {
72  this->m_ov->scanOptionsValues();
73  }
74 
75 #ifdef QUESO_MEMORY_DEBUGGING
76  std::cout << "In InfiniteDimensionalMCMCSamplerOptions,"
77  << " finished scanning options" << std::endl;
78 #endif
79 
80  // Verify parent directory exists (for cases when a user specifies a
81  // relative path for the desired output file).
82  // Only subprocess of subrank 0 creates the output file
83  if ((this->m_env).subRank() == 0) {
84  int irtrn = CheckFilePath((this->m_ov->m_dataOutputDirName +
85  (this->m_env).subIdString() +
86  "/test.txt").c_str());
87  UQ_FATAL_TEST_MACRO(irtrn < 0,
88  (this->m_env).subId(),
89  "Environment::constructor()",
90  "unable to verify output path");
91  }
92 
93  // Only subprocess of subrank 0 creates the output file
94  if ((this->m_env).subRank() == 0) {
95  this->_outfile = H5Fcreate((this->m_ov->m_dataOutputDirName +
96  (this->m_env).subIdString() + "/" +
97  this->m_ov->m_dataOutputFileName).c_str(),
98  H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
99  }
100 
101  this->_acc_dset = this->_create_scalar_dataset("acc");
102  this->_avg_acc_dset = this->_create_scalar_dataset("avg_acc");
103  this->_neg_log_llhd_dset = this->_create_scalar_dataset("neg_log_llhd");
104  this->_L2_norm_samples_dset = this->_create_scalar_dataset("L2_norm_samples");
105  this->_L2_norm_mean_dset = this->_create_scalar_dataset("L2_norm_mean");
106  this->_L2_norm_var_dset = this->_create_scalar_dataset("L2_norm_var");
107 
108  // Ensure that we created the path and the output files
109  ((this->m_env).fullComm()).Barrier();
110 
111  this->_iteration = 0;
112  this->_acc_prob = 0.0;
113  this->_avg_acc_prob = 0.0;
114 
115  // FIXME: Should use the QUESO rng here instead
116  r = gsl_rng_alloc(gsl_rng_taus2);
117 
118  // Zero out these guys. There's probably a better way of doing this than
119  // calling prior.draw() at the start, but creation of a Sampler object
120  // should only be done a O(1) times anyway.
121  this->_delta->zero();
122  this->_M2->zero();
123  this->current_physical_mean->zero();
124  this->current_physical_var->zero();
125 
126  // LibMeshFunction & p = libmesh_cast_ref<LibMeshFunction &>(*(this->current_physical_state));
127 
128  // Seed the sampler at the truth
129  // for (unsigned int ii = 0; ii < 513; ii++) {
130  // p.equation_systems->get_system<ExplicitSystem>("Function").solution->set(ii, std::cos(2.0 * boost::math::constants::pi<double>() * ii / 512.0));
131  // }
132  // p.equation_systems->get_system<ExplicitSystem>("Function").solution->close();
133  // std::string seedname("seedfn");
134  // p.save_function(seedname);
135 
136  // Initialise cost function
137  this->_llhd_val = this->llhd.evaluate(*(this->current_physical_state));
138 
139  std::cout.setf(std::ios::fixed, std::ios::floatfield);
140  std::cout.precision(15);
141 }
142 
143 InfiniteDimensionalMCMCSampler::~InfiniteDimensionalMCMCSampler()
144 {
145  if ((this->m_env).subRank() == 0) {
146  H5Dclose(this->_acc_dset);
147  H5Dclose(this->_avg_acc_dset);
148  H5Dclose(this->_neg_log_llhd_dset);
149  H5Dclose(this->_L2_norm_samples_dset);
150  H5Dclose(this->_L2_norm_mean_dset);
151  H5Dclose(this->_L2_norm_var_dset);
152  H5Fclose(this->_outfile);
153  }
154 }
155 
156 void InfiniteDimensionalMCMCSampler::_propose()
157 {
158  const double rwmh_step_sq = (this->m_ov->m_rwmh_step * this->m_ov->m_rwmh_step);
159  const double coeff = std::sqrt(1.0 - rwmh_step_sq);
160 
161  boost::shared_ptr<FunctionBase> p(prior.draw());
162 
163  this->proposed_physical_state->zero();
164  this->proposed_physical_state->add(coeff, *(this->current_physical_state));
165  this->proposed_physical_state->add(this->m_ov->m_rwmh_step, *p);
166 }
167 
168 void InfiniteDimensionalMCMCSampler::_metropolis_hastings()
169 {
170  // Downcast since we know we're dealing with a libmesh function
171  // LibMeshFunction & p = static_cast<LibMeshFunction &>(*(this->proposed_physical_state));
172  // LibMeshFunction & q = static_cast<LibMeshFunction &>(*(this->current_physical_state));
173  // Evaluate the likelihood at the proposed state
174  double proposed_llhd = this->llhd.evaluate(*(this->proposed_physical_state));
175  // double current_llhd = this->llhd.evaluate(q);
176  // std::cout << "llhd of current is: " << current_llhd << std::endl;
177  // std::cout << "llhd of proposal is: " << proposed_llhd << std::endl;
178 
179  double diff = this->_llhd_val - proposed_llhd;
180  double alpha = std::min(1.0, std::exp(diff));
181  double rand = gsl_rng_uniform(this->r);
182  if (rand < alpha) {
183  // Accept
184  // std::cout << "accepted" << std::endl;
185  this->current_physical_state.swap(this->proposed_physical_state);
186  this->proposed_physical_state->zero();
187  this->_acc_prob = alpha;
188  this->_llhd_val = proposed_llhd;
189  }
190  else {
191  // std::cout << "rejected" << std::endl;
192  this->_acc_prob = 0.0;
193  }
194 }
195 
196 void InfiniteDimensionalMCMCSampler::_update_moments()
197 {
198  // Increment the current iteration number and update the running mean and
199  // variance.
200  this->_iteration += 1;
201 
202  // Make _delta contain the difference from the mean
203  this->_delta->zero();
204  this->_delta->add(1.0, *(this->current_physical_state));
205  this->_delta->add(-1.0, *(this->current_physical_mean));
206 
207  // Scale _delta to update the mean field
208  this->current_physical_mean->add(1.0 / this->iteration(), *(this->_delta));
209 
210  // Update running sum-of-squares
211  boost::shared_ptr<FunctionBase> temp_ptr(this->_delta->zero_clone());
212  // LibMeshFunction & temp = static_cast<LibMeshFunction &>(*temp_ptr);
213 
214  temp_ptr->pointwise_mult(*(this->_delta), *(this->current_physical_state));
215  this->_M2->add(1.0, *temp_ptr);
216  temp_ptr->pointwise_mult(*(this->_delta), *(this->current_physical_mean));
217  this->_M2->add(-1.0, *temp_ptr);
218 
219  if (this->iteration() > 1) {
220  this->current_physical_var->zero();
221  this->current_physical_var->add(1.0 / (this->iteration() - 1), *(this->_M2));
222  }
223 
224  // Update acceptance rate
225  double delta_acc = this->acc_prob() - this->avg_acc_prob();
226  this->_avg_acc_prob += delta_acc / this->iteration();
227 }
228 
229 void InfiniteDimensionalMCMCSampler::step()
230 {
231  this->_propose();
232  this->_metropolis_hastings();
233  this->_update_moments();
234 
235  // We never save the 0th iteration
236  if (this->_iteration % this->m_ov->m_save_freq == 0) {
237  this->_write_state();
238  }
239 }
240 
241 hid_t InfiniteDimensionalMCMCSampler::_create_scalar_dataset(const std::string & name)
242 {
243  // Only subprocess with rank 0 manipulates the output file
244  if ((this->m_env).subRank() == 0) {
245  // Create a 1D dataspace. Unlimited size. Initially set to 0. We will
246  // extend it later
247  const int ndims = 1;
248  hsize_t dims[ndims] = {0}; // dataset dimensions at creation
249  hsize_t maxdims[ndims] = {H5S_UNLIMITED};
250 
251  hid_t file_space = H5Screate_simple(ndims, dims, maxdims);
252 
253  // Create dataset creation property list. Unlimited datasets must be
254  // chunked. Choosing the chunk size is an issue, here we set it to 1
255  hsize_t chunk_dims[ndims] = {1};
256  hid_t plist = H5Pcreate(H5P_DATASET_CREATE);
257 
258  H5Pset_layout(plist, H5D_CHUNKED);
259  H5Pset_chunk(plist, ndims, chunk_dims);
260 
261  // Create the dataset
262  hid_t dset = H5Dcreate(this->_outfile, name.c_str(), H5T_NATIVE_DOUBLE,
263  file_space, H5P_DEFAULT, plist, H5P_DEFAULT);
264 
265  // We don't need the property list anymore. We also don't need the file
266  // dataspace anymore because we'll extend it later, making this one
267  // invalild anyway.
268  H5Pclose(plist);
269  H5Sclose(file_space);
270 
271  return dset;
272  }
273 
274  hid_t dummy;
275  return dummy;
276 }
277 
278 void InfiniteDimensionalMCMCSampler::_append_scalar_dataset(hid_t dset, double data)
279 {
280  // Only subprocess with rank 0 manipulates the output file
281  if ((this->m_env).subRank() == 0) {
282  int err;
283  // Create a memory dataspace for data to append
284  const int ndims = 1;
285  hsize_t dims[ndims] = { 1 }; // Only writing one double
286  hid_t mem_space = H5Screate_simple(ndims, dims, NULL);
287 
288  // Extend the dataset
289  // Set dims to be the *new* dimension of the extended dataset
290  dims[0] = this->_iteration / this->m_ov->m_save_freq;
291  err = H5Dset_extent(dset, dims);
292 
293  // Select hyperslab on file dataset
294  hid_t file_space = H5Dget_space(dset);
295  hsize_t start[1] = {(this->_iteration / this->m_ov->m_save_freq) - 1};
296  hsize_t count[1] = {1};
297 
298  err = H5Sselect_hyperslab(file_space, H5S_SELECT_SET, start, NULL, count, NULL);
299 
300  // hsize_t size[1];
301  // size[0] = this->_iteration / this->m_ov->m_save_freq;
302 
303  // Write the data
304  H5Dwrite(dset, H5T_NATIVE_DOUBLE, mem_space, file_space, H5P_DEFAULT, &data);
305 
306  // Close a bunch of stuff
307  H5Sclose(file_space);
308  H5Sclose(mem_space);
309  }
310 }
311 
312 void InfiniteDimensionalMCMCSampler::_write_state()
313 {
314  this->_append_scalar_dataset(this->_acc_dset, this->acc_prob());
315  this->_append_scalar_dataset(this->_avg_acc_dset, this->avg_acc_prob());
316  this->_append_scalar_dataset(this->_neg_log_llhd_dset, this->_llhd_val);
317  this->_append_scalar_dataset(this->_L2_norm_samples_dset, this->current_physical_state->L2_norm());
318  this->_append_scalar_dataset(this->_L2_norm_mean_dset, this->current_physical_mean->L2_norm());
319  this->_append_scalar_dataset(this->_L2_norm_var_dset, this->current_physical_var->L2_norm());
320 
321  // Now to write the fields. It appears to be a pain in the arse to write a
322  // method to spit this out to HDF5 format. Also, this won't scale to
323  // non-uniform finite element meshes. Therefore, I'm going to spit out an
324  // ExodusII file for each sample, average and variance. Got disk space?
325  std::stringstream basename;
326  basename << this->m_ov->m_dataOutputDirName;
327  basename << (this->m_env).subIdString();
328  basename << "/"; // Sigh
329 
330  std::ostringstream curr_iter;
331  curr_iter << this->iteration();
332 
333  std::string sample_name(basename.str() + "sample.e-s.");
334  sample_name += curr_iter.str();
335  this->current_physical_state->save_function(sample_name, this->iteration());
336 
337  std::string mean_name(basename.str() + "mean.e-s.");
338  mean_name += curr_iter.str();
339  this->current_physical_mean->save_function(mean_name, this->iteration());
340 
341  std::string var_name(basename.str() + "var.e-s.");
342  var_name += curr_iter.str();
343  this->current_physical_var->save_function(var_name, this->iteration());
344 }
345 
346 boost::shared_ptr<InfiniteDimensionalMCMCSampler> InfiniteDimensionalMCMCSampler::clone_and_reset() const
347 {
348  // Set up a clone
349  boost::shared_ptr<InfiniteDimensionalMCMCSampler> clone(new InfiniteDimensionalMCMCSampler(this->m_env, this->prior, this->llhd, this->m_ov));
350 
351  // Copy the state.
352  clone->current_physical_state = this->current_physical_state;
353  clone->proposed_physical_state = this->proposed_physical_state;
354  clone->_llhd_val = this->_llhd_val;
355  clone->_acc_prob = this->_acc_prob;
356  clone->_avg_acc_prob = 0.0;
357 
358  return clone;
359 }
360 
361 double InfiniteDimensionalMCMCSampler::acc_prob()
362 {
363  return this->_acc_prob;
364 }
365 
366 double InfiniteDimensionalMCMCSampler::avg_acc_prob()
367 {
368  return this->_avg_acc_prob;
369 }
370 
371 double InfiniteDimensionalMCMCSampler::llhd_val() const
372 {
373  return this->_llhd_val;
374 }
375 
376 unsigned int InfiniteDimensionalMCMCSampler::iteration() const
377 {
378  return this->_iteration;
379 }
380 
381 } // End namespace QUESO
382 
383 #endif // QUESO_HAVE_HDF5
int CheckFilePath(const char *path)
#define UQ_FATAL_TEST_MACRO(test, givenRank, where, what)
Definition: Defines.h:223

Generated on Thu Apr 23 2015 19:26:15 for queso-0.51.1 by  doxygen 1.8.5