Canoe
Comprehensive Atmosphere N' Ocean Engine
mcmc.cpp
Go to the documentation of this file.
1 // C/C++
2 #include <cassert>
3 #include <cmath>
4 #include <cstdio>
5 #include <cstdlib>
6 #include <cstring>
7 #include <iostream>
8 
9 // canoe
10 #include <configure.hpp>
11 
12 #ifdef FITSOUTPUT
13 extern "C" {
14 #include <fitsio.h>
15 }
16 #endif
17 
18 // climath
19 #include <climath/core.h>
20 
21 // utils
22 #include <utils/ndarrays.hpp>
23 
24 // inversion
25 #include "mcmc.hpp"
26 
27 void _choldc(double **a, int n, double *p) {
28  int i, j, k;
29  double sum;
30 
31  for (i = 0; i < n; ++i)
32  for (j = i; j < n; ++j) {
33  for (sum = a[i][j], k = i - 1; k >= 0; --k) {
34  sum -= a[i][k] * a[j][k];
35  }
36  if (i == j) {
37  assert(sum > 0.);
38  p[i] = sqrt(sum);
39  } else {
40  a[j][i] = sum / p[i];
41  }
42  }
43 }
44 
45 // Compute tau directly only if tau < TAUMAX.
46 // Otherwise compute tau using the pairwise sum series
47 #define TAUMAX 2
48 
49 // Compute autocovariances up to lag s = WINMULT*TAU
50 #define WINMULT 5
51 
52 // The autocovariance array is double C[MAXLAG+1]
53 // so that C[s] makes sense for s = MAXLAG.
54 #define MAXLAG TAUMAX *WINMULT
55 
56 // Stop and print an error message if the array is shorter
57 // than MINFAC * MAXLAG.
58 #define MINFAC 5
59 
60 int _acor(double *mean, double *sigma, double *tau, double *X, int L) {
61  *mean = 0.; // Compute the mean of X ...
62  for (int i = 0; i < L; i++) *mean += X[i];
63  *mean = *mean / L;
64  for (int i = 0; i < L; i++) X[i] -= *mean; // ... and subtract it away.
65 
66  if (L < MINFAC * MAXLAG) {
67  // printf("Acor error 1: The autocorrelation time is too long relative to
68  // the variance.\n");
69  return 1;
70  }
71 
72  double C[MAXLAG + 1];
73  for (int s = 0; s <= MAXLAG; s++)
74  C[s] =
75  0.; // Here, s=0 is the variance, s = MAXLAG is the last one computed.
76 
77  int iMax = L - MAXLAG; // Compute the autocovariance function . . .
78  for (int i = 0; i < iMax; i++)
79  for (int s = 0; s <= MAXLAG; s++)
80  C[s] += X[i] * X[i + s]; // ... first the inner products ...
81  for (int s = 0; s <= MAXLAG; s++)
82  C[s] = C[s] / iMax; // ... then the normalization.
83 
84  double D =
85  C[0]; // The "diffusion coefficient" is the sum of the autocovariances
86  for (int s = 1; s <= MAXLAG; s++)
87  D += 2 *
88  C[s]; // The rest of the C[s] are double counted since C[-s] = C[s].
89  *sigma = sqrt(
90  D / L); // The standard error bar formula, if D were the complete sum.
91  *tau = D / C[0]; // A provisional estimate, since D is only part of the
92  // complete sum.
93 
94  if (*tau * WINMULT < MAXLAG) {
95  return 0; // Stop if the D sum includes the given multiple of tau.
96  // This is the self consistent window approach.
97 
98  } else { // If the provisional tau is so large that we don't think tau
99  // is accurate, apply the acor procedure to the pairwase sums
100  // of X.
101  int Lh = L / 2; // The pairwise sequence is half the length (if L is even)
102  double newMean; // The mean of the new sequence, to throw away.
103  int j1 = 0;
104  int j2 = 1;
105  for (int i = 0; i < Lh; i++) {
106  X[i] = X[j1] + X[j2];
107  j1 += 2;
108  j2 += 2;
109  }
110  _acor(&newMean, sigma, tau, X, Lh);
111  D = .25 * (*sigma) * (*sigma) *
112  L; // Reconstruct the fine time series numbers from the coarse series
113  // numbers.
114  *tau = D / C[0]; // As before, but with a corrected D.
115  *sigma = sqrt(D / L); // As before, again.
116  }
117 
118  return 0;
119 }
120 
121 #undef TAUMAX
122 #undef WINMULT
123 #undef MAXLAG
124 #undef MINFAC
125 
126 void mcmc_alloc(mcmc_recs *recs, int nstep, int nwalker, int ndim, int nvalue) {
127  recs->nstep = nstep;
128  recs->nwalker = nwalker;
129  recs->ndim = ndim;
130  recs->nvalue = nvalue;
131 
132  NewCArray(recs->par, nstep, nwalker, ndim);
133  NewCArray(recs->val, nstep, nwalker, nvalue);
134  NewCArray(recs->lnp, nstep, nwalker);
135  NewCArray(recs->newstate, nstep, nwalker);
136 
137  memset(recs->par[0][0], 0, nstep * nwalker * ndim * sizeof(double));
138  memset(recs->val[0][0], 0, nstep * nwalker * nvalue * sizeof(double));
139  memset(recs->lnp[0], 0, nstep * nwalker * sizeof(double));
140  memset(recs->newstate[0], 0, nstep * nwalker * sizeof(int));
141 
142  recs->opt_par = new double[ndim];
143  recs->opt_val = new double[nvalue];
144 
145  recs->cur = 0;
146  recs->accept = 0;
147  recs->reset = 0;
148  recs->opt_lnp = -1.E10;
149 }
150 
151 void mcmc_free(mcmc_recs *recs) {
152  FreeCArray(recs->par);
153  FreeCArray(recs->val);
154  FreeCArray(recs->lnp);
155  FreeCArray(recs->newstate);
156  delete[] recs->opt_par;
157  delete[] recs->opt_val;
158 }
159 
160 void mcmc_statistics(double *mean, double *sigma, double *tau,
161  mcmc_recs *recs) {
162  double *x = new double[recs->cur];
163 
164  for (size_t p = 0; p < recs->ndim; ++p) {
165  for (size_t t = 0; t < recs->cur; ++t) {
166  x[t] = 0.;
167  for (size_t k = 0; k < recs->nwalker; ++k) x[t] += recs->par[t][k][p];
168  x[t] /= recs->nwalker;
169  }
170 
171  int err = _acor(mean + p, sigma + p, tau + p, x, recs->cur);
172 
173  if (err != 0) tau[p] = -1.;
174  }
175 
176  delete[] x;
177 }
178 
179 void mcmc_save_fits(char const *fname, mcmc_opts *opts, mcmc_recs *recs,
180  int include_last) {
181  double ***buf;
182  int ***ibuf;
183 
184  double ***par, ***val, **lnp;
185  int **newstate;
186 
187  // indices
188  int rank = 0, size = 1;
189  int nwalker = recs->nwalker;
190  int ndim = recs->ndim;
191  int nvalue = recs->nvalue;
192  int cur = include_last ? recs->cur : recs->cur - 1;
193 
194  int accept = recs->accept;
195  int reset = recs->reset;
196  double opt_lnp = recs->opt_lnp;
197 
198  // do not make outputs if cur <= 0
199  if (cur <= 0) return;
200 
201 #ifdef MPI_PARALLEL
202  MPI_Comm_rank(opts->mpi_comm, &rank);
203  MPI_Comm_size(opts->mpi_comm, &size);
204 
205  NewCArray(par, cur, size * nwalker, ndim);
206  NewCArray(val, cur, size * nwalker, nvalue);
207  NewCArray(lnp, cur, size * nwalker);
208  NewCArray(newstate, cur, size * nwalker);
209 
210  // 1. gather walker positions
211  NewCArray(buf, size, cur * nwalker, ndim);
212  MPI_Gather(**recs->par, cur * nwalker * ndim, MPI_DOUBLE, **buf,
213  cur * nwalker * ndim, MPI_DOUBLE, 0, opts->mpi_comm);
214  if (rank == 0) { // reorder dimension
215  for (int t = 0; t < cur; ++t)
216  for (int r = 0; r < size; ++r)
217  for (int k = 0; k < nwalker; ++k)
218  for (int d = 0; d < ndim; ++d)
219  par[t][r * nwalker + k][d] = buf[r][t * nwalker + k][d];
220  }
221  FreeCArray(buf);
222 
223  // 2. gather function values
224  NewCArray(buf, size, cur * nwalker, nvalue);
225  MPI_Gather(**recs->val, cur * nwalker * nvalue, MPI_DOUBLE, **buf,
226  cur * nwalker * nvalue, MPI_DOUBLE, 0, opts->mpi_comm);
227  if (rank == 0) { // reorder dimension
228  for (int t = 0; t < cur; ++t)
229  for (int r = 0; r < size; ++r)
230  for (int k = 0; k < nwalker; ++k)
231  for (int d = 0; d < nvalue; ++d)
232  val[t][r * nwalker + k][d] = buf[r][t * nwalker + k][d];
233  }
234  FreeCArray(buf);
235 
236  // 3. gather log probability
237  NewCArray(buf, size, cur, nwalker);
238  MPI_Gather(*recs->lnp, cur * nwalker, MPI_DOUBLE, **buf, cur * nwalker,
239  MPI_DOUBLE, 0, opts->mpi_comm);
240  if (rank == 0) { // reorder dimension
241  for (int t = 0; t < cur; ++t)
242  for (int r = 0; r < size; ++r)
243  for (int k = 0; k < nwalker; ++k)
244  lnp[t][r * nwalker + k] = buf[r][t][k];
245  }
246  FreeCArray(buf);
247 
248  // 4. reduce optimal log probability
249  MPI_Reduce(&recs->opt_lnp, &opt_lnp, 1, MPI_DOUBLE, MPI_MAX, 0,
250  opts->mpi_comm);
251 
252  // 5. reduce accepted states
253  MPI_Reduce(&recs->accept, &accept, 1, MPI_INT, MPI_SUM, 0, opts->mpi_comm);
254 
255  // 6. reduce resetted states
256  MPI_Reduce(&recs->reset, &reset, 1, MPI_INT, MPI_SUM, 0, opts->mpi_comm);
257 
258  // 7. gather new state indicator
259  NewCArray(ibuf, size, cur, nwalker);
260  MPI_Gather(*recs->newstate, cur * nwalker, MPI_INT, **ibuf, cur * nwalker,
261  MPI_INT, 0, opts->mpi_comm);
262  if (rank == 0) { // reorder dimension
263  for (int t = 0; t < cur; ++t)
264  for (int r = 0; r < size; ++r)
265  for (int k = 0; k < nwalker; ++k)
266  newstate[t][r * nwalker + k] = ibuf[r][t][k];
267  }
268  FreeCArray(ibuf);
269 #endif
270 
271  // 6. write FITS file
272 #ifdef FITSOUTPUT
273  if (rank == 0) {
274  fitsfile *fp;
275  int status = 0;
276  long naxis = 3;
277  long naxes[3] = {ndim, size * nwalker, cur};
278  long fpixel = 1;
279  long nelements = naxes[0] * naxes[1] * naxes[2];
280 
281  fits_create_file(&fp, fname, &status);
282  if (status) fits_report_error(stderr, status);
283 
284  // 6.1 create parameter fields
285  fits_create_img(fp, DOUBLE_IMG, naxis, naxes, &status);
286  if (status) fits_report_error(stderr, status);
287 
288  // 6.2 write parameter fields
289 #ifdef MPI_PARALLEL
290  fits_write_img(fp, TDOUBLE, fpixel, nelements, **par, &status);
291 #else
292  fits_write_img(fp, TDOUBLE, fpixel, nelements, **recs->par, &status);
293 #endif
294  if (status) fits_report_error(stderr, status);
295 
296  // 6.3 write headers
297  char key[80] = "C.Li";
298  fits_write_key(fp, TSTRING, "CREATOR", key, "file created by Cheng Li",
299  &status);
300 
301  snprintf(key, sizeof(key), "%s", "par");
302  fits_write_key(fp, TSTRING, "VAR", key, "retrieved parameters", &status);
303 
304  snprintf(key, sizeof(key), "%s", "MCMC");
305  fits_write_key(fp, TSTRING, "METHOD", key, "retrieval method", &status);
306 
307  fits_write_key(fp, TDOUBLE, "A", &opts->a, "stretch move parameter",
308  &status);
309  fits_write_key(fp, TINT, "P", &opts->p, "walk move parameter", &status);
310 
311  fits_write_key(fp, TDOUBLE, "LOGP", &opt_lnp, "optimal log probability",
312  &status);
313  fits_write_key(fp, TINT, "RESET", &reset, "number of resetted states",
314  &status);
315  fits_write_key(fp, TINT, "ACCEPT", &accept, "number of accepted states",
316  &status);
317 
318  // 6.4 create function value fields, 2nd HDU
319  naxes[0] = nvalue;
320  nelements = naxes[0] * naxes[1] * naxes[2];
321  fits_create_img(fp, DOUBLE_IMG, naxis, naxes, &status);
322  if (status) fits_report_error(stderr, status);
323 
324  // write function values
325 #ifdef MPI_PARALLEL
326  fits_write_img(fp, TDOUBLE, fpixel, nelements, **val, &status);
327 #else
328  fits_write_img(fp, TDOUBLE, fpixel, nelements, **recs->val, &status);
329 #endif
330  if (status) fits_report_error(stderr, status);
331 
332  snprintf(key, sizeof(key), "%s", "val");
333  fits_write_key(fp, TSTRING, "VAR", key, "values of forward model", &status);
334 
335  // 6.5 create log probability fields, 3rd HDU
336  naxis = 2;
337  nelements = naxes[1] * naxes[2];
338  fits_create_img(fp, DOUBLE_IMG, naxis, naxes + 1, &status);
339  if (status) fits_report_error(stderr, status);
340 
341  snprintf(key, sizeof(key), "%s", "lnp");
342  fits_write_key(fp, TSTRING, "VAR", key, "log probability", &status);
343 
344  // write log probability
345 #ifdef MPI_PARALLEL
346  fits_write_img(fp, TDOUBLE, fpixel, nelements, *lnp, &status);
347 #else
348  fits_write_img(fp, TDOUBLE, fpixel, nelements, *recs->lnp, &status);
349 #endif
350  if (status) fits_report_error(stderr, status);
351 
352  // 6.6 create newstate masks, 4th HDU
353  fits_create_img(fp, SHORT_IMG, naxis, naxes + 1, &status);
354  if (status) fits_report_error(stderr, status);
355 
356  snprintf(key, sizeof(key), "%s", "inew");
357  fits_write_key(fp, TSTRING, "VAR", key, "new state indicator", &status);
358 
359  // write new state indicator
360 #ifdef MPI_PARALLEL
361  fits_write_img(fp, TINT, fpixel, nelements, *newstate, &status);
362 #else
363  fits_write_img(fp, TINT, fpixel, nelements, *recs->newstate, &status);
364 #endif
365  if (status) fits_report_error(stderr, status);
366 
367  fits_close_file(fp, &status);
368  }
369 #endif // FITSOUTPUT
370 
371 #ifdef MPI_PARALLEL
372  FreeCArray(par);
373  FreeCArray(val);
374  FreeCArray(lnp);
375  FreeCArray(newstate);
376 #endif
377 }
378 
379 void mcmc_load_fits(char const *fname, mcmc_opts *opts, mcmc_recs *recs,
380  int alloc) {
381  int status = 0, hdutype;
382  int nstep, nwalker, ndim, nvalue;
383  long dims[3] = {1, 1, 1};
384  long fpixel[3] = {1, 1, 1};
385 
386 #ifdef FITSOUTPUT
387  fitsfile *fp;
388 
389  // open FITS file
390  fits_open_file(&fp, fname, READONLY, &status);
391  if (status) {
392  fits_report_error(stderr, status);
393  exit(1);
394  }
395 
396  // move to the first hdu, containing the parameters
397  fits_movabs_hdu(fp, 1, &hdutype, &status);
398 
399  // read img dimensions
400  fits_get_img_size(fp, 3, dims, &status);
401  nstep = dims[2];
402  nwalker = dims[1];
403  ndim = dims[0];
404 
405  // move to the second hdu, containing the values of the forward model
406  fits_movabs_hdu(fp, 2, &hdutype, &status);
407  fits_get_img_size(fp, 3, dims, &status);
408  nvalue = dims[0];
409 
410  // allocate memory
411  if (alloc) {
412  mcmc_alloc(recs, nstep, nwalker, ndim, nvalue);
413  } else {
414  assert(recs->nstep >= nstep);
415  assert(recs->nwalker == nwalker);
416  assert(recs->ndim == ndim);
417  assert(recs->nvalue == nvalue);
418  }
419 
420  // move to first hdu, read positions
421  fits_movabs_hdu(fp, 1, &hdutype, &status);
422  fits_read_pix(fp, TDOUBLE, fpixel, nstep * nwalker * ndim, NULL, **recs->par,
423  NULL, &status);
424 
425  // read keywords
426  fits_read_key(fp, TDOUBLE, "LOGP", &recs->opt_lnp, NULL, &status);
427  fits_read_key(fp, TDOUBLE, "A", &opts->a, NULL, &status);
428  fits_read_key(fp, TINT, "P", &opts->p, NULL, &status);
429  fits_read_key(fp, TINT, "RESET", &recs->reset, NULL, &status);
430  fits_read_key(fp, TINT, "ACCEPT", &recs->accept, NULL, &status);
431 
432  // move to second hdu, read values
433  fits_movabs_hdu(fp, 2, &hdutype, &status);
434  fits_read_pix(fp, TDOUBLE, fpixel, nstep * nwalker * nvalue, NULL,
435  **recs->val, NULL, &status);
436 
437  // move to third hdu, read lnp
438  fits_movabs_hdu(fp, 3, &hdutype, &status);
439  fits_read_pix(fp, TDOUBLE, fpixel, nstep * nwalker, NULL, *recs->lnp, NULL,
440  &status);
441 
442  // move to forth hdu, read new state indicator
443  fits_movabs_hdu(fp, 4, &hdutype, &status);
444  // fits_read_pix(fp, TSHORT, fpixel, nstep*nwalker, NULL,
445  fits_read_pix(fp, TINT, fpixel, nstep * nwalker, NULL, *recs->newstate, NULL,
446  &status);
447 
448  if (status) {
449  fits_report_error(stderr, status);
450  exit(1);
451  }
452 
453  recs->cur = nstep;
454 
455  fits_close_file(fp, &status);
456 #endif
457 }
458 
460  assert(dst->ndim == src->ndim);
461  assert(dst->nvalue == src->nvalue);
462  assert(dst->nwalker == src->nwalker);
463  assert(dst->nstep >= dst->cur + src->cur);
464 
465  int size_par = src->cur * src->nwalker * src->ndim;
466  int size_val = src->cur * src->nwalker * src->nvalue;
467  int size_lnp = src->cur * src->nwalker;
468  int cur = dst->cur;
469 
470  memcpy(*dst->par[cur], **src->par, size_par * sizeof(double));
471  memcpy(*dst->val[cur], **src->val, size_val * sizeof(double));
472  memcpy(dst->lnp[cur], *src->lnp, size_lnp * sizeof(double));
473  memcpy(dst->newstate[cur], *src->newstate, size_lnp * sizeof(int));
474 
475  if (dst->opt_lnp < src->opt_lnp) {
476  memcpy(dst->opt_par, src->opt_par, src->ndim * sizeof(double));
477  memcpy(dst->opt_val, src->opt_val, src->nvalue * sizeof(double));
478  dst->opt_lnp = src->opt_lnp;
479  }
480 
481  dst->cur += src->cur;
482  dst->accept += src->accept;
483  dst->reset += src->reset;
484 }
485 
486 void mcmc_report(mcmc_opts *opts, mcmc_recs *recs, char const *mode) {
487  int rank = 0, size = 1;
488  double **par, *lnp, **opt_par, **opt_val;
489  int accept;
490  double *mean, *sigma, *tau, **cov;
491 
492  struct {
493  double value;
494  int rank;
495  } opt_lnp;
496 
497  // indices
498  int nwalker = recs->nwalker;
499  int ndim = recs->ndim;
500  int nvalue = recs->nvalue;
501  int cur = recs->cur;
502 
503  // local statistics
504  mean = new double[ndim];
505  sigma = new double[ndim];
506  tau = new double[ndim];
507  NewCArray(cov, ndim, ndim);
508  mcmc_statistics(mean, sigma, tau, recs);
509 
510  // amend the calculation of standard deviation
511  for (int d = 0; d < ndim; ++d) {
512  sigma[d] = 0.;
513  for (int t = 0; t < cur; ++t)
514  for (int k = 0; k < nwalker; ++k)
515  sigma[d] += sqr(recs->par[t][k][d] - mean[d]);
516  }
517 
518  // calculate correlation coefficients
519  for (int i = 0; i < ndim; ++i)
520  for (int j = 0; j < ndim; ++j) {
521  cov[i][j] = 0;
522  for (int t = 0; t < cur; ++t)
523  for (int k = 0; k < nwalker; ++k)
524  cov[i][j] +=
525  (recs->par[t][k][i] - mean[i]) * (recs->par[t][k][j] - mean[j]);
526  }
527 
528 #ifdef MPI_PARALLEL
529  MPI_Comm_rank(opts->mpi_comm, &rank);
530  MPI_Comm_size(opts->mpi_comm, &size);
531 
532  lnp = new double[nwalker * size];
533  NewCArray(par, nwalker * size, ndim);
534  NewCArray(opt_par, size, ndim);
535  NewCArray(opt_val, size, nvalue);
536 
537  // 1. gather walker positions
538  MPI_Gather(*recs->par[cur - 1], nwalker * ndim, MPI_DOUBLE, *par,
539  nwalker * ndim, MPI_DOUBLE, 0, opts->mpi_comm);
540 
541  // 2. gather log probability
542  MPI_Gather(recs->lnp[cur - 1], nwalker, MPI_DOUBLE, lnp, nwalker, MPI_DOUBLE,
543  0, opts->mpi_comm);
544 
545  // 3. gather optimal positions
546  MPI_Gather(recs->opt_par, ndim, MPI_DOUBLE, *opt_par, ndim, MPI_DOUBLE, 0,
547  opts->mpi_comm);
548 
549  // 4. gather optimal forward result
550  MPI_Gather(recs->opt_val, nvalue, MPI_DOUBLE, *opt_val, nvalue, MPI_DOUBLE, 0,
551  opts->mpi_comm);
552 
553  // 5. reduce optimal log probability with rank
554  opt_lnp.value = recs->opt_lnp;
555  opt_lnp.rank = rank;
556  if (rank == 0)
557  MPI_Reduce(MPI_IN_PLACE, &opt_lnp, 1, MPI_DOUBLE_INT, MPI_MAXLOC, 0,
558  opts->mpi_comm);
559  else
560  MPI_Reduce(&opt_lnp, &opt_lnp, 1, MPI_DOUBLE_INT, MPI_MAXLOC, 0,
561  opts->mpi_comm);
562 
563  // 6. reduce total number of accepted states
564  MPI_Reduce(&recs->accept, &accept, 1, MPI_INT, MPI_SUM, 0, opts->mpi_comm);
565 
566  // 7. reduce mean value
567  MPI_Allreduce(MPI_IN_PLACE, mean, ndim, MPI_DOUBLE, MPI_SUM, opts->mpi_comm);
568  for (int d = 0; d < ndim; ++d) mean[d] /= size;
569 
570  // 8. reduce standard deviation
571  if (rank == 0)
572  MPI_Reduce(MPI_IN_PLACE, sigma, ndim, MPI_DOUBLE, MPI_SUM, 0,
573  opts->mpi_comm);
574  else
575  MPI_Reduce(sigma, sigma, ndim, MPI_DOUBLE, MPI_SUM, 0, opts->mpi_comm);
576 
577  // 9. reduce correlation coefficients
578  if (rank == 0)
579  MPI_Reduce(MPI_IN_PLACE, *cov, ndim * ndim, MPI_DOUBLE, MPI_SUM, 0,
580  opts->mpi_comm);
581  else
582  MPI_Reduce(*cov, *cov, ndim * ndim, MPI_DOUBLE, MPI_SUM, 0, opts->mpi_comm);
583 
584  // 10. reduce autocorrelation time
585  if (rank == 0)
586  MPI_Reduce(MPI_IN_PLACE, tau, ndim, MPI_DOUBLE, MPI_SUM, 0, opts->mpi_comm);
587  else
588  MPI_Reduce(tau, tau, ndim, MPI_DOUBLE, MPI_SUM, 0, opts->mpi_comm);
589  for (int d = 0; d < ndim; ++d) tau[d] /= size;
590 #else
591  par = recs->par[cur - 1];
592  lnp = recs->lnp[cur - 1];
593  opt_par = new double *[1];
594  opt_par[0] = recs->opt_par;
595  opt_val = new double *[1];
596  opt_val[0] = recs->opt_val;
597  opt_lnp.value = recs->opt_lnp;
598  opt_lnp.rank = rank;
599  accept = recs->accept;
600 #endif
601 
602  // final step for standard deviation
603  for (int d = 0; d < ndim; ++d)
604  sigma[d] = sqrt(sigma[d] / (nwalker * size * cur));
605 
606  // final step for correlation coefficients
607  for (int i = 0; i < ndim; ++i)
608  for (int j = 0; j < ndim; ++j) cov[i][j] /= size * nwalker * cur;
609 
610  // report
611  if (rank == 0) {
612  FILE *fout = fopen(opts->logfile, mode);
613 
614  fprintf(fout, "#### MCMC Iteration: No. %d ####\n", recs->reset + cur);
615  // 1. walkers positions
616  fprintf(fout, "1. Current positions:\n");
617  fprintf(fout, "%3s", " ");
618  for (int d = 0; d < ndim; ++d) fprintf(fout, "%9s%-2d", "D", d + 1);
619  fprintf(fout, "\n");
620  for (int k = 0; k < nwalker * size; k++) {
621  fprintf(fout, "%3d", static_cast<int>(k) + 1);
622  for (int d = 0; d < ndim; ++d) fprintf(fout, "%11.4g", par[k][d]);
623  fprintf(fout, " |%9.4f\n", lnp[k]);
624  fflush(stdout);
625  }
626 
627  // 2. optimal position
628  fprintf(fout, "2. Optimal parameters:\n");
629  fprintf(fout, "%3s", " ");
630  for (int d = 0; d < ndim; ++d)
631  fprintf(fout, "%11.4g", opt_par[opt_lnp.rank][d]);
632  fprintf(fout, "\n");
633 
634  // 3. mean value
635  fprintf(fout, "4. Mean value:\n");
636  fprintf(fout, "%3s", " ");
637  for (int d = 0; d < ndim; ++d) fprintf(fout, "%11.4g", mean[d]);
638  fprintf(fout, "\n");
639 
640  // 4. standard deviation
641  fprintf(fout, "4. Standard deviation:\n");
642  fprintf(fout, "%3s", " ");
643  for (int d = 0; d < ndim; ++d) fprintf(fout, "%11.4g", sigma[d]);
644  fprintf(fout, "\n");
645 
646  // 5. correlation coefficient
647  fprintf(fout, "5. Correlation coefficient:\n");
648  for (int i = 0; i < ndim; ++i) {
649  fprintf(fout, "%1s%-2d", "D", i + 1);
650  for (int j = 0; j < ndim; ++j)
651  fprintf(fout, "%11.4g", cov[i][j] / (sigma[i] * sigma[j]));
652  fprintf(fout, "\n");
653  }
654 
655  // 6. autocorrelation time
656  fprintf(fout, "6. Autocorrelation time:\n");
657  fprintf(fout, "%3s", " ");
658  for (int d = 0; d < ndim; ++d) fprintf(fout, "%11.4g", tau[d]);
659  fprintf(fout, "\n");
660 
661  // 7. optimal model results
662  fprintf(fout, "7. Optimal model results:\n");
663  for (int d = 0; d < nvalue; ++d) {
664  fprintf(fout, "%11.4f", opt_val[opt_lnp.rank][d]);
665  if ((d + 1) % 6 == 0) fprintf(fout, "\n");
666  }
667  if (nvalue % 6 != 0) fprintf(fout, "\n");
668 
669  // 8. optimal probability
670  fprintf(fout, "8. Optimal log probability:\n");
671  fprintf(fout, "%11.4g\n", opt_lnp.value);
672 
673  // 9. acceptance fraction
674  fprintf(fout, "9. Acceptance fraction:\n");
675  fprintf(fout, "%11.4g",
676  1. * accept / ((recs->reset + cur) * nwalker * size));
677  fprintf(fout, "\n##############################\n");
678 
679  fclose(fout);
680  }
681 
682 #ifdef MPI_PARALLEL
683  delete[] lnp;
684  FreeCArray(par);
685  FreeCArray(opt_par);
686  FreeCArray(opt_val);
687 #else
688  delete[] opt_par;
689  delete[] opt_val;
690 #endif
691 
692  delete[] mean;
693  delete[] sigma;
694  delete[] tau;
695  FreeCArray(cov);
696 }
697 
698 void mcmc_init(ObjectiveFunction_t lnprob, double **par, mcmc_opts *opts,
699  mcmc_recs *recs, void *obj) {
700  int nwalker = recs->nwalker;
701  int ndim = recs->ndim;
702  int nval = recs->nvalue;
703 
704  // make sure that the start points are valid
705  for (int k = 0; k < nwalker; ++k) {
706  recs->lnp[0][k] = lnprob(par[k], recs->val[0][k], ndim, nval, obj);
707 
708  int niter = 0;
709  while (std::isnan(recs->lnp[0][k]) &&
710  (niter++ < 10)) { // if point (k) is invalid
711  mcmc_stretch_move(par[k], par, k, nwalker, ndim, opts);
712  recs->lnp[0][k] = lnprob(par[k], recs->val[0][k], ndim, nval, obj);
713  }
714 
715  if (niter >= 10) {
716  std::cerr << "Starting point iteration > 10 times" << std::endl;
717  std::exit(1);
718  }
719 
720  // transfer input parameters to records
721  for (int d = 0; d < ndim; ++d) recs->par[0][k][d] = par[k][d];
722 
723  if (recs->lnp[0][k] > recs->opt_lnp) {
724  recs->opt_lnp = recs->lnp[0][k];
725  for (int d = 0; d < ndim; ++d) recs->opt_par[d] = recs->par[0][k][d];
726  for (int d = 0; d < nval; ++d) recs->opt_val[d] = recs->val[0][k][d];
727  }
728  recs->newstate[0][k] = 1;
729  }
730 
731  recs->cur++;
732  recs->accept += nwalker;
733 
734  // make initial output
735  mcmc_report(opts, recs, "w");
736 }
737 
739  void *obj) {
740  int cur = recs->cur;
741  int ndim = recs->ndim;
742  int nwalker = recs->nwalker;
743  int nval = recs->nvalue;
744 
745  double *par = new double[ndim];
746 
747  unsigned int seed = time(NULL);
748  for (int k = 0; k < nwalker; ++k) {
749  double zz =
750  mcmc_stretch_move(par, recs->par[cur - 1], k, nwalker, ndim, opts);
751  // mcmc_walk_move(par_all + k*np, par, np, k, nwalker, zz + k, opts);
752 
753  recs->lnp[cur][k] = lnprob(par, recs->val[cur][k], ndim, nval, obj);
754 
755  double lnp0 = recs->lnp[cur - 1][k], lnp1 = recs->lnp[cur][k],
756  pdiff = (ndim - 1.) * log(zz) + lnp1 - lnp0;
757 
758  if (pdiff > log(1. * rand_r(&seed) / RAND_MAX)) { // accept this position
759  for (int d = 0; d < ndim; ++d) recs->par[cur][k][d] = par[d];
760 
761  if (lnp1 > recs->opt_lnp) { // new best position
762  recs->opt_lnp = lnp1;
763  for (int d = 0; d < ndim; ++d) recs->opt_par[d] = recs->par[cur][k][d];
764  for (int d = 0; d < nval; ++d) recs->opt_val[d] = recs->val[cur][k][d];
765  }
766 
767  recs->accept++;
768  recs->newstate[cur][k] = 1;
769  } else { // do not accept this position
770  for (int d = 0; d < ndim; ++d)
771  recs->par[cur][k][d] = recs->par[cur - 1][k][d];
772  for (int d = 0; d < nval; ++d)
773  recs->val[cur][k][d] = recs->val[cur - 1][k][d];
774  recs->lnp[cur][k] = recs->lnp[cur - 1][k];
775  recs->newstate[cur][k] = 0;
776  }
777  }
778 
779  recs->cur++;
780  if (recs->cur % opts->print == 0) mcmc_report(opts, recs, "a");
781  delete[] par;
782 }
783 
784 double mcmc_stretch_move(double *newp, double **oldp, int iwalker, int nwalker,
785  int ndim, mcmc_opts *opts) {
786  int irank = 0, size = 1;
787  double ***par;
788 
789 #ifdef MPI_PARALLEL
790  MPI_Comm_rank(opts->mpi_comm, &irank);
791  MPI_Comm_size(opts->mpi_comm, &size);
792 #endif
793 
794  NewCArray(par, size, nwalker, ndim);
795 
796 #ifdef MPI_PARALLEL
797  MPI_Allgather(*oldp, nwalker * ndim, MPI_DOUBLE, **par, nwalker * ndim,
798  MPI_DOUBLE, opts->mpi_comm);
799 #else
800  for (int k = 0; k < nwalker; ++k)
801  for (int d = 0; d < ndim; ++d) par[0][k][d] = oldp[k][d];
802 #endif
803 
804  // strech step
805  unsigned int seed = time(NULL);
806  double r = 1. * rand_r(&seed) / RAND_MAX;
807  // *zz = sqr((opts->a - 1.) * r + 1.) / opts->a;
808  double zz = ((opts->a - 1.) * r + 1.) * ((opts->a - 1.) * r + 1) / opts->a;
809 
810  int jwalker; // pick a waker
811  int jrank = rand_r(&seed) % size; // pick a rank
812  if (jrank == irank) { // same rank
813  jwalker = rand_r(&seed) % (nwalker - 1);
814  if (jwalker >= iwalker) jwalker++; // avoid myself
815  } else { // another rank
816  jwalker = rand_r(&seed) % nwalker;
817  }
818 
819  for (int d = 0; d < ndim; ++d)
820  newp[d] = (1. - zz) * par[jrank][jwalker][d] + zz * par[irank][iwalker][d];
821 
822  FreeCArray(par);
823 
824  return zz;
825 }
826 
827 void mcmc_walk_move(double *newp, double **oldp, int k, int nwalker, int np,
828  mcmc_opts *opts) {
829  int *sub = new int[opts->p];
830  double **cov;
831  double *mean = new double[np], *diag = new double[np];
832 
833  NewCArray(cov, np, np);
834 
835  // draw unique sub-sample of size opts->p
836  bool redraw;
837  assert(opts->p < static_cast<int>(nwalker));
838  assert(opts->p > static_cast<int>(np));
839 
840  unsigned int seed = time(NULL);
841 
842  for (int i = 0; i < opts->p; ++i) {
843  do {
844  int s = rand_r(&seed) % (nwalker - 1);
845  if (s >= static_cast<int>(k)) s++;
846  redraw = false;
847  for (int j = 0; j < i; ++j)
848  if (sub[j] == s) redraw = true;
849  if (!redraw) sub[i] = s;
850  } while (redraw);
851  }
852 
853  // calculate mean
854  for (size_t p = 0; p < np; ++p) {
855  mean[p] = 0.;
856  for (int q = 0; q < opts->p; ++q) mean[p] += oldp[sub[q]][p];
857  mean[p] /= opts->p;
858  }
859 
860  // calculate covariance matrix of this sample
861  for (size_t i = 0; i < np; ++i) {
862  for (size_t j = 0; j < np; ++j) {
863  cov[i][j] = 0.;
864  for (int q = 0; q < opts->p; ++q)
865  cov[i][j] += (oldp[sub[q]][i] - mean[i]) * (oldp[sub[q]][j] - mean[j]);
866  cov[i][j] /= opts->p;
867  }
868  }
869 
870  // Cholesky decomposition: cov = L * L'
871  // L is stored in the lower triangle of A, with diag being the diagonal
872  // elements
873  _choldc(cov, np, diag);
874 
875  // Box-Muller method to generate standard multi-variate normal
876  // https://en.wikipedia.org/wiki/Normal_distribution#Generating_values_from_normal_distribution
877  // mean is reused to store the standard normal variable
878 
879  for (size_t i = 0; i < np; ++i) {
880  double u = 1. * rand_r(&seed) / RAND_MAX;
881  double v = 1. * rand_r(&seed) / RAND_MAX;
882 
883  mean[i] = sqrt(-2. * log(u)) * cos(2. * M_PI * v);
884  }
885 
886  // multi-variate gaussian with cov: Y = P + L * X, x is a standard normal
887  for (size_t i = 0; i < np; ++i) {
888  newp[i] = oldp[k][i];
889  for (size_t j = 0; j < i; ++j) newp[i] += cov[i][j] * mean[j];
890  newp[i] += diag[i] * mean[i];
891  }
892 
893  delete[] diag;
894  delete[] mean;
895  delete[] sub;
896 
897  FreeCArray(cov);
898 }
double sqr(double x)
Definition: core.h:14
void mcmc_load_fits(char const *fname, mcmc_opts *opts, mcmc_recs *recs, int alloc)
Definition: mcmc.cpp:379
#define MAXLAG
Definition: mcmc.cpp:54
void mcmc_statistics(double *mean, double *sigma, double *tau, mcmc_recs *recs)
Definition: mcmc.cpp:160
void mcmc_append_recs(mcmc_recs *dst, mcmc_recs *src)
Definition: mcmc.cpp:459
void _choldc(double **a, int n, double *p)
Definition: mcmc.cpp:27
#define MINFAC
Definition: mcmc.cpp:58
void mcmc_advance(ObjectiveFunction_t lnprob, mcmc_opts *opts, mcmc_recs *recs, void *obj)
Definition: mcmc.cpp:738
void mcmc_report(mcmc_opts *opts, mcmc_recs *recs, char const *mode)
Definition: mcmc.cpp:486
void mcmc_init(ObjectiveFunction_t lnprob, double **par, mcmc_opts *opts, mcmc_recs *recs, void *obj)
Definition: mcmc.cpp:698
#define WINMULT
Definition: mcmc.cpp:50
void mcmc_free(mcmc_recs *recs)
Definition: mcmc.cpp:151
int _acor(double *mean, double *sigma, double *tau, double *X, int L)
Definition: mcmc.cpp:60
void mcmc_alloc(mcmc_recs *recs, int nstep, int nwalker, int ndim, int nvalue)
Definition: mcmc.cpp:126
void mcmc_save_fits(char const *fname, mcmc_opts *opts, mcmc_recs *recs, int include_last)
Definition: mcmc.cpp:179
void mcmc_walk_move(double *newp, double **oldp, int k, int nwalker, int np, mcmc_opts *opts)
Definition: mcmc.cpp:827
double mcmc_stretch_move(double *newp, double **oldp, int iwalker, int nwalker, int ndim, mcmc_opts *opts)
Definition: mcmc.cpp:784
This file contains data structure and subroutines implementing Markov Chain Monte Carlo sampler.
double(* ObjectiveFunction_t)(double *, double *, int, int, void *)
Definition: mcmc.hpp:93
void FreeCArray(T **a)
Definition: ndarrays.hpp:13
void NewCArray(T **&a, int n1, int n2)
Definition: ndarrays.hpp:5
int print
Definition: mcmc.hpp:40
int p
Definition: mcmc.hpp:38
char logfile[80]
Definition: mcmc.hpp:41
double a
Definition: mcmc.hpp:37
double *** val
Definition: mcmc.hpp:56
int ** newstate
Definition: mcmc.hpp:62
double * opt_par
Definition: mcmc.hpp:59
int nstep
Definition: mcmc.hpp:53
int reset
Definition: mcmc.hpp:66
int ndim
Definition: mcmc.hpp:50
int accept
Definition: mcmc.hpp:65
double * opt_val
Definition: mcmc.hpp:60
int nvalue
Definition: mcmc.hpp:51
double ** lnp
Definition: mcmc.hpp:57
double opt_lnp
Definition: mcmc.hpp:67
int cur
Definition: mcmc.hpp:64
int nwalker
Definition: mcmc.hpp:52
double *** par
Definition: mcmc.hpp:55