15 #include <gsl/gsl_multifit_nlin.h> 45 std::vector<const Detector*>
48 std::vector<mapDataType>
59 int f_gray(
const gsl_vector *x,
void *p, gsl_vector *f)
62 const auto &Fobs = gd->
Fobs, &Ferr = gd->
Ferr;
63 const auto &gray = *gd->
gray;
65 size_t n = Ferr.size();
66 double T = gsl_vector_get(x, 0), S = gsl_vector_get(x, 1);
67 for (
size_t i=0; i != n; i++) {
68 auto Di = gd->
band[i];
69 double iFerr = 1.0/Ferr[i];
70 gsl_vector_set(f, i, (gray.F(T, S, Di) - Fobs[i])*iFerr);
83 int df_gray(
const gsl_vector *x,
void *p, gsl_matrix *J)
86 const auto &Ferr = gd->
Ferr;
87 const auto &gray = *gd->
gray;
89 size_t n = Ferr.size();
90 double T = gsl_vector_get(x, 0), S = gsl_vector_get(x, 1);
91 for (
size_t i=0; i != n; i++) {
92 auto Di = gd->
band[i];
93 double iFerr = 1.0/Ferr[i];
94 gsl_matrix_set(J, i, 0, gray.dF_dT(T, S, Di)*iFerr);
95 gsl_matrix_set(J, i, 1, gray.dF_dS(T, S, Di)*iFerr);
109 int fdf_gray(
const gsl_vector *x,
void *p, gsl_vector *f, gsl_matrix *J)
118 auto t = std::time(
nullptr);
119 std::string rtn = asctime_r(localtime_r(&t, &tmbuf), buf);
139 const std::vector<mapDataType> &bandData,
140 const std::vector<mapDataType> &bandError,
142 const GrayData &gdata0,
unsigned id,
unsigned nThreads)
144 const char *
const fn =
"solveStage1";
145 size_t nBands = bandData.size(), nParam = 2,
147 const double imu_g = 1.0/(2.75*
m_H);
148 auto &Tmap = gdata0.
outMap->at(0),
149 &dTmap = gdata0.
outMap->at(1),
150 &Nmap = gdata0.
outMap->at(2),
151 &dNmap = gdata0.
outMap->at(3),
152 &Cmap = gdata0.
outMap->at(4);
160 gsl_multifit_fdfsolver *solver =
161 gsl_multifit_fdfsolver_alloc(gsl_multifit_fdfsolver_lmsder,
164 gsl_multifit_function_fdf fdf;
173 gsl_vector *x0 = gsl_vector_alloc(nParam);
174 gsl_vector_set(x0, 0, 15.0);
175 gsl_vector_set(x0, 1, 1.0);
178 gsl_matrix *cov = gsl_matrix_alloc(nParam, nParam);
181 const double relerr = cli.
getDouble(
'A', 1e-2);
182 size_t maxIter = std::max(1L, cli.
getInteger(
'M', 25)),
183 px = bandData[0].size(),
184 i0 = (
id*px)/nThreads, i1 = ((
id+1)*px)/nThreads;
185 for (
unsigned i=i0; i != i1; i++) {
188 for (
size_t j=0; j != nBands; j++) {
189 gdata.Fobs[j] = gdata.dnu0[j]*bandData[j][i];
190 gdata.Ferr[j] = gdata.dnu0[j]*bandError[j][i];
192 if (gdata.Fobs[j] > 0.0 && gdata.Ferr[j] > 0.0) {
196 gdata.Ferr[j] = 1e10;
202 "Fitting solution %2.0f%% complete @ %s",
206 if (nOk < minBands) {
207 Tmap[i] = dTmap[i] = Nmap[i] = dNmap[i] = Cmap[i] = NAN;
212 gsl_multifit_fdfsolver_set(solver, &fdf, x0);
217 gsl_multifit_fdfsolver_iterate(solver);
218 MU_DEBUG(fn,
"[%2lu] T = %.2f S = %.4f", iter,
219 gsl_vector_get(solver->x, 0), gsl_vector_get(solver->x, 1));
220 }
while (gsl_multifit_test_delta(solver->dx, solver->x, 0.0, relerr) ==
221 GSL_CONTINUE && ++iter != maxIter);
224 gsl_multifit_covar(solver->J, 1e-8, cov);
226 for (
size_t k=0; k != nBands; k++) {
227 auto fk = gsl_vector_get(solver->f, k);
231 double chi2_dof = chi2/(nBands-nParam), vscale = std::max(1.0, chi2_dof),
232 T = gsl_vector_get(solver->x, 0), S = gsl_vector_get(solver->x, 1),
233 dT = sqrt(vscale * gsl_matrix_get(cov, 0, 0)),
234 dS = sqrt(vscale * gsl_matrix_get(cov, 1, 1));
235 MU_DEBUG(fn,
"T = %.2f(%.2f), S = %.4f(%.4f), chi2/DOF = %.3f\n",
236 T, dT, S, dS, chi2_dof);
238 Tmap[i] = T, dTmap[i] = dT;
239 Nmap[i] = S*imu_g, dNmap[i] = dS*imu_g;
243 "Fitting failed for pixel (%ld,%ld): dT/T = %.4g, dN/N = %.4g",
244 1+i%gdata.axes[0], 1+i/gdata.axes[0],
245 gsl_vector_get(solver->dx, 0)/T,
246 gsl_vector_get(solver->dx, 1)/S);
249 gsl_vector_set(x0, 0, T);
250 gsl_vector_set(x0, 1, S);
254 gsl_multifit_fdfsolver_free(solver);
256 gsl_matrix_free(cov);
286 void solve(std::vector<mapDataType> &outMap,
287 std::vector<CCfits::ExtHDU *> &outHDU,
288 CCfits::FITS *outFITS,
289 const std::vector<mapDataType> &bandData,
290 const std::vector<mapDataType> &bandError,
291 const std::vector<CCfits::PHDU*> &bandHDU,
294 const char *
const fn =
"solve";
299 MU_INFO(fn,
"Using %s source detector response",
300 extend ?
"extended" :
"point");
301 MU_INFO(fn,
"Dust model: %s, gas-to-dust ratio = %g",
302 dust.name(), dust.rho());
305 const double relerr = cli.
getDouble(
'A', 1e-2);
306 std::vector<long> axes = {bandHDU[0]->axis(0), bandHDU[0]->axis(1)};
307 auto px = axes[0]*axes[1];
309 snprintf(comm,
sizeof(comm),
310 "%s sources, %s dust, gas/dust = %g, relerr = %.1e",
311 (extend ?
"Extended" :
"Point"), dust.name().c_str(),
314 for (
auto name: {
"T",
"dT",
"N(H2)",
"dN(H2)",
"Chi2/DOF"}) {
316 outHDU.push_back(outFITS->addImage(name,
mapDataCode, axes));
317 outHDU.back()->writeDate();
318 outHDU.back()->writeComment(comm);
323 size_t nBands = bandData.size();
324 std::vector<std::unique_ptr<Detector>> detect;
325 for (
size_t j=0; j != nBands; j++) {
327 bandHDU[j]->keyWord(
"BAND").value(band);
329 auto d = (band < 200 ? (
Detector *)
new PACS(band, extend)
332 detect.emplace_back(d);
336 constexpr
double MJy = 1e-17;
338 GrayData gdata{&gray, &outMap, nBands};
339 for (
size_t j=0; j != nBands; j++) {
340 gdata.
band[j] = detect[j].get();
341 gdata.dnu0.push_back(detect[j]->freqWidth() * MJy);
346 unsigned nThreads = std::max(1L, cli.
getInteger(
't', 1));
347 std::vector<std::thread> threads;
348 for (
unsigned i=1; i != nThreads; i++) {
349 threads.emplace_back(&
solveStage1, bandData, bandError, cli,
352 solveStage1(bandData, bandError, cli, gdata, 0, nThreads);
354 for (
auto &t: threads) { t.join(); }
#define MU_WARN_IF(cond, src, msg,...)
Conditionally log a message at level Log::WARN.
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.
std::vector< double > Fobs
Observed flux in each band.
unsigned getOption(const Option &option, Arguments *values=nullptr, unsigned nMax=-1) const
Retrieves all copies of a command line option.
std::string asctime()
Current time a la std::asctime().
std::vector< long > axes
Image dimensions.
Command line options and arguments.
int df_gray(const gsl_vector *x, void *p, gsl_matrix *J)
Observation fitting function Jacobian.
std::string getString(char shortName, const std::string &defValue) const
Retrieves unique string option.
#define MU_DEBUG(src, msg,...)
Log a message at level Log::DEBUG.
int f_gray(const gsl_vector *x, void *p, gsl_vector *f)
Observation fitting function.
constexpr double m_H
Mass of hygdrogen atom (g).
void solveStage1(const std::vector< mapDataType > &bandData, const std::vector< mapDataType > &bandError, const mu::CommandLine &cli, const GrayData &gdata0, unsigned id, unsigned nThreads)
Stage 1 solver.
std::vector< double > Ferr
Flux uncertainty in each band.
int fdf_gray(const gsl_vector *x, void *p, gsl_vector *f, gsl_matrix *J)
Observation fitting function plus Jacobian.
std::vector< double > dnu0
Effective bandwidth.
std::vector< mapDataType > * outMap
Output maps.
std::vector< const Detector * > band
Band detectors.
Graybody * gray
Graybody emission model.
#define MU_INFO(src, msg,...)
Log a message at level Log::INFO.
#define MU_INFO_IF(cond, src, msg,...)
Conditionally log a message at level Log::INFO.
Observation fitting data structure.
constexpr int mapDataCode
Output FITS maps data code (cf. mapDataType).
GrayData(Graybody *g, std::vector< mapDataType > *o, size_t n)
Constructor.
long getInteger(char shortName) const
Retrieves unique decimal integer option.
double getDouble(char shortName, double defValue) const
Retrieves unique floating point option.
std::valarray< float > mapDataType
Output FITS maps data type (cf. mapDataCode).