Manticore  Version 2.0alpha
Physics of Molecular Clouds
solve.cc
Go to the documentation of this file.
1 
12 #include <algorithm>
13 #include <ctime>
14 #include <thread>
15 
16 #include <gsl/gsl_multifit_nlin.h>
17 
18 #include "Graybody.h"
19 #include "PACS.h"
20 #include "SPIRE.h"
21 
22 namespace mu = mutils;
23 
25 namespace manticore {
26 
27 const double mu_g = (2.75*m_H),
28  imu_g = 1.0/mu_g;
29 
31 struct GrayData {
33  GrayData(Graybody *g, std::vector<mapDataType> *o,
34  size_t bands, size_t param) :
35  gray(g), outMap(o), nBands(bands), nParam(param)
36  {
37  Fobs.resize(nBands);
38  Ferr.resize(nBands);
39  band.resize(nBands);
40  }
41 
43 
44  std::vector<long> axes;
45 
46  std::vector<double> Fobs,
47  Ferr,
48  dnu0,
49  fixed;
50 
51  std::vector<const Detector*>
52  band;
53 
54  std::vector<mapDataType>
55  *outMap;
56 
57 
58  size_t nBands,
59  nParam;
60 };
61 
62 
70 int f_gray(const gsl_vector *x, void *p, gsl_vector *f)
71 {
72  GrayData *gd = static_cast<GrayData *>(p);
73  const auto &Fobs = gd->Fobs, &Ferr = gd->Ferr;
74  const auto &gray = *gd->gray;
75 
76  size_t n = Ferr.size();
77  double T = gsl_vector_get(x, 0), S = gsl_vector_get(x, 1);
78  for (size_t i=0; i != n; i++) {
79  auto Di = gd->band[i];
80  double iFerr = 1.0/Ferr[i], F = gray.F(T, S, Di);
81  gsl_vector_set(f, i, (F - Fobs[i])*iFerr);
82  }
83 
84  return GSL_SUCCESS;
85 }
86 
94 int df_gray(const gsl_vector *x, void *p, gsl_matrix *J)
95 {
96  GrayData *gd = static_cast<GrayData *>(p);
97  const auto &Ferr = gd->Ferr;
98  const auto &gray = *gd->gray;
99 
100  size_t n = Ferr.size();
101  double T = gsl_vector_get(x, 0), S = gsl_vector_get(x, 1);
102  for (size_t i=0; i != n; i++) {
103  auto Di = gd->band[i];
104  double iFerr = 1.0/Ferr[i];
105  gsl_matrix_set(J, i, 0, gray.dF_dT(T, S, Di)*iFerr);
106  gsl_matrix_set(J, i, 1, gray.dF_dS(T, S, Di)*iFerr);
107  }
108 
109  return GSL_SUCCESS;
110 }
111 
120 int fdf_gray(const gsl_vector *x, void *p, gsl_vector *f, gsl_matrix *J)
121 { return f_gray(x, p, f), df_gray(x, p, J); }
122 
123 
131 int f_gray2(const gsl_vector *x, void *p, gsl_vector *f)
132 {
133  GrayData *gd = static_cast<GrayData *>(p);
134  const auto &Fobs = gd->Fobs, &Ferr = gd->Ferr;
135  const auto &gray = *gd->gray;
136 
137  size_t n = Ferr.size(), nParam = gd->nParam;
138  double Sc = gsl_vector_get(x, 0), Tc = gsl_vector_get(x, 1),
139  Sh = gsl_vector_get(x, 2),
140  Th = (nParam == 4 ? gsl_vector_get(x, 3) : gd->fixed[0]);
141  for (size_t i=0; i != n; i++) {
142  auto Di = gd->band[i];
143  double iFerr = 1.0/Ferr[i];
144  gsl_vector_set(f, i, (gray.F(Tc, Sc, Th, Sh, Di) - Fobs[i])*iFerr);
145  }
146 
147  return GSL_SUCCESS;
148 }
149 
157 int df_gray2(const gsl_vector *x, void *p, gsl_matrix *J)
158 {
159  GrayData *gd = static_cast<GrayData *>(p);
160  const auto &Ferr = gd->Ferr;
161  const auto &gray = *gd->gray;
162 
163  size_t n = Ferr.size(), nParam = gd->nParam;
164  double Sc = gsl_vector_get(x, 0), Tc = gsl_vector_get(x, 1),
165  Sh = gsl_vector_get(x, 2),
166  Th = (nParam == 4 ? gsl_vector_get(x, 3) : gd->fixed[0]);
167  for (size_t i=0; i != n; i++) {
168  auto Di = gd->band[i];
169  double iFerr = 1.0/Ferr[i];
170  gsl_matrix_set(J, i, 0, gray.dF_dSc(Tc, Sc, Th, Sh, Di)*iFerr);
171  gsl_matrix_set(J, i, 1, gray.dF_dTc(Tc, Sc, Th, Sh, Di)*iFerr);
172  gsl_matrix_set(J, i, 2, gray.dF_dSh(Tc, Sc, Th, Sh, Di)*iFerr);
173  if (nParam == 4) {
174  gsl_matrix_set(J, i, 3, gray.dF_dTh(Tc, Sc, Th, Sh, Di)*iFerr);
175  }
176  }
177 
178  return GSL_SUCCESS;
179 }
180 
189 int fdf_gray2(const gsl_vector *x, void *p, gsl_vector *f, gsl_matrix *J)
190 { return f_gray2(x, p, f), df_gray2(x, p, J); }
191 
192 
194 std::string asctime()
195 {
196  char buf[64];
197  struct tm tmbuf;
198  auto t = std::time(nullptr);
199  std::string rtn = asctime_r(localtime_r(&t, &tmbuf), buf);
200  rtn.pop_back(); // Remove newline.
201  return rtn;
202 }
203 
204 
219 void makeModelMap(std::vector<mapDataType> &bandData,
220  std::vector<mapDataType> &bandError,
221  const GrayData &gdata)
222 {
223  const auto nParam = gdata.nParam;
224  const auto &gray = *gdata.gray;
225  const int n = sqrt(1.0*modelMapLen);
226  const double in1 = 1.0/(n-1);
227 
228  for (unsigned iMap=0; iMap != modelMapLen*modelMapLen; iMap++) {
229  auto i = iMap/modelMapLen, j = iMap%modelMapLen;
230  double
231  Tc = 6.0*(1.0 + (j%n)*in1), // Tc ~ [6, 12] K
232  Sc = mu_g*3e21*pow(100.0, (j/n)*in1), // Nc(H2) ~ [3e21, 3e23] cm^-2
233  Th = 15.0 + 3.0*(i%n)*in1, // Th ~ [15, 18] K
234  Sh = mu_g*3e19*pow(100.0, (i/n)*in1); // Nc(H2) ~ [3e19, 3e21] cm^-2
235  MU_DEBUG( "makeModelMap",
236  "(%lu, %lu) Tc = %.2f, Sc = %.2e, Th = %.2f, Sh = %.2e",
237  i, j, Tc, Sc, Th, Sh);
238 
239  for (unsigned iBand=0; iBand != bandData.size(); iBand++) {
240  auto &data = bandData[iBand], &err = bandError[iBand];
241  auto Di = gdata.band[iBand];
242  data[iMap] = (nParam == 2 ? gray.F(Th, Sh, Di) :
243  gray.F(Tc, Sc, Th, Sh, Di)) /
244  gdata.dnu0[iBand];
245  err[iMap] = 0.001*data[iMap];
246  MU_DEBUG("makeModelMap", " [%lu] %.4e", iBand, data[iMap]);
247  }
248  }
249 }
250 
251 
265 void solveStage1(const std::vector<mapDataType> &bandData,
266  const std::vector<mapDataType> &bandError,
267  const mapDataType &chi2Map,
268  const mu::CommandLine &cli,
269  const GrayData &gdata0, unsigned id, unsigned nThreads)
270 {
271  const char *const fn = "solveStage1";
272  size_t nBands = gdata0.nBands, nParam = gdata0.nParam,
273  minBands = cli.getInteger('n', 3);
274  auto &Tmap = gdata0.outMap->at(0),
275  &dTmap = gdata0.outMap->at(1),
276  &Nmap = gdata0.outMap->at(2),
277  &dNmap = gdata0.outMap->at(3),
278  &Cmap = gdata0.outMap->at(4),
279  &Imap = gdata0.outMap->at(5);
280  auto *diffMap = &gdata0.outMap->at(6);
281  bool modelMap = cli.getOption('M');
282  MU_WARN_IF(chi2Map.size(), fn,
283  "Fit is 2-param, ignoring --single-temp map");
284 
285  // Thread-local storage.
286  Graybody gray{*gdata0.gray};
287  GrayData gdata{gdata0};
288  gdata.gray = &gray;
289 
290  // GSL v1.x least-squares fitting setup.
291  gsl_multifit_fdfsolver *solver =
292  gsl_multifit_fdfsolver_alloc(gsl_multifit_fdfsolver_lmsder, // or lmder
293  nBands, nParam);
294  //
295  gsl_multifit_function_fdf fdf;
296  fdf.f = f_gray;
297  fdf.df = df_gray;
298  fdf.fdf = fdf_gray;
299  fdf.n = nBands;
300  fdf.p = nParam;
301  fdf.params = &gdata;
302  //
303  // Initial guess.
304  const double T0 = cli.getDouble('T', 16.5), S0 = 0.1;
305  gsl_vector *x0 = gsl_vector_alloc(nParam);
306  gsl_vector_set(x0, 0, T0);
307  gsl_vector_set(x0, 1, S0);
308  //
309  // Covariance storage.
310  gsl_matrix *cov = gsl_matrix_alloc(nParam, nParam);
311 
312  // Loop over map pixels.
313  const bool absdiff = cli.getOption('a');
314  const double relerr = cli.getDouble('A', 1e-2);
315  size_t maxIter = std::max(1L, cli.getInteger('m', 25)),
316  px = (modelMap ? modelMapLen*modelMapLen : bandData[0].size()),
317  i0 = (id*px)/nThreads, i1 = ((id+1)*px)/nThreads;
318  for (unsigned i=i0; i != i1; i++) {
319  // Set target data.
320  unsigned nOk = 0;
321  for (size_t j=0; j != nBands; j++) {
322  gdata.Fobs[j] = gdata.dnu0[j]*bandData[j][i];
323  gdata.Ferr[j] = gdata.dnu0[j]*bandError[j][i];
324 
325  if (std::isfinite(gdata.Fobs[j]) && std::isfinite(gdata.Ferr[j])) {
326  nOk++;
327  } else {
328  gdata.Fobs[j] = 0.0;
329  gdata.Ferr[j] = 1e10; // Weight-out bad data.
330  }
331  }
332 
333  // Progress display.
334  MU_INFO_IF(id == 0 && i%std::max(i1/10, 1UL) == 0, fn,
335  "Fitting solution %2.0f%% complete @ %s",
336  (100.0*i)/i1, asctime());
337 
338  // Skip invalid pixels.
339  if (nOk < minBands) {
340  for (auto &omap: *gdata0.outMap) { omap[i] = NAN; }
341  continue;
342  }
343 
344  // Initialize solver.
345  gsl_multifit_fdfsolver_set(solver, &fdf, x0);
346 
347  // Iterate on solution.
348  size_t iter = 0;
349  do {
350  iter++;
351  gsl_multifit_fdfsolver_iterate(solver);
352  MU_DEBUG(fn, "[%2lu] T = %.2f S = %.4f", iter,
353  gsl_vector_get(solver->x, 0), gsl_vector_get(solver->x, 1));
354  } while (gsl_multifit_test_delta(solver->dx, solver->x, 0.0, relerr) ==
355  GSL_CONTINUE && iter != maxIter);
356 
357  // Results.
358  gsl_multifit_covar(solver->J, 1e-8, cov);
359  double chi2 = 0.0;
360  for (size_t j=0; j != nBands; j++) {
361  auto fj = gsl_vector_get(solver->f, j);
362  diffMap[j][i] = fj*(absdiff ? bandError[j][i] : 1.0);
363  chi2 += fj*fj;
364  }
365  //
366  double chi2_dof = chi2/(nBands-nParam), vscale = std::max(1.0, chi2_dof),
367  T = gsl_vector_get(solver->x, 0), S = gsl_vector_get(solver->x, 1),
368  dT = sqrt(vscale * gsl_matrix_get(cov, 0, 0)),
369  dS = sqrt(vscale * gsl_matrix_get(cov, 1, 1));
370  MU_DEBUG(fn, "T = %.2f(%.2f), S = %.4f(%.4f), chi2/DOF = %.3f\n",
371  T, dT, S, dS, chi2_dof);
372  //
373  Tmap[i] = T, dTmap[i] = dT;
374  Nmap[i] = S*imu_g, dNmap[i] = dS*imu_g;
375  Cmap[i] = chi2_dof; Imap[i] = iter;
376  //
377  MU_WARN_IF(iter == maxIter, fn,
378  "Fitting failed for pixel (%ld,%ld): dT/T = %.4g, dN/N = %.4g",
379  1+i%gdata.axes[0], 1+i/gdata.axes[0],
380  gsl_vector_get(solver->dx, 0)/T,
381  gsl_vector_get(solver->dx, 1)/S);
382 
383  // Chain next initial guess to previous solution (if sane).
384  // Vary guess for model maps to test convergence robustness.
385  if (modelMap) { T += (i%7)-2.5, S *= 1.0 + ((i%11)-5.5)/10.0; }
386  gsl_vector_set(x0, 0, T > 1.0 && T < 1e3 ? T : T0);
387  gsl_vector_set(x0, 1, S > 1e-3 && S < 1e3 ? S : S0);
388  }
389 
390  // Free storage.
391  gsl_multifit_fdfsolver_free(solver);
392  gsl_vector_free(x0);
393  gsl_matrix_free(cov);
394 }
395 
396 
413 void solveStage2(const std::vector<mapDataType> &bandData,
414  const std::vector<mapDataType> &bandError,
415  const mapDataType &chi2Map,
416  const mu::CommandLine &cli,
417  const GrayData &gdata0, unsigned id, unsigned nThreads)
418 {
419  const char *const fn = "solveStage2";
420  size_t nBands = gdata0.nBands, nParam = gdata0.nParam,
421  minBands = cli.getInteger('n', 4);
422  auto &Tcore = gdata0.outMap->at(0),
423  &dTcore = gdata0.outMap->at(1),
424  &Ncore = gdata0.outMap->at(2),
425  &dNcore = gdata0.outMap->at(3),
426  &Thalo = gdata0.outMap->at(4),
427  &dThalo = gdata0.outMap->at(5),
428  &Nhalo = gdata0.outMap->at(6),
429  &dNhalo = gdata0.outMap->at(7),
430  &Cmap = gdata0.outMap->at(8),
431  &Imap = gdata0.outMap->at(9);
432  auto *diffMap = &gdata0.outMap->at(10);
433  bool modelMap = cli.getOption('M');
434 
435  // Single-temperature chi^2 bypass mask.
436  // Pixels whose chi2Map[i] < chi2Max are skipped (NaN-filled) here.
437  double chi2Max = (chi2Map.size() ? cli.getDouble('c', 1.0) : -1.0);
438  if (chi2Map.size() && chi2Map.size() != bandData[0].size()) {
439  MU_ERROR(fn, "Ignoring --single-temp map (size %lu, require %lu)",
440  chi2Map.size(), bandData[0].size());
441  chi2Max = -1.0;
442  }
443 
444  // Thread-local storage.
445  Graybody gray{*gdata0.gray};
446  GrayData gdata{gdata0};
447  gdata.gray = &gray;
448 
449  // GSL v1.x least-squares fitting setup.
450  gsl_multifit_fdfsolver *solver =
451  gsl_multifit_fdfsolver_alloc(gsl_multifit_fdfsolver_lmsder, // or lmder
452  nBands, nParam);
453  //
454  gsl_multifit_function_fdf fdf;
455  fdf.f = f_gray2;
456  fdf.df = df_gray2;
457  fdf.fdf = fdf_gray2;
458  fdf.n = nBands;
459  fdf.p = nParam;
460  fdf.params = &gdata;
461  //
462  // Initial guess.
463  const double T0 = cli.getDouble('T', 16.5), S0 = 1.0, S1 = 0.1;
464  gsl_vector *x0 = gsl_vector_alloc(nParam);
465  gsl_vector_set(x0, 0, S0);
466  gsl_vector_set(x0, 1, T0-5.0);
467  gsl_vector_set(x0, 2, S1);
468  if (nParam == 4) {
469  gsl_vector_set(x0, 3, T0+5.0);
470  }
471  gdata.fixed.resize(1); // Used when Th held fixed.
472  //
473  // Covariance storage.
474  gsl_matrix *cov = gsl_matrix_alloc(nParam, nParam);
475 
476  // Loop over map pixels.
477  const double relerr = cli.getDouble('A', 1e-2);
478  size_t maxIter = std::max(1L, cli.getInteger('m', 25)),
479  px = (modelMap ? modelMapLen*modelMapLen : bandData[0].size()),
480  i0 = (id*px)/nThreads, i1 = ((id+1)*px)/nThreads;
481  for (unsigned i=i0; i != i1; i++) {
482  // Set target data.
483  unsigned nOk = 0;
484  for (size_t j=0; j != nBands; j++) {
485  gdata.Fobs[j] = gdata.dnu0[j]*bandData[j][i];
486  gdata.Ferr[j] = gdata.dnu0[j]*bandError[j][i];
487 
488  if (std::isfinite(gdata.Fobs[j]) && std::isfinite(gdata.Ferr[j])) {
489  nOk++;
490  } else {
491  gdata.Fobs[j] = 0.0;
492  gdata.Ferr[j] = 1e10; // Weight-out bad data.
493  }
494  }
495  gdata.fixed[0] = T0;
496 
497  // Progress display.
498  MU_INFO_IF(id == 0 && i%(i1/10) == 0, fn,
499  "Fitting solution %2.0f%% complete @ %s",
500  (100.0*i)/i1, asctime());
501 
502  // Skip invalid/masked pixels.
503  if (nOk < minBands || (chi2Max >= 0.0 && chi2Map[i] <= chi2Max)) {
504  for (auto &omap: *gdata0.outMap) { omap[i] = NAN; }
505  continue;
506  }
507 
508  // Initialize solver.
509  gsl_multifit_fdfsolver_set(solver, &fdf, x0);
510 
511  // Iterate on solution.
512  size_t iter = 0;
513  do {
514  MU_DEBUG(fn, "[%2lu] Tc = %5.2f Sc = %7.4f "
515  " Th = %5.2f Sh = %7.4f", iter,
516  gsl_vector_get(solver->x, 1), gsl_vector_get(solver->x, 0),
517  nParam == 4 ? gsl_vector_get(solver->x, 3) : gdata.fixed[0],
518  gsl_vector_get(solver->x, 2));
519  iter++;
520  gsl_multifit_fdfsolver_iterate(solver);
521  } while (gsl_multifit_test_delta(solver->dx, solver->x, 0.0, relerr) ==
522  GSL_CONTINUE && ++iter != maxIter);
523 
524  // Results.
525  gsl_multifit_covar(solver->J, 1e-6, cov);
526  double chi2 = 0.0;
527  for (size_t j=0; j != nBands; j++) {
528  auto fj = gsl_vector_get(solver->f, j);
529  diffMap[j][i] = fj;
530  chi2 += fj*fj;
531  }
532  //
533  double chi2_dof = chi2/std::max(nBands-nParam, 1UL),
534  vscale = std::max(1.0, chi2_dof),
535  Sc = gsl_vector_get(solver->x, 0),
536  Tc = gsl_vector_get(solver->x, 1),
537  Sh = gsl_vector_get(solver->x, 2),
538  Th = nParam == 4 ? gsl_vector_get(solver->x, 3) : gdata.fixed[0],
539  dSc = sqrt(vscale * gsl_matrix_get(cov, 0, 0)),
540  dTc = sqrt(vscale * gsl_matrix_get(cov, 1, 1)),
541  dSh = sqrt(vscale * gsl_matrix_get(cov, 2, 2)),
542  dTh = nParam == 4 ? sqrt(vscale * gsl_matrix_get(cov, 3, 3)) : 0.0;
543  MU_DEBUG(fn, "(%ld,%ld) Tc = %5.2f(%.2f), Sc = %7.4f(%.4f), "
544  "Th = %5.2f(%.2f), Sh = %7.4f(%.4f), chi2/DOF = %.3f\n",
545  1+i%gdata.axes[0], 1+i/gdata.axes[0],
546  Tc, dTc, Sc, dSc, Th, dTh, Sh, dSh, chi2_dof);
547  //
548  Tcore[i] = Tc, dTcore[i] = dTc;
549  Ncore[i] = Sc*imu_g, dNcore[i] = dSc*imu_g;
550  Thalo[i] = Th, dThalo[i] = dTh;
551  Nhalo[i] = Sh*imu_g, dNhalo[i] = dSh*imu_g;
552  Cmap[i] = chi2_dof; Imap[i] = iter;
553  //
554  MU_WARN_IF(iter == maxIter, fn,
555  "Fitting failed for pixel (%ld,%ld): "
556  "dTc/Tc = %.4g, dNc/Nc = %.4g, "
557  "dTh/Th = %.4g, dNh/Nh = %.4g",
558  1+i%gdata.axes[0], 1+i/gdata.axes[0],
559  gsl_vector_get(solver->dx, 1)/Tc,
560  gsl_vector_get(solver->dx, 0)/Sc,
561  nParam == 4 ? gsl_vector_get(solver->dx, 3)/Th : 0.0,
562  gsl_vector_get(solver->dx, 2)/Sh);
563 
564  // Chain next initial guess to previous solution (if sane).
565  // !!!! Disabled pending resolution of GSL integrator convergence.
566  gsl_vector_set(x0, 0, S0);//Sc > 1e-2 && Sc < 10.0 ? Sc : S0);
567  gsl_vector_set(x0, 1, T0-5.0);//Tc > 3.0 && Tc < 100.0 ? Tc : T0-5.0);
568  gsl_vector_set(x0, 2, S1);//Sh > 1e-3 && Sh < 1e3 ? Sh : 0.05*S0);
569  if (nParam == 4) {
570  gsl_vector_set(x0, 3, T0+5.0);//Th > 10.0 && Th < 100.0 ? Th : T0+5.0);
571  }
572  }
573 
574  // Free storage.
575  gsl_multifit_fdfsolver_free(solver);
576  gsl_vector_free(x0);
577  gsl_matrix_free(cov);
578 }
579 
580 
594 {
595  mapDataType chi2;
597 
598  if (cli.getOption('s', &files, 1)) {
599  const std::string hduName = "Chi2/DOF";
600  std::unique_ptr<CCfits::FITS>
601  fchi2{new CCfits::FITS(files.front(), CCfits::Read, hduName, true)};
602  fchi2->extension(hduName).read(chi2);
603  }
604 
605  return chi2;
606 }
607 
608 
635 void solve(std::vector<mapDataType> &outMap,
636  std::vector<CCfits::ExtHDU *> &outHDU,
637  CCfits::FITS *outFITS,
638  const std::vector<mapDataType> &bandData,
639  const std::vector<mapDataType> &bandError,
640  const std::vector<CCfits::PHDU*> &bandHDU,
641  const mu::CommandLine &cli)
642 {
643  const char *const fn = "solve";
644  bool modelMap = cli.getOption('M');
645 
646  // Dust model.
647  bool extend = !cli.getOption('p');
648  Dust dust(cli.getString('D', "OH5"), cli.getDouble('g', 100.0));
649  MU_INFO(fn, "Using %s source detector response",
650  extend ? "extended" : "point");
651  MU_INFO(fn, "Dust model: %s, gas-to-dust ratio = %g",
652  dust.name(), dust.rho());
653 
654  // Band detector setup.
655  // Currently supports PACS/SPIRE only!
656  size_t nBands = bandData.size();
657  std::vector<std::unique_ptr<Detector>> detect;
658  for (size_t j=0; j != nBands; j++) {
659  int band = getBand(*bandHDU[j]);
660  auto d = (band < 200 ? (Detector *)new PACS(band, extend)
661  : (Detector *)new SPIRE(band, extend));
662  d->init();
663  detect.emplace_back(d);
664  }
665 
666  // Allocate result maps.
667  const double relerr = cli.getDouble('A', 1e-2);
668  std::vector<long> axes = {bandHDU[0]->axis(0), bandHDU[0]->axis(1)};
669  if (modelMap) { axes = {modelMapLen, modelMapLen}; }
670 
671  auto px = axes[0]*axes[1];
672  char comm[1024];
673  snprintf(comm, sizeof(comm),
674  "%s sources, %s dust, gas/dust = %g, relerr = %.1e",
675  (extend ? "Extended" : "Point"), dust.name().c_str(),
676  dust.rho(), relerr);
677  //
678  size_t nParam = (cli.getOption('4') ? 4 : cli.getOption('3') ? 3 : 2);
679  auto solver = &solveStage1;
680  std::vector<std::string>
681  mapNames = {"T", "dT", "N(H2)", "dN(H2)", "Chi2/DOF", "nIter"};
682  if (nParam > 2) {
683  solver = &solveStage2;
684  mapNames = {"Tc", "dTc", "Nc(H2)", "dNc(H2)",
685  "Th", "dTh", "Nh(H2)", "dNh(H2)", "Chi2/DOF", "nIter"};
686  }
687  for (auto &b: bandHDU) {
688  // Band fit residuals.
689  mapNames.push_back("diff" + std::to_string(getBand(*b)));
690  }
691  //
692  for (auto name: mapNames) {
693  outMap.push_back(mapDataType(0.0, px));
694  outHDU.push_back(outFITS->addImage(name, mapDataCode, axes));
695  outHDU.back()->writeDate();
696  outHDU.back()->writeComment(comm);
697  }
698 
699  // Emission model.
700  constexpr double MJy = 1e-17; // MJy -> erg/cm^2/s/Hz
701  Graybody gray{dust, 0.1*relerr};
702  GrayData gdata{&gray, &outMap, nBands, nParam};
703  for (size_t j=0; j != nBands; j++) {
704  gdata.band[j] = detect[j].get();
705  gdata.dnu0.push_back(detect[j]->freqWidth() * MJy);
706  }
707  gdata.axes = axes;
708 
709  // Theoretical model map option.
710  if (modelMap) {
711  makeModelMap(const_cast<std::vector<mapDataType>&>(bandData),
712  const_cast<std::vector<mapDataType>&>(bandError),
713  gdata);
714  }
715 
716  // Create threads and process maps.
717  unsigned nThreads = std::max(1L, cli.getInteger('t', 1));
718  auto chi2Map = getChi2(cli);
719  std::vector<std::thread> threads;
720  for (unsigned i=1; i != nThreads; i++) {
721  threads.emplace_back(solver, bandData, bandError, chi2Map, cli,
722  gdata, i, nThreads);
723  }
724  solver(bandData, bandError, chi2Map, cli, gdata, 0, nThreads);
725  //
726  for (auto &t: threads) { t.join(); }
727 
728  MU_INFO(fn, "Solution complete @ %s", asctime());
729 }
730 
731 } // namespace manticore
std::vector< double > fixed
Fixed parameters (optional).
Definition: solve.cc:46
int df_gray2(const gsl_vector *x, void *p, gsl_matrix *J)
Two-temperature observation fitting function Jacobian.
Definition: solve.cc:157
#define MU_WARN_IF(cond, src, msg,...)
Conditionally log a message at level Log::WARN.
Definition: Log.h:142
int f_gray2(const gsl_vector *x, void *p, gsl_vector *f)
Two-temperature observation fitting function.
Definition: solve.cc:131
mapDataType getChi2(const mu::CommandLine &cli)
Read 2-param reduced map.
Definition: solve.cc:593
void solve(std::vector< mapDataType > &outMap, std::vector< CCfits::ExtHDU *> &outHDU, CCfits::FITS *outFITS, const std::vector< mapDataType > &bandData, const std::vector< mapDataType > &bandError, const std::vector< CCfits::PHDU *> &bandHDU, const mutils::CommandLine &cli)
Performs least-squares fitting of band SEDs.
Definition: solve.cc:635
std::vector< double > Fobs
Observed flux in each band.
Definition: solve.cc:46
unsigned getOption(const Option &option, Arguments *values=nullptr, unsigned nMax=-1) const
Retrieves all copies of a command line option.
Definition: CommandLine.cc:197
#define MU_ERROR(src, msg,...)
Log a message at level Log::ERROR.
Definition: Log.h:164
std::string asctime()
Current time a la std::asctime().
Definition: solve.cc:194
std::vector< long > axes
Image dimensions.
Definition: solve.cc:44
Command line options and arguments.
Definition: CommandLine.h:47
int df_gray(const gsl_vector *x, void *p, gsl_matrix *J)
Single-temperature observation fitting function Jacobian.
Definition: solve.cc:94
std::string getString(char shortName, const std::string &defValue) const
Retrieves unique string option.
Definition: CommandLine.cc:392
#define MU_DEBUG(src, msg,...)
Log a message at level Log::DEBUG.
Definition: Log.h:68
std::vector< std::string > Arguments
Command line arguments type.
Definition: CommandLine.h:51
const double imu_g
Inverse mean molecular weight.
Definition: solve.cc:28
int f_gray(const gsl_vector *x, void *p, gsl_vector *f)
Single-temperature observation fitting function.
Definition: solve.cc:70
Package namespace.
Definition: Detector.cc:13
GrayData(Graybody *g, std::vector< mapDataType > *o, size_t bands, size_t param)
Constructor.
Definition: solve.cc:33
constexpr double m_H
Mass of hygdrogen atom (g).
Definition: manticore.h:32
void solveStage2(const std::vector< mapDataType > &bandData, const std::vector< mapDataType > &bandError, const mapDataType &chi2Map, const mu::CommandLine &cli, const GrayData &gdata0, unsigned id, unsigned nThreads)
Stage 2 solver.
Definition: solve.cc:413
std::vector< double > Ferr
Flux uncertainty in each band.
Definition: solve.cc:46
int fdf_gray(const gsl_vector *x, void *p, gsl_vector *f, gsl_matrix *J)
Single-temperature observation fitting function plus Jacobian.
Definition: solve.cc:120
int fdf_gray2(const gsl_vector *x, void *p, gsl_vector *f, gsl_matrix *J)
Two-temperature observation fitting function plus Jacobian.
Definition: solve.cc:189
void makeModelMap(std::vector< mapDataType > &bandData, std::vector< mapDataType > &bandError, const GrayData &gdata)
Replace input observations with theoretical model.
Definition: solve.cc:219
std::map< std::string, manticore::tableType > modelMap
Definition: Dust.cc:137
std::vector< double > dnu0
Effective bandwidth.
Definition: solve.cc:46
std::vector< mapDataType > * outMap
Output maps.
Definition: solve.cc:55
MathUtils package.
Definition: CommandLine.cc:10
PACS detector class.
Definition: PACS.h:17
Detector base class.
Definition: Detector.h:50
Graybody emission model.
Definition: Graybody.h:38
size_t nBands
Number of observation bands.
Definition: solve.cc:58
std::vector< const Detector * > band
Band detectors.
Definition: solve.cc:52
int getBand(const CCfits::HDU &hdu)
Returns nominal band center (microns) from an HDU.
Definition: manticore.cc:97
Graybody * gray
Graybody emission model.
Definition: solve.cc:42
const double mu_g
Mean molecular weight.
Definition: solve.cc:27
SPIRE detector class.
Definition: SPIRE.h:14
#define MU_INFO(src, msg,...)
Log a message at level Log::INFO.
Definition: Log.h:100
constexpr long modelMapLen
One-dimensional length of model map image.
Definition: manticore.h:17
#define MU_INFO_IF(cond, src, msg,...)
Conditionally log a message at level Log::INFO.
Definition: Log.h:110
Observation fitting data structure.
Definition: solve.cc:31
constexpr int mapDataCode
Output FITS maps data code (cf. mapDataType).
Definition: manticore.h:14
long getInteger(char shortName) const
Retrieves unique decimal integer option.
Definition: CommandLine.cc:341
double getDouble(char shortName, double defValue) const
Retrieves unique floating point option.
Definition: CommandLine.cc:376
void solveStage1(const std::vector< mapDataType > &bandData, const std::vector< mapDataType > &bandError, const mapDataType &chi2Map, const mu::CommandLine &cli, const GrayData &gdata0, unsigned id, unsigned nThreads)
Stage 1 solver.
Definition: solve.cc:265
size_t nParam
Number of fitting parameters.
Definition: solve.cc:58
std::valarray< float > mapDataType
Output FITS maps data type (cf. mapDataCode).
Definition: manticore.h:11
Dust model.
Definition: Dust.h:28