//# ImagePolarimetry.h: Polarimetric analysis of images //# Copyright (C) 1996,1997,1998,1999,2000,2001,2002 //# 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: ImagePolarimetry.h 19817 2006-12-22 05:24:00Z gvandiep $ #ifndef IMAGES_IMAGEPOLARIMETRY_H #define IMAGES_IMAGEPOLARIMETRY_H #include <casacore/casa/aips.h> #include <casacore/casa/Arrays/Vector.h> #include <casacore/casa/Containers/Block.h> #include <casacore/measures/Measures/Stokes.h> #include <casacore/casa/BasicSL/Complex.h> #include <casacore/images/Images/ImageInterface.h> #include <casacore/scimath/Fitting/LinearFitSVD.h> #include <imageanalysis/ImageTypedefs.h> namespace casacore{ template <class T> class SubImage; template <class T> class ImageExpr; template <class T> class Quantum; template <class T> class LatticeStatistics; class CoordinateSystem; class IPosition; class LatticeExprNode; class LCBox; class LogIO; } namespace casa { // <summary> // Polarimetric analysis of images // </summary> // <use visibility=export> // <reviewed reviewer="" date="yyyy/mm/dd" tests="" demos=""> // </reviewed> // <prerequisite> // <li> <linkto class=casacore::ImageExpr>ImageExpr</linkto> // <li> <linkto class=casacore::ImageInterface>ImageInterface</linkto> // </prerequisite> // <etymology> // Polarimetric analysis of Images // </etymology> // <synopsis> // This class provides polarimetric image analysis capability. // It takes an image with a casacore::Stokes axis (some combination // of IQUV is needed) as its input. // // Many functions return casacore::ImageExpr objects. These are // read-only images. // // Sometimes the standard deviation of the noise is needed. // This is for debiasing polarized intensity images or working out // error images. By default it is worked out for you with a // clipped mean algorithm. However, you can provide sigma if you // know it accurately. It should be the standard deviation of the noise in // the absence of signal. You won't measure that very well from // casacore::Stokes I if it is dynamic range limited. Better to get it from // V or Q or U. When this class needs the standard deviation of // the noise, it will try and get it from V or Q and U and finally I. // // However, note that the functions sigmaStokes{I,Q,U,V} DO return the standard // deviation of the noise for that specific casacore::Stokes type. // // The ImageExpr objects returned have the brightness units and ImageInfo // set. The MiscInfo (a permanent record) and logSink are not set. // // </synopsis> // // <motivation> // Basic image analysis capability // </motivation> // <todo asof="1999/11/01"> // <li> plotting for function rotationMeasure // <li> some assessment of the curvature of pa-l**2 // </todo> class ImagePolarimetry { public: // casacore::Stokes types enum StokesTypes {I, Q, U, V}; // Constructor. The input image must have a Stokes // axis with some subset of I,Q,U, and V ImagePolarimetry (const casacore::ImageInterface<casacore::Float>& image); // Copy constructor (reference semantics) ImagePolarimetry(const ImagePolarimetry& other); // Destructor ~ImagePolarimetry (); // Assignment operator (reference semantics) ImagePolarimetry& operator=(const ImagePolarimetry& other); // Summary. Just invokes the casacore::ImageSummary list function // to summarize the header of the construction image void summary(casacore::LogIO& os) const; // Get the casacore::ImageInterface pointer of the construction image // Don't delete it ! SPCIIF imageInterface() const { return _image; } // Get the casacore::CoordinateSystem of the construction image casacore::CoordinateSystem coordinates() const { return _image->coordinates(); } // Get the shape of the construction image casacore::IPosition shape() const { return _image->shape(); } // Is the construction image masked ? casacore::Bool isMasked() const { return _image->isMasked(); } // Get the shape and casacore::CoordinateSystem of an image for a single // Stokes pixel. Thus, if the construction image shape was [10,10,4,20] // where axis 2 (shape 4) is the casacore::Stokes axis, this function // would return [10,10,1,20] Specify the type of casacore::Stokes pixel // you want. casacore::IPosition singleStokesShape( casacore::CoordinateSystem& cSys, casacore::Stokes::StokesTypes type ) const; // Complex linear polarization casacore::ImageExpr<casacore::Complex> complexLinearPolarization (); // casacore::Complex fractional linear polarization casacore::ImageExpr<casacore::Complex> complexFractionalLinearPolarization (); // Get the Stokes I image and the standard deviation of the // I image. This is worked out by first clipping // outliers from the mean at the specified level. // <group> casacore::ImageExpr<casacore::Float> stokesI() const; casacore::Float sigmaStokesI (casacore::Float clip=10.0); // </group> // Get the casacore::Stokes Q image and the standard deviation // of the Q image. This is worked out by first clipping // outliers from the mean at the specified level. // <group> casacore::ImageExpr<casacore::Float> stokesQ() const; casacore::Float sigmaStokesQ (casacore::Float clip=10.0); // </group> // Get the casacore::Stokes U image and the standard deviation // of the U image. This is worked out by first clipping // outliers from the mean at the specified level. // <group> casacore::ImageExpr<casacore::Float> stokesU() const; casacore::Float sigmaStokesU (casacore::Float clip=10.0); // </group> // Get the casacore::Stokes V image and the standard deviation // of the V image. This is worked out by first clipping // outliers from the mean at the specified level. // <group> casacore::ImageExpr<casacore::Float> stokesV() const; casacore::Float sigmaStokesV (casacore::Float clip=10.0); // </group> // Get the specified casacore::Stokes image and the standard deviation // of the image. This is worked out by first clipping // outliers from the mean at the specified level. // <group> casacore::ImageExpr<casacore::Float> stokes( ImagePolarimetry::StokesTypes index ) const; casacore::Float sigmaStokes ( ImagePolarimetry::StokesTypes index, casacore::Float clip=10.0 ); // </group> // Get the best estimate of the statistical noise. This gives you the // standard deviation with outliers from the mean clipped first. The idea is // to not be confused by source or dynamic range issues. Generally Stokes V // is empty of sources (not always), then Q and U are generally less bright // than I. So this function first tries V, then Q and U and lastly I to // give you its noise estimate casacore::Float sigma(casacore::Float clip=10.0); // Get the linearly polarized intensity image and its // standard deviation. If wish to debias the image, you // can either provide <src>sigma</src> (the standard // deviation of the termal noise ) or if <src>sigma</src> is non-positive, // it will be worked out for you with a clipped mean algorithm. // <group> casacore::Float sigmaLinPolInt( casacore::Float clip=10.0, casacore::Float sigma=-1.0 ); // </group> // Get the total polarized intensity (from whatever combination // of Q, U, and V the construction image has) image and its error // (standard deviation). If wish to debias the image, you // can either provide <src>sigma</src> (the standard deviation // of the thermal noise) or if <src>sigma</src> is // non-positive, it will be worked out for you with a // clipped mean algorithm. // <group> casacore::ImageExpr<casacore::Float> totPolInt( casacore::Bool debias, casacore::Float clip=10.0, casacore::Float sigma=-1.0 ); casacore::Float sigmaTotPolInt( casacore::Float clip=10.0, casacore::Float sigma=-1.0 ); // </group> // Get linearly polarized position angle (degrees or radians) image // and error (standard deviation). If you provide // <src>sigma</src> it is the standard deviation of // the termal noise. If <src>sigma</src> is non-positive, it will be // worked out for you with a clipped mean algorithm. // <group> casacore::ImageExpr<casacore::Float> linPolPosAng( casacore::Bool radians ) const; casacore::ImageExpr<casacore::Float> sigmaLinPolPosAng( casacore::Bool radians, casacore::Float clip=10.0, casacore::Float sigma=-1.0 ); // </group> // Get fractional linear polarization image // and error (standard deviation). If wish to debias the image, you // can either provide <src>sigma</src> (the standard // deviation of the termal noise) or if <src>sigma</src> is non-positive, // it will be worked out for you with a clipped mean algorithm. // <group> casacore::ImageExpr<casacore::Float> fracLinPol( casacore::Bool debias, casacore::Float clip=10.0, casacore::Float sigma=-1.0 ); casacore::ImageExpr<casacore::Float> sigmaFracLinPol( casacore::Float clip=10.0, casacore::Float sigma=-1.0 ); // </group> // Get Fractional total polarization and error (standard deviation) // <src>var</src> is the standard deviation of the thermal noise. // If <src>sigma</src> is non-positive, // it will be worked out for you with a clipped mean algorithm. // <group> casacore::ImageExpr<casacore::Float> fracTotPol( casacore::Bool debias, casacore::Float clip=10.0, casacore::Float sigma=-1.0 ); casacore::ImageExpr<casacore::Float> sigmaFracTotPol( casacore::Float clip=10.0, casacore::Float sigma=-1.0 ); // </group> // Fourier Rotation Measure. The output image is the complex polarization // (Q + iU) with the spectral axis replaced by a RotationMeasure axis. The // appropriate shape and casacore::CoordinateSystem must be obtained with // function singleStokesShape (ask for type STokes::Plinear). // Howeverm this function will replace the casacore::SpectralCoordinate // by a LinearCoordinate describing the Rotation Measure. // casacore::ImageInfo, and Units are copied to the output. MiscInfo and // history are not. If the output has a mask, // and the input is masked, the mask is copied. If the output // has a mask, it should already have been initialized to true void fourierRotationMeasure( casacore::ImageInterface<casacore::Complex>& pol, casacore::Bool zeroZeroLag ); // This function is used in concert with the rotationMeasure function. // It tells you what the shape of the output RM image should be, and // gives you its CoordinateSystem. Because the ImagePolarimetry // construction image may house the frequencies coordinate description // in a Spectral, Tabular or Linear coordinate, you may explicitly // specify which axis is the Spectral axis (spectralAxis). By default, // it tries to find the SpectralCoordinate. If there is none, it will // look for Tabular or Linear coordinates with a "FREQ" label. // It returns to you the frequencyAxis (i.e. the one it is concluded // houses the frequency spectrum) and the stokesAxis that it // finds. casacore::IPosition rotationMeasureShape( casacore::CoordinateSystem& cSys, casacore::Int& frequencyAxis, casacore::Int& stokesAxis, casacore::LogIO& os, casacore::Int spectralAxis=-1 ) const; // This function is used in concert with the rotationMeasure function. // It tells you what the shape of the output Position Angle image should be, // and gives you its CoordinateSystem. Because the ImagePolarimetry // construction image may house the frequencies coordinate description // in a Spectral, Tabular or Linear coordinate, you may explicitly // specify which axis is the Spectral axis (spectralAxis). By default, // it tries to find the SpectralCoordinate. If there is none, it will // look for Tabular or Linear coordinates with a "FREQ" label. casacore::IPosition positionAngleShape( casacore::CoordinateSystem& cSys, casacore::Int& frequencyAxis, casacore::Int& stokesAxis, casacore::LogIO& os, casacore::Int spectralAxis=-1 ) const; // This function applies a traditional (i.e. non-Fourier) Rotation Measure // algorithm (Leahy et al, A&A, 156, 234) approach. For the RM images // you must get the shape and CoordinateSYstem from function // rotationMeasureShape. For the position angle images, use function // singleStokesShape. Null pointer ImageInterface objects are // not accessed so you can select which output images you want. // Any output images not masked will be given a mask. // The position angles are all in degrees. The RM images in rad/m/m. // ImageInfo and Units, are copied to the output. MiscInfo and history are // not. You specify which axis houses the frequencies, the noise level of // Q and U if you know it (by default it is worked out for you) // for error images, the value of the foreground RM if you know it // (helps for unwinding ambiguity), the absolute maximum RM it should // solve for, and the maximum error in the position angle that should // be allowed. The state of the plotter should be set by the caller // (e.g. character size, number of plots in x and y etc). void rotationMeasure( casacore::ImageInterface<casacore::Float>*& rmPtr, casacore::ImageInterface<casacore::Float>*& rmErrPtr, casacore::ImageInterface<casacore::Float>*& pa0Ptr, casacore::ImageInterface<casacore::Float>*& pa0ErrPtr, casacore::ImageInterface<casacore::Float>*& nTurns, casacore::ImageInterface<casacore::Float>*& rChiSqPtr, casacore::Int spectralAxis, casacore::Float rmMax, casacore::Float maxPaErr=1.0e30, casacore::Float sigma=-1.0, casacore::Float rmFg=0.0, casacore::Bool showProgress=false ); // Depolarization ratio image and error. Requires two images hence static // functions. // <group> static casacore::ImageExpr<casacore::Float> depolarizationRatio( const casacore::ImageInterface<casacore::Float>& im1, const casacore::ImageInterface<casacore::Float>& im2, casacore::Bool debias, casacore::Float clip=10.0, casacore::Float sigma=-1.0 ); static casacore::ImageExpr<casacore::Float> sigmaDepolarizationRatio( const casacore::ImageInterface<casacore::Float>& im1, const casacore::ImageInterface<casacore::Float>& im2, casacore::Bool debias, casacore::Float clip=10.0, casacore::Float sigma=-1.0 ); // </group> private: static const map<StokesTypes, casacore::String> polMap; SPCIIF _image = nullptr; // const casacore::ImageInterface<casacore::Float>* _image; casacore::LinearFitSVD<casacore::Float>* _fitter = nullptr; casacore::Float _oldClip = 0.0; // These blocks are always size 4, with IQUV in slots 0,1,2,3 // If your image is IV only, they still use slots 0 and 3 casacore::PtrBlock<casacore::ImageInterface<casacore::Float>*> _stokes {}; casacore::PtrBlock<casacore::LatticeStatistics<casacore::Float>*> _stokesStats {}; casacore::Matrix<casacore::Bool> _beamsEqMat {}; // Delete all private pointers void _cleanup(); // For traiditional RM approach, give output a mask if possible casacore::Bool _dealWithMask( casacore::Lattice<casacore::Bool>*& pMask, casacore::ImageInterface<casacore::Float>*& pIm, casacore::LogIO& os, const casacore::String& type ) const; // Change the Stokes Coordinate for the given float image to be of the // specified Stokes type void _fiddleStokesCoordinate( casacore::ImageInterface<casacore::Float>& ie, casacore::Stokes::StokesTypes type ) const; void _fiddleStokesCoordinate( casacore::CoordinateSystem& cSys, casacore::Stokes::StokesTypes type ) const; // Change the casacore::Stokes casacore::Coordinate for the given complex // image to be of the specified casacore::Stokes type void _fiddleStokesCoordinate( casacore::ImageInterface<casacore::Complex>& ie, casacore::Stokes::StokesTypes type ) const; // Change the time coordinate to be rotation measure void _fiddleTimeCoordinate( casacore::ImageInterface<casacore::Complex>& ie, const casacore::Quantum<casacore::Double>& f, casacore::Int coord ) const; // Find the central frequency from the given spectral coordinate casacore::Quantum<casacore::Double> _findCentralFrequency( const casacore::Coordinate& coord, casacore::Int shape ) const; // Fit the spectrum of position angles to find the // rotation measure via Leahy algorithm casacore::Bool _findRotationMeasure( casacore::Float& rmFitted, casacore::Float& rmErrFitted, casacore::Float& pa0Fitted, casacore::Float& pa0ErrFitted, casacore::Float& rChiSqFitted, casacore::Float& nTurns, const casacore::Vector<casacore::uInt>& sortidx, const casacore::Vector<casacore::Float>& wsq, const casacore::Vector<casacore::Float>& pa, const casacore::Array<casacore::Bool>& paMask, const casacore::Array<casacore::Float>& paerr, casacore::Float rmfg, casacore::Float rmmax, casacore::Float paErrMax, const casacore::String& posString ); // Find the casacore::Stokes in the construction image and assign pointers void _findStokes(); // Find the spectral coordinate. casacore::Int _findSpectralCoordinate( const casacore::CoordinateSystem& cSys, casacore::LogIO& os, casacore::Bool fail ) const; // FInd frequency axis void _findFrequencyAxis( casacore::Int& spectralCoord, casacore::Int& fAxis, const casacore::CoordinateSystem& cSys, casacore::Int spectralAxis ) const; // So we have Q and U ? Excpetion if not void _hasQU () const; // Make a LEN for the give types of polarized intensity casacore::LatticeExprNode _makePolIntNode( casacore::LogIO& os, casacore::Bool debias, casacore::Float clip, casacore::Float sigma, casacore::Bool doLin, casacore::Bool doCirc ); // Make an IE for the specified Stokes casacore::ImageExpr<casacore::Float> _makeStokesExpr( casacore::ImageInterface<casacore::Float>* imPtr, casacore::Stokes::StokesTypes type, const casacore::String& name ) const; // Make a casacore::SubImage from the construction image for the specified // pixel along the specified pixel axis casacore::ImageInterface<casacore::Float>* _makeSubImage( casacore::IPosition& blc, casacore::IPosition& trc, casacore::Int axis, casacore::Int pix ) const; // Least squares fit to find RM from position angles casacore::Bool _rmLsqFit( casacore::Vector<casacore::Float>& pars, const casacore::Vector<casacore::Float>& wsq, const casacore::Vector<casacore::Float> pa, const casacore::Vector<casacore::Float>& paerr ) const; // Fit the spectrum of position angles to find the rotation measure // via Leahy algorithm for primary (n>2) points casacore::Bool _rmPrimaryFit( casacore::Float& nTurns, casacore::Float& rmFitted, casacore::Float& rmErrFitted, casacore::Float& pa0Fitted, casacore::Float& pa0ErrFitted, casacore::Float& rChiSqFitted, const casacore::Vector<casacore::Float>& wsq, const casacore::Vector<casacore::Float>& pa, const casacore::Vector<casacore::Float>& paerr, casacore::Float rmmax, const casacore::String& posString ); // Fit the spectrum of position angles to find the rotation measure // via Leahy algorithm for supplementary (n==2) points casacore::Bool _rmSupplementaryFit( casacore::Float& nTurns, casacore::Float& rmFitted, casacore::Float& rmErrFitted, casacore::Float& pa0Fitted, casacore::Float& pa0ErrFitted, casacore::Float& rChiSqFitted, const casacore::Vector<casacore::Float>& wsq, const casacore::Vector<casacore::Float>& pa, const casacore::Vector<casacore::Float>& paerr ); // Return I, Q, U or V for specified integer index (0-3) casacore::String _stokesName( ImagePolarimetry::StokesTypes index ) const; // Return I, Q, U or V for specified integer index (0-3) casacore::Stokes::StokesTypes _stokesType( ImagePolarimetry::StokesTypes index ) const; // Find the standard deviation for the Stokes image // specified by the integer index casacore::Float _sigma( ImagePolarimetry::StokesTypes index, casacore::Float clip ); // Subtract profile mean from image void _subtractProfileMean( casacore::ImageInterface<casacore::Float>& im, casacore::uInt axis ) const; void _createBeamsEqMat(); casacore::Bool _checkBeams( const std::vector<StokesTypes>& stokes, casacore::Bool requireChannelEquality, casacore::Bool throws=true ) const; casacore::Bool _checkIQUBeams( casacore::Bool requireChannelEquality, casacore::Bool throws=true ) const ; casacore::Bool _checkIVBeams( casacore::Bool requireChannelEquality, casacore::Bool throws=true ) const; casacore::Bool _checkQUBeams( casacore::Bool requireChannelEquality, casacore::Bool throws=true ) const; static void _checkBeams( const ImagePolarimetry& im1, const ImagePolarimetry& im2, const casacore::Vector<StokesTypes>& stokes ); void _setInfo( casacore::ImageInterface<casacore::Complex>& im, StokesTypes stokes ) const; void _setInfo( casacore::ImageInterface<casacore::Float>& im, StokesTypes stokes ) const; void _setDoLinDoCirc(casacore::Bool& doLin, casacore::Bool& doCirc) const; }; } #endif