mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
astroSpectrum.hpp
Go to the documentation of this file.
1 /** \file astroSpectrum.hpp
2  * \author Jared R. Males
3  * \brief A class for working with astronomical spectra.
4  * \ingroup astrophot
5  *
6  */
7 
8 #ifndef mx_astro_astroSpectrum_hpp
9 #define mx_astro_astroSpectrum_hpp
10 
11 #include <cmath>
12 
13 
14 #include "../sys/environment.hpp"
15 #include "../ioutils/readColumns.hpp"
16 #include "../math/gslInterpolation.hpp"
17 #include "constants.hpp"
18 #include "units.hpp"
19 
20 namespace mx
21 {
22 namespace astro
23 {
24 
25 ///Base spectrum class which provides manipulation and characterization functionality.
26 /**
27  * \ingroup astrophot
28  */
29 template<typename realT>
31 {
32  std::vector<realT> _spectrum; ///< Contains the spectrum after it is set.
33 
34  /// Get the current size of the spectrum
35  /**
36  * \returns the number of points in the spectrum
37  */
38  size_t size()
39  {
40  return _spectrum.size();
41  }
42 
43  ///Access a single point in the spectrum, specified by its vector index.
44  /**
45  * \returns a reference to the value at i.
46  */
47  realT & operator[](size_t i /**< [in] the index of the spectral point*/)
48  {
49  return _spectrum[i];
50  }
51 
52  ///Access a single point in the spectrum, specified by its vector index.
53  /**
54  * \returns the value of point i.
55  */
56  const realT operator[](size_t i /**< [in] the index of the spectral point*/) const
57  {
58  return _spectrum[i];
59  }
60 
61  ///Multiply two spectra together.
62  /**
63  * \returns a new baseSpectrum
64  */
65  template<typename compSpectrumT>
66  baseSpectrum<realT> operator*( const compSpectrumT & spec /**< [in] the spectrum to multiply by */ )
67  {
68  baseSpectrum outVec;
69  outVec._spectrum.resize( _spectrum.size() );
70 
71  for(int i=0; i< _spectrum.size(); ++i)
72  {
73  outVec[i] = _spectrum[i] * spec[i];
74  }
75 
76  return outVec;
77  }
78 
79  ///Calculate the mean value of the spectrum.
80  /**
81  * \returns the mean value of the spectrum
82  */
83  realT mean()
84  {
85  realT sum = 0;
86 
87  for(int i=0; i< _spectrum.size(); ++i) sum += _spectrum[i];
88 
89  return sum/_spectrum.size();
90  }
91 
92  ///Calculate the mean value of the spectrum when mutiplied by another.
93  /** The result is normalized by the mean value of the input spectrum, equivalent to:
94  * \f[
95  \mu = \frac{\int T(\lambda)S(\lambda) d\lambda}{\int T(\lambda) d\lambda}
96  \f]
97  * For instance, use this to get the mean value of a spectrum in a filter.
98  *
99  * \returns the mean value of the multiplied spectrum.
100  *
101  * \tparam compSpectrumT the vector-like type of the comparison spectrum.
102  */
103  template<typename compSpectrumT>
104  realT mean( const compSpectrumT & T /**< [in] the spectrum to multiply by*/ )
105  {
106  realT sum1 = 0, sum2 = 0;
107 
108  for(int i=0; i< _spectrum.size(); ++i)
109  {
110  sum1 += _spectrum[i]*T[i];
111  sum2 += T[i];
112  }
113 
114  return sum1/sum2;
115  }
116 
117 
118  /// Characterize the spectrum as a filter transmission curve.
119  /** For a photonic transmission curve given by \f$ S(\lambda ) \f$ The mean photon wavelength is defined as
120  * \f[
121  \lambda_0 = \frac{1}{\Delta\lambda_{0}}\int \frac{S(\lambda )}{S_{max}} \lambda d\lambda
122  \f]
123  * which Equation A14 of Bessel 2012.
124  *
125  * where the effective width is defined by
126  \f[
127  \Delta\lambda_{o} = \int \frac{S(\lambda )} { S_{max}} d\lambda
128  \f]
129  *
130  * The full-width at half-maximum, FWHM, is the distance between the points at 50% of maximum \f$ S(\lambda) \f$.
131  *
132  */
133  void charTrans( realT & lambda0, ///< [out] the central wavelength of the filter
134  realT & weff, ///< [out] the effective width of the filter
135  realT & max, ///< [out] the maximum value of the transmission curve
136  realT & fwhm, ///< [out] the full-width at half-maximum of the filter profile
137  std::vector<realT> & lambda ///< [in] the wavelength scale, should correspond to the spectrum.
138  )
139  {
140  size_t N = lambda.size();
141  realT dl = lambda[1] - lambda[0];
142  realT half = static_cast<realT>(0.5);
143 
144  max = 0;
145  for(int i=0; i< N; ++i)
146  {
147  if(_spectrum[i] > max) max = _spectrum[i];
148  }
149 
150  weff = half * _spectrum[0];
151  for(int i=1; i< N-1; ++i) weff += _spectrum[i];
152  weff += half * _spectrum[N-1];
153  weff *= dl/max;
154 
155  lambda0 = half*lambda[0]*_spectrum[0];
156  for(int i=1; i< N-1; ++i) lambda0 += lambda[i]*_spectrum[i];
157  lambda0 += half*lambda[N-1]*_spectrum[N-1];
158  lambda0 *= dl/max/weff;
159 
160  realT left, right;
161 
162  int i=1;
163  while(i < lambda.size())
164  {
165  if(_spectrum[i] >= 0.5*max) break;
166  ++i;
167  }
168 
169  //Interpolate
170  left = lambda[i-1] + (0.5*max - _spectrum[i-1])* ( dl / (_spectrum[i]-_spectrum[i-1]));
171 
172  i = N-2;
173  while( _spectrum[i] < 0.5*max )
174  {
175  --i;
176  if(i < 0 ) break;
177  }
178 
179  right = lambda[i] + (_spectrum[i]-0.5*max)* ( dl / (_spectrum[i]-_spectrum[i+1]));
180 
181  fwhm = right-left;
182  }
183 
184  /// Characterize the flux densities of the spectrum w.r.t. a filter transmission curve
185  /** To obtain the flux (e.g. W/m^2) multiply these quantities by the effective width calculated using
186  * \ref charTrans.
187  *
188  * This implements Equations A11, A12, and A13 of Bessel 2012.
189  *
190  * \warning this only produces correct fphot0 for a spectrum in W/m^3. DO NOT USE FOR ANYTHING ELSE.
191  *
192  * \todo use unit conversions to make it work for everything.
193  * \todo check on integration method, should it be trap?
194  *
195  */
196  template<class filterT>
197  void charFlux( realT & flambda0, ///< [out] the flux of the star at \f$ \lambda_0 \f$ in W/m^3
198  realT & fnu0, ///< [out] the flux of the star at \f$ \lambda_0 \f$ in W/m^2/Hz
199  realT & fphot0, ///< [out] the flux of the star at \f$ \lambda_0 \f$ in photons/sec/m^3
200  const realT & lambda_0, ///< [in] the mean photon wavelength lambda_0 (from charTrans).
201  const std::vector<realT> & lambda, ///< [in] the wavelength scale of this spectrum.
202  const filterT & trans ///< [in] the filter transmission curve over which to characterize, on the same wavelength grid.
203  )
204  {
205  charFlux(flambda0, fnu0, fphot0, lambda_0, lambda, trans._spectrum);
206  }
207 
208  /// Characterize the flux densities of the spectrum w.r.t. a filter transmission curve
209  /** To obtain the flux (e.g. W/m^2) multiply these quantities by the effective width calculated using
210  * \ref charTrans.
211  *
212  * This implements Equations A11, A12, and A13 of Bessel 2012.
213  *
214  * \warning this only produces correct fphot0 for a spectrum in W/m^3. DO NOT USE FOR ANYTHING ELSE.
215  *
216  * \todo use unit conversions to make it work for everything.
217  * \todo check on integration method, should it be trap?
218  *
219  */
220  void charFlux( realT & flambda0, ///< [out] the flux of the star at \f$ \lambda_0 \f$ in W/m^3
221  realT & fnu0, ///< [out] the flux of the star at \f$ \lambda_0 \f$ in W/m^2/Hz
222  realT & fphot0, ///< [out] the flux of the star at \f$ \lambda_0 \f$ in photons/sec/m^3
223  const realT & lambda_0, ///< [in] the mean photon wavelength lambda_0 (from charTrans).
224  const std::vector<realT> & lambda, ///< [in] the wavelength scale of this spectrum.
225  const std::vector<realT> & trans ///< [in] the filter transmission curve over which to characterize, on the same wavelength grid.
226  )
227  {
228  constexpr realT h = constants::h<units::si<realT>>();
229  constexpr realT c = constants::c<units::si<realT>>();
230 
231  size_t N = lambda.size();
232  realT dl = lambda[1] - lambda[0];
233  realT half = static_cast<realT>(0.5);
234 
235  // flambda0 -- Eqn A11
236 
237  realT denom = half*trans[0]*lambda[0];
238  for(int i=1; i< N-1; ++i) denom += trans[i]*lambda[i];
239  denom += half*trans[N-1]*lambda[N-1];
240  denom *= dl;
241 
242  realT num = half*_spectrum[0]*trans[0]*lambda[0];
243  for(int i=1; i< N-1; ++i) num += _spectrum[i]*trans[i]*lambda[i];
244  num += half*_spectrum[N-1]*trans[N-1]*lambda[N-1];
245  num *= dl;
246 
247  flambda0 = num / denom;
248 
249  // fnu0 -- Eqn A12
250 
251  denom = half*trans[0]/lambda[0];
252  for(int i=1; i< N-1; ++i) denom += trans[i]/lambda[i];
253  denom += half*trans[N-1]/lambda[N-1];
254  denom *= dl*c;
255 
256  fnu0 = num / denom;
257 
258  //fphot0 -- Eqn A13
259 
260  fphot0 = flambda0 * lambda_0/(h*c);
261 
262  }
263 };
264 
265 ///Class to manage an astronomical spectrum.
266 /** Details of the spectra, including units, file-location, and how they are read from disk, are specified by template parameter _spectrumT:
267  * see \ref astrophot_spectra "the available spectrum definitions."
268  * Spectra are loaded and immediately interpolated onto a wavelength grid. This is to facilitate manipulation of spectra, i.e.
269  * for multiplying by filters, etc.
270  *
271  * Inherits functions and operators to manipulate and characterize spectra from \ref mx::astro::baseSpectrum "baseSpectrum".
272  *
273  * \tparam _spectrumT is the underlying spectrum type, which provides (through static interfaces) the specifications of how to read or calculate the spectrum.
274  * \tparam freq specify whether this spectrum uses frequency instead of wavelength. Default is false.
275  *
276  * \ingroup astrophot
277  */
278 template<typename _spectrumT, bool freq=false>
279 struct astroSpectrum : public baseSpectrum<typename _spectrumT::units::realT>
280 {
281  typedef _spectrumT spectrumT;
282  typedef typename spectrumT::units units;
283  typedef typename units::realT realT;
284  typedef typename spectrumT::paramsT paramsT;
285 
286  std::string _dataDir; ///< The directory containing the spectrum
287 
288  paramsT _params; ///< The parameters of the spectrum, e.g. its name or the numerical parameters needed to generate the name.
289 
290  ///Default c'tor
292 
293  ///Constructor specifying name, the enivronment will be queried for data directory.
294  explicit astroSpectrum( const paramsT & params /**< [in] The name of the spectrum */)
295  {
296  setParameters(params);
297  }
298 
299  ///Constructor specifying name and data directory.
300  astroSpectrum( const paramsT & params, ///< [in] The name of the spectrum
301  const std::string & dataDir ///< [in] The directory containing the spectrum
302  )
303  {
304  setParameters(params, dataDir);
305  }
306 
307  ///Set the parameters of the spectrum, using the underlying spectrums parameter type.
308  int setParameters( const paramsT & params /**< [in] The name of the spectrum */)
309  {
310  _params = params;
311 
312  if(spectrumT::dataDirEnvVar)
313  {
314  _dataDir = sys::getEnv(spectrumT::dataDirEnvVar);
315  }
316 
317  return 0;
318  }
319 
320  ///Set the parameters of the spectrum, using the underlying spectrum's parameter type.
321  /** This version also sets the data directory, instead of using the enivronment variable.
322  *
323  * \overload
324  */
325  int setParameters( const paramsT & params, ///< [in] The name of the spectrum
326  const std::string & dataDir ///< [in] The directory containing the spectrum
327  )
328  {
329  _params = params;
330  _dataDir = dataDir;
331 
332  return 0;
333  }
334 
335  ///Load the spectrum and interpolate it onto a wavelength scale.
336  template<typename gridT>
337  int setSpectrum( gridT & lambda )
338  {
339  std::vector<realT> rawLambda;
340  std::vector<realT> rawSpectrum;
341 
342  std::string fileName = spectrumT::fileName(_params);
343 
344  std::string path;
345 
346  if(fileName.size() < 1)
347  {
348  mxError("astroSpectrum", MXE_PARAMNOTSET, "fileName is empty");
349  return -1;
350  }
351 
352  if(_dataDir == "" && fileName[0] == '/')
353  {
354  path = fileName;
355  }
356  else
357  {
358  if(_dataDir == "") _dataDir = ".";
359 
360  path = _dataDir + "/" + fileName;
361  }
362 
363  if( spectrumT::readSpectrum(rawLambda, rawSpectrum, path, _params) < 0)
364  {
365  return -1; ///\returns -1 on an error reading the spectrum.
366  }
367 
368  //Unit conversions
369  for(int i=0; i < rawLambda.size(); ++i)
370  {
371  rawLambda[i] /= spectrumT::wavelengthUnits/(units::length);
372  rawSpectrum[i] /= spectrumT::fluxUnits/(units::energy/(units::time * units::length * units::length * units::length));
373  }
374 
375  math::gsl_interpolate(::gsl_interp_linear, rawLambda, rawSpectrum, lambda, this->_spectrum);
376 
377  for(int i=0; i < lambda.size(); ++i)
378  {
379  if( !std::isnormal(this->_spectrum[i])) this->_spectrum[i] = 0;
380  }
381 
382  return 0; ///\returns 0 on success.
383  }
384 
385 
386 };
387 
388 
389 
390 
391 } //namespace astro
392 
393 } //namespace mx
394 
395 
396 
397 
398 
399 #endif //mx_astro_astroSpectrum_hpp
constexpr units::realT c()
The speed of light.
Definition: constants.hpp:60
constexpr units::realT h()
Planck Constant.
Definition: constants.hpp:91
int gsl_interpolate(const gsl_interp_type *interpT, realT *xin, realT *yin, size_t Nin, realT *xout, realT *yout, size_t Nout)
Interpolate a 1-D data X vs Y discrete function onto a new X axis.
std::string getEnv(const std::string &estr)
Return the value of an environment variable.
Definition: environment.cpp:33
The mxlib c++ namespace.
Definition: mxError.hpp:107
Class to manage an astronomical spectrum.
astroSpectrum()
Default c'tor.
paramsT _params
The parameters of the spectrum, e.g. its name or the numerical parameters needed to generate the name...
int setSpectrum(gridT &lambda)
Load the spectrum and interpolate it onto a wavelength scale.
int setParameters(const paramsT &params)
Set the parameters of the spectrum, using the underlying spectrums parameter type.
int setParameters(const paramsT &params, const std::string &dataDir)
Set the parameters of the spectrum, using the underlying spectrum's parameter type.
astroSpectrum(const paramsT &params, const std::string &dataDir)
Constructor specifying name and data directory.
std::string _dataDir
The directory containing the spectrum.
astroSpectrum(const paramsT &params)
Constructor specifying name, the enivronment will be queried for data directory.
Base spectrum class which provides manipulation and characterization functionality.
size_t size()
Get the current size of the spectrum.
const realT operator[](size_t i) const
Access a single point in the spectrum, specified by its vector index.
void charTrans(realT &lambda0, realT &weff, realT &max, realT &fwhm, std::vector< realT > &lambda)
Characterize the spectrum as a filter transmission curve.
realT & operator[](size_t i)
Access a single point in the spectrum, specified by its vector index.
baseSpectrum< realT > operator*(const compSpectrumT &spec)
Multiply two spectra together.
realT mean()
Calculate the mean value of the spectrum.
void charFlux(realT &flambda0, realT &fnu0, realT &fphot0, const realT &lambda_0, const std::vector< realT > &lambda, const std::vector< realT > &trans)
Characterize the flux densities of the spectrum w.r.t. a filter transmission curve.
void charFlux(realT &flambda0, realT &fnu0, realT &fphot0, const realT &lambda_0, const std::vector< realT > &lambda, const filterT &trans)
Characterize the flux densities of the spectrum w.r.t. a filter transmission curve.
std::vector< realT > _spectrum
Contains the spectrum after it is set.
realT mean(const compSpectrumT &T)
Calculate the mean value of the spectrum when mutiplied by another.
Unit specifications and conversions.