//# SpectralModel.h: Base class for Spectral Models //# Copyright (C) 1998,1999,2000,2003 //# Associated Universities, Inc. Washington DC, USA. //# //# This library is free software; you can redistribute it and/or modify it //# under the terms of the GNU Library General Public License as published by //# the Free Software Foundation; either version 2 of the License, or (at your //# option) any later version. //# //# This library is distributed in the hope that it will be useful, but WITHOUT //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public //# License for more details. //# //# You should have received a copy of the GNU Library General Public License //# along with this library; if not, write to the Free Software Foundation, //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. //# //# Correspondence concerning AIPS++ should be addressed as follows: //# Internet email: aips2-request@nrao.edu. //# Postal address: AIPS++ Project Office //# National Radio Astronomy Observatory //# 520 Edgemont Road //# Charlottesville, VA 22903-2475 USA //# //# $Id: SpectralModel.h 18093 2004-11-30 17:51:10Z ddebonis $ #ifndef COMPONENTS_SPECTRALMODEL_H #define COMPONENTS_SPECTRALMODEL_H #include <casacore/casa/aips.h> #include <components/ComponentModels/ComponentType.h> #include <casacore/casa/Utilities/RecordTransformable.h> #include <casacore/measures/Measures/MFrequency.h> #include <casacore/casa/Quanta/Unit.h> #include <casacore/casa/Quanta/Quantum.h> #include <casacore/casa/Arrays/ArrayFwd.h> namespace casacore{ class RecordInterface; class String; } namespace casa { //# NAMESPACE CASA - BEGIN // <summary>Base class for spectral models</summary> // <use visibility=export> // <reviewed reviewer="" date="yyyy/mm/dd" tests="tConstantSpectrum" demos="dSpectralModel"> // </reviewed> // <prerequisite> // <li> <linkto class=casacore::MFrequency>MFrequency</linkto> // </prerequisite> // // <synopsis> // This abstract base class defines the interface for different classes which // model the spectrum of a component. The most fundamental derived class is the // <linkto class=ConstantSpectrum>ConstantSpectrum</linkto> class but the // <linkto class=SpectralIndex>SpectralIndex</linkto> class is also // available. These classes model the spectrum of emission from the sky. // Classes derived from the // <linkto class=ComponentShape>ComponentShape</linkto> class are used to model // the shape and the <linkto class=Flux>Flux</linkto> class is used to model // the flux. The <linkto class=SkyComponent>SkyComponent</linkto> class // incorporates these three characteristics (flux, shape & spectrum) and the // <linkto class=ComponentList>ComponentList</linkto> class handles groups of // SkyComponent objects. // This class parameterises spectral models with two quantities. // <dl> // <dt><em> A reference frequency.</em> // <dd> This is specified using an <linkto class=casacore::MFrequency>MFrequency</linkto> // object and defines a frequency where the model // is interesting. See the description of derived classes for the // specific interpretation of the reference frequency. // <dt> <em>A casacore::Vector of parameters.</em> // <dd> This contains other parameters that the are defined differently for // different spectral models. The length of the vector may vary for // different spectral models. // </dl> // // The basic operation of classes using this interface is to model the flux as // a function of frequency. Classes derived from this one do not know what the // flux is at the reference frequency. Instead the sample functions return // factors that are used to scale the flux and calculate the amount of flux at // a specified frequency. // Any allowed frequency reference frame can be used. However the reference // frame must be adequately specified in order to allow conversions to other // reference frames. For example if the reference frame code for the frequency // is casacore::MFrequency::TOPO then the reference frame must also contain the time, // position on the earth, and direction of the observation that corresponds to // the specified frequency. This way the sample functions can convert the // frequency to a value in the LSR reference frame (if you specify the sample // frequency in the LSR frame). // </synopsis> // // <example> // Because this is an abstract base class, an actual instance of this class // cannot be constructed. However the interface it defines can be used inside a // function. This is always recommended as it allows functions which have // SpectralModels as arguments to work for any derived class. // In this example the plotSpectrum function prints out the type of spectral // model it is working with and the reference frequency of that model. It then // uses the model to calculate the proportion of the flux at other // frequencies. This example is coded in the dSpectralModel.cc file. // <srcblock> // void plotSpectrum(const SpectralModel& modelSpectrum) { // cout << "This is a " // << ComponentType::name(modelSpectrum.type()) // << " spectrum with a reference frequency of: " // << setprecision(4) << modelSpectrum.refFrequency().get("GHz") << " (" // << modelSpectrum.refFrequency().getRefString() << ")" // << endl; // const casacore::MVFrequency step(casacore::Quantity(100.0, "MHz")); // casacore::MVFrequency sampleFreq(casacore::Quantity(1, "GHz")); // casacore::MeasFrame obsFrame; // { // casacore::Quantity obsRa; casacore::MVAngle::read(obsRa, "19:39:"); // casacore::Quantity obsDec; casacore::MVAngle::read(obsDec, "-63.43."); // casacore::Quantity obsDay; casacore::MVTime::read(obsDay, "1996/11/20/5:20"); // obsFrame.set(casacore::MEpoch(obsDay, casacore::MEpoch::UTC), // casacore::MDirection(obsRa, obsDec, casacore::MDirection::J2000)); // } // casacore::MFrequency::Ref obsRef(casacore::MFrequency::GEO, obsFrame); // cout << "Frequency\t scale\n"; // for (casacore::uInt i = 0; i < 11; i++) { // cout << setprecision(7) << sampleFreq.get("GHz") // << "\t\t " << modelSpectrum.sample(casacore::MFrequency(sampleFreq, obsRef)) // << endl; // sampleFreq += step; // } // } // </srcblock> // </example> // // <motivation> // The SpectralModel base class was seperated from the ComponentShape base // class so that mixing components with different spatial and spectral shapes // did not result in a combinatorial explosion in the number of classes // required. // </motivation> // // <todo asof="1999/11/23"> // <li> I would not be surprised if the base class will need to be updated // when classes modelling spectral lines are written. // </todo> class SpectralModel: public casacore::RecordTransformable { public: // a virtual destructor is needed so that the actual destructor in the // derived class will be used. virtual ~SpectralModel(); // return the actual spectral type. The ident function returns it as a // String. // <group> virtual ComponentType::SpectralShape type() const = 0; virtual const casacore::String& ident() const; // </group> // set/get the reference frequency // <group> virtual void setRefFrequency(const casacore::MFrequency& newRefFreq); const casacore::MFrequency& refFrequency() const; // </group> // get the frequency unit, and change the default frequency unit to the // specified one. This will only affect the units used in the casacore::Record returned // by the toRecord function. // <group> const casacore::Unit& frequencyUnit() const; void convertFrequencyUnit(const casacore::Unit& freqUnit); // </group> // set/get the error in the reference frequency. Values must be positive // angular quantities otherwise an casacore::AipsError exception is thrown. The errors // are usually interpreted as the 1-sigma bounds in latitude/longitude and // implicitly assume a Gaussian distribution. They must have units with the // same dimensions as the Hz. // <group> void setRefFrequencyError(const casacore::Quantum<casacore::Double>& newRefFreqErr); const casacore::Quantum<casacore::Double>& refFrequencyError() const; // </group> // Return the scaling factor that indicates what proportion of the flux is at // the specified frequency. ie. if the centreFrequency argument is the // reference frequency then this function will always return one. At other // frequencies it will return a non-negative number. virtual casacore::Double sample(const casacore::MFrequency& centerFrequency) const = 0; // return full casacore::Stokes version especially for models which have different // frequency dependence for the casacore::Stokes param (1 or 4 elements) // So as allow for fractional pol change and angle change of linear pol w.r.t frequency // A a four casacore::Vector of original IQUV should be passed in and it will hold the return values virtual void sampleStokes(const casacore::MFrequency& centerFrequency, casacore::Vector<casacore::Double>& stokesval ) const = 0; // Same as the previous function except that many frequencies can be sampled // at once. The reference frame must be the same for all the specified // frequencies. A default implementation of this function is available that // uses the sample function described above. However customised versions of // this function will be more efficient as intermediate values only need to // be computed once. virtual void sample(casacore::Vector<casacore::Double>& scale, const casacore::Vector<casacore::MFrequency::MVType>& frequencies, const casacore::MFrequency::Ref& refFrame) const = 0; // So as allow for fractional pol change and angle change of linear pol w.r.t frequency // Matrix should have shape (frequencies.size(), 4), each row corresponds to the four stokes // at one frequency. // Uitimately this math should really go in Flux and FluxRep to where a rotation of linear pol is allowed virtual void sampleStokes( casacore::Matrix<casacore::Double>& stokesval, const casacore::Vector<casacore::MFrequency::MVType>& frequencies, const casacore::MFrequency::Ref& refFrame ) const = 0; // Return a pointer to a copy of the derived object upcast to a SpectralModel // object. The class that uses this function is responsible for deleting the // pointer. This is used to implement a virtual copy constructor. virtual SpectralModel* clone() const = 0; // return the number of parameters in this spectral shape and set/get them. // <group> virtual casacore::uInt nParameters() const = 0; virtual void setParameters(const casacore::Vector<casacore::Double>& newParms) = 0; virtual casacore::Vector<casacore::Double> parameters() const = 0; virtual void setErrors(const casacore::Vector<casacore::Double>& newErrors) = 0; virtual casacore::Vector<casacore::Double> errors() const = 0; // </group> // These functions convert between a record and a SpectralModel. This way // derived classes can interpret fields in the record in a class specific // way. They return false if the record is malformed and append an error // message to the supplied string giving the reason. These functions define // how a spectral model is represented in glish. All records should have // 'type' & 'frequency' fields which contain respectively; a string // indicating which spectral model is actually used, and a record // representation of a frequency measure. The interpretation of all other // fields depends on the specific spectral model used. // <group> virtual casacore::Bool fromRecord(casacore::String& errorMessage, const casacore::RecordInterface& record) = 0; virtual casacore::Bool toRecord(casacore::String& errorMessage, casacore::RecordInterface& record) const = 0; // </group> // Convert the parameters of the spectral model to the specified units. The // casacore::Record must contain the same fields that the to/from casacore::Record functions have // (with the exception of the frequency & type fields). These fields will // contain strings (and not Quantums) that specify the new units for these // parameters. The new units must have the same dimensions as the existing // ones. If there is any problem parsing the record then an error message is // appended to the supplied string and the function returns false. virtual casacore::Bool convertUnit(casacore::String& errorMessage, const casacore::RecordInterface& record) = 0; // Return the spectral shape that the supplied record represents. The // spectral shape is determined by parsing a 'type' field in the supplied // record. Returns ComponentType::UNKNOWN_SPECTRAL_SHAPE if the type field // (which contains a string) could not be translated into a known spectral // shape. It then appends an appropriate error message to the errorMessage // String. static ComponentType::SpectralShape getType(casacore::String& errorMessage, const casacore::RecordInterface& record); // casacore::Function which checks the internal data of this class for correct // dimensionality and consistant values. Returns true if everything is fine // otherwise returns false. virtual casacore::Bool ok() const; protected: // The constructors and assignment operator are protected as only derived // classes should use them. // <group> //# The default reference frequency is at 1 GHz in the LSR frame SpectralModel(); //# Construct a SpectralModel at the specified reference frequency. SpectralModel(const casacore::MFrequency& refFreq, const casacore::Unit& = casacore::Unit("GHz")); //# The copy constructor uses copy semantics. SpectralModel(const SpectralModel& other); //# The assignment operator uses copy semantics. SpectralModel& operator=(const SpectralModel& other); // </group> // Return the value refFrequency in the requested frame... //exception is thrown if convert does not work. //No direction or epoch is available..so better ask for a frame // that works or better convert to the frame of the refFrequency . casacore::Double refFreqInFrame(const casacore::MFrequency::Ref& frame) const; // returns true if the quantum is not a non-negative quantity with units // dimensionally identical to the Hz static casacore::Bool badError(const casacore::Quantum<casacore::Double>& quantum); private: //# The reference frequency of the spectral model casacore::MFrequency itsRefFreq; //# the units (Hz, GHz etc.) that the record functions should use for the //# reference frequency. casacore::Unit itsFreqUnit; casacore::Quantity itsFreqErr; }; } //# NAMESPACE CASA - END #endif