diff --git a/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqNumericalDipoleBeam.h b/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqNumericalDipoleBeam.h index dc179bfdf7d1b6b5db888f987b42a0edce7f9abf..410f31e0a5121d17c7a46ccdfe7e4c93807c6117 100644 --- a/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqNumericalDipoleBeam.h +++ b/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqNumericalDipoleBeam.h @@ -42,6 +42,25 @@ namespace BBS // \addtogroup MNS // @{ +class BeamCoeff +{ +public: + BeamCoeff() + : freqAvg(0.0), freqRange(1.0) + {} + + BeamCoeff(double avg, double range, + const shared_ptr<const boost::multi_array<dcomplex, 4> > &ptr) + : freqAvg(avg), + freqRange(range), + coeff(ptr) + {} + + double freqAvg, freqRange; + shared_ptr<const boost::multi_array<dcomplex, 4> > coeff; +}; + + class MeqNumericalDipoleBeam: public MeqJonesExprRep { public: @@ -52,10 +71,8 @@ public: N_InputPort } InputPort; - typedef boost::multi_array<dcomplex, 4> BeamCoeffType; - - MeqNumericalDipoleBeam(shared_ptr<const BeamCoeffType> coeff, MeqExpr azel, - MeqExpr orientation); + MeqNumericalDipoleBeam(const BeamCoeff &coeff, const MeqExpr &azel, + const MeqExpr &orientation); virtual MeqJonesResult getJResult(const MeqRequest &request); @@ -64,15 +81,12 @@ public: MeqMatrix &out_E11, MeqMatrix &out_E12, MeqMatrix &out_E21, MeqMatrix &out_E22); -private: - inline void evalProjectionMatrix(size_t harmonic, - const vector<double> &theta, const vector<double> &freq, dcomplex P[]); - #ifdef EXPR_GRAPH virtual std::string getLabel(); #endif - shared_ptr<const BeamCoeffType> itsCoeff; +private: + BeamCoeff itsBeamCoeff; }; // @} diff --git a/CEP/BB/BBSKernel/src/MNS/MeqNumericalDipoleBeam.cc b/CEP/BB/BBSKernel/src/MNS/MeqNumericalDipoleBeam.cc index 47322d07f18b0459ea012e71e40d966eb54ddc70..ddf361559759a251c40df488b9ae1ecb65da817c 100644 --- a/CEP/BB/BBSKernel/src/MNS/MeqNumericalDipoleBeam.cc +++ b/CEP/BB/BBSKernel/src/MNS/MeqNumericalDipoleBeam.cc @@ -31,14 +31,18 @@ namespace LOFAR namespace BBS { -MeqNumericalDipoleBeam::MeqNumericalDipoleBeam - (shared_ptr<const BeamCoeffType> coeff, MeqExpr azel, MeqExpr orientation) - : itsCoeff(coeff) +MeqNumericalDipoleBeam::MeqNumericalDipoleBeam(const BeamCoeff &coeff, + const MeqExpr &azel, const MeqExpr &orientation) + : itsBeamCoeff(coeff) { + ASSERT(itsBeamCoeff.coeff); + ASSERT(itsBeamCoeff.coeff->size() > 0); + addChild(azel); addChild(orientation); } + MeqJonesResult MeqNumericalDipoleBeam::getJResult(const MeqRequest &request) { // Evaluate children. @@ -136,54 +140,68 @@ void MeqNumericalDipoleBeam::evaluate(const MeqRequest &request, out_E22.dcomplexStorage(E22_re, E22_im); // Evaluate beam. - const size_t nHarmonics = itsCoeff->shape()[1]; - const size_t nTheta = itsCoeff->shape()[2]; - const size_t nFreq = itsCoeff->shape()[3]; + const size_t nHarmonics = itsBeamCoeff.coeff->shape()[1]; + const size_t nTheta = itsBeamCoeff.coeff->shape()[2]; + const size_t nFreq = itsBeamCoeff.coeff->shape()[3]; - vector<double> thetaExp(nTheta); - vector<double> freqExp(nFreq); + const boost::multi_array<dcomplex, 4> &coeff = *itsBeamCoeff.coeff; size_t sample = 0; for(size_t t = 0; t < static_cast<size_t>(request.ny()); ++t) { double freq = request.domain().startX() + 0.5 * request.stepX(); - const double theta = casa::C::pi_2 - el[t]; - // Compute vector of powers of the current _zenith angle_ theta. - thetaExp[0] = 1.0; - for(size_t i = 1; i < thetaExp.size(); ++i) - { - thetaExp[i] = thetaExp[i - 1] * theta; - } + // Correct azimuth for dipole orientation. + const double phi = az[t] - orientation; + + // NB: The model is parameterized in terms of zenith angle. The + // appropriate conversion is taken care of below. + const double theta = casa::C::pi_2 - el[t]; for(size_t f = 0; f < static_cast<size_t>(request.nx()); ++f) { - // Compute vector of powers of the current frequency. - freqExp[0] = 1.0; - for(size_t i = 1; i < freqExp.size(); ++i) - { - freqExp[i] = freqExp[i - 1] * freq; - } - - dcomplex P[2], J[2][2]; + // NB: The model is parameterized in terms of a normalized + // frequency in the range [-1, 1]. The appropriate conversion is + // taken care of below. + const double scaledFreq = (freq - itsBeamCoeff.freqAvg) + / itsBeamCoeff.freqRange; + + // J-jones matrix (2x2 complex matrix) + dcomplex J[2][2]; J[0][0] = J[0][1] = J[1][0] = J[1][1] = makedcomplex(0.0, 0.0); for(size_t k = 0; k < nHarmonics; ++k) { - // Compute P for the current harmonic. - evalProjectionMatrix(k, thetaExp, freqExp, P); + // Compute diagonal projection matrix P for the current + // harmonic. + dcomplex P[2]; + P[0] = P[1] = makedcomplex(0.0, 0.0); + + dcomplex inner[2]; + for(long i = nTheta - 1; i >= 0; --i) + { + inner[0] = coeff[0][k][i][nFreq - 1]; + inner[1] = coeff[1][k][i][nFreq - 1]; + + for(long j = nFreq - 2; j >= 0; --j) + { + inner[0] = inner[0] * scaledFreq + coeff[0][k][i][j]; + inner[1] = inner[1] * scaledFreq + coeff[1][k][i][j]; + } + P[0] = P[0] * theta + inner[0]; + P[1] = P[1] * theta + inner[1]; + } + + // Compute J-jonex matrix for this harmonic by rotating + // P over kappa * phi and add it to the result. + const double kappa = ((k & 1) == 0 ? 1.0 : -1.0) * (2.0 * k + 1.0); + const double cphi = std::cos(kappa * phi); + const double sphi = std::sin(kappa * phi); - const double kappa = ((k + 1) % 2 == 0 ? 1 : -1) * (2 * k + 1); - const double phi = kappa * (az[t] - orientation); - - const double cosphi = std::cos(phi); - const double sinphi = std::sin(phi); - - // R(kappa(k) * phi) * Pk(theta). - J[0][0] += cosphi * P[0]; - J[0][1] += -sinphi * P[1]; - J[1][0] += sinphi * P[0]; - J[1][1] += cosphi * P[1]; + J[0][0] += cphi * P[0]; + J[0][1] += -sphi * P[1]; + J[1][0] += sphi * P[0]; + J[1][1] += cphi * P[1]; } E11_re[sample] = real(J[0][0]); @@ -205,31 +223,6 @@ void MeqNumericalDipoleBeam::evaluate(const MeqRequest &request, } -void MeqNumericalDipoleBeam::evalProjectionMatrix(size_t harmonic, - const vector<double> &theta, const vector<double> &freq, dcomplex P[]) -{ - typedef boost::multi_array<dcomplex, 4>::index_range range; - boost::multi_array<dcomplex, 4>::const_array_view<2>::type coeff00 = - (*itsCoeff)[boost::indices[0][harmonic][range()][range()]]; - boost::multi_array<dcomplex, 4>::const_array_view<2>::type coeff11 = - (*itsCoeff)[boost::indices[1][harmonic][range()][range()]]; - - dcomplex inner[2]; - P[0] = P[1] = makedcomplex(0.0, 0.0); - for(size_t i = 0; i < theta.size(); ++i) - { - inner[0] = inner[1] = makedcomplex(0.0, 0.0); - for(size_t j = 0; j < freq.size(); ++j) - { - inner[0] += coeff00[i][j] * freq[j]; - inner[1] += coeff11[i][j] * freq[j]; - } - P[0] += inner[0] * theta[i]; - P[1] += inner[1] * theta[i]; - } -} - - #ifdef EXPR_GRAPH std::string MeqNumericalDipoleBeam::getLabel() {