diff --git a/StationResponse/CMakeLists.txt b/StationResponse/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..16350a206a86c1e877f491e6a2e865ddebdf9386 --- /dev/null +++ b/StationResponse/CMakeLists.txt @@ -0,0 +1,14 @@ +# $Id$ + +lofar_package(StationResponse 0.1 DEPENDS Common ElementResponse) + +include(LofarFindPackage) +lofar_find_package(Boost REQUIRED) +lofar_find_package(Casacore REQUIRED COMPONENTS casa measures ms tables images coordinates) + +# Uncomment to check for unsafe conversions (gcc), for example conversion of +# size_t to unsigned int (truncation). +#add_definitions(-Wconversion) + +add_subdirectory(include/StationResponse) +add_subdirectory(src) diff --git a/StationResponse/include/StationResponse/AntennaField.h b/StationResponse/include/StationResponse/AntennaField.h new file mode 100644 index 0000000000000000000000000000000000000000..934e0b2247251b8628449391c62277ffb526a319 --- /dev/null +++ b/StationResponse/include/StationResponse/AntennaField.h @@ -0,0 +1,261 @@ +//# AntennaField.h: Representation of a LOFAR antenna field, with methods to +//# compute its response to incoming radiation. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#ifndef LOFAR_STATIONRESPONSE_ARRAYFIELD_H +#define LOFAR_STATIONRESPONSE_ARRAYFIELD_H + +// \file +// Representation of a LOFAR antenna field, with methods to compute its response +// to incoming radiation. + +#include <Common/lofar_smartptr.h> +#include <Common/lofar_string.h> +#include <Common/lofar_vector.h> +#include <StationResponse/Constants.h> +#include <StationResponse/Types.h> +#include <StationResponse/ITRFDirection.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +// \addtogroup StationResponse +// @{ + +/** + * \brief Base class that represents a generic LOFAR antenna field. + */ +class AntennaField +{ +public: + typedef shared_ptr<AntennaField> Ptr; + typedef shared_ptr<const AntennaField> ConstPtr; + + /** + * \brief Antenna field coordinate system. + * + * A right handed, cartesian, local coordinate system with coordinate axes + * \p p, \p q, and \p r is associated with each antenna field. + * + * The r-axis is orthogonal to the antenna field, and points towards the + * local pseudo zenith. + * + * The q-axis is the northern bisector of the \p X and \p Y dipoles, i.e. + * it is the reference direction from which the orientation of the dual + * dipole antennae is determined. The q-axis points towards the North at + * the core. At remote sites it is defined as the intersection of the + * antenna field plane and a plane parallel to the meridian plane at the + * core. This ensures the reference directions at all sites are similar. + * + * The p-axis is orthogonal to both other axes, and points towards the East + * at the core. + * + * The axes and origin of the anntena field coordinate system are expressed + * as vectors in the geocentric, cartesian, ITRF coordinate system, in + * meters. + * + * \sa "LOFAR Reference Plane and Reference Direction", M.A. Brentjens, + * LOFAR-ASTRON-MEM-248. + */ + struct CoordinateSystem + { + struct Axes + { + vector3r_t p; + vector3r_t q; + vector3r_t r; + }; + + vector3r_t origin; + Axes axes; + }; + + /** A single antenna. */ + struct Antenna + { + /** + * \brief Position of the antenna relative to the antenna field center + * (origin). This is a vector expressed in the geocentric, cartesian, + * ITRF coordinate system, in meters. + */ + vector3r_t position; + + /** + * \brief Status of the \p X and \p Y signal paths of the antenna, + * respectively. + */ + bool enabled[2]; + }; + + typedef vector<Antenna> AntennaList; + + + AntennaField(const string &name, const CoordinateSystem &coordinates); + + virtual ~AntennaField(); + + /** Return the name of the antenna field. */ + const string &name() const; + + /** Return the phase reference position of the antenna field. */ + const vector3r_t &position() const; + + /** Return the antenna field coordinate system. */ + const CoordinateSystem &coordinates() const; + + /** Add an antenna to the antenna field. */ + void addAntenna(const Antenna &antenna); + + /** Return the number of antennae in the antenna field. */ + size_t nAntennae() const; + + /*! + * \name Antennae accessors + * These member functions provide access to the antennae that are part of + * the antenna field. + */ + // @{ + + /** Return a read-only reference to the antenna with the requested index. */ + const Antenna &antenna(size_t n) const; + + /** Return a writeable reference to the antenna with the requested index. */ + Antenna &antenna(size_t n); + + /** Return a read-only iterator that points to the first antenna of the + * antenna field. + */ + AntennaList::const_iterator beginAntennae() const; + + /** Return a read-only iterator that points one position past the last + * antenna of the antenna field. + */ + AntennaList::const_iterator endAntennae() const; + + // @} + + /*! + * \brief Compute the response of the antenna field for a plane wave of + * frequency \p freq, arriving from direction \p direction, with the analog + * %tile beam former steered towards \p direction0. For LBA antenna fields, + * \p direction0 has no effect. + * + * \param time Time, modified Julian date, UTC, in seconds (MJD(UTC), s). + * \param freq Frequency of the plane wave (Hz). + * \param direction Direction of arrival (ITRF, m). + * \param direction0 Tile beam former reference direction (ITRF, m). + * \return Jones matrix that represents the response of the antenna field. + * + * The directions \p direction, and \p direction0 are vectors that + * represent a direction of \e arrival. These vectors have unit length and + * point \e from the ground \e towards the direction from which the plane + * wave arrives. + */ + virtual matrix22c_t response(real_t time, real_t freq, + const vector3r_t &direction, const vector3r_t &direction0) const; + + /*! + * \brief Compute the array factor of the antenna field for a plane wave of + * frequency \p freq, arriving from direction \p direction, analog %tile + * beam former steered towards \p direction0. For LBA antenna fields, + * \p direction0 has no effect. + * + * \param time Time, modified Julian date, UTC, in seconds (MJD(UTC), s). + * \param freq Frequency of the plane wave (Hz). + * \param direction Direction of arrival (ITRF, m). + * \param direction0 Tile beam former reference direction (ITRF, m). + * \return A diagonal matrix with the array factor of the X and Y antennae. + * + * The directions \p direction, and \p direction0 are vectors that + * represent a direction of \e arrival. These vectors have unit length and + * point \e from the ground \e towards the direction from which the plane + * wave arrives. + */ + virtual diag22c_t arrayFactor(real_t time, real_t freq, + const vector3r_t &direction, const vector3r_t &direction0) const; + + /*! + * \brief Compute the response of the antenna field for a plane wave of + * frequency \p freq, arriving from direction \p direction, with the analog + * %tile beam former steered towards \p direction0. For LBA antenna fields, + * \p direction0 has no effect. + * + * This method returns the non-normalized (raw) response. This allows the + * response of several antenna fields to be summed together, followed by + * normalization of the sum. + * + * \see response(real_t time, real_t freq, const vector3r_t &direction, + * const vector3r_t &direction0) const + */ + virtual raw_response_t rawResponse(real_t time, real_t freq, + const vector3r_t &direction, const vector3r_t &direction0) const; + + /*! + * \brief Compute the array factor of the antenna field for a plane wave of + * frequency \p freq, arriving from direction \p direction, analog %tile + * beam former steered towards \p direction0. For LBA antenna fields, + * \p direction0 has no effect. + * + * This method returns the non-normalized (raw) array factor. This allows + * the array factor of several antenna fields to be summed together, + * followed by normalization of the sum. + * + * \see diag22c_t arrayFactor(real_t time, real_t freq, + * const vector3r_t &direction, const vector3r_t &direction0) const + */ + virtual raw_array_factor_t rawArrayFactor(real_t time, real_t freq, + const vector3r_t &direction, const vector3r_t &direction0) const = 0; + + /*! + * \brief Compute the response of a single antenna for a plane wave of + * frequency \p freq, arriving from direction \p direction. + * + */ + virtual matrix22c_t elementResponse(real_t time, real_t freq, + const vector3r_t &direction) const = 0; + +protected: + /** Compute the parallactic rotation. */ + matrix22r_t rotation(real_t time, const vector3r_t &direction) const; + + /** Transform a vector from ITRF to antenna field coordinates. */ + vector3r_t itrf2field(const vector3r_t &itrf) const; + +private: + vector3r_t ncp(real_t time) const; + + string itsName; + CoordinateSystem itsCoordinateSystem; + AntennaList itsAntennae; + ITRFDirection::Ptr itsNCP; + mutable real_t itsNCPCacheTime; + mutable vector3r_t itsNCPCacheDirection; +}; + +// @} + +} //# namespace StationResponse +} //# namespace LOFAR + +#endif diff --git a/StationResponse/include/StationResponse/AntennaFieldHBA.h b/StationResponse/include/StationResponse/AntennaFieldHBA.h new file mode 100644 index 0000000000000000000000000000000000000000..6caafee496441b05685dafa17c97a54e51bdd7a4 --- /dev/null +++ b/StationResponse/include/StationResponse/AntennaFieldHBA.h @@ -0,0 +1,73 @@ +//# AntennaFieldHBA.h: Representation of an HBA antenna field. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#ifndef LOFAR_STATIONRESPONSE_ANTENNAFIELDHBA_H +#define LOFAR_STATIONRESPONSE_ANTENNAFIELDHBA_H + +// \file +// Representation of an HBA antenna field. + +#include <StationResponse/AntennaField.h> +#include <StationResponse/AntennaModelHBA.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +// \addtogroup StationResponse +// @{ + +class AntennaFieldHBA: public AntennaField +{ +public: + typedef shared_ptr<AntennaFieldHBA> Ptr; + typedef shared_ptr<const AntennaFieldHBA> ConstPtr; + + AntennaFieldHBA(const string &name, const CoordinateSystem &coordinates, + const AntennaModelHBA::ConstPtr &model); + + virtual matrix22c_t response(real_t time, real_t freq, + const vector3r_t &direction, const vector3r_t &direction0) const; + + virtual diag22c_t arrayFactor(real_t time, real_t freq, + const vector3r_t &direction, const vector3r_t &direction0) const; + + virtual raw_response_t rawResponse(real_t time, real_t freq, + const vector3r_t &direction, const vector3r_t &direction0) const; + + virtual raw_array_factor_t rawArrayFactor(real_t time, real_t freq, + const vector3r_t &direction, const vector3r_t &direction0) const; + + virtual matrix22c_t elementResponse(real_t time, real_t freq, + const vector3r_t &direction) const; + +private: + AntennaModelHBA::ConstPtr itsAntennaModel; +}; + +// @} + +} //# namespace StationResponse +} //# namespace LOFAR + +#endif diff --git a/StationResponse/include/StationResponse/AntennaFieldLBA.h b/StationResponse/include/StationResponse/AntennaFieldLBA.h new file mode 100644 index 0000000000000000000000000000000000000000..f4c082542910e7bf94109bed6ab3ff3c828d8c94 --- /dev/null +++ b/StationResponse/include/StationResponse/AntennaFieldLBA.h @@ -0,0 +1,64 @@ +//# AntennaFieldLBA.h: Representation of an LBA antenna field. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#ifndef LOFAR_STATIONRESPONSE_ANTENNAFIELDLBA_H +#define LOFAR_STATIONRESPONSE_ANTENNAFIELDLBA_H + +// \file +// Representation of an LBA antenna field. + +#include <StationResponse/AntennaField.h> +#include <StationResponse/AntennaModelLBA.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +// \addtogroup StationResponse +// @{ + +class AntennaFieldLBA: public AntennaField +{ +public: + typedef shared_ptr<AntennaFieldLBA> Ptr; + typedef shared_ptr<const AntennaFieldLBA> ConstPtr; + + AntennaFieldLBA(const string &name, const CoordinateSystem &coordinates, + const AntennaModelLBA::ConstPtr &model); + + virtual raw_array_factor_t rawArrayFactor(real_t time, real_t freq, + const vector3r_t &direction, const vector3r_t &direction0) const; + + virtual matrix22c_t elementResponse(real_t time, real_t freq, + const vector3r_t &direction) const; + +private: + AntennaModelLBA::ConstPtr itsAntennaModel; +}; + +// @} + +} //# namespace StationResponse +} //# namespace LOFAR + +#endif diff --git a/StationResponse/include/StationResponse/AntennaModelHBA.h b/StationResponse/include/StationResponse/AntennaModelHBA.h new file mode 100644 index 0000000000000000000000000000000000000000..9ef452c0d5be39b56da9b69004a737018dfdca8d --- /dev/null +++ b/StationResponse/include/StationResponse/AntennaModelHBA.h @@ -0,0 +1,69 @@ +//# AntennaModelHBA.h: HBA antenna model interface definitions. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#ifndef LOFAR_STATIONRESPONSE_ANTENNAMODELHBA_H +#define LOFAR_STATIONRESPONSE_ANTENNAMODELHBA_H + +// \file +// HBA antenna model interface definitions. + +#include <StationResponse/Types.h> +#include <Common/lofar_smartptr.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +// \addtogroup StationResponse +// @{ + +class AntennaModelHBA +{ +public: + typedef shared_ptr<AntennaModelHBA> Ptr; + typedef shared_ptr<const AntennaModelHBA> ConstPtr; + + virtual ~AntennaModelHBA(); + + virtual matrix22c_t response(real_t freq, const vector3r_t &direction, + const vector3r_t &direction0) const; + + virtual diag22c_t arrayFactor(real_t freq, const vector3r_t &direction, + const vector3r_t &direction0) const; + + virtual raw_response_t rawResponse(real_t freq, const vector3r_t &direction, + const vector3r_t &direction0) const; + + virtual raw_array_factor_t rawArrayFactor(real_t freq, + const vector3r_t &direction, const vector3r_t &direction0) const = 0; + + virtual matrix22c_t elementResponse(real_t freq, + const vector3r_t &direction) const = 0; +}; + +// @} + +} //# namespace StationResponse +} //# namespace LOFAR + +#endif diff --git a/StationResponse/include/StationResponse/AntennaModelLBA.h b/StationResponse/include/StationResponse/AntennaModelLBA.h new file mode 100644 index 0000000000000000000000000000000000000000..7b6bfa543c633284dd52813866bbe6fa9c2ac9d4 --- /dev/null +++ b/StationResponse/include/StationResponse/AntennaModelLBA.h @@ -0,0 +1,57 @@ +//# AntennaModelLBA.h: LBA antenna model interface definitions. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#ifndef LOFAR_STATIONRESPONSE_ANTENNAMODELLBA_H +#define LOFAR_STATIONRESPONSE_ANTENNAMODELLBA_H + +// \file +// LBA antenna model interface definitions. + +#include <StationResponse/Types.h> +#include <Common/lofar_smartptr.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +// \addtogroup StationResponse +// @{ + +class AntennaModelLBA +{ +public: + typedef shared_ptr<AntennaModelLBA> Ptr; + typedef shared_ptr<const AntennaModelLBA> ConstPtr; + + virtual ~AntennaModelLBA(); + + virtual matrix22c_t response(real_t freq, const vector3r_t &direction) + const = 0; +}; + +// @} + +} //# namespace StationResponse +} //# namespace LOFAR + +#endif diff --git a/StationResponse/include/StationResponse/CMakeLists.txt b/StationResponse/include/StationResponse/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..b4dc8dff3c3c708ec21a53a78bc8c087148742f7 --- /dev/null +++ b/StationResponse/include/StationResponse/CMakeLists.txt @@ -0,0 +1,23 @@ +# $Id$ + +# Create symbolic link to include directory. +execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_BINARY_DIR}/include/${PACKAGE_NAME}) + +# Install header files. +install(FILES + AntennaField.h + AntennaFieldHBA.h + AntennaFieldLBA.h + AntennaModelHBA.h + AntennaModelLBA.h + Constants.h + DualDipoleAntenna.h + ITRFDirection.h + LofarMetaDataUtil.h + MathUtil.h + Station.h + TileAntenna.h + Types.h + DESTINATION include/${PACKAGE_NAME}) diff --git a/StationResponse/include/StationResponse/Constants.h b/StationResponse/include/StationResponse/Constants.h new file mode 100644 index 0000000000000000000000000000000000000000..c77be6d22cdbe63369c4f9cc3a6c9d45745d62a4 --- /dev/null +++ b/StationResponse/include/StationResponse/Constants.h @@ -0,0 +1,60 @@ +//# Constants.h: %Constants used in this library. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#ifndef LOFAR_STATIONRESPONSE_CONSTANTS_H +#define LOFAR_STATIONRESPONSE_CONSTANTS_H + +// \file +// %Constants used in this library. + +#include <StationResponse/Types.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +// \addtogroup StationResponse +// @{ + +/** %Constants used in this library. */ +namespace Constants +{ +/** 2.0 * pi */ +const real_t _2pi = 6.283185307179586476925286; + +/** pi / 2.0 */ +const real_t pi_2 = 1.570796326794896619231322; + +/** pi / 4.0 */ +const real_t pi_4 = 0.7853981633974483096156608; + +/** Speed of light (m/s) */ +const real_t c = 2.99792458e+08; +} //# namespace Constants + +// @} + +} //# namespace StationResponse +} //# namespace LOFAR + +#endif diff --git a/StationResponse/include/StationResponse/DualDipoleAntenna.h b/StationResponse/include/StationResponse/DualDipoleAntenna.h new file mode 100644 index 0000000000000000000000000000000000000000..4ac6439fc6e7572464a4f29cb72362b2d3d5df96 --- /dev/null +++ b/StationResponse/include/StationResponse/DualDipoleAntenna.h @@ -0,0 +1,55 @@ +//# DualDipoleAntenna.h: Semi-analytical model of a LOFAR LBA dual dipole +//# antenna. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#ifndef LOFAR_STATIONRESPONSE_DUALDIPOLEANTENNA_H +#define LOFAR_STATIONRESPONSE_DUALDIPOLEANTENNA_H + +// \file +// Semi-analytical model of a LOFAR LBA dual dipole antenna. + +#include <StationResponse/AntennaModelLBA.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +// \addtogroup StationResponse +// @{ + +class DualDipoleAntenna: public AntennaModelLBA +{ +public: + typedef shared_ptr<DualDipoleAntenna> Ptr; + typedef shared_ptr<const DualDipoleAntenna> ConstPtr; + + virtual matrix22c_t response(real_t freq, const vector3r_t &direction) + const; +}; + +// @} + +} //# namespace StationResponse +} //# namespace LOFAR + +#endif diff --git a/StationResponse/include/StationResponse/ITRFDirection.h b/StationResponse/include/StationResponse/ITRFDirection.h new file mode 100644 index 0000000000000000000000000000000000000000..280a6111a99443ddbe180c8eb45bdd5a72906d45 --- /dev/null +++ b/StationResponse/include/StationResponse/ITRFDirection.h @@ -0,0 +1,65 @@ +//# ITRFDirection.h: Functor that maps time to an ITRF direction. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#ifndef LOFAR_STATIONRESPONSE_ITRFDIRECTION_H +#define LOFAR_STATIONRESPONSE_ITRFDIRECTION_H + +// \file +// Functor that maps time to an ITRF direction. + +#include <StationResponse/Types.h> +#include <Common/lofar_smartptr.h> + +#include <casacore/measures/Measures/MeasFrame.h> +#include <casacore/measures/Measures/MeasConvert.h> +#include <casacore/measures/Measures/MCDirection.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +// \addtogroup StationResponse +// @{ + +class ITRFDirection +{ +public: + typedef shared_ptr<ITRFDirection> Ptr; + typedef shared_ptr<const ITRFDirection> ConstPtr; + + ITRFDirection(const vector3r_t &position, const vector2r_t &direction); + ITRFDirection(const vector3r_t &position, const vector3r_t &direction); + + vector3r_t at(real_t time) const; + +private: + mutable casacore::MeasFrame itsFrame; + mutable casacore::MDirection::Convert itsConverter; +}; + +// @} + +} //# namespace BBS +} //# namespace LOFAR + +#endif diff --git a/StationResponse/include/StationResponse/LofarMetaDataUtil.h b/StationResponse/include/StationResponse/LofarMetaDataUtil.h new file mode 100644 index 0000000000000000000000000000000000000000..57327b0ed0eb3c0bfbdd7857ef71b4335822a401 --- /dev/null +++ b/StationResponse/include/StationResponse/LofarMetaDataUtil.h @@ -0,0 +1,65 @@ +//# LofarMetaDataUtil.h: Utility functions to read the meta data relevant for +//# simulating the beam from LOFAR observations stored in MS format. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#ifndef LOFAR_STATIONRESPONSE_LOFARMETADATAUTIL_H +#define LOFAR_STATIONRESPONSE_LOFARMETADATAUTIL_H + +// \file +// Utility functions to read the meta data relevant for simulating the beam from +// LOFAR observations stored in MS format. + +#include <StationResponse/Station.h> +#include <casacore/ms/MeasurementSets/MeasurementSet.h> +#include <casacore/ms/MeasurementSets/MSAntennaColumns.h> +#include <casacore/measures/Measures/MDirection.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +// \addtogroup StationResponse +// @{ + +Station::Ptr readStation(const casacore::MeasurementSet &ms, unsigned int id); + +template <typename T> +void readStations(const casacore::MeasurementSet &ms, T out_it) +{ + casacore::ROMSAntennaColumns antenna(ms.antenna()); + for(unsigned int i = 0; i < antenna.nrow(); ++i) + { + *out_it++ = readStation(ms, i); + } +} + +// Read the tile beam direction from a LOFAR MS. If it is not defined, +// this function returns the delay center. +casacore::MDirection readTileBeamDirection(const casacore::MeasurementSet &ms); + +// @} + +} //# namespace StationResponse +} //# namespace LOFAR + +#endif diff --git a/StationResponse/include/StationResponse/MathUtil.h b/StationResponse/include/StationResponse/MathUtil.h new file mode 100644 index 0000000000000000000000000000000000000000..cb16fb898c2e0f9e229b7253823d53525fcb502a --- /dev/null +++ b/StationResponse/include/StationResponse/MathUtil.h @@ -0,0 +1,172 @@ +//# MathUtil.h: Various mathematical operations on vectors and matrices. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#ifndef LOFAR_STATIONRESPONSE_MATHUTIL_H +#define LOFAR_STATIONRESPONSE_MATHUTIL_H + +// \file +// Various mathematical operations on vectors and matrices. + +#include <StationResponse/Constants.h> +#include <StationResponse/Types.h> +#include <Common/lofar_math.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +// \addtogroup StationResponse +// @{ + +inline real_t dot(const vector3r_t &arg0, const vector3r_t &arg1) +{ + return arg0[0] * arg1[0] + arg0[1] * arg1[1] + arg0[2] * arg1[2]; +} + +inline double norm(const vector3r_t &arg0) +{ + return sqrt(dot(arg0, arg0)); +} + +inline vector3r_t operator*(real_t arg0, const vector3r_t arg1) +{ + vector3r_t result = {{arg0 * arg1[0], arg0 * arg1[1], arg0 * arg1[2]}}; + return result; +} + +inline vector3r_t normalize(const vector3r_t &arg0) +{ + return 1.0 / norm(arg0) * arg0; +} + +inline vector2r_t cart2thetaphi(const vector3r_t &cart) +{ + real_t r = sqrt(cart[0] * cart[0] + cart[1] * cart[1]); + vector2r_t thetaphi = {{Constants::pi_2 - atan2(cart[2], r), atan2(cart[1], + cart[0])}}; + return thetaphi; +} + +inline vector3r_t thetaphi2cart(const vector2r_t &thetaphi) +{ + real_t r = sin(thetaphi[0]); + vector3r_t cart = {{r * cos(thetaphi[1]), r * sin(thetaphi[1]), + cos(thetaphi[0])}}; + return cart; +} + +// returns az, el, r. +inline vector3r_t cart2sph(const vector3r_t &cart) +{ + real_t r = sqrt(cart[0] * cart[0] + cart[1] * cart[1]); + + vector3r_t sph; + sph[0] = atan2(cart[1], cart[0]); + sph[1] = atan2(cart[2], r); + sph[2] = norm(cart); + return sph; +} + +// expects az, el, r. +inline vector3r_t sph2cart(const vector3r_t &sph) +{ + vector3r_t cart = {{sph[2] * cos(sph[1]) * cos(sph[0]), sph[2] * cos(sph[1]) + * sin(sph[0]), sph[2] * sin(sph[1])}}; + return cart; +} + +inline matrix22c_t operator*(const matrix22c_t &arg0, const matrix22r_t &arg1) +{ + matrix22c_t result; + result[0][0] = arg0[0][0] * arg1[0][0] + arg0[0][1] * arg1[1][0]; + result[0][1] = arg0[0][0] * arg1[0][1] + arg0[0][1] * arg1[1][1]; + result[1][0] = arg0[1][0] * arg1[0][0] + arg0[1][1] * arg1[1][0]; + result[1][1] = arg0[1][0] * arg1[0][1] + arg0[1][1] * arg1[1][1]; + return result; +} + +inline vector3r_t cross(const vector3r_t &arg0, const vector3r_t &arg1) +{ + vector3r_t result; + result[0] = arg0[1] * arg1[2] - arg0[2] * arg1[1]; + result[1] = arg0[2] * arg1[0] - arg0[0] * arg1[2]; + result[2] = arg0[0] * arg1[1] - arg0[1] * arg1[0]; + return result; +} + +inline vector3r_t operator+(const vector3r_t &arg0, const vector3r_t &arg1) +{ + vector3r_t result = {{arg0[0] + arg1[0], arg0[1] + arg1[1], + arg0[2] + arg1[2]}}; + return result; +} + +inline vector3r_t operator-(const vector3r_t &arg0, const vector3r_t &arg1) +{ + vector3r_t result = {{arg0[0] - arg1[0], arg0[1] - arg1[1], + arg0[2] - arg1[2]}}; + return result; +} + +inline matrix22c_t normalize(const raw_response_t &raw) +{ + matrix22c_t response = {{ {{}}, {{}} }}; + + if(raw.weight[0] != 0.0) + { + response[0][0] = raw.response[0][0] / raw.weight[0]; + response[0][1] = raw.response[0][1] / raw.weight[0]; + } + + if(raw.weight[1] != 0.0) + { + response[1][0] = raw.response[1][0] / raw.weight[1]; + response[1][1] = raw.response[1][1] / raw.weight[1]; + } + + return response; +} + +inline diag22c_t normalize(const raw_array_factor_t &raw) +{ + diag22c_t af = {{}}; + + if(raw.weight[0] != 0.0) + { + af[0] = raw.factor[0] / raw.weight[0]; + } + + if(raw.weight[1] != 0.0) + { + af[1] = raw.factor[1] / raw.weight[1]; + } + + return af; +} + +// @} + +} //# namespace StationResponse +} //# namespace LOFAR + +#endif diff --git a/StationResponse/include/StationResponse/Station.h b/StationResponse/include/StationResponse/Station.h new file mode 100644 index 0000000000000000000000000000000000000000..0019c33dcdf0c9577e4b0e9ec9184096812ab710 --- /dev/null +++ b/StationResponse/include/StationResponse/Station.h @@ -0,0 +1,361 @@ +//# Station.h: Representation of the station beam former. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#ifndef LOFAR_STATIONRESPONSE_STATION_H +#define LOFAR_STATIONRESPONSE_STATION_H + +// \file +// Representation of the station beam former. + +#include <Common/lofar_smartptr.h> +#include <Common/lofar_string.h> +#include <Common/lofar_vector.h> +#include <StationResponse/AntennaField.h> +#include <StationResponse/Types.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +// \addtogroup StationResponse +// @{ + +class Station +{ +public: + typedef shared_ptr<Station> Ptr; + typedef shared_ptr<const Station> ConstPtr; + typedef vector<AntennaField::ConstPtr> FieldList; + + /*! + * \brief Construct a new Station instance. + * + * \param name Name of the station. + * \param position Position of the station (ITRF, m). + */ + Station(const string &name, const vector3r_t &position); + + /*! + * \brief Return the name of the station. + */ + const string &name() const; + + /*! + * \brief Return the position of the station (ITRF, m). + */ + const vector3r_t &position() const; + + /*! + * \brief Set the phase reference position. This is the position where the + * delay of the incoming plane wave is assumed to be zero. + * + * \param reference Phase reference position (ITRF, m). + * + * By default, it is assumed the position of the station is also the phase + * reference position. Use this method to set the phase reference position + * explicitly when this assumption is false. + */ + void setPhaseReference(const vector3r_t &reference); + + /*! + * \brief Return the phase reference position (ITRF, m). + * + * \see Station::setPhaseReference() + */ + const vector3r_t &phaseReference() const; + + /*! + * \brief Add an antenna field to the station. + * + * Physical %LOFAR stations consist of an LBA field, and either one (remote + * and international stations) or two (core stations) HBA fields. Virtual + * %LOFAR stations can consist of a combination of the antenna fields of + * several physical stations. + * + * Use this method to add the appropriate antenna fields to the station. + */ + void addField(const AntennaField::ConstPtr &field); + + + /*! + * \brief Return the number of available antenna fields. + */ + size_t nFields() const; + + /*! + * \brief Return the requested antenna field. + * + * \param i Antenna field number (0-based). + * \return An AntennaField::ConstPtr to the requested AntennaField + * instance, or an empty AntennaField::ConstPtr if \p i is out of bounds. + */ + AntennaField::ConstPtr field(size_t i) const; + + /*! + * \brief Return an iterator that points to the beginning of the list of + * antenna fields. + */ + FieldList::const_iterator beginFields() const; + + /*! + * \brief Return an iterator that points to the end of the list of antenna + * fields. + */ + FieldList::const_iterator endFields() const; + + /*! + * \brief Compute the response of the station for a plane wave of frequency + * \p freq, arriving from direction \p direction, with the %station beam + * former steered towards \p station0, and, for HBA stations, the analog + * %tile beam former steered towards \p tile0. For LBA stations, \p tile0 + * has no effect. + * + * \param time Time, modified Julian date, UTC, in seconds (MJD(UTC), s). + * \param freq Frequency of the plane wave (Hz). + * \param direction Direction of arrival (ITRF, m). + * \param freq0 %Station beam former reference frequency (Hz). + * \param station0 %Station beam former reference direction (ITRF, m). + * \param tile0 Tile beam former reference direction (ITRF, m). + * \return Jones matrix that represents the %station response. + * + * For any given sub-band, the %LOFAR station beam former computes weights + * for a single reference frequency. Usually, this reference frequency is + * the center frequency of the sub-band. For any frequency except the + * reference frequency, these weights are an approximation. This aspect of + * the system is taken into account in the computation of the response. + * Therefore, both the frequency of interest \p freq and the reference + * frequency \p freq0 need to be specified. + * + * The directions \p direction, \p station0, and \p tile0 are vectors that + * represent a direction of \e arrival. These vectors have unit length and + * point \e from the ground \e towards the direction from which the plane + * wave arrives. + */ + matrix22c_t response(real_t time, real_t freq, const vector3r_t &direction, + real_t freq0, const vector3r_t &station0, const vector3r_t &tile0) + const; + + /*! + * \brief Compute the array factor of the station for a plane wave of + * frequency \p freq, arriving from direction \p direction, with the + * %station beam former steered towards \p station0, and, for HBA stations + * the analog %tile beam former steered towards \p tile0. For LBA stations, + * \p tile0 has no effect. + * + * \param time Time, modified Julian date, UTC, in seconds (MJD(UTC), s). + * \param freq Frequency of the plane wave (Hz). + * \param direction Direction of arrival (ITRF, m). + * \param freq0 %Station beam former reference frequency (Hz). + * \param station0 %Station beam former reference direction (ITRF, m). + * \param tile0 Tile beam former reference direction (ITRF, m). + * \return A diagonal matrix with the array factor of the X and Y antennae. + * + * For any given sub-band, the %LOFAR station beam former computes weights + * for a single reference frequency. Usually, this reference frequency is + * the center frequency of the sub-band. For any frequency except the + * reference frequency, these weights are an approximation. This aspect of + * the system is taken into account in the computation of the response. + * Therefore, both the frequency of interest \p freq and the reference + * frequency \p freq0 need to be specified. + * + * The directions \p direction, \p station0, and \p tile0 are vectors that + * represent a direction of \e arrival. These vectors have unit length and + * point \e from the ground \e towards the direction from which the plane + * wave arrives. + */ + diag22c_t arrayFactor(real_t time, real_t freq, const vector3r_t &direction, + real_t freq0, const vector3r_t &station0, const vector3r_t &tile0) + const; + + /*! + * \name Convenience member functions + * These member functions perform the same function as the corresponding + * non-template member functions, for a list of frequencies or (frequency, + * reference frequency) pairs. + */ + // @{ + + /*! + * \brief Convenience method to compute the response of the station for a + * list of frequencies, and a fixed reference frequency. + * + * \param count Number of frequencies. + * \param time Time, modified Julian date, UTC, in seconds (MJD(UTC), s). + * \param freq Input iterator for a list of frequencies (Hz) of length + * \p count. + * \param direction Direction of arrival (ITRF, m). + * \param freq0 %Station beam former reference frequency (Hz). + * \param station0 %Station beam former reference direction (ITRF, m). + * \param tile0 Tile beam former reference direction (ITRF, m). + * \param buffer Output iterator with room for \p count instances of type + * ::matrix22c_t. + * + * \see response(real_t time, real_t freq, const vector3r_t &direction, + * real_t freq0, const vector3r_t &station0, const vector3r_t &tile0) const + */ + template <typename T, typename U> + void response(unsigned int count, real_t time, T freq, + const vector3r_t &direction, real_t freq0, const vector3r_t &station0, + const vector3r_t &tile0, U buffer) const; + + /*! + * \brief Convenience method to compute the array factor of the station for + * a list of frequencies, and a fixed reference frequency. + * + * \param count Number of frequencies. + * \param time Time, modified Julian date, UTC, in seconds (MJD(UTC), s). + * \param freq Input iterator for a list of frequencies (Hz) of length + * \p count. + * \param direction Direction of arrival (ITRF, m). + * \param freq0 %Station beam former reference frequency (Hz). + * \param station0 %Station beam former reference direction (ITRF, m). + * \param tile0 Tile beam former reference direction (ITRF, m). + * \param buffer Output iterator with room for \p count instances of type + * ::diag22c_t. + * + * \see arrayFactor(real_t time, real_t freq, const vector3r_t &direction, + * real_t freq0, const vector3r_t &station0, const vector3r_t &tile0) const + */ + template <typename T, typename U> + void arrayFactor(unsigned int count, real_t time, T freq, + const vector3r_t &direction, real_t freq0, const vector3r_t &station0, + const vector3r_t &tile0, U buffer) const; + + /*! + * \brief Convenience method to compute the response of the station for a + * list of (frequency, reference frequency) pairs. + * + * \param count Number of frequencies. + * \param time Time, modified Julian date, UTC, in seconds (MJD(UTC), s). + * \param freq Input iterator for a list of frequencies (Hz) of length + * \p count. + * \param direction Direction of arrival (ITRF, m). + * \param freq0 Input iterator for a list of %Station beam former reference + * frequencies (Hz) of length \p count. + * \param station0 %Station beam former reference direction (ITRF, m). + * \param tile0 Tile beam former reference direction (ITRF, m). + * \param buffer Output iterator with room for \p count instances of type + * ::matrix22c_t. + * + * \see response(real_t time, real_t freq, const vector3r_t &direction, + * real_t freq0, const vector3r_t &station0, const vector3r_t &tile0) const + */ + template <typename T, typename U> + void response(unsigned int count, real_t time, T freq, + const vector3r_t &direction, T freq0, const vector3r_t &station0, + const vector3r_t &tile0, U buffer) const; + + /*! + * \brief Convenience method to compute the array factor of the station for + * list of (frequency, reference frequency) pairs. + * + * \param count Number of frequencies. + * \param time Time, modified Julian date, UTC, in seconds (MJD(UTC), s). + * \param freq Input iterator for a list of frequencies (Hz) of length + * \p count. + * \param direction Direction of arrival (ITRF, m). + * \param freq0 %Station beam former reference frequency (Hz). + * \param station0 %Station beam former reference direction (ITRF, m). + * \param tile0 Tile beam former reference direction (ITRF, m). + * \param buffer Output iterator with room for \p count instances of type + * ::diag22c_t. + * + * \see arrayFactor(real_t time, real_t freq, const vector3r_t &direction, + * real_t freq0, const vector3r_t &station0, const vector3r_t &tile0) const + */ + template <typename T, typename U> + void arrayFactor(unsigned int count, real_t time, T freq, + const vector3r_t &direction, T freq0, const vector3r_t &station0, + const vector3r_t &tile0, U buffer) const; + + // @} + +private: + raw_array_factor_t fieldArrayFactor(const AntennaField::ConstPtr &field, + real_t time, real_t freq, const vector3r_t &direction, real_t freq0, + const vector3r_t &position0, const vector3r_t &direction0) const; + +private: + string itsName; + vector3r_t itsPosition; + vector3r_t itsPhaseReference; + FieldList itsFields; +}; + +// @} + +//# ------------------------------------------------------------------------- // +//# - Implementation: Station - // +//# ------------------------------------------------------------------------- // + +template <typename T, typename U> +void Station::response(unsigned int count, real_t time, T freq, + const vector3r_t &direction, real_t freq0, const vector3r_t &station0, + const vector3r_t &tile0, U buffer) const +{ + for(unsigned int i = 0; i < count; ++i) + { + *buffer++ = response(time, *freq++, direction, freq0, station0, tile0); + } +} + +template <typename T, typename U> +void Station::arrayFactor(unsigned int count, real_t time, T freq, + const vector3r_t &direction, real_t freq0, const vector3r_t &station0, + const vector3r_t &tile0, U buffer) const +{ + for(unsigned int i = 0; i < count; ++i) + { + *buffer++ = arrayFactor(time, *freq++, direction, freq0, station0, + tile0); + } +} + +template <typename T, typename U> +void Station::response(unsigned int count, real_t time, T freq, + const vector3r_t &direction, T freq0, const vector3r_t &station0, + const vector3r_t &tile0, U buffer) const +{ + for(unsigned int i = 0; i < count; ++i) + { + *buffer++ = response(time, *freq++, direction, *freq0++, station0, + tile0); + } +} + +template <typename T, typename U> +void Station::arrayFactor(unsigned int count, real_t time, T freq, + const vector3r_t &direction, T freq0, const vector3r_t &station0, + const vector3r_t &tile0, U buffer) const +{ + for(unsigned int i = 0; i < count; ++i) + { + *buffer++ = arrayFactor(time, *freq++, direction, *freq0++, station0, + tile0); + } +} + +} //# namespace StationResponse +} //# namespace LOFAR + +#endif diff --git a/StationResponse/include/StationResponse/TileAntenna.h b/StationResponse/include/StationResponse/TileAntenna.h new file mode 100644 index 0000000000000000000000000000000000000000..3695aa3e81657a3bcdbe5bfb91726287d5cf9040 --- /dev/null +++ b/StationResponse/include/StationResponse/TileAntenna.h @@ -0,0 +1,68 @@ +//# TileAntenna.h: Semi-analytical model of a LOFAR HBA tile. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#ifndef LOFAR_STATIONRESPONSE_TILEANTENNA_H +#define LOFAR_STATIONRESPONSE_TILEANTENNA_H + +// \file +// Semi-analytical model of a LOFAR HBA tile. + +#include <StationResponse/AntennaModelHBA.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +// \addtogroup StationResponse +// @{ + +class TileAntenna: public AntennaModelHBA +{ +public: + typedef shared_ptr<TileAntenna> Ptr; + typedef shared_ptr<const TileAntenna> ConstPtr; + + typedef static_array<vector3r_t, 16> TileConfig; + + explicit TileAntenna(const TileConfig &config); + + void setConfig(const TileConfig &config); + + const TileConfig &config() const; + + virtual raw_array_factor_t rawArrayFactor(real_t freq, + const vector3r_t &direction, const vector3r_t &direction0) const; + + virtual matrix22c_t elementResponse(real_t freq, + const vector3r_t &direction) const; + +private: + TileConfig itsConfig; +}; + +// @} + +} //# namespace StationResponse +} //# namespace LOFAR + +#endif diff --git a/StationResponse/include/StationResponse/Types.h b/StationResponse/include/StationResponse/Types.h new file mode 100644 index 0000000000000000000000000000000000000000..8565e127528dc692ae7750e4b9c4ee09c7cad037 --- /dev/null +++ b/StationResponse/include/StationResponse/Types.h @@ -0,0 +1,234 @@ +//# Types.h: Types used in this library. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#ifndef LOFAR_STATIONRESPONSE_TYPES_H +#define LOFAR_STATIONRESPONSE_TYPES_H + +// \file +// Types used in this library. + +#include <Common/lofar_complex.h> +#include <Common/StreamUtil.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +// \addtogroup StationResponse +// @{ + +/** + * \brief Array of static size. + * + * This struct wraps a (unidimensional) C array. Like C arrays, it is possible + * to use initializers, for example: + * \code + * int foo[3] = {1, 2, 3}; + * static_array<int, 3> bar = {{1, 2, 3}}; + * \endcode + * Note the \e double curly braces. + * + * Unlike C arrays, it is possible to return instances of this struct. + * \code + * static_array<int, 3> foo() + * { + * static_array<int, 3> bar = {{1, 2, 3}}; + * return bar; + * } + * \endcode + * \see boost::array + */ +template <typename T, size_t N> +struct static_array +{ + typedef T *iterator; + typedef const T *const_iterator; + + T __data[N]; + + /** Returns the size of the array. */ + static size_t size(); + + /** + * \brief Read-only access to a specific array element. + * \param n Index (0-based) of the element to access. + * \return A constant reference to the element at index \p n. + * + * This operator provides array-style element access. No range check is + * performed on the index \p n. The result of this operator is undefined + * for out of range indices. + */ + const T &operator[](size_t n) const; + + /** + * \brief Access to a specific array element. + * \param n Index (0-based) of the element to access. + * \return A non-constant reference to the element at index \p n. + * + * This operator provides array-style element access. No range check is + * performed on the index \p n. The result of this operator is undefined + * for out of range indices. + */ + T &operator[](size_t n); + + /** Returns an iterator that points to the first element in the array. */ + iterator begin(); + + /** Returns an iterator that points one past the last element in the + * array. + */ + iterator end(); + + /** Returns a read-only iterator that points to the first element in the + * array. + */ + const_iterator begin() const; + + /** Returns a read-only iterator that points one past the last element in + * the array. + */ + const_iterator end() const; +}; + +/** Print the contents of a static array. */ +template <typename T, size_t N> +ostream &operator<<(ostream &out, const static_array<T,N> &obj); + +/** Type used for real scalars. */ +typedef double real_t; + +/** Type used for complex scalars. */ +typedef dcomplex complex_t; + +/** Type used for 2-dimensional real vectors. */ +typedef static_array<real_t, 2> vector2r_t; + +/** Type used for 3-dimensional real vectors. */ +typedef static_array<real_t, 3> vector3r_t; + +/** Type used for 2x2 real diagonal matrices. */ +typedef static_array<real_t, 2> diag22r_t; + +/** Type used for 2x2 complex diagonal matrices. */ +typedef static_array<complex_t, 2> diag22c_t; + +/** Type used for 2x2 real matrices. */ +typedef static_array<static_array<real_t, 2>, 2> matrix22r_t; + +/** Type used for 2x2 complex matrices. */ +typedef static_array<static_array<complex_t, 2>, 2> matrix22c_t; + +/** Response of an array of antenna elements. */ +struct raw_response_t +{ + /** Combined response of all (enabled) antenna elements in the array. */ + matrix22c_t response; + + /** Number of antenna elements contributing to the combined response, per + * polarization. + */ + diag22r_t weight; +}; + +/** Array factor of an array of antenna elements. A wave front of an incident + * plane wave will arrive at each antenna element at a potentially different + * time. The time of arrival depends on the location of the antenna element and + * the direction of arrival of the plane wave. With respect to a pre-defined + * phase reference location, there is a (possibly negative) delay between the + * arrival of a wave front at a given antenna element and the arrival of the + * same wave front at the phase reference location. The array factor is the sum + * of the phase shifts due to these delays. It describes the "sensitivity" of + * the array as a function of direction. + */ +struct raw_array_factor_t +{ + /** Array factor due to all (enabled) antenna elements in the array. */ + diag22c_t factor; + + /** Number of antenna elements contributing to the array factor, per + * polarization. + */ + diag22r_t weight; +}; + +// @} + +//# ------------------------------------------------------------------------- // +//# - Implementation: static_array - // +//# ------------------------------------------------------------------------- // + +template <typename T, size_t N> +inline const T &static_array<T, N>::operator[](size_t n) const +{ + return __data[n]; +} + +template <typename T, size_t N> +inline T &static_array<T, N>::operator[](size_t n) +{ + return __data[n]; +} + +template <typename T, size_t N> +inline typename static_array<T, N>::iterator static_array<T, N>::begin() +{ + return __data; +} + +template <typename T, size_t N> +inline typename static_array<T, N>::iterator static_array<T, N>::end() +{ + return __data + N; +} + +template <typename T, size_t N> +inline typename static_array<T, N>::const_iterator static_array<T, N>::begin() + const +{ + return __data; +} + +template <typename T, size_t N> +inline typename static_array<T, N>::const_iterator static_array<T, N>::end() + const +{ + return __data + N; +} + +template <typename T, size_t N> +inline size_t static_array<T, N>::size() +{ + return N; +} + +template <typename T, size_t N> +ostream &operator<<(ostream &out, const static_array<T,N> &obj) +{ + print(out, obj.begin(), obj.end()); + return out; +} + +} //# namespace StationResponse +} //# namespace LOFAR + +#endif diff --git a/StationResponse/src/AntennaField.cc b/StationResponse/src/AntennaField.cc new file mode 100644 index 0000000000000000000000000000000000000000..d3ca5879353d523a70109c631d1046055f08b713 --- /dev/null +++ b/StationResponse/src/AntennaField.cc @@ -0,0 +1,233 @@ +//# AntennaField.cc: Representation of a LOFAR antenna field, with methods to +//# compute its response to incoming radiation. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#include <lofar_config.h> +#include <StationResponse/AntennaField.h> +#include <StationResponse/Constants.h> +#include <StationResponse/MathUtil.h> +#include <ElementResponse/ElementResponse.h> +#include <casacore/measures/Measures/MeasFrame.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +AntennaField::AntennaField(const string &name, + const CoordinateSystem &coordinates) + : itsName(name), + itsCoordinateSystem(coordinates), + itsNCPCacheTime(-1) +{ + vector3r_t ncp = {{0.0, 0.0, 1.0}}; + itsNCP.reset(new ITRFDirection(position(), ncp)); +} + +AntennaField::~AntennaField() +{ +} + +const string &AntennaField::name() const +{ + return itsName; +} + +const vector3r_t &AntennaField::position() const +{ + return itsCoordinateSystem.origin; +} + +const AntennaField::CoordinateSystem &AntennaField::coordinates() const +{ + return itsCoordinateSystem; +} + +void AntennaField::addAntenna(const Antenna &antenna) +{ + itsAntennae.push_back(antenna); +} + +size_t AntennaField::nAntennae() const +{ + return itsAntennae.size(); +} + +const AntennaField::Antenna &AntennaField::antenna(size_t n) const +{ + return itsAntennae[n]; +} + +AntennaField::Antenna &AntennaField::antenna(size_t n) +{ + return itsAntennae[n]; +} + +AntennaField::AntennaList::const_iterator AntennaField::beginAntennae() const +{ + return itsAntennae.begin(); +} + +AntennaField::AntennaList::const_iterator AntennaField::endAntennae() const +{ + return itsAntennae.end(); +} + +vector3r_t AntennaField::ncp(real_t time) const +{ + if(time != itsNCPCacheTime) + { + itsNCPCacheDirection = itsNCP->at(time); + itsNCPCacheTime = time; + } + + return itsNCPCacheDirection; +} + +vector3r_t AntennaField::itrf2field(const vector3r_t &itrf) const +{ + const CoordinateSystem::Axes &axes = itsCoordinateSystem.axes; + vector3r_t station = {{dot(axes.p, itrf), dot(axes.q, itrf), + dot(axes.r, itrf)}}; + return station; +} + +matrix22r_t AntennaField::rotation(real_t time, const vector3r_t &direction) + const +{ + // Compute the cross product of the NCP and the target direction. This + // yields a vector tangent to the celestial sphere at the target + // direction, pointing towards the East (the direction of +Y in the IAU + // definition, or positive right ascension). + // Test if the direction is equal to the NCP. If it is, take a random + // vector orthogonal to v1 (the east is not defined here). + vector3r_t v1; + if (abs(ncp(time)[0]-direction[0])<1e-9 && + abs(ncp(time)[1]-direction[1])<1e-9 && + abs(ncp(time)[2]-direction[2])<1e-9) { + // Make sure v1 is orthogonal to ncp(time). The first two components + // of v1 are arbitrary. + v1[0]=1.; + v1[1]=0.; + v1[2]=-(ncp(time)[0]*v1[0]+ncp(time)[1]*v1[1])/ncp(time)[2]; + v1=normalize(v1); + } else { + v1 = normalize(cross(ncp(time), direction)); + } + + // Compute the cross product of the antenna field normal (R) and the + // target direction. This yields a vector tangent to the topocentric + // spherical coordinate system at the target direction, pointing towards + // the direction of positive phi (which runs East over North around the + // pseudo zenith). + // Test if the normal is equal to the target direction. If it is, take + // a random vector orthogonal to the normal. + vector3r_t v2; + if (abs(itsCoordinateSystem.axes.r[0]-direction[0])<1e-9 && + abs(itsCoordinateSystem.axes.r[1]-direction[1])<1e-9 && + abs(itsCoordinateSystem.axes.r[2]-direction[2])<1e-9) { + // Make sure v2 is orthogonal to r. The first two components + // of v2 are arbitrary. + v2[0]=1.; + v2[1]=0.; + v2[2]=-(itsCoordinateSystem.axes.r[0]*v2[0]+ + itsCoordinateSystem.axes.r[1]*v2[1])/ + itsCoordinateSystem.axes.r[2]; + v2=normalize(v2); + } else { + v2 = normalize(cross(itsCoordinateSystem.axes.r, direction)); + } + + // Compute the cosine and sine of the parallactic angle, i.e. the angle + // between v1 and v2, both tangent to a latitude circle of their + // respective spherical coordinate systems. + real_t coschi = dot(v1, v2); + real_t sinchi = dot(cross(v1, v2), direction); + + // The input coordinate system is a right handed system with its third + // axis along the direction of propagation (IAU +Z). The output + // coordinate system is right handed as well, but its third axis points + // in the direction of arrival (i.e. exactly opposite). + // + // Because the electromagnetic field is always perpendicular to the + // direction of propagation, we only need to relate the (X, Y) axes of + // the input system to the corresponding (theta, phi) axes of the output + // system. + // + // To this end, we first rotate the input system around its third axis + // to align the Y axis with the phi axis. The X and theta axis are + // parallel after this rotation, but point in opposite directions. To + // align the X axis with the theta axis, we flip it. + // + // The Jones matrix to align the Y axis with the phi axis when these are + // separated by an angle phi (measured counter-clockwise around the + // direction of propagation, looking towards the origin), is given by: + // + // [ cos(phi) sin(phi)] + // [-sin(phi) cos(phi)] + // + // Here, cos(phi) and sin(phi) can be computed directly, without having + // to compute phi first (see the computation of coschi and sinchi + // above). + // + // Now, sinchi as computed above is opposite to sin(phi), because the + // direction used in the computation is the direction of arrival instead + // of the direction of propagation. Therefore, the sign of sinchi needs + // to be reversed. Furthermore, as explained above, the X axis has to be + // flipped to align with the theta axis. The Jones matrix returned from + // this function is therefore given by: + // + // [-coschi sinchi] + // [ sinchi coschi] + matrix22r_t rotation = {{{{-coschi, sinchi}}, {{sinchi, coschi}}}}; + return rotation; +} + +matrix22c_t AntennaField::response(real_t time, real_t freq, + const vector3r_t &direction, const vector3r_t &direction0) const +{ + return normalize(rawResponse(time, freq, direction, direction0)); +} + +diag22c_t AntennaField::arrayFactor(real_t time, real_t freq, + const vector3r_t &direction, const vector3r_t &direction0) const +{ + return normalize(rawArrayFactor(time, freq, direction, direction0)); +} + +raw_response_t AntennaField::rawResponse(real_t time, real_t freq, + const vector3r_t &direction, const vector3r_t &direction0) const +{ + raw_array_factor_t af = rawArrayFactor(time, freq, direction, direction0); + + raw_response_t result; + result.response = elementResponse(time, freq, direction); + result.response[0][0] *= af.factor[0]; + result.response[0][1] *= af.factor[0]; + result.response[1][0] *= af.factor[1]; + result.response[1][1] *= af.factor[1]; + result.weight = af.weight; + return result; +} + +} //# namespace StationResponse +} //# namespace LOFAR diff --git a/StationResponse/src/AntennaFieldHBA.cc b/StationResponse/src/AntennaFieldHBA.cc new file mode 100644 index 0000000000000000000000000000000000000000..ff099fb04a22ea2987f0f8c397f353bb69b66e6a --- /dev/null +++ b/StationResponse/src/AntennaFieldHBA.cc @@ -0,0 +1,77 @@ +//# AntennaFieldHBA.cc: Representation of an HBA antenna field. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#include <lofar_config.h> +#include <StationResponse/AntennaFieldHBA.h> +#include <StationResponse/MathUtil.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +AntennaFieldHBA::AntennaFieldHBA(const string &name, + const CoordinateSystem &coordinates, const AntennaModelHBA::ConstPtr &model) + : AntennaField(name, coordinates), + itsAntennaModel(model) +{ +} + +matrix22c_t AntennaFieldHBA::response(real_t time, real_t freq, + const vector3r_t &direction, const vector3r_t &direction0) const +{ + return itsAntennaModel->response(freq, itrf2field(direction), + itrf2field(direction0)) * rotation(time, direction); +} + +diag22c_t AntennaFieldHBA::arrayFactor(real_t, real_t freq, + const vector3r_t &direction, const vector3r_t &direction0) const +{ + return itsAntennaModel->arrayFactor(freq, itrf2field(direction), + itrf2field(direction0)); +} + +raw_response_t AntennaFieldHBA::rawResponse(real_t time, real_t freq, + const vector3r_t &direction, const vector3r_t &direction0) const +{ + raw_response_t result = itsAntennaModel->rawResponse(freq, + itrf2field(direction), itrf2field(direction0)); + result.response = result.response * rotation(time, direction); + return result; +} + +raw_array_factor_t AntennaFieldHBA::rawArrayFactor(real_t, real_t freq, + const vector3r_t &direction, const vector3r_t &direction0) const +{ + return itsAntennaModel->rawArrayFactor(freq, itrf2field(direction), + itrf2field(direction0)); +} + +matrix22c_t AntennaFieldHBA::elementResponse(real_t time, real_t freq, + const vector3r_t &direction) const +{ + return itsAntennaModel->elementResponse(freq, itrf2field(direction)) + * rotation(time, direction); +} + +} //# namespace StationResponse +} //# namespace LOFAR diff --git a/StationResponse/src/AntennaFieldLBA.cc b/StationResponse/src/AntennaFieldLBA.cc new file mode 100644 index 0000000000000000000000000000000000000000..90838c135e6790e2a9d757bf6a108a24d3933059 --- /dev/null +++ b/StationResponse/src/AntennaFieldLBA.cc @@ -0,0 +1,54 @@ +//# AntennaFieldLBA.cc: Representation of an LBA antenna field. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#include <lofar_config.h> +#include <StationResponse/AntennaFieldLBA.h> +#include <StationResponse/MathUtil.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +AntennaFieldLBA::AntennaFieldLBA(const string &name, + const CoordinateSystem &coordinates, const AntennaModelLBA::ConstPtr &model) + : AntennaField(name, coordinates), + itsAntennaModel(model) +{ +} + +raw_array_factor_t AntennaFieldLBA::rawArrayFactor(real_t, real_t, + const vector3r_t&, const vector3r_t&) const +{ + raw_array_factor_t af = {{{1.0, 1.0}}, {{1.0, 1.0}}}; + return af; +} + +matrix22c_t AntennaFieldLBA::elementResponse(real_t time, real_t freq, + const vector3r_t &direction) const +{ + return itsAntennaModel->response(freq, itrf2field(direction)) + * rotation(time, direction); +} + +} //# namespace StationResponse +} //# namespace LOFAR diff --git a/StationResponse/src/AntennaModelHBA.cc b/StationResponse/src/AntennaModelHBA.cc new file mode 100644 index 0000000000000000000000000000000000000000..52ca0accc5428c38aa73964bd74046d36dcda223 --- /dev/null +++ b/StationResponse/src/AntennaModelHBA.cc @@ -0,0 +1,64 @@ +//# AntennaModelHBA.cc: HBA antenna model interface definitions. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#include <lofar_config.h> +#include <StationResponse/AntennaModelHBA.h> +#include <StationResponse/MathUtil.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +AntennaModelHBA::~AntennaModelHBA() +{ +} + +matrix22c_t AntennaModelHBA::response(real_t freq, const vector3r_t &direction, + const vector3r_t &direction0) const +{ + return normalize(rawResponse(freq, direction, direction0)); +} + +diag22c_t AntennaModelHBA::arrayFactor(real_t freq, const vector3r_t &direction, + const vector3r_t &direction0) const +{ + return normalize(rawArrayFactor(freq, direction, direction0)); +} + +raw_response_t AntennaModelHBA::rawResponse(real_t freq, + const vector3r_t &direction, const vector3r_t &direction0) const +{ + raw_array_factor_t af = rawArrayFactor(freq, direction, direction0); + + raw_response_t result; + result.response = elementResponse(freq, direction); + result.response[0][0] *= af.factor[0]; + result.response[0][1] *= af.factor[0]; + result.response[1][0] *= af.factor[1]; + result.response[1][1] *= af.factor[1]; + result.weight = af.weight; + return result; +} + +} //# namespace StationResponse +} //# namespace LOFAR diff --git a/StationResponse/src/AntennaModelLBA.cc b/StationResponse/src/AntennaModelLBA.cc new file mode 100644 index 0000000000000000000000000000000000000000..87d02b945013406efe05d18c4481dc98a2651d42 --- /dev/null +++ b/StationResponse/src/AntennaModelLBA.cc @@ -0,0 +1,36 @@ +//# AntennaModelLBA.cc: LBA antenna model interface definitions. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#include <lofar_config.h> +#include <StationResponse/AntennaModelLBA.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +AntennaModelLBA::~AntennaModelLBA() +{ +} + +} //# namespace StationResponse +} //# namespace LOFAR diff --git a/StationResponse/src/CMakeLists.txt b/StationResponse/src/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e31a7a54574b0e908c6ba2760cf49626696f1850 --- /dev/null +++ b/StationResponse/src/CMakeLists.txt @@ -0,0 +1,20 @@ +# $Id$ + +include(LofarPackageVersion) + +lofar_add_library(stationresponse + Package__Version.cc + AntennaField.cc + AntennaFieldHBA.cc + AntennaFieldLBA.cc + AntennaModelHBA.cc + AntennaModelLBA.cc + DualDipoleAntenna.cc + ITRFDirection.cc + LofarMetaDataUtil.cc + MathUtil.cc + Station.cc + TileAntenna.cc + Types.cc) + +lofar_add_bin_program(makeresponseimage makeresponseimage.cc) diff --git a/StationResponse/src/DualDipoleAntenna.cc b/StationResponse/src/DualDipoleAntenna.cc new file mode 100644 index 0000000000000000000000000000000000000000..659d9f45ddb16ad04a66678d36fad174439fa152 --- /dev/null +++ b/StationResponse/src/DualDipoleAntenna.cc @@ -0,0 +1,51 @@ +//# DualDipoleAntenna.cc: Semi-analytical model of a LOFAR LBA dual dipole +//# antenna. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#include <lofar_config.h> +#include <StationResponse/DualDipoleAntenna.h> +#include <StationResponse/Constants.h> +#include <StationResponse/MathUtil.h> +#include <ElementResponse/ElementResponse.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +matrix22c_t DualDipoleAntenna::response(real_t freq, + const vector3r_t &direction) const +{ + // The positive X dipole direction is SW of the reference orientation, + // which translates to a phi coordinate of 5/4*pi in the topocentric + // spherical coordinate system. The phi coordinate is corrected for this + // offset before evaluating the antenna model. + vector2r_t thetaphi = cart2thetaphi(direction); + thetaphi[1] -= 5.0 * Constants::pi_4; + matrix22c_t response; + element_response_lba(freq, thetaphi[0], thetaphi[1], + reinterpret_cast<std::complex<double> (&)[2][2]>(response)); + return response; +} + +} //# namespace StationResponse +} //# namespace LOFAR diff --git a/StationResponse/src/ITRFDirection.cc b/StationResponse/src/ITRFDirection.cc new file mode 100644 index 0000000000000000000000000000000000000000..f7f9c49e02551bfac1b6afbdeb0c14acbeaa449d --- /dev/null +++ b/StationResponse/src/ITRFDirection.cc @@ -0,0 +1,77 @@ +//# ITRFDirection.cc: Functor that maps time to an ITRF direction. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#include <lofar_config.h> +#include <StationResponse/ITRFDirection.h> + +#include <casacore/measures/Measures/MPosition.h> +#include <casacore/measures/Measures/MDirection.h> +#include <casacore/measures/Measures/MEpoch.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +ITRFDirection::ITRFDirection(const vector3r_t &position, + const vector2r_t &direction) +{ + casacore::MVPosition mvPosition(position[0], position[1], position[2]); + casacore::MPosition mPosition(mvPosition, casacore::MPosition::ITRF); + itsFrame = casacore::MeasFrame(casacore::MEpoch(), mPosition); + + // Order of angles seems to be longitude (along the equator), lattitude + // (towards the pole). + casacore::MVDirection mvDirection(direction[0], direction[1]); + casacore::MDirection mDirection(mvDirection, casacore::MDirection::J2000); + itsConverter = casacore::MDirection::Convert(mDirection, + casacore::MDirection::Ref(casacore::MDirection::ITRF, itsFrame)); +} + +ITRFDirection::ITRFDirection(const vector3r_t &position, + const vector3r_t &direction) +{ + casacore::MVPosition mvPosition(position[0], position[1], position[2]); + casacore::MPosition mPosition(mvPosition, casacore::MPosition::ITRF); + itsFrame = casacore::MeasFrame(casacore::MEpoch(), mPosition); + + casacore::MVDirection mvDirection(direction[0], direction[1], direction[2]); + casacore::MDirection mDirection(mvDirection, casacore::MDirection::J2000); + itsConverter = casacore::MDirection::Convert(mDirection, + casacore::MDirection::Ref(casacore::MDirection::ITRF, itsFrame)); +} + +vector3r_t ITRFDirection::at(real_t time) const +{ + // Cannot use MeasFrame::resetEpoch(Double), because that assumes the + // argument is UTC in (fractional) days (MJD). + itsFrame.resetEpoch(casacore::Quantity(time, "s")); + + const casacore::MDirection &mITRF = itsConverter(); + const casacore::MVDirection &mvITRF = mITRF.getValue(); + + vector3r_t itrf = {{mvITRF(0), mvITRF(1), mvITRF(2)}}; + return itrf; +} + +} //# namespace StationResponse +} //# namespace LOFAR diff --git a/StationResponse/src/LofarMetaDataUtil.cc b/StationResponse/src/LofarMetaDataUtil.cc new file mode 100644 index 0000000000000000000000000000000000000000..4d96af8dfe4f3f0c1b7b945d625e66bc5d977282 --- /dev/null +++ b/StationResponse/src/LofarMetaDataUtil.cc @@ -0,0 +1,335 @@ +//# LofarMetaDataUtil.cc: Utility functions to read the meta data relevant for +//# simulating the beam from LOFAR observations stored in MS format. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#include <lofar_config.h> +#include <StationResponse/LofarMetaDataUtil.h> +#include <StationResponse/AntennaFieldLBA.h> +#include <StationResponse/AntennaFieldHBA.h> +#include <StationResponse/MathUtil.h> +#include <StationResponse/TileAntenna.h> +#include <StationResponse/DualDipoleAntenna.h> + +#include <casacore/measures/Measures/MDirection.h> +#include <casacore/measures/Measures/MPosition.h> +#include <casacore/measures/Measures/MCDirection.h> +#include <casacore/measures/Measures/MCPosition.h> +#include <casacore/measures/Measures/MeasTable.h> +#include <casacore/measures/Measures/MeasConvert.h> +#include <casacore/measures/TableMeasures/ScalarMeasColumn.h> + +#include <stdexcept> + +#include <casacore/ms/MeasurementSets/MSAntenna.h> +#include <casacore/ms/MSSel/MSSelection.h> +#include <casacore/ms/MSSel/MSAntennaParse.h> +#include <casacore/ms/MeasurementSets/MSAntennaColumns.h> +#include <casacore/ms/MeasurementSets/MSDataDescription.h> +#include <casacore/ms/MeasurementSets/MSDataDescColumns.h> +#include <casacore/ms/MeasurementSets/MSField.h> +#include <casacore/ms/MeasurementSets/MSFieldColumns.h> +#include <casacore/ms/MeasurementSets/MSObservation.h> +#include <casacore/ms/MeasurementSets/MSObsColumns.h> +#include <casacore/ms/MeasurementSets/MSPolarization.h> +#include <casacore/ms/MeasurementSets/MSPolColumns.h> +#include <casacore/ms/MeasurementSets/MSSpectralWindow.h> +#include <casacore/ms/MeasurementSets/MSSpWindowColumns.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +using namespace casacore; + +bool hasColumn(const Table &table, const string &column) +{ + return table.tableDesc().isColumn(column); +} + +bool hasSubTable(const Table &table, const string &name) +{ + return table.keywordSet().isDefined(name); +} + +Table getSubTable(const Table &table, const string &name) +{ + return table.keywordSet().asTable(name); +} + +TileAntenna::TileConfig readTileConfig(const Table &table, unsigned int row) +{ + ROArrayQuantColumn<Double> c_tile_offset(table, "TILE_ELEMENT_OFFSET", "m"); + + // Read tile configuration for HBA antenna fields. + Matrix<Quantity> aips_offset = c_tile_offset(row); + assert(aips_offset.ncolumn() == TileAntenna::TileConfig::size()); + + TileAntenna::TileConfig config; + for(unsigned int i = 0; i < config.size(); ++i) + { + config[i][0] = aips_offset(0, i).getValue(); + config[i][1] = aips_offset(1, i).getValue(); + config[i][2] = aips_offset(2, i).getValue(); + } + return config; +} + +void transformToFieldCoordinates(TileAntenna::TileConfig &config, + const AntennaField::CoordinateSystem::Axes &axes) +{ + for(unsigned int i = 0; i < config.size(); ++i) + { + const vector3r_t position = config[i]; + config[i][0] = dot(position, axes.p); + config[i][1] = dot(position, axes.q); + config[i][2] = dot(position, axes.r); + } +} + +AntennaField::CoordinateSystem readCoordinateSystemAartfaac( + const Table &table, unsigned int id) +{ + ROArrayQuantColumn<Double> c_position(table, "POSITION", "m"); + + // Read antenna field center (ITRF). + Vector<Quantity> aips_position = c_position(id); + assert(aips_position.size() == 3); + + vector3r_t position = {{aips_position(0).getValue(), + aips_position(1).getValue(), aips_position(2).getValue()}}; + + TableRecord keywordset = table.keywordSet(); + Matrix<double> aips_axes; + keywordset.get("AARTFAAC_COORDINATE_AXES", aips_axes); + assert(aips_axes.shape().isEqual(IPosition(2, 3, 3))); + + vector3r_t p = {{aips_axes(0, 0), aips_axes(1, 0), aips_axes(2, 0)}}; + vector3r_t q = {{aips_axes(0, 1), aips_axes(1, 1), aips_axes(2, 1)}}; + vector3r_t r = {{aips_axes(0, 2), aips_axes(1, 2), aips_axes(2, 2)}}; + + AntennaField::CoordinateSystem system = {position, {p, q, r}}; + + return system; +} + +AntennaField::CoordinateSystem readCoordinateSystem(const Table &table, + unsigned int id) +{ + ROArrayQuantColumn<Double> c_position(table, "POSITION", "m"); + ROArrayQuantColumn<Double> c_axes(table, "COORDINATE_AXES", "m"); + + // Read antenna field center (ITRF). + Vector<Quantity> aips_position = c_position(id); + assert(aips_position.size() == 3); + + vector3r_t position = {{aips_position(0).getValue(), + aips_position(1).getValue(), aips_position(2).getValue()}}; + + // Read antenna field coordinate axes (ITRF). + Matrix<Quantity> aips_axes = c_axes(id); + assert(aips_axes.shape().isEqual(IPosition(2, 3, 3))); + + vector3r_t p = {{aips_axes(0, 0).getValue(), aips_axes(1, 0).getValue(), + aips_axes(2, 0).getValue()}}; + vector3r_t q = {{aips_axes(0, 1).getValue(), aips_axes(1, 1).getValue(), + aips_axes(2, 1).getValue()}}; + vector3r_t r = {{aips_axes(0, 2).getValue(), aips_axes(1, 2).getValue(), + aips_axes(2, 2).getValue()}}; + + AntennaField::CoordinateSystem system = {position, {p, q, r}}; + return system; +} + +void readAntennae(const Table &table, unsigned int id, + const AntennaField::Ptr &field) +{ + ROArrayQuantColumn<Double> c_offset(table, "ELEMENT_OFFSET", "m"); + ROArrayColumn<Bool> c_flag(table, "ELEMENT_FLAG"); + + // Read element offsets and flags. + Matrix<Quantity> aips_offset = c_offset(id); + assert(aips_offset.shape().isEqual(IPosition(2, 3, aips_offset.ncolumn()))); + + Matrix<Bool> aips_flag = c_flag(id); + assert(aips_flag.shape().isEqual(IPosition(2, 2, aips_offset.ncolumn()))); + + for(size_t i = 0; i < aips_offset.ncolumn(); ++i) + { + AntennaField::Antenna antenna; + antenna.position[0] = aips_offset(0, i).getValue(); + antenna.position[1] = aips_offset(1, i).getValue(); + antenna.position[2] = aips_offset(2, i).getValue(); + antenna.enabled[0] = !aips_flag(0, i); + antenna.enabled[1] = !aips_flag(1, i); + field->addAntenna(antenna); + } +} + +AntennaField::Ptr readAntennaField(const Table &table, unsigned int id) +{ + AntennaField::Ptr field; + AntennaField::CoordinateSystem system = readCoordinateSystem(table, id); + + ROScalarColumn<String> c_name(table, "NAME"); + const string &name = c_name(id); + + if(name == "LBA") + { + DualDipoleAntenna::Ptr model(new DualDipoleAntenna()); + field = AntennaField::Ptr(new AntennaFieldLBA(name, system, model)); + } + else // HBA, HBA0, HBA1 + { + TileAntenna::TileConfig config = readTileConfig(table, id); + transformToFieldCoordinates(config, system.axes); + + TileAntenna::Ptr model(new TileAntenna(config)); + field = AntennaField::Ptr(new AntennaFieldHBA(name, system, model)); + } + + readAntennae(table, id, field); + return field; +} + +AntennaField::Ptr readAntennaFieldAartfaac(const Table &table, const string &ant_type, + unsigned int id) +{ + AntennaField::Ptr field; + AntennaField::CoordinateSystem system = readCoordinateSystemAartfaac(table, id); + + if (ant_type == "LBA") + { + DualDipoleAntenna::Ptr model(new DualDipoleAntenna()); + field = AntennaField::Ptr(new AntennaFieldLBA(ant_type, system, model)); + } + else // HBA + { + // TODO: implement this + throw std::runtime_error("HBA for Aartfaac is not implemented yet."); + } + + // Add only one antenna to the field (no offset, always enabled) + AntennaField::Antenna antenna; + antenna.position[0] = 0.; + antenna.position[1] = 0.; + antenna.position[2] = 0.; + antenna.enabled[0] = true; + antenna.enabled[1] = true; + + field->addAntenna(antenna); + + return field; +} + +void readStationPhaseReference(const Table &table, unsigned int id, + const Station::Ptr &station) +{ + const string columnName("LOFAR_PHASE_REFERENCE"); + if(hasColumn(table, columnName)) + { + ROScalarMeasColumn<MPosition> c_reference(table, columnName); + MPosition mReference = MPosition::Convert(c_reference(id), + MPosition::ITRF)(); + MVPosition mvReference = mReference.getValue(); + vector3r_t reference = {{mvReference(0), mvReference(1), + mvReference(2)}}; + + station->setPhaseReference(reference); + } +} + +Station::Ptr readStation(const MeasurementSet &ms, unsigned int id) +{ + ROMSAntennaColumns antenna(ms.antenna()); + assert(antenna.nrow() > id && !antenna.flagRow()(id)); + + // Get station name. + const string name(antenna.name()(id)); + + // Get station position (ITRF). + MPosition mPosition = MPosition::Convert(antenna.positionMeas()(id), + MPosition::ITRF)(); + MVPosition mvPosition = mPosition.getValue(); + const vector3r_t position = {{mvPosition(0), mvPosition(1), mvPosition(2)}}; + + // Create station. + Station::Ptr station(new Station(name, position)); + + // Read phase reference position (if available). + readStationPhaseReference(ms.antenna(), id, station); + + // Read antenna field information. + ROScalarColumn<String> telescope_name_col(getSubTable(ms, "OBSERVATION"), + "TELESCOPE_NAME"); + string telescope_name = telescope_name_col(0); + + if (telescope_name == "LOFAR") + { + Table tab_field = getSubTable(ms, "LOFAR_ANTENNA_FIELD"); + tab_field = tab_field(tab_field.col("ANTENNA_ID") == static_cast<Int>(id)); + + for(size_t i = 0; i < tab_field.nrow(); ++i) + { + station->addField(readAntennaField(tab_field, i)); + } + } + else if (telescope_name == "AARTFAAC") + { + ROScalarColumn<String> ant_type_col(getSubTable(ms, "OBSERVATION"), + "AARTFAAC_ANTENNA_TYPE"); + string ant_type = ant_type_col(0); + + Table tab_field = getSubTable(ms, "ANTENNA"); + station -> addField(readAntennaFieldAartfaac(tab_field, ant_type, id)); + } + + return station; +} + +MDirection readTileBeamDirection(const casacore::MeasurementSet &ms) { + MDirection tileBeamDir; + + Table fieldTable = getSubTable(ms, "FIELD"); + + if (fieldTable.nrow() != 1) { + throw std::runtime_error("MS has multiple fields, this does not work with the LOFAR beam library."); + } + + if (hasColumn(fieldTable, "LOFAR_TILE_BEAM_DIR")) + { + ROArrayMeasColumn<MDirection> tileBeamCol(fieldTable, + "LOFAR_TILE_BEAM_DIR"); + tileBeamDir = *(tileBeamCol(0).data()); + } + else + { + ROArrayMeasColumn<MDirection> tileBeamCol(fieldTable, + "DELAY_DIR"); + tileBeamDir = *(tileBeamCol(0).data()); + } + + return tileBeamDir; +} + +} //# namespace StationResponse +} //# namespace LOFAR diff --git a/StationResponse/src/MathUtil.cc b/StationResponse/src/MathUtil.cc new file mode 100644 index 0000000000000000000000000000000000000000..1ce4c5af2ee7bf1169d138edacbd2beb6657c881 --- /dev/null +++ b/StationResponse/src/MathUtil.cc @@ -0,0 +1,32 @@ +//# MathUtil.cc: Various mathematical operations on vectors and matrices. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#include <lofar_config.h> +#include <StationResponse/MathUtil.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +} //# namespace StationResponse +} //# namespace LOFAR diff --git a/StationResponse/src/Station.cc b/StationResponse/src/Station.cc new file mode 100644 index 0000000000000000000000000000000000000000..7c4e21045a43e83bd37767c818b8f980fcd93c5c --- /dev/null +++ b/StationResponse/src/Station.cc @@ -0,0 +1,176 @@ +//# Station.cc: Representation of the station beam former. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#include <lofar_config.h> +#include <StationResponse/Station.h> +#include <StationResponse/MathUtil.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +Station::Station(const string &name, const vector3r_t &position) + : itsName(name), + itsPosition(position), + itsPhaseReference(position) +{ +} + +const string &Station::name() const +{ + return itsName; +} + +const vector3r_t &Station::position() const +{ + return itsPosition; +} + +void Station::setPhaseReference(const vector3r_t &reference) +{ + itsPhaseReference = reference; +} + +const vector3r_t &Station::phaseReference() const +{ + return itsPhaseReference; +} + +void Station::addField(const AntennaField::ConstPtr &field) +{ + itsFields.push_back(field); +} + +size_t Station::nFields() const +{ + return itsFields.size(); +} + +AntennaField::ConstPtr Station::field(size_t i) const +{ + return (i < itsFields.size() ? itsFields[i] : AntennaField::ConstPtr()); +} + +Station::FieldList::const_iterator Station::beginFields() const +{ + return itsFields.begin(); +} + +Station::FieldList::const_iterator Station::endFields() const +{ + return itsFields.end(); +} + +matrix22c_t Station::response(real_t time, real_t freq, + const vector3r_t &direction, real_t freq0, const vector3r_t &station0, + const vector3r_t &tile0) const +{ + raw_response_t result = {{{{{}}, {{}}}}, {{}}}; + for(FieldList::const_iterator field_it = beginFields(), + field_end = endFields(); field_it != field_end; ++field_it) + { + raw_array_factor_t field = fieldArrayFactor(*field_it, time, freq, + direction, freq0, phaseReference(), station0); + + raw_response_t antenna = (*field_it)->rawResponse(time, freq, + direction, tile0); + + result.response[0][0] += field.factor[0] * antenna.response[0][0]; + result.response[0][1] += field.factor[0] * antenna.response[0][1]; + result.response[1][0] += field.factor[1] * antenna.response[1][0]; + result.response[1][1] += field.factor[1] * antenna.response[1][1]; + + result.weight[0] += field.weight[0] * antenna.weight[0]; + result.weight[1] += field.weight[1] * antenna.weight[1]; + } + + return normalize(result); +} + +diag22c_t Station::arrayFactor(real_t time, real_t freq, + const vector3r_t &direction, real_t freq0, const vector3r_t &station0, + const vector3r_t &tile0) const +{ + raw_array_factor_t af = {{{}}, {{}}}; + for(FieldList::const_iterator field_it = beginFields(), + field_end = endFields(); field_it != field_end; ++field_it) + { + raw_array_factor_t field = fieldArrayFactor(*field_it, time, freq, + direction, freq0, phaseReference(), station0); + + raw_array_factor_t antenna = (*field_it)->rawArrayFactor(time, freq, + direction, tile0); + + af.factor[0] += field.factor[0] * antenna.factor[0]; + af.factor[1] += field.factor[1] * antenna.factor[1]; + af.weight[0] += field.weight[0] * antenna.weight[0]; + af.weight[1] += field.weight[1] * antenna.weight[1]; + } + + return normalize(af); +} + +raw_array_factor_t +Station::fieldArrayFactor(const AntennaField::ConstPtr &field, + real_t, real_t freq, const vector3r_t &direction, real_t freq0, + const vector3r_t &position0, const vector3r_t &direction0) const +{ + real_t k = Constants::_2pi * freq / Constants::c; + real_t k0 = Constants::_2pi * freq0 / Constants::c; + + vector3r_t offset = field->position() - position0; + + raw_array_factor_t af = {{{}}, {{}}}; + typedef AntennaField::AntennaList AntennaList; + for(AntennaList::const_iterator antenna_it = field->beginAntennae(), + antenna_end = field->endAntennae(); antenna_it != antenna_end; + ++antenna_it) + { + if(!antenna_it->enabled[0] && !antenna_it->enabled[1]) + { + continue; + } + + vector3r_t position = offset + antenna_it->position; + real_t phase = k * dot(position, direction) - k0 * dot(position, + direction0); + complex_t shift = complex_t(cos(phase), sin(phase)); + + if(antenna_it->enabled[0]) + { + af.factor[0] += shift; + ++af.weight[0]; + } + + if(antenna_it->enabled[1]) + { + af.factor[1] += shift; + ++af.weight[1]; + } + } + + return af; +} + +} //# namespace StationResponse +} //# namespace LOFAR diff --git a/StationResponse/src/TileAntenna.cc b/StationResponse/src/TileAntenna.cc new file mode 100644 index 0000000000000000000000000000000000000000..2813563ec96cad64914c102168e2470aef1854b6 --- /dev/null +++ b/StationResponse/src/TileAntenna.cc @@ -0,0 +1,100 @@ +//# TileAntenna.cc: Semi-analytical model of a LOFAR HBA tile. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#include <lofar_config.h> +#include <StationResponse/TileAntenna.h> +#include <StationResponse/Constants.h> +#include <StationResponse/MathUtil.h> +#include <ElementResponse/ElementResponse.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +TileAntenna::TileAntenna(const TileConfig &config) + : itsConfig(config) +{ +} + +void TileAntenna::setConfig(const TileConfig &config) +{ + itsConfig = config; +} + +const TileAntenna::TileConfig &TileAntenna::config() const +{ + return itsConfig; +} + +raw_array_factor_t TileAntenna::rawArrayFactor(real_t freq, + const vector3r_t &direction, const vector3r_t &direction0) const +{ + // Angular wave number. + real_t k = Constants::_2pi * freq / Constants::c; + + // We need to compute the phase difference between a signal arriving from + // the target direction and a signal arriving from the reference direction, + // both relative to the center of the tile. + // + // This phase difference can be computed using a single dot product per + // dipole element by exploiting the fact that the dot product is + // distributive over vector addition: + // + // a . b + a . c = a . (b + c) + // + vector3r_t difference = direction - direction0; + + complex_t af(0.0, 0.0); + for(TileConfig::const_iterator element_it = itsConfig.begin(), + element_end = itsConfig.end(); element_it != element_end; ++element_it) + { + // Compute the effective delay for a plane wave approaching from the + // direction of interest with respect to the position of element i + // when beam forming in the reference direction using time delays. + real_t shift = k * dot(difference, *element_it); + af += complex_t(cos(shift), sin(shift)); + } + + real_t size = itsConfig.size(); + raw_array_factor_t result = {{{af, af}}, {{size, size}}}; + return result; +} + +matrix22c_t TileAntenna::elementResponse(real_t freq, + const vector3r_t &direction) const +{ + // The positive X dipole direction is SW of the reference orientation, + // which translates to a phi coordinate of 5/4*pi in the topocentric + // spherical coordinate system. The phi coordinate is corrected for this + // offset before evaluating the antenna model. + vector2r_t thetaphi = cart2thetaphi(direction); + thetaphi[1] -= 5.0 * Constants::pi_4; + + matrix22c_t response; + element_response_hba(freq, thetaphi[0], thetaphi[1], + reinterpret_cast<std::complex<double> (&)[2][2]>(response)); + return response; +} + +} //# namespace StationResponse +} //# namespace LOFAR diff --git a/StationResponse/src/Types.cc b/StationResponse/src/Types.cc new file mode 100644 index 0000000000000000000000000000000000000000..5267ae75691117365e166f513d915a879f48ee8a --- /dev/null +++ b/StationResponse/src/Types.cc @@ -0,0 +1,32 @@ +//# Types.cc: Declaration of types used in this library. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#include <lofar_config.h> +#include <StationResponse/Types.h> + +namespace LOFAR +{ +namespace StationResponse +{ + +} //# namespace StationResponse +} //# namespace LOFAR diff --git a/StationResponse/src/makeresponseimage.cc b/StationResponse/src/makeresponseimage.cc new file mode 100644 index 0000000000000000000000000000000000000000..aa545ed0ca194e826fd40a80e320758ca6855a62 --- /dev/null +++ b/StationResponse/src/makeresponseimage.cc @@ -0,0 +1,636 @@ +//# makeresponseimage.cc: Generate images of the station response for a given +//# MeasurementSet. +//# +//# Copyright (C) 2013 +//# ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite 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 General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#include <lofar_config.h> + +#include <StationResponse/Package__Version.h> +#include <StationResponse/LofarMetaDataUtil.h> +#include <Common/InputParSet.h> +#include <Common/lofar_sstream.h> +#include <Common/LofarLogger.h> +#include <Common/SystemUtil.h> +#include <Common/Version.h> +#include <casacore/coordinates/Coordinates/CoordinateSystem.h> +#include <casacore/coordinates/Coordinates/SpectralCoordinate.h> +#include <casacore/coordinates/Coordinates/StokesCoordinate.h> +#include <casacore/coordinates/Coordinates/DirectionCoordinate.h> +#include <casacore/images/Images/PagedImage.h> +#include <casacore/measures/Measures/MCDirection.h> +#include <casacore/measures/Measures/MCPosition.h> +#include <casacore/measures/Measures/MDirection.h> +#include <casacore/measures/Measures/MeasConvert.h> +#include <casacore/measures/Measures/MeasTable.h> +#include <casacore/measures/Measures/MEpoch.h> +#include <casacore/measures/Measures/MPosition.h> +#include <casacore/ms/MeasurementSets/MeasurementSet.h> +#include <casacore/ms/MeasurementSets/MSDataDescription.h> +#include <casacore/ms/MeasurementSets/MSDataDescColumns.h> +#include <casacore/ms/MeasurementSets/MSField.h> +#include <casacore/ms/MeasurementSets/MSFieldColumns.h> +#include <casacore/ms/MeasurementSets/MSObservation.h> +#include <casacore/ms/MeasurementSets/MSObsColumns.h> +#include <casacore/ms/MeasurementSets/MSSpectralWindow.h> +#include <casacore/ms/MeasurementSets/MSSpWindowColumns.h> +#include <casacore/tables/Tables/ExprNode.h> + +// There is no wrapped include file lofar_iterator.h. +#include <iterator> + +using namespace casacore; +using namespace LOFAR; +using namespace LOFAR::StationResponse; +using LOFAR::operator<<; + +namespace +{ + /*! + * \brief Map of ITRF directions required to compute an image of the + * station beam. + * + * The station beam library uses the ITRF coordinate system to express + * station positions and source directions. Since the Earth moves with + * respect to the sky, the ITRF coordinates of a source vary with time. + * This structure stores the ITRF coordinates for the station and tile beam + * former reference directions, as well as for a grid of points on the sky, + * along with the time for which these ITRF coordinates are valid. + */ + struct ITRFDirectionMap + { + /*! + * \brief The time for which this ITRF direction map is valid (MJD(UTC) + * in seconds). + */ + double_t time0; + + /*! + * \brief Station beam former reference direction expressed in ITRF + * coordinates. + */ + vector3r_t station0; + + /*! + * \brief Tile beam former reference direction expressed in ITRF + * coordinates. + */ + vector3r_t tile0; + + /*! + * \brief ITRF coordinates for a grid of points on the sky. + */ + Matrix<vector3r_t> directions; + }; + + /*! + * \brief Create an ITRFDirectionMap. + * + * \param coordinates Sky coordinate system definition. + * \param shape Number of points along the RA and DEC axis. + * \param epoch Time for which to compute the ITRF coordinates. + * \param position0 Station beam former reference position (phase + * reference). + * \param station0 Station beam former reference direction (pointing). + * \param tile0 Tile beam former reference direction (pointing). + */ + ITRFDirectionMap makeDirectionMap(const DirectionCoordinate &coordinates, + const IPosition &shape, const MEpoch &epoch, const MPosition &position0, + const MDirection &station0, const MDirection &tile0); + + /*! + * \brief Create a DirectionCoordinate instance that defines an image + * coordinate system on the sky (J2000). + * + * \param reference Direction that corresponds to the origin of the + * coordinate system. + * \param size Number of points along each axis (RA, DEC). The index of the + * origin of the coordinate system is (size / 2, size / 2). + * \param delta Angular step size in radians (assumed to be the same for + * both axes). + */ + DirectionCoordinate makeCoordinates(const MDirection &reference, + unsigned int size, double delta); + + /*! + * \brief Convert an ITRF position given as a StationResponse::vector3r_t + * instance to a casacore::MPosition. + */ + MPosition toMPositionITRF(const vector3r_t &position); + + /*! + * \brief Convert a casacore::MPosition instance to a + * StationResponse::vector3r_t instance. + */ + vector3r_t fromMPosition(const MPosition &position); + + /*! + * \brief Convert a casacore::MDirection instance to a + * StationResponse::vector3r_t instance. + */ + vector3r_t fromMDirection(const MDirection &direction); + + /*! + * \brief Check if the specified column exists as a column of the specified + * table. + * + * \param table The Table instance to check. + * \param column The name of the column. + */ + bool hasColumn(const Table &table, const string &column); + + /*! + * \brief Check if the specified sub-table exists as a sub-table of the + * specified table. + * + * \param table The Table instance to check. + * \param name The name of the sub-table. + */ + bool hasSubTable(const Table &table, const string &name); + + /*! + * \brief Provide access to a sub-table by name. + * + * \param table The Table instance to which the sub-table is associated. + * \param name The name of the sub-table. + */ + Table getSubTable(const Table &table, const string &name); + + /*! + * \brief Attempt to read the position of the observatory. If the + * observatory position is unknown, the specified default position is + * returned. + * + * \param ms MeasurementSet to read the observatory position from. + * \param idObservation Identifier that determines of which observation the + * observatory position should be read. + * \param defaultPosition The position that will be returned if the + * observatory position is unknown. + */ + MPosition readObservatoryPosition(const MeasurementSet &ms, + unsigned int idObservation, const MPosition &defaultPosition); + + /*! + * \brief Read the list of unique timestamps. + * + * \param ms MeasurementSet to read the list of unique timestamps from. + */ + Vector<Double> readUniqueTimes(const MeasurementSet &ms); + + /*! + * \brief Read the reference frequency of the subband associated to the + * specified data description identifier. + * + * \param ms MeasurementSet to read the reference frequency from. + * \param idDataDescription Identifier that determines of which subband the + * reference frequency should be read. + */ + double readFreqReference(const MeasurementSet &ms, + unsigned int idDataDescription); + + /*! + * \brief Read the phase reference direction. + * + * \param ms MeasurementSet to read the phase reference direction from. + * \param idField Identifier of the field of which the phase reference + * direction should be read. + */ + MDirection readPhaseReference(const MeasurementSet &ms, + unsigned int idField); + + /*! + * \brief Read the station beam former reference direction. + * + * \param ms MeasurementSet to read the station beam former reference + * direction from. + * \param idField Identifier of the field of which the station beam former + * reference direction should be read. + */ + MDirection readDelayReference(const MeasurementSet &ms, + unsigned int idField); + + /*! + * \brief Read the station beam former reference direction. + * + * \param ms MeasurementSet to read the tile beam former reference + * direction from. + * \param idField Identifier of the field of which the tile beam former + * reference direction should be read. + */ + MDirection readTileReference(const MeasurementSet &ms, + unsigned int idField); + + /*! + * \brief Store the specified cube of pixel data as a CASA image. + * + * \param data Pixel data. The third dimension is assumed to be of length + * 4, referring to the correlation products XX, XY, YX, YY (in this order). + * \param coordinates Sky coordinate system definition. + * \param frequency Frequency for which the pixel data is valid (Hz). + * \param name File name of the output image. + */ + template <class T> + void store(const Cube<T> &data, const DirectionCoordinate &coordinates, + double frequency, const string &name); + + /*! + * \brief Convert a string to a CASA Quantity (value with unit). + */ + Quantity readQuantity(const String &in); + + /*! + * \brief Remove all elements from the range [first, last) that fall + * outside the interval [min, max]. + * + * This function returns an iterator new_last such that the range [first, + * new_last) contains no elements that fall outside the interval [min, + * max]. The iterators in the range [new_last, last) are all still + * dereferenceable, but the elements that they point to are unspecified. + * The order of the elements that are not removed is unchanged. + */ + template <typename T> + T filter(T first, T last, int min, int max); +} //# unnamed namespace + + +int main(int argc, char *argv[]) +{ + TEST_SHOW_VERSION(argc, argv, StationResponse); + INIT_LOGGER(basename(string(argv[0]))); + Version::show<StationResponseVersion>(cout); + + // Parse inputs. + LOFAR::InputParSet inputs; + inputs.create("ms", "", "Name of input MeasurementSet", "string"); + inputs.create("stations", "0", "IDs of stations to process", "int vector"); + inputs.create("cellsize", "60arcsec", "Angular pixel size", + "quantity string"); + inputs.create("size", "256", "Number of pixels along each axis", "int"); + inputs.create("offset", "0s", "Time offset from the start of the MS", + "quantity string"); + inputs.create("frames", "0", "Number of images that will be generated for" + " each station (equally spaced over the duration of the MS)", "int"); + inputs.create("abs", "false", "If set to true, store the absolute value of" + " the beam response instead of the complex value (intended for use with" + " older versions of casaviewer)", "bool"); + inputs.readArguments(argc, argv); + + vector<int> stationIDs(inputs.getIntVector("stations")); + Quantity cellsize = readQuantity(inputs.getString("cellsize")); + unsigned int size = max(inputs.getInt("size"), 1); + Quantity offset = readQuantity(inputs.getString("offset")); + unsigned int nFrames = max(inputs.getInt("frames"), 1); + Bool abs = inputs.getBool("abs"); + + // Open MS. + MeasurementSet ms(inputs.getString("ms")); + unsigned int idObservation = 0, idField = 0, idDataDescription = 0; + + // Read station meta-data. + vector<Station::Ptr> stations; + readStations(ms, std::back_inserter(stations)); + + // Remove illegal station indices. + stationIDs.erase(filter(stationIDs.begin(), stationIDs.end(), 0, + static_cast<int>(stations.size()) - 1), stationIDs.end()); + + // Read unique timestamps + Table selection = + ms(ms.col("OBSERVATION_ID") == static_cast<Int>(idObservation) + && ms.col("FIELD_ID") == static_cast<Int>(idField) + && ms.col("DATA_DESC_ID") == static_cast<Int>(idDataDescription)); + Vector<Double> time = readUniqueTimes(selection); + + // Read reference frequency. + double refFrequency = readFreqReference(ms, idDataDescription); + + // Use the position of the first selected station as the array reference + // position if the observatory position cannot be found. + MPosition refPosition = readObservatoryPosition(ms, idField, + toMPositionITRF(stations.front()->position())); + + // Read phase reference direction. + MDirection refPhase = readPhaseReference(ms, idField); + + // Read delay reference direction. + MDirection refDelay = readDelayReference(ms, idField); + + // Read tile reference direction. + MDirection refTile = readTileReference(ms, idField); + + // Create image coordinate system. + IPosition shape(2, size, size); + DirectionCoordinate coordinates = makeCoordinates(refPhase, size, + cellsize.getValue("rad")); + + // Compute station response images. + Cube<Complex> response(size, size, 4); + + MEpoch refEpoch; + Quantity refTime(time(0), "s"); + refTime = refTime + offset; + Quantity deltaTime((time(time.size() - 1) - time(0) - offset.getValue("s")) + / (nFrames - 1), "s"); + + for(size_t j = 0; j < nFrames; ++j) + { + cout << "[ Frame: " << (j + 1) << "/" << nFrames << " Offset: +" + << refTime.getValue() - time(0) << " s ]" << endl; + + // Update reference epoch. + refEpoch.set(refTime); + + cout << "Creating ITRF direction map... " << flush; + ITRFDirectionMap directionMap = makeDirectionMap(coordinates, shape, + refEpoch, refPosition, refDelay, refTile); + cout << "done." << endl; + + cout << "Computing response images... " << flush; + for(vector<int>::const_iterator it = stationIDs.begin(), + end = stationIDs.end(); it != end; ++it) + { + Station::ConstPtr station = stations[*it]; + cout << *it << ":" << station->name() << " " << flush; + + for(size_t y = 0; y < size; ++y) + { + for(size_t x = 0; x < size; ++x) + { + matrix22c_t E = station->response(directionMap.time0, + refFrequency, directionMap.directions(x, y), + refFrequency, directionMap.station0, + directionMap.tile0); + + response(x, y, 0) = E[0][0]; + response(x, y, 1) = E[0][1]; + response(x, y, 2) = E[1][0]; + response(x, y, 3) = E[1][1]; + } + } + + std::ostringstream oss; + oss << "response-" << station->name() << "-frame-" << (j + 1) + << ".img"; + + if(abs) + { + store(Cube<Float>(amplitude(response)), coordinates, + refFrequency, oss.str()); + } + else + { + store(response, coordinates, refFrequency, oss.str()); + } + } + cout << endl; + + refTime = refTime + deltaTime; + } + + return 0; +} + +namespace +{ + ITRFDirectionMap makeDirectionMap(const DirectionCoordinate &coordinates, + const IPosition &shape, const MEpoch &epoch, const MPosition &position0, + const MDirection &station0, const MDirection &tile0) + { + ITRFDirectionMap map; + + // Convert from MEpoch to a time in MJD(UTC) in seconds. + MEpoch mEpochUTC = MEpoch::Convert(epoch, MEpoch::Ref(MEpoch::UTC))(); + MVEpoch mvEpochUTC = mEpochUTC.getValue(); + Quantity qEpochUTC = mvEpochUTC.getTime(); + map.time0 = qEpochUTC.getValue("s"); + + // Create conversion engine J2000 => ITRF at the specified epoch. + MDirection::Convert convertor = MDirection::Convert(MDirection::J2000, + MDirection::Ref(MDirection::ITRF, MeasFrame(epoch, position0))); + + // Compute station and tile beam former reference directions in ITRF at + // the specified epoch. + map.station0 = fromMDirection(convertor(station0)); + map.tile0 = fromMDirection(convertor(tile0)); + + // Pre-allocate space for the grid of ITRF directions. + map.directions.resize(shape); + + // Compute ITRF directions. + MDirection world; + Vector<Double> pixel = coordinates.referencePixel(); + for(pixel(1) = 0.0; pixel(1) < shape(1); ++pixel(1)) + { + for(pixel(0) = 0.0; pixel(0) < shape(0); ++pixel(0)) + { + // CoordinateSystem::toWorld(): RA range [-pi,pi], DEC range + // [-pi/2,pi/2]. + if(coordinates.toWorld(world, pixel)) + { + map.directions(pixel(0), pixel(1)) = + fromMDirection(convertor(world)); + } + } + } + + return map; + } + + DirectionCoordinate makeCoordinates(const MDirection &reference, + unsigned int size, double delta) + { + MDirection referenceJ2000 = MDirection::Convert(reference, + MDirection::J2000)(); + Quantum<Vector<Double> > referenceAngles = referenceJ2000.getAngle(); + double ra = referenceAngles.getBaseValue()(0); + double dec = referenceAngles.getBaseValue()(1); + + Matrix<Double> xform(2,2); + xform = 0.0; xform.diagonal() = 1.0; + return DirectionCoordinate(MDirection::J2000, + Projection(Projection::SIN), ra, dec, -delta, delta, xform, + size / 2, size / 2); + } + + MPosition toMPositionITRF(const vector3r_t &position) + { + MVPosition mvITRF(position[0], position[1], position[2]); + return MPosition(mvITRF, MPosition::ITRF); + } + + vector3r_t fromMPosition(const MPosition &position) + { + MVPosition mvPosition = position.getValue(); + vector3r_t result = {{mvPosition(0), mvPosition(1), mvPosition(2)}}; + return result; + } + + vector3r_t fromMDirection(const MDirection &direction) + { + MVDirection mvDirection = direction.getValue(); + vector3r_t result = {{mvDirection(0), mvDirection(1), mvDirection(2)}}; + return result; + } + + bool hasColumn(const Table &table, const string &column) + { + return table.tableDesc().isColumn(column); + } + + bool hasSubTable(const Table &table, const string &name) + { + return table.keywordSet().isDefined(name); + } + + Table getSubTable(const Table &table, const string &name) + { + return table.keywordSet().asTable(name); + } + + MPosition readObservatoryPosition(const MeasurementSet &ms, + unsigned int idObservation, const MPosition &defaultPosition) + { + // Get the instrument position in ITRF coordinates, or use the centroid + // of the station positions if the instrument position is unknown. + ROMSObservationColumns observation(ms.observation()); + ASSERT(observation.nrow() > idObservation); + ASSERT(!observation.flagRow()(idObservation)); + + // Read observatory name and try to look-up its position. + const string observatory = observation.telescopeName()(idObservation); + + // Look-up observatory position, default to specified default position. + MPosition position(defaultPosition); + MeasTable::Observatory(position, observatory); + return position; + } + + Vector<Double> readUniqueTimes(const MeasurementSet &ms) + { + Table tab_sorted = ms.sort("TIME", Sort::Ascending, Sort::HeapSort + | Sort::NoDuplicates); + + ROScalarColumn<Double> c_time(tab_sorted, "TIME"); + return c_time.getColumn(); + } + + double readFreqReference(const MeasurementSet &ms, + unsigned int idDataDescription) + { + ROMSDataDescColumns desc(ms.dataDescription()); + ASSERT(desc.nrow() > idDataDescription); + ASSERT(!desc.flagRow()(idDataDescription)); + uInt idWindow = desc.spectralWindowId()(idDataDescription); + + ROMSSpWindowColumns window(ms.spectralWindow()); + ASSERT(window.nrow() > idWindow); + ASSERT(!window.flagRow()(idWindow)); + + return window.refFrequency()(idWindow); + } + + MDirection readPhaseReference(const MeasurementSet &ms, + unsigned int idField) + { + ROMSFieldColumns field(ms.field()); + ASSERT(field.nrow() > idField); + ASSERT(!field.flagRow()(idField)); + + return field.phaseDirMeas(idField); + } + + MDirection readDelayReference(const MeasurementSet &ms, + unsigned int idField) + { + ROMSFieldColumns field(ms.field()); + ASSERT(field.nrow() > idField); + ASSERT(!field.flagRow()(idField)); + + return field.delayDirMeas(idField); + } + + MDirection readTileReference(const MeasurementSet &ms, unsigned int idField) + { + // The MeasurementSet class does not support LOFAR specific columns, so + // we use ROArrayMeasColumn to read the tile beam reference direction. + Table tab_field = getSubTable(ms, "FIELD"); + + static const String columnName = "LOFAR_TILE_BEAM_DIR"; + if(hasColumn(tab_field, columnName)) + { + ROArrayMeasColumn<MDirection> c_direction(tab_field, columnName); + if(c_direction.isDefined(idField)) + { + return c_direction(idField)(IPosition(1, 0)); + } + } + + // By default, the tile beam reference direction is assumed to be equal + // to the station beam reference direction (for backward compatibility, + // and for non-HBA measurements). + return readDelayReference(ms, idField); + } + + template <class T> + void store(const Cube<T> &data, const DirectionCoordinate &coordinates, + double frequency, const string &name) + { + ASSERT(data.shape()(2) == 4); + + Vector<Int> stokes(4); + stokes(0) = Stokes::XX; + stokes(1) = Stokes::XY; + stokes(2) = Stokes::YX; + stokes(3) = Stokes::YY; + + CoordinateSystem csys; + csys.addCoordinate(coordinates); + csys.addCoordinate(StokesCoordinate(stokes)); + csys.addCoordinate(SpectralCoordinate(MFrequency::TOPO, frequency, 0.0, + 0.0)); + + PagedImage<T> im(TiledShape(IPosition(4, data.shape()(0), + data.shape()(1), 4, 1)), csys, name); + im.putSlice(data, IPosition(4, 0, 0, 0, 0)); + } + + Quantity readQuantity(const String &in) + { + Quantity result; + bool status = Quantity::read(result, in); + ASSERT(status); + return result; + } + + template <typename T> + T filter(T first, T last, int min, int max) + { + T new_last = first; + for(; first != last; ++first) + { + if(*first >= min && *first <= max) + { + *new_last++ = *first; + } + } + + return new_last; + } +} // unnamed namespace.