SedSat3 1.1.6
Sediment Source Apportionment Tool - Advanced statistical methods for environmental pollution research
Loading...
Searching...
No Matches
MCMC.hpp
Go to the documentation of this file.
1// MCMC.cpp : Defines the entry point for the console application.
2//
3
4#include <vector>
5#include "NormalDist.h"
6#include <string>
7#ifndef mac_version
8#include <omp.h>
9#endif
10#include "MCMC.h"
11#include "progressreporter.h"
12#include <QCoreApplication>
13#include <QEventLoop>
14#include <iostream>
15#include "Utilities.h"
16
17
18
19//using namespace std;
20
21template<class T>
23{
24}
25
26template<class T>
28{
29 Params.clear();
30 logp1.clear();
31 logp.clear();
32}
33
34
35template<class T>
37{
38 return &parameters->at(i);
39}
40
41
42template <class T>
44{
45 return (&observations->at(i));
46}
47
48template<class T>
49TimeSeriesSet<double> CMCMC<T>::model(vector<double> par)
50{
51 double sum = 0;
52 vector<TimeSeriesSet<double>> res;
53
54
55 T G1 = *Model;
56 G1.SetSilent(true);
57 G1.SetRecordResults(false);
58 G1.SetNumThreads(1);
59 for (int i=0; i<MCMC_Settings.number_of_parameters; i++)
60 G1.SetParameterValue(i, par[i]);
61
62 G1.ApplyParameters();
63 G1.Solve();
64 sum +=G1.GetObjectiveFunctionValue();
65
66 return G1.Outputs.ObservedOutputs;
67
68}
69
70template<class T>
71bool CMCMC<T>::SetProperty(const string &varname, const string &value)
72{
73
74 if (aquiutils::tolower(varname) == "number_of_samples") {MCMC_Settings.total_number_of_samples = aquiutils::atoi(value); return true;}
75 if (aquiutils::tolower(varname) == "number_of_chains") {MCMC_Settings.number_of_chains = aquiutils::atoi(value); return true;}
76 if (aquiutils::tolower(varname) == "number_of_burnout_samples") {MCMC_Settings.burnout_samples = aquiutils::atoi(value); return true;}
77 if (aquiutils::tolower(varname) == "initial_purturbation_factor") {MCMC_Settings.purturbation_factor = aquiutils::atof(value); return true;}
78 if (aquiutils::tolower(varname) == "record_interval") {MCMC_Settings.save_interval = aquiutils::atoi(value); return true;}
79 if (aquiutils::tolower(varname) == "initial_purturbation")
80 {
81 if (aquiutils::tolower(value)=="yes")
82 MCMC_Settings.noinipurt = false;
83 else
84 MCMC_Settings.noinipurt = true;
85 return true;
86 }
87 if (aquiutils::tolower(varname) == "perform_global_sensitivity")
88 {
89 if (aquiutils::tolower(value)=="yes")
90 MCMC_Settings.global_sensitivity = true;
91 else
92 MCMC_Settings.global_sensitivity = false;
93 return true;
94 }
95 if (aquiutils::tolower(varname) == "continue_based_on_file_name")
96 {
97 if (value!="")
98 { MCMC_Settings.continue_filename = value;
99 MCMC_Settings.continue_mcmc = true;
100 }
101 else
102 MCMC_Settings.continue_mcmc = false;
103 return true;
104 }
105 if (aquiutils::tolower(varname) == "samples_filename")
106 {
107 if (value!="")
108 {
109 if (value.find_first_of('/')!=string::npos || value.find_first_of('\\')!=string::npos)
110 FileInformation.outputfilename = value;
111 else
112 FileInformation.outputfilename = FileInformation.outputpath + value;
113 }
114
115
116 return true;
117 }
118 if (aquiutils::tolower(varname) == "number_of_post_estimate_realizations")
119 {
120 MCMC_Settings.number_of_post_estimate_realizations = aquiutils::atoi(value);
121 return true;
122 }
123 if (aquiutils::tolower(varname) == "increment_for_sensitivity_analysis")
124 {
125 MCMC_Settings.dp_sens = aquiutils::atof(value);
126 return true;
127 }
128 if (aquiutils::tolower(varname) == "add_noise_to_realizations")
129 {
130 if (aquiutils::tolower(value)=="yes")
131 MCMC_Settings.noise_realization_writeout = true;
132 else
133 MCMC_Settings.noise_realization_writeout = false;
134 return true;
135
136 }
137 if (aquiutils::tolower(varname) == "number_of_threads")
138 {
139 MCMC_Settings.numberOfThreads = aquiutils::atoi(value);
140 return true;
141 }
142 if (aquiutils::tolower(varname) == "acceptance_rate")
143 {
144 MCMC_Settings.acceptance_rate = aquiutils::atof(value);
145 return true;
146 }
147 if (aquiutils::tolower(varname) == "purturbation_change_scale")
148 {
149 MCMC_Settings.purt_change_scale = aquiutils::atof(value);
150 return true;
151 }
152 if (aquiutils::tolower(varname) == "dissolve_chains")
153 {
154 if (aquiutils::tolower(value)=="true")
155 MCMC_Settings.dissolve_chains = true;
156 else
157 MCMC_Settings.dissolve_chains = false;
158 return true;
159 }
160
161 last_error = "Property '" + varname + "' was not found!";
162 return false;
163}
164
165
166template<class T>
167double CMCMC<T>::posterior(vector<double> par, int chain_counter)
168{
169 double sum = 0;
170
171 for (int i = 0; i < MCMC_Settings.number_of_parameters; i++)
172 CopiedModels[chain_counter].SetParameterValue(i, par[i]);
173
174 for (int i = 0; i < MCMC_Settings.number_of_parameters; i++)
175 sum+=parameter(i)->CalcLogPriorProbability(par[i]);
176
177
178 sum+= -CopiedModels[chain_counter].GetObjectiveFunctionValue();
179 temp_predicted[chain_counter] = CopiedModels[chain_counter].GetPredictedValues();
180
181 return sum;
182}
183
184template<class T>
185void CMCMC<T>::model(T *Model1, vector<double> par)
186{
187
188 for (int i=0; i<MCMC_Settings.number_of_parameters; i++)
189 {
190 Model1->SetSilent(true);
191 Model1->SetRecordResults(false);
192 Model1->SetNumThreads(1);
193 for (unsigned int i = 0; i < MCMC_Settings.number_of_parameters; i++)
194 Model1->SetParameterValue(i, par[i]);
195 Model1->ApplyParameters();
196 }
197
198 Model1->Solve();
199
200}
201
202template<class T>
203void CMCMC<T>::initialize(CMBTimeSeriesSet *results, bool random)
204{
205 parameters = &Model->Parameters();
206 Params.resize(MCMC_Settings.total_number_of_samples);
207 logp.resize(MCMC_Settings.total_number_of_samples);
208 logp1.resize(MCMC_Settings.total_number_of_samples);
209 pertcoeff.resize(parameters->size());
210 MCMC_Settings.number_of_parameters = Model->Parameters().size();
211
212 for (unsigned int i=0; i<MCMC_Settings.total_number_of_samples; i++)
213 Params[i].resize(MCMC_Settings.number_of_parameters);
214
215 results->resize(MCMC_Settings.number_of_parameters);
216 results->SetAllSeriesSize(MCMC_Settings.total_number_of_samples);
217 predicted.resize(Model->ObservationsCount());
218 predicted.SetAllSeriesSize(MCMC_Settings.total_number_of_samples);
219 temp_predicted.resize(MCMC_Settings.number_of_chains);
220 CopiedModels.resize(MCMC_Settings.number_of_chains);
221 for (unsigned int i=0; i<MCMC_Settings.number_of_chains; i++)
222 {
223 CopiedModels[i] = *Model;
224 }
225 double pp=0;
226 for (int j = 0; j<MCMC_Settings.number_of_parameters; j++)
227 {
228 if (parameter(j)->GetPriorDistribution()=="normal" || parameter(j)->GetPriorDistribution()=="uniform")
229 {
230 pertcoeff[j] = MCMC_Settings.purturbation_factor*(-parameter(j)->GetRange(_range::low) + parameter(j)->GetRange(_range::high));
231 }
232 if (parameter(j)->GetPriorDistribution()=="log-normal")
233 {
234 pertcoeff[j] = MCMC_Settings.purturbation_factor*(-log(parameter(j)->GetRange(_range::low)) + log(parameter(j)->GetRange(_range::high)));
235 }
236 }
237
238 if (random)
239 { for (int j=0; j<MCMC_Settings.number_of_chains; j++)
240 {
241 double posterior_value = -2e6;
242 while (posterior_value<-1e6)
243 { for (int i=0; i<MCMC_Settings.number_of_parameters; i++)
244 { if (parameter(i)->GetPriorDistribution()=="log-normal")
245 Params[j][i] = exp(log(parameter(i)->GetRange(_range::low))+(log(parameter(i)->GetRange(_range::high))-log(parameter(i)->GetRange(_range::low)))*unitrandom());
246 else
247 Params[j][i] = parameter(i)->GetRange(_range::low)+(parameter(i)->GetRange(_range::high)-parameter(i)->GetRange(_range::low))*unitrandom();
248 if (parameter(i)->GetPriorDistribution()=="log-normal")
249 pp += log(Params[j][i]);
250 }
251
252 logp[j] = posterior(Params[j],j);
253 posterior_value = logp[j];
254 logp1[j] = logp[j]+pp;
255 }
256 results->SetRow(j,j,Params[j]);
257 cout<<"success!";
258 predicted.SetRow(j,j,CopiedModels[j].GetPredictedValues().vec);
259 temp_predicted[j] = CopiedModels[j].GetPredictedValues();
260 }
261 }
262
263 else
264 {
265 for (int j=0; j<MCMC_Settings.number_of_chains; j++)
266 { for (int i=0; i<MCMC_Settings.number_of_parameters; i++)
267 { Params[j][i] = parameter(i)->GetValue();
268 if (parameter(i)->GetPriorDistribution()=="log-normal")
269 pp += log(Params[j][i]);
270 }
271 logp[j] = posterior(Params[j],j);
272 logp1[j] = logp[j]+pp;
273 }
274 }
275
276}
277
278
279
280template<class T>
281void CMCMC<T>::initialize(vector<double> par)
282{
283
284 if (MCMC_Settings.sensbasedpurt == true)
285 {
286 CVector X = sensitivity(1e-4, par);
287
288 for (int j = 0; j<MCMC_Settings.number_of_parameters; j++)
289 {
290 if (parameter(j).Get_Distribution()=="normal" || parameter(j).Get_Distribution()=="uniform")
291 {
292 pertcoeff[j] = MCMC_Settings.purturbation_factor / fabs(X[getparamno(j, 0)]);
293 }
294 if (parameter(j).Get_Distribution()=="log-normal")
295 {
296 pertcoeff[j] = MCMC_Settings.purturbation_factor / fabs(sqrt(par[j])*X[getparamno(j, 0)]);
297 }
298
299 }
300 }
301 else
302 for (int j = 0; j<MCMC_Settings.number_of_parameters; j++)
303 {
304 if (parameter(j).Get_Distribution()=="normal" || parameter(j).Get_Distribution()=="uniform")
305 {
306 pertcoeff[j] = MCMC_Settings.purturbation_factor*(-parameter(j)->GetRange().low + -parameter(j)->GetRange().high);
307 }
308 if (parameter(j).Get_Distribution()=="log-normal")
309 {
310 pertcoeff[j] = MCMC_Settings.purturbation_factor*(-log(parameter(j)->GetRange().low) + log(parameter(j)->GetRange().high));
311 }
312 }
313 double alpha;
314 if (MCMC_Settings.noinipurt == true) alpha = 0; else alpha = 1;
315
316
317 for (int j = 0; j<MCMC_Settings.number_of_chains; j++)
318 {
319 Params[j].resize(MCMC_Settings.number_of_parameters);
320 double pp = 0;
321 for (int i = 0; i<MCMC_Settings.number_of_parameters; i++)
322 {
323 if (parameter(i).Get_Distribution()=="normal" || parameter(i).Get_Distribution()=="uniform")
324 Params[j][i] = par[i] + alpha*getnormalrand(0, pertcoeff[i]);
325 else
326 { Params[j][i] = par[i] * exp(alpha*getnormalrand(0, pertcoeff[i]));
327 pp+=log(par[i]);
328 }
329 if (parameter(i).Get_Distribution()=="uniform")
330 while ((Params[j][i]<parameter(i).GetRange().low) || (Params[j][i]>parameter(i).GetRange(_range::high)))
331 Params[j][i] = par[i] + alpha*getnormalrand(0, pertcoeff[i]);
332
333 }
334 logp[j] = posterior(Params[j]);
335 logp1[j] = logp[j] + pp;
336 }
337}
338
339template<class T>
340bool CMCMC<T>::step(int k, int chain_counter)
341{
342
343 vector<double> X = purturb(k-MCMC_Settings.number_of_chains);
344 double pp =0;
345 for (int i=0; i<MCMC_Settings.number_of_parameters; i++)
346 {
347 if (parameter(i)->GetPriorDistribution()=="log-normal")
348 pp += log(X[i]);
350 double logp_0 = posterior(X,chain_counter) + pp;
351
352
353 double logp_1 = logp_0;
354 bool res;
355
356
357 if (unitrandom() <exp(logp_0-logp[k-MCMC_Settings.number_of_chains]) && !isnan(logp_0))
358 {
359 res=true;
360 Params[k] = X;
361 logp[k] = logp_0;
362 logp1[k] = logp_1;
363 predicted.SetRow(k,k,temp_predicted[chain_counter].vec);
364
365 //accepted_count += 1;
367 else
368 {
369 res = false;
370 Params[k] = Params[k-MCMC_Settings.number_of_chains];
371 logp[k] = logp[k-MCMC_Settings.number_of_chains];
372 logp1[k] = logp_1;
373 predicted.SetRow(k,k,predicted.getrow(k-MCMC_Settings.number_of_chains));
374 }
375 //total_count += 1;
376 return res;
377}
378
379template<class T>
380vector<double> CMCMC<T>::purturb(int k)
381{
382 vector<double> X;
383 X.resize(MCMC_Settings.number_of_parameters);
384 for (int i=0; i<MCMC_Settings.number_of_parameters; i++)
385 {
386 if (parameter(i)->GetPriorDistribution() == "log-normal")
387 X[i] = Params[k][i]*exp(pertcoeff[i]*getstdnormalrand());
388 else
389 X[i] = Params[k][i]+pertcoeff[i]*getstdnormalrand();
390
391 }
392 return X;
393}
394
395template<class T>
396bool CMCMC<T>::step(int k, int nsamps, string filename, CMBTimeSeriesSet *results, ProgressReporter *rtw)
397{
398 FILE *file;
399 if (!MCMC_Settings.continue_mcmc)
400 {
401 // fopen returns null when the path cannot be written, for instance
402 // when no working folder has been set and the name resolves to the
403 // root of the filesystem. Passing that to fclose or fprintf crashes,
404 // so refuse the run and say which path failed.
405 file = fopen(filename.c_str(),"w");
406 if (file == nullptr)
407 {
408 std::cerr << "MCMC: could not open '" << filename
409 << "' to write the sample output." << std::endl;
410 return false;
411 }
412 fclose(file);
413 }
414 qDebug()<<5;
415 if (!MCMC_Settings.continue_mcmc)
416 {
417 file = fopen(filename.c_str(),"a");
418 if (file == nullptr)
419 {
420 std::cerr << "MCMC: could not append to '" << filename
421 << "' to write the sample output." << std::endl;
422 return false;
423 }
424 fprintf(file,"%s, ", "no.");
425 for (unsigned int i=0; i<MCMC_Settings.number_of_parameters; i++)
426 { fprintf(file, "%s, ", parameter(i)->Name().c_str());
427 results->setname(i,parameter(i)->Name());
428 }
429 fprintf(file,"%s, %s, %s,", "logp", "logp_1", "stuck_counter");
430 for (unsigned int j=0; j<pertcoeff.size(); j++) fprintf(file,"%s,", string("purt_coeff_" + QString("%1").arg(j).toStdString()).c_str());
431 fprintf(file, "\n");
432 fclose(file);
433 }
434
435 CVector stuckcounter(MCMC_Settings.number_of_chains);
436 CVector accepted(MCMC_Settings.number_of_chains);
437
438 MCMC_Settings.ini_purt_fact = pertcoeff[0];
439 int k_0 = k;
440 qDebug()<<6;
441 for (unsigned int kk=k; kk<k+nsamps+MCMC_Settings.number_of_chains; kk+=MCMC_Settings.number_of_chains)
442 {
443 QCoreApplication::processEvents(QEventLoop::AllEvents,10*1000);
444
445#ifndef NO_OPENMP
446 omp_set_num_threads(MCMC_Settings.numberOfThreads);
447#endif
448
449
450#ifdef WIN64
451#pragma omp parallel
452 {
453 srand(int(time(NULL)) ^ omp_get_thread_num() + kk);
454 }
455#endif
456qDebug()<<7;
457#pragma omp parallel for
458 for (int jj = kk; jj < min(kk + MCMC_Settings.number_of_chains, MCMC_Settings.total_number_of_samples); jj++)
459 {
460 qDebug() << "Starting step: " + QString::number(jj);
461 bool stepstuck = !step(jj,jj-kk);
462 qDebug() << "Step: " + QString::number(jj) + "Done!";
463 if (stepstuck)
464 { stuckcounter[jj - kk]++;
465 accepted[jj-kk]=0;
466 }
467 else
468 { stuckcounter[jj - kk] = 0;
469 accepted[jj-kk]=1;
470 }
471
472 }
473
474 accepted_count += accepted.sum();
475 total_count += accepted.num;
476 QCoreApplication::processEvents(QEventLoop::AllEvents,100*1000);
477
478 if ((kk-k_0) % (50 * MCMC_Settings.number_of_chains) == 0 || kk == k + nsamps + MCMC_Settings.number_of_chains - 1)
479 {
480
481 if (MCMC_Settings.dissolve_chains)
482 { int_value_pair minchain = Min(logp,min(kk + MCMC_Settings.number_of_chains, MCMC_Settings.total_number_of_samples),MCMC_Settings.number_of_chains);
483 int_value_pair maxchain = Max(logp,min(kk + MCMC_Settings.number_of_chains, MCMC_Settings.total_number_of_samples),MCMC_Settings.number_of_chains);
484 double ratio = maxchain.value-minchain.value;
485 qDebug()<<"Ratio:"<<ratio;
486 if (ratio>5)
487 {
488 Params[minchain.counter] = Params[maxchain.counter];
489 logp[minchain.counter] = logp[maxchain.counter];
490 logp1[minchain.counter] = logp1[maxchain.counter];
491 }
492 }
493 file = fopen(filename.c_str(), "a");
494 for (int jj = max(int(min(kk + MCMC_Settings.number_of_chains, MCMC_Settings.total_number_of_samples) - 50 * MCMC_Settings.number_of_chains), k_0); jj < min(kk + MCMC_Settings.number_of_chains, MCMC_Settings.total_number_of_samples); jj++)
495 {
496 if (jj%MCMC_Settings.save_interval == 0)
497 {
498 //QCoreApplication::processEvents(QEventLoop::AllEvents,100*1000);
499
500 fprintf(file, "%i, ", jj);
501 for (int i = 0; i < MCMC_Settings.number_of_parameters; i++)
502 fprintf(file, "%le, ", Params[jj][i]);
503 if (!results->SetRow(jj, jj,Params[jj]))
504 {
505 cout<<"not enough room!";
506 }
507
508 fprintf(file, "%le, %le, %f,", logp[jj], logp1[jj], stuckcounter[jj%MCMC_Settings.number_of_chains]);
509 for (int j = 0; j < pertcoeff.size(); j++) fprintf(file, "%le,", pertcoeff[j]);
510 fprintf(file, "\n");
511
512 }
513
514 //cout << jj << "," << pertcoeff[0] << "," << stuckcounter.max() << "," << stuckcounter.min() << endl;
516 //if (jj<n_burnout)
517 }
518 fclose(file);
519 }
520
521 if ((kk-k_0) % (50*MCMC_Settings.number_of_chains) == 0)
522 {
523
524 if (double(accepted_count) / double(total_count)>MCMC_Settings.acceptance_rate)
525 for (int i = 0; i < MCMC_Settings.number_of_parameters; i++) pertcoeff[i] /= MCMC_Settings.purt_change_scale;
526 else
527 for (int i = 0; i < MCMC_Settings.number_of_parameters; i++) pertcoeff[i] *= MCMC_Settings.purt_change_scale;
528 accepted_count = 0;
529 total_count = 0;
530
531 }
532
533
534 if (rtw)
535 {
536 double average_log_p = CVector::Extract(logp,kk-100,kk).mean();
537 double progress = double(kk) / double(nsamps)*0.98;
538 rtw->SetProgress(progress);
539 rtw->AppendPoint(kk,double(accepted_count) / double(total_count),0);
540 rtw->AppendPoint(kk,double(pertcoeff[0] / MCMC_Settings.ini_purt_fact),1);
541 rtw->AppendPoint(kk,double(average_log_p),2);
542 QCoreApplication::processEvents();
543 }
544 }
545 qDebug()<<"MCMC done!";
546 return 0;
547}
548
549template<class T>
551{
552 rtw = _rtw;
553}
554
555template<class T>
557{
558 Model = _system;
559 MCMC_Settings.number_of_parameters = 0;
560 MCMC_Settings.numberOfThreads = 20;
561 FileInformation.outputpath = Model->OutputPath();
562
563 for (unsigned int i=0; i<Model->Parameters().size(); i++)
564 {
565 MCMC_Settings.number_of_parameters++;
566 params.push_back(i);
567 }
568 parameters = &Model->Parameters();
569 observations = Model->Observations();
570 pertcoeff.resize(parameters->size());
571}
572
573template<class T>
574CVector CMCMC<T>::sensitivity(double d, vector<double> par)
575{
576
577 double base = posterior(par);
578 CVector X(MCMC_Settings.number_of_parameters);
579 for (int i=0; i<MCMC_Settings.number_of_parameters; i++)
580 {
581 vector<double> par1 = par;
582 par1[i]=par[i]*(1+d);
583 double base_1 = posterior(par1);
584
585 X[i] = (sqrt(fabs(base))-sqrt(fabs(base_1)))/(d*par[i]);
586 }
587 return X;
588}
589
590
591template<class T>
592CVector CMCMC<T>::sensitivity_ln(double d, vector<double> par)
593{
594
595 CVector X = sensitivity(d, par);
596 for (int i=0; i<MCMC_Settings.number_of_parameters; i++)
597 {
598 X[i] = par[i]*X[i];
599 }
600 return X;
601}
602
603template<class T>
604int CMCMC<T>::readfromfile(string filename)
605{
606 ifstream file(filename);
607 vector<string> s;
608 s = aquiutils::getline(file);
609 int jj=0;
610 while (file.eof() == false)
611 {
612 s = aquiutils::getline(file);
613 if (s.size() == 2*MCMC_Settings.number_of_parameters+4)
614 { Params[jj].resize(MCMC_Settings.number_of_parameters);
615 for (int i=0; i<MCMC_Settings.number_of_parameters; i++)
616 {
617 Params[jj][i] = atof(s[i+1].c_str());
618 pertcoeff[i] = atof(s[MCMC_Settings.number_of_parameters+i+4].c_str());
619 }
620 logp[jj] = atof(s[MCMC_Settings.number_of_parameters+1].c_str());
621 logp1[jj] = atof(s[MCMC_Settings.number_of_parameters+2].c_str());
622 jj++;
623 }
624 }
625 file.close();
626 return jj;
627}
628
629template<class T>
630TimeSeriesSet<double> CMCMC<T>::prior_distribution(int n_bins)
631{
632 TimeSeriesSet<double> prior_dist(MCMC_Settings.number_of_parameters);
633 TimeSeries<double> B(n_bins);
634
635 double min_range , max_range;
636
637 for (int i=0; i<MCMC_Settings.number_of_parameters; i++)
638 {
639 if (parameter(i).GetDistribution() != "log-normal")
640 {
641 min_range = parameter(i)->mean() - 4*parameter(i)->std();
642 max_range = parameter(i)->mean() + 4*parameter(i)->std();;
643 }
644 if (parameter(i).GetDistribution() == "log-normal")
645 {
646 min_range = parameter(i)->mean() * exp(-4*parameter(i)->std());
647 max_range = parameter(i)->mean() * exp(4*parameter(i)->std());
648 }
649
650
651 double dp = abs(max_range - min_range) / n_bins;
652
653 B.setTime(0, min_range + dp/2);
654 for (int j=0; j<n_bins-1; j++)
655 B.setTime(j+1, B.getTime(j) + dp);
656
657 if (parameter(i).GetDistribution() != "log-normal")
658 for (int j=0; j<n_bins; j++)
659 B.setValue(j , exp(-pow(B.getTime(j)-parameter(i)->mean(),2)/(2.0*pow(parameter(i)->std(),2)))/(parameter(i)->std()*pow(6.28,0.5)));
660
661 if (parameter(i).GetDistribution() == "log-normal")
662 for (int j=0; j<n_bins; j++)
663 B.setValue(j, exp(-pow(log(B.getTime(j))-log(parameter(i)->mean()),2)/(2.0*pow(parameter(i)->std(),2)))/(B.getTime(j)*parameter(i)->std()*pow(6.28,0.5)));
664
665 prior_dist.at(i) = B;
666 }
667
668 return prior_dist;
669}
670
671template<class T>
672void CMCMC<T>::ProduceRealizations(TimeSeriesSet<double> &MCMCout)
673{
674
675 vector<TimeSeriesSet<double>> realized_timeseries(observations->size());
676 vector<TimeSeriesSet<double>> predicted_percentiles(observations->size());
677
678 for (unsigned int jj = 0; jj <=MCMC_Settings.number_of_post_estimate_realizations/MCMC_Settings.numberOfThreads; jj++)
679 {
680 vector<T> Sys1(MCMC_Settings.numberOfThreads);
681#ifndef NO_OPENMP
682 omp_set_num_threads(MCMC_Settings.numberOfThreads);
683#endif
684#pragma omp parallel for
685 for (int j = 0; j < min(MCMC_Settings.numberOfThreads, MCMC_Settings.number_of_post_estimate_realizations - jj*MCMC_Settings.numberOfThreads); j++)
686 {
687 Sys1[j] = *Model;
688 vector<double> sampled_parameters = MCMCout.getrandom(MCMC_Settings.burnout_samples);
689 model(&Sys1[j],sampled_parameters);
690 }
691
692 for (unsigned int j = 0; j < min(MCMC_Settings.numberOfThreads, MCMC_Settings.number_of_post_estimate_realizations - jj*MCMC_Settings.numberOfThreads); j++)
693 for (unsigned int i=0; i<observations->size(); i++)
694 realized_timeseries[i].append(*(Sys1[j].observation(i)->GetModeledTimeSeries()));
695
696 if (rtw)
697 {
698 double progress = double(jj*MCMC_Settings.numberOfThreads) / double(MCMC_Settings.number_of_post_estimate_realizations);
699 rtw->SetProgress(progress);
700 }
701 }
702 vector<double> percents; percents.push_back(0.025); percents.push_back(0.5); percents.push_back(0.975);
703 for (unsigned int i=0; i<observations->size(); i++)
704 {
705 realized_timeseries[i].write(FileInformation.outputpath + "Realizations_" + observation(i)->GetName() + ".txt");
706 predicted_percentiles[i] = realized_timeseries[i].getpercentiles(percents);
707 observation(i)->SetPercentile95(predicted_percentiles[i]);
708 predicted_percentiles[i].write(FileInformation.outputpath + "Predicted_95p_Bracket" + observation(i)->GetName() + ".txt");
709 observation(i)->SetRealizations(realized_timeseries[i]);
710
711 }
712 rtw->SetProgress(1);
713}
714
715template<class T>
716void CMCMC<T>::get_outputpercentiles(TimeSeriesSet<double> &MCMCout)
718
719 ProduceRealizations(MCMCout);
720 int n_BTCout_obs = Model->ObservationsCount();
721
722 BTCout_obs_prcntle.resize(1); for (int j = 0; j < 1; j++) BTCout_obs_prcntle[j].resize(n_BTCout_obs);
723 BTCout_obs_prcntle_noise.resize(1); for (int j = 0; j < 1; j++) BTCout_obs_prcntle_noise[j].resize(n_BTCout_obs);
724
725 if (calc_output_percentiles.size()>0)
726 for (int i = 0; i < n_BTCout_obs; i++)
727 {
728 for (int j = 0; j < 1; j++)
729 {
730 BTCout_obs_prcntle[j][i] = BTCout_obs[j][i].getpercentiles(calc_output_percentiles);
731
732 BTCout_obs_prcntle[j][i].write(FileInformation.outputpath + "BTC_obs_prcntl_" + Model->Observation(i)->GetName() + ".txt");
733
734 if (MCMC_Settings.noise_realization_writeout)
735 BTCout_obs_prcntle_noise[j][i] = BTCout_obs_noise[j][i].getpercentiles(calc_output_percentiles);
736
737 BTCout_obs_prcntle_noise[j][i].write(FileInformation.outputpath + "BTC_obs_prcntl_noise_" + Model->Observation(i)->GetName() + ".txt");
738
739 }
740 }
741
742}
743
744template<class T>
746{
747 initialize(false);
748 int mcmcstart = MCMC_Settings.number_of_chains;
749 if (MCMC_Settings.continue_mcmc)
750 {
751 //if (rtw) rtw->AppendText("Reading samples from ... " + MCMC_Settings.continue_filename);
752 mcmcstart = readfromfile(MCMC_Settings.continue_filename);
753 }
754 //if (rtw) rtw->AppendText(string("Generating samples ... "));
755 step(mcmcstart, int((MCMC_Settings.total_number_of_samples - mcmcstart) / MCMC_Settings.number_of_chains)*MCMC_Settings.number_of_chains, FileInformation.outputfilename , rtw);
756 //if (rtw) rtw->AppendText(string("Creating posterior distribution ..."));
757 TimeSeriesSet<double> all_posterior_distributions;
758 TimeSeriesSet<double> parameter_samples;
759 for (unsigned int i=0; i<parameters->size(); i++)
760 {
761 TimeSeriesSet<double> chain_values(MCMC_Settings.number_of_chains);
762 TimeSeries<double> all_samples;
763 for (unsigned int i=0; i<MCMC_Settings.number_of_chains; i++)
764 {
765 chain_values.setname(i,"Chain_" + aquiutils::numbertostring(i));
766 }
767 for (unsigned int j=MCMC_Settings.burnout_samples; j<MCMC_Settings.total_number_of_samples; j++)
768 chain_values[j%MCMC_Settings.number_of_chains].append(j,Params[j][i]);
769
770 for (unsigned int i=0; i<MCMC_Settings.number_of_chains; i++)
771 {
772 all_samples.append(chain_values[i]);
773 }
774
775 //chain_values.name = parameter(i)->GetName();
776 parameter(i)->SetMCMCSamples(chain_values);
777
778 TimeSeries<double> posterior_distribution = all_samples.distribution(all_samples.size()/100,0);
779 all_posterior_distributions.append(posterior_distribution,parameter(i)->GetName());
780 posterior_distribution.setName("Posterior density");
781 parameter(i)->SetPosteriorDistribution(posterior_distribution);
782 parameter_samples.append(all_samples);
783
784 }
785 all_posterior_distributions.write(FileInformation.outputpath + "Posterior_distributions.txt");
786 //if (rtw) rtw->AppendText(string("Generating Realizations ..."));
787 ProduceRealizations(parameter_samples);
789
790template<class T>
791int_value_pair CMCMC<T>::Min(const vector<double> &vec, int current_counter, int n_chains)
792{
793 int_value_pair out;
794 out.value = 1e12;
795 for (unsigned int i=max(current_counter-n_chains,0); i<current_counter; i++)
796 {
797 if (vec[i]<out.value)
798 {
799 out.value = vec[i];
800 out.counter = i;
801 }
802 }
803 return out;
805
806template<class T>
807int_value_pair CMCMC<T>::Max(const vector<double> &vec, int current_counter, int n_chains)
808{
809 int_value_pair out;
810 out.value = -1e12;
811 for (unsigned int i=max(current_counter-n_chains,0); i<current_counter; i++)
812 {
813 if (vec[i]>out.value)
814 {
815 out.value = vec[i];
816 out.counter = i;
817 }
818 }
819 return out;
820}
821
Collection of time series with labels and observed values.
void model(T *Model1, vector< double > par)
Evaluate model with given parameters.
Definition MCMC.hpp:185
bool SetProperty(const string &varname, const string &value)
Set MCMC properties from string key-value pairs.
Definition MCMC.hpp:71
TimeSeriesSet< double > prior_distribution(int n_bins)
Generate histogram of prior distributions.
Definition MCMC.hpp:630
void ProduceRealizations(TimeSeriesSet< double > &MCMCout)
Generate posterior predictive realizations.
Definition MCMC.hpp:672
Observation * observation(int i)
Get pointer to specific observation.
Definition MCMC.hpp:43
vector< double > purturb(int k)
Generate proposed parameter values by perturbing current state.
Definition MCMC.hpp:380
CMCMC(void)
Default constructor.
Definition MCMC.hpp:22
bool step(int k, int chain_counter)
Perform single MCMC step for one chain.
Definition MCMC.hpp:340
Parameter * parameter(int i)
Get pointer to specific parameter.
Definition MCMC.hpp:36
int_value_pair Max(const vector< double > &vec, int current_counter, int n_chains)
Find maximum value and its chain index.
Definition MCMC.hpp:807
double posterior(vector< double > par, int chain_counter)
Calculate log-posterior probability for given parameters.
Definition MCMC.hpp:167
void Perform()
Main entry point to run complete MCMC analysis.
Definition MCMC.hpp:745
void initialize(CMBTimeSeriesSet *results, bool random=false)
Initialize MCMC chains with starting parameter values.
Definition MCMC.hpp:203
int_value_pair Min(const vector< double > &vec, int current_counter, int n_chains)
Find minimum value and its chain index.
Definition MCMC.hpp:791
CVector sensitivity(double d, vector< double > par)
Calculate sensitivity of model output to parameters.
Definition MCMC.hpp:574
void get_outputpercentiles(TimeSeriesSet< double > &MCMCout)
Calculate percentiles of model outputs from MCMC samples.
Definition MCMC.hpp:716
CVector sensitivity_ln(double d, vector< double > par)
Calculate log-space sensitivity (for lognormal parameters)
Definition MCMC.hpp:592
int readfromfile(string filename)
Read MCMC state from file to continue previous run.
Definition MCMC.hpp:604
void SetRunTimeWindow(ProgressReporter *_rtw)
Set progress window for GUI updates.
Definition MCMC.hpp:550
~CMCMC(void)
Destructor.
Definition MCMC.hpp:27
Represents a model parameter with prior distribution and constraints.
Definition parameter.h:73
Abstract sink for progress information produced by a running analysis.
virtual void SetProgress(const double &prog)=0
Sets the primary progress fraction.
virtual void AppendPoint(const double &x, const double &y, int chart=0)=0
Adds a point to one of the progress charts.
@ low
Lower bound of the parameter range.
@ high
Upper bound of the parameter range.
Utility structure pairing an integer counter with a double value.
Definition MCMC.h:236
double value
Associated value (likelihood, parameter, etc.)
Definition MCMC.h:238
int counter
Chain or sample index.
Definition MCMC.h:237