Manticore  Version 1.5.3
Physics of Molecular Clouds
process.cc
Go to the documentation of this file.
1 
8 #include "manticore.h"
9 #include "version.h"
10 
11 namespace mu = mutils;
12 
14 namespace manticore {
15 
33 mapDataType getError(const mapDataType &data, CCfits::PHDU &hdu,
34  const mu::CommandLine &cli,
35  const std::vector<long> &ll,
36  const std::vector<long> &ur,
37  const std::vector<long> &st)
38 {
39  const char *const fn = "getError";
40  mapDataType err;
42 
43  int band0 = getBand(hdu), band;
44  std::string tele0, tele, bandKey = "BAND", teleKey = "TELESCOP";
45  hdu.keyWord(teleKey).value(tele0);
46 
47  if (cli.getOption('e', &files)) {
48  for (auto &file: files) {
50  ferr{new CCfits::FITS(file, CCfits::Read, false, {bandKey, teleKey})};
51  auto &phdu = ferr->pHDU();
52  band = getBand(phdu);
53  phdu.keyWord(teleKey).value(tele);
54  if (band == band0 && tele == tele0) {
55  if (st[0]) { phdu.read(err, ll, ur, st); }
56  else { phdu.read(err); }
57  MU_EXCEPTION_IF(phdu.axis(0) != hdu.axis(0) ||
58  phdu.axis(1) != hdu.axis(1), fn,
59  "Error map '%s' size mismatch (%lux%lu pixels, %lux%lu in parent)",
60  file, phdu.axis(0), phdu.axis(1), hdu.axis(0), hdu.axis(1));
61 
62  MU_INFO(fn, "Using error map '%s' for %ld micron band", file, band0);
63  return err;
64  }
65  }
66  }
67 
68  double relerr = 0.01*cli.getDouble('E', 3.0);
69  err = data;
70  for (auto &elem: err) { elem = fabs(elem * relerr); }
71  MU_INFO(fn, "No error map found for %ld micron band, assuming %g%% of input",
72  band0, 100*relerr);
73  return err;
74 }
75 
82 void resetRefPix(CCfits::HDU &hdu, const std::vector<long> &ll)
83 {
84  if (ll[0]) {
85  double pix;
86  hdu.keyWord("CRPIX1").setValue(1+hdu.keyWord("CRPIX1").value(pix)-ll[0]);
87  hdu.keyWord("CRPIX2").setValue(1+hdu.keyWord("CRPIX2").value(pix)-ll[1]);
88  }
89 }
90 
104 void process(const mu::CommandLine &cli)
105 {
106  const char *const fn = "process";
107  auto &files = cli.arguments();
108  bool modelMap = cli.getOption('M');
109 
110  // Sanity check.
111  MU_EXCEPTION_IF(files.size() < 2, fn,
112  "Minimum of 2 input bands required (%lu given); try --help",
113  files.size());
114 
115  // Cutout processing.
116  std::vector<long> ll{0,0}, ur{10000,10000}, st{0,0};
117  auto cutout = cli.getString('C', mutils::nullStr);
118  if (cutout != mutils::nullStr) {
119  unsigned nc, nr, r0, c0;
120  MU_EXCEPTION_IF(4 != sscanf(cutout.c_str(), "%ux%u@%u,%u",
121  &nc, &nr, &c0, &r0), fn,
122  "Invalid syntax '--cutout %s'; try --help", cutout);
123  MU_INFO(fn, "Processing %lux%lu cutout at (%lu,%lu)",
124  nc, nr, c0, r0);
125  ll[0] = c0, ll[1] = r0;
126  ur[0] = c0+nc-1, ur[1] = r0+nr-1;
127  st[0] = st[1] = 1;
128  }
129 
130  // Read the FITS images.
131  // It is assumed ALL images have the same pixel scale and dimensions,
132  // even if the beams are mismatched.
135  std::vector<mapDataType> bandData, bandError;
136  for (auto &file: files) {
137  img.emplace_back(new CCfits::FITS(file, CCfits::Read, true));
138  bandHDU.push_back(&img.back()->pHDU());
139 
140  // Axis check.
141  std::string name;
142  auto &hd0 = *bandHDU.front(), &hd = *bandHDU.back();
143  int naxes = hd.axes();
144  MU_EXCEPTION_IF(naxes != 2, fn, "%s has %ld axes (expected 2)", file,naxes);
145 
146  // Get image data and keywords.
147  std::string facility;
148  bandData.push_back(mapDataType());
149  if (st[0]) { hd.read(bandData.back(), ll, ur, st); }
150  else { hd.read(bandData.back()); }
152  bandData.back().size() < modelMapLen*modelMapLen, fn,
153  "Input maps too small for %ldx%ld model",
155  MU_ERROR_IF(hd.axis(0) != hd0.axis(0) || hd.axis(1) != hd0.axis(1), fn,
156  "%s dimensions are %ldx%ld (fiducial is %ldx%ld)",
157  file, hd.axis(0), hd.axis(1), hd0.axis(0), hd0.axis(1));
158 
159  hd.readAllKeys();
160  MU_INFO(fn, "%s (%s): %ldx%ld @ %3ld microns (%s)", file,
161  hd.keyWord("OBJECT").value(name),
162  hd.axis(0), hd.axis(1), getBand(hd),
163  hd.keyWord("TELESCOP").value(facility));
164 
165  // Unit check.
166  std::string units;
167  hd.readKey("BUNIT", units);
168  MU_EXCEPTION_IF(units != "MJy/sr", fn,
169  "%s map units are '%s' (need MJy/sr)", file, units);
170  }
171 
172  // Find or create associated error maps.
173  for (unsigned i=0; i != bandData.size(); i++) {
174  bandError.push_back(getError(bandData[i], *bandHDU[i], cli, ll, ur, st));
175  }
176 
177  //
178  // Output maps (one image extension per map).
179  auto mtfile = cli.getString('o', "mtcore.fits");
180  if (cli.getOption('F')) { mtfile.insert(0, 1, '!'); }
182  outFITS(new CCfits::FITS(mtfile, BYTE_IMG, 0, nullptr));
183 
184  // Fit the mass and temperature maps.
187  std::vector<long> axis{
188  modelMap ? modelMapLen : ll[0] ? 1+ur[0]-ll[0] : bandHDU[0]->axis(0),
189  modelMap ? modelMapLen : ll[0] ? 1+ur[1]-ll[1] : bandHDU[0]->axis(1)
190  };
191  solve(outMap, outHDU, outFITS.get(), bandData, bandError, bandHDU, axis,
192  cli, ll, ur, st);
193 
194  // Populate header keywords and write data.
195  for (unsigned i=0, n=outMap.size(); i != n; i++) {
196  setKeys(*outHDU.at(i), *bandHDU[0], cli, ll);
197  outHDU[i]->write(1, outMap[i].size(), outMap[i]);
198  }
199 
200  if (!cli.getOption('B')) {
201  // Append input band data to FITS output.
202  for (unsigned i=0, n=bandData.size(); i != n; i++) {
203  std::string name = "BAND" + std::to_string(getBand(*bandHDU[i]));
204  std::string bunit = "BUNIT", units,
205  comm = bandHDU[i]->getComments();
206  bandHDU[i]->readKey(bunit, units);
207 
208  if (modelMap) { axis = {modelMapLen, modelMapLen}; }
209 
210  auto eHDU = outFITS->addImage(name, mapDataCode, axis);
211  eHDU->addKey(bunit, units, "Image flux units");
212  eHDU->copyAllKeys(bandHDU[i]);
213  eHDU->writeComment(comm);
214  eHDU->write(1, axis[0]*axis[1], bandData[i]);
215  resetRefPix(*eHDU, ll);
216 
217  name.insert(0, "d");
218  eHDU = outFITS->addImage(name, mapDataCode, axis);
219  eHDU->writeComment("ERROR map used for the associated parent image");
220  eHDU->addKey(bunit, units, "Error flux units");
221  eHDU->copyAllKeys(bandHDU[i]);
222  eHDU->writeComment(comm);
223  eHDU->write(1, axis[0]*axis[1], bandError[i]);
224  resetRefPix(*eHDU, ll);
225  }
226  }
227 }
228 
229 
241 void setKeys(CCfits::ExtHDU &hdu, const CCfits::PHDU &hdu0,
242  const mu::CommandLine &cli, const std::vector<long> &ll)
243 {
244  const char *const fn = "setKeys";
245 
246  // Local keywords.
247  hdu.addKey("CREATOR", std::string("Manticore v") + version,
248  "FITS file creator");
249  //
250  // Units are determined from the extension name:
251  // - N/dN: 1/cm^2
252  // - T/dT: K
253  // - Chi2: chi2/DOF
254  // - nIter: counts
255  // - diff*: absolute/relative flux difference
256  // - frac*: unity
257  auto name = hdu.name();
258  if (name[0] == 'N' || name[1] == 'N') {
259  hdu.addKey<std::string>("BUNIT", "cm^-2", "Gas column density units");
260  }
261  if (name[0] == 'T' || name[1] == 'T') {
262  hdu.addKey<std::string>("BUNIT", "K", "Gas temperature units");
263  }
264  if (name[0] == 'C' || ! name.compare(0, 4, "dChi")) {
265  hdu.addKey<std::string>("BUNIT", "chi2/DOF", "Goodness of fit units");
266  }
267  if (name[0] == 'n') {
268  hdu.addKey<std::string>("BUNIT", "counts", "Fitter iterations");
269  }
270  if (! name.compare(0, 4, "diff")) {
271  if (cli.getOption('a')) {
272  hdu.addKey<std::string>("BUNIT", "MJy/sr",
273  "Absolute differential flux units");
274  } else {
275  hdu.addKey<std::string>("BUNIT", "sigma",
276  "Relative differential flux units");
277  }
278  }
279  if (! name.compare(0, 4, "frac")) {
280  hdu.addKey<std::string>("BUNIT", "ratio", "Cold flux fraction");
281  }
282 
283  // Copy select keywords from fiducial image.
284  auto &inKeys = hdu0.keyWord();
285  for (auto &key: {"OBJECT", "RADESYS",
286  "CTYPE1", "CRVAL1", "CRPIX1", "CDELT1",
287  "CTYPE2", "CRVAL2", "CRPIX2", "CDELT2",
288  }) {
289  auto kp = inKeys.find(key);
290  if (kp != inKeys.end()) {
291  hdu.addKey(kp->second);
292  } else {
293  MU_EXCEPTION(fn, "Fiducial image missing keyword '%s'", key);
294  }
295  }
296 
297  // Sky coordinates.
298  resetRefPix(hdu, ll);
299 }
300 
301 } // namespace manticore
void process(const mutils::CommandLine &cli)
Processes multi-wavelength maps into temperature/column density maps.
Definition: process.cc:104
unsigned getOption(const Option &option, Arguments *values=nullptr, unsigned nMax=-1) const
Retrieves all copies of a command line option.
Definition: CommandLine.cc:197
T front(T... args)
T to_string(T... args)
const Arguments & arguments() const
Returns remaining arguments (read-only).
Definition: CommandLine.h:132
Command line options and arguments.
Definition: CommandLine.h:47
std::string getString(char shortName, const std::string &defValue) const
Retrieves unique string option.
Definition: CommandLine.cc:392
std::vector< std::string > Arguments
Command line arguments type.
Definition: CommandLine.h:51
#define MU_EXCEPTION_IF(cond, src, msg,...)
Conditionally throws mutils::Exception.
Definition: Exception.h:101
Package namespace.
Definition: Detector.cc:15
T at(T... args)
T push_back(T... args)
std::map< std::string, manticore::tableType > modelMap
Definition: Dust.cc:641
void resetRefPix(CCfits::HDU &hdu, const std::vector< long > &ll)
Reset cutout header coordinates.
Definition: process.cc:82
constexpr const char *const version
Version string.
Definition: version.h:6
MathUtils package.
Definition: CommandLine.cc:10
mapDataType getError(const mapDataType &data, CCfits::PHDU &hdu, const mutils::CommandLine &cli)
#define MU_EXCEPTION(src, msg,...)
Throws mutils::Exception using uniform messaging.
Definition: Exception.h:90
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 std::vector< long > &axis, const mutils::CommandLine &cli, const std::vector< long > &ll, const std::vector< long > &ur, const std::vector< long > &st)
Performs least-squares fitting of band SEDs.
Definition: solve.cc:1006
T get(T... args)
T insert(T... args)
T find(T... args)
T size(T... args)
#define MU_ERROR_IF(cond, src, msg,...)
Conditionally log a message at level Log::ERROR.
Definition: Log.h:174
int getBand(const CCfits::HDU &hdu)
Returns nominal band center (microns) from an HDU.
Definition: manticore.cc:105
#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:18
T back(T... args)
const std::string nullStr(1, 0)
constexpr int mapDataCode
Output FITS maps data code (cf. mapDataType).
Definition: manticore.h:15
double getDouble(char shortName, double defValue) const
Retrieves unique floating point option.
Definition: CommandLine.cc:376
void setKeys(CCfits::ExtHDU &hdu, const CCfits::PHDU &hdu0, const mutils::CommandLine &cli, const std::vector< long > &ll)
Sets header keywords for an output map.
Definition: process.cc:241
std::valarray< float > mapDataType
Output FITS maps data type (cf. mapDataCode).
Definition: manticore.h:12
T emplace_back(T... args)