diff --git a/CEP/BB/BBSKernel/src/MNS/MeqAzEl.cc b/CEP/BB/BBSKernel/src/MNS/MeqAzEl.cc new file mode 100644 index 0000000000000000000000000000000000000000..e6359c41398531def5465294e3fadc4c6b667244 --- /dev/null +++ b/CEP/BB/BBSKernel/src/MNS/MeqAzEl.cc @@ -0,0 +1,180 @@ +//# MeqAzEl.cc: Azimuth and elevation for a direction (ra,dec) on the sky. +//# +//# Copyright (C) 2007 +//# ASTRON (Netherlands Foundation for Research in Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl +//# +//# This program 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 2 of the License, or +//# (at your option) any later version. +//# +//# This program 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 this program; if not, write to the Free Software +//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//# +//# $Id$ + +#include <lofar_config.h> + +#include <BBSKernel/MNS/MeqAzEl.h> +#include <BBSKernel/MNS/MeqSource.h> +#include <BBSKernel/MNS/MeqStation.h> +#include <BBSKernel/MNS/MeqRequest.h> +#include <Common/LofarLogger.h> + +#include <measures/Measures/MDirection.h> +#include <measures/Measures/MEpoch.h> +#include <measures/Measures/MPosition.h> +#include <measures/Measures/MeasFrame.h> +#include <measures/Measures/MeasConvert.h> +#include <casa/Quanta/Quantum.h> + +using namespace casa; + +namespace LOFAR +{ +namespace BBS +{ + +MeqAzEl::MeqAzEl(MeqSource &source, MeqStation &station) +{ + addChild(source.getRa()); + addChild(source.getDec()); + addChild(station.getPosX()); + addChild(station.getPosY()); + addChild(station.getPosZ()); +} + + +MeqResultVec MeqAzEl::getResultVec(const MeqRequest& request) +{ + // Check preconditions. + ASSERTSTR(request.ny() > 0, "Need time values."); + + // Evaluate children. + MeqResult res_ra, res_dec, res_x, res_y, res_z; + const MeqResult &ra = + getChild(MeqAzEl::IN_RA).getResultSynced(request, res_ra); + const MeqResult &dec = + getChild(MeqAzEl::IN_DEC).getResultSynced(request, res_dec); + const MeqResult &x = + getChild(MeqAzEl::IN_X).getResultSynced(request, res_x); + const MeqResult &y = + getChild(MeqAzEl::IN_Y).getResultSynced(request, res_y); + const MeqResult &z = + getChild(MeqAzEl::IN_Z).getResultSynced(request, res_z); + + // Check preconditions. + ASSERTSTR(!ra.getValue().isArray() && !dec.getValue().isArray(), "Variable" + " source positions are not supported yet."); + ASSERTSTR(!x.getValue().isArray() && !y.getValue().isArray() + && !z.getValue().isArray(), "Variable station positions are not" + " supported yet."); + + // Create result. + MeqResultVec result(2, request.nspid()); + + // Evaluate main value. + evaluate(request, ra.getValue(), dec.getValue(), x.getValue(), y.getValue(), + z.getValue(), result[0].getValueRW(), result[1].getValueRW()); + + // Evaluate perturbed values. + const MeqParmFunklet *perturbedParm; + for(int i = 0; i < request.nspid(); ++i) + { + // Find out if this perturbed value needs to be computed. + if(ra.isDefined(i)) + { + perturbedParm = ra.getPerturbedParm(i); + } + else if(dec.isDefined(i)) + { + perturbedParm = dec.getPerturbedParm(i); + } + else if(x.isDefined(i)) + { + perturbedParm = x.getPerturbedParm(i); + } + else if(y.isDefined(i)) + { + perturbedParm = y.getPerturbedParm(i); + } + else if(z.isDefined(i)) + { + perturbedParm = z.getPerturbedParm(i); + } + else + { + continue; + } + + evaluate(request, ra.getPerturbedValue(i), dec.getPerturbedValue(i), + x.getPerturbedValue(i), y.getPerturbedValue(i), + z.getPerturbedValue(i), result[0].getPerturbedValueRW(i), + result[1].getPerturbedValueRW(i)); + + result[0].setPerturbedParm(i, perturbedParm); + result[1].setPerturbedParm(i, perturbedParm); + } + + return result; +} + + +void MeqAzEl::evaluate(const MeqRequest& request, const MeqMatrix &in_ra, + const MeqMatrix &in_dec, const MeqMatrix &in_x, const MeqMatrix &in_y, + const MeqMatrix &in_z, MeqMatrix &out_az, MeqMatrix &out_el) +{ + MPosition position(MVPosition(in_x.getDouble(0, 0), in_y.getDouble(0, 0), + in_z.getDouble(0, 0)), MPosition::Ref(MPosition::ITRF)); + Quantum<double> qepoch(0, "s"); + MEpoch epoch(qepoch, MEpoch::UTC); + + // Create and initialize a frame. + MeasFrame frame; + frame.set(position); + frame.set(epoch); + + // Create conversion engine. + MDirection dir(MVDirection(in_ra.getDouble(0, 0), in_dec.getDouble(0, 0)), + MDirection::Ref(MDirection::J2000)); + MDirection::Convert converter = MDirection::Convert(dir, + MDirection::Ref(MDirection::AZEL, frame)); + + // Result is only time variable. + double *az = out_az.setDoubleFormat(1, request.ny()); + double *el = out_el.setDoubleFormat(1, request.ny()); + + for(int i = 0; i < request.ny(); ++i) + { + // Update reference frame. + qepoch.setValue(request.y(i)); + epoch.set(qepoch); + frame.set(epoch); + + // Compute azimuth and elevation. + MDirection azel(converter()); + Vector<Double> vec_azel = azel.getValue().getAngle("rad").getValue(); + *az = vec_azel(0); + *el = vec_azel(1); + ++az; ++el; + } +} + + +#ifdef EXPR_GRAPH +std::string MeqAzEl::getLabel() +{ + return std::string("MeqAzEl\\nAzimuth and elevation of a source."); +} +#endif + +} //# namespace BBS +} //# namespace LOFAR + diff --git a/CEP/BB/BBSKernel/src/MNS/MeqDipoleBeam.cc b/CEP/BB/BBSKernel/src/MNS/MeqDipoleBeam.cc new file mode 100644 index 0000000000000000000000000000000000000000..b1b92fb77d3a4c788668be1ad2624ee9346bbaa4 --- /dev/null +++ b/CEP/BB/BBSKernel/src/MNS/MeqDipoleBeam.cc @@ -0,0 +1,228 @@ +//# MeqDipoleBeam.cc: Dipole voltage beam (analytic) +//# +//# Copyright (C) 2007 +//# ASTRON (Netherlands Foundation for Research in Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl +//# +//# This program 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 2 of the License, or +//# (at your option) any later version. +//# +//# This program 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 this program; if not, write to the Free Software +//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//# +//# $Id$ + +#include <lofar_config.h> +#include <BBSKernel/MNS/MeqDipoleBeam.h> +#include <Common/lofar_complex.h> + +namespace LOFAR +{ +namespace BBS +{ +//using LOFAR::dcomplex; +//using LOFAR::conj; + + +MeqDipoleBeam::MeqDipoleBeam(MeqExpr azel, double height, double length, + double slant, double orientation) + : itsHeight(height), + itsLength(length), + itsSlant(slant), + itsOrientation(orientation) +{ + addChild(azel); +} + + +MeqJonesResult MeqDipoleBeam::getJResult(const MeqRequest &request) +{ + // Evaluate children. + MeqResultVec res_azel; + const MeqResultVec &azel = + getChild(MeqDipoleBeam::IN_AZEL).getResultVecSynced(request, res_azel); + + // Create result. + MeqJonesResult result(request.nspid()); + MeqResult& result11 = result.result11(); + MeqResult& result12 = result.result12(); + MeqResult& result21 = result.result21(); + MeqResult& result22 = result.result22(); + + // Evaluate main value. + // Evaluate X polarization. + evaluate(request, azel[0].getValue(), azel[1].getValue(), + result11.getValueRW(), result12.getValueRW(), itsHeight, itsLength, + itsSlant, itsOrientation); + // Evaluate Y polarization. + evaluate(request, azel[0].getValue(), azel[1].getValue(), + result21.getValueRW(), result22.getValueRW(), itsHeight, itsLength, + itsSlant, itsOrientation - casa::C::pi_2); + + // Evaluate perturbed values. + const MeqParmFunklet *perturbedParm; + for(int i = 0; i < request.nspid(); ++i) + { + // Find out if this perturbed value needs to be computed. + if(azel[0].isDefined(i)) + { + perturbedParm = azel[0].getPerturbedParm(i); + } + else if(azel[1].isDefined(i)) + { + perturbedParm = azel[1].getPerturbedParm(i); + } + else + { + continue; + } + + // Evaluate X polarization. + evaluate(request, azel[0].getValue(), azel[1].getValue(), + result11.getPerturbedValueRW(i), result12.getPerturbedValueRW(i), + itsHeight, itsLength, itsSlant, itsOrientation); + + // Evaluate Y polarization. + evaluate(request, azel[0].getValue(), azel[1].getValue(), + result21.getPerturbedValueRW(i), result22.getPerturbedValueRW(i), + itsHeight, itsLength, itsSlant, itsOrientation - casa::C::pi_2); + + result11.setPerturbedParm(i, perturbedParm); + result12.setPerturbedParm(i, perturbedParm); + result21.setPerturbedParm(i, perturbedParm); + result22.setPerturbedParm(i, perturbedParm); + } + + return result; +} + + +void MeqDipoleBeam::evaluate(const MeqRequest &request, const MeqMatrix &in_az, + const MeqMatrix &in_el, MeqMatrix &out_E_theta, MeqMatrix &out_E_phi, + double height, double length, double slant, double orientation) +{ + const double *az = in_az.doubleStorage(); + const double *el = in_el.doubleStorage(); + + double *E_theta_re, *E_theta_im; + out_E_theta.setDCMat(request.nx(), request.ny()); + out_E_theta.dcomplexStorage(E_theta_re, E_theta_im); + + double *E_phi_re, *E_phi_im; + out_E_phi.setDCMat(request.nx(), request.ny()); + out_E_phi.dcomplexStorage(E_phi_re, E_phi_im); + + for(int t = 0; t < request.ny(); ++t) + { + double phi = orientation + (*az); + double theta = casa::C::pi_2 - (*el); + + if(theta >= casa::C::_2pi) + { + // Below the horizon. + for(int f = 0; f < request.nx(); ++f) + { + *E_theta_re = 0.0; + *E_theta_im = 0.0; + E_theta_re++; + E_theta_im++; + + *E_phi_re = 0.0; + *E_phi_im = 0.0; + E_phi_re++; + E_phi_im++; + } + } + else + { + // Common terms that depend on direction (and therefore on time). + double sin_theta = sin(theta); + double cos_theta = cos(theta); + double sin_phi = sin(phi); + double cos_phi = cos(phi); + double sin_alpha = sin(slant); + double cos_alpha = cos(slant); + double tan_alpha = tan(slant); + double inv_sin_alpha = 1.0 / sin_alpha; + double inv_sin_alpha_sqr = 1.0 / (sin_alpha * sin_alpha); + + double A = sin_theta * cos_phi; + double B = cos_theta / tan_alpha; + double F = A + B; + double G = A - B; + + double I = sin_alpha * sin_phi; + double J = cos_alpha * sin_theta; + double K = sin_alpha * cos_theta * cos_phi; + double M = J + K; + double N = J - K; + + double freq = request.domain().startX() + request.stepX() / 2.0; + + for(int f = 0; f < request.nx(); ++f) + { + // Common terms that depend on frequency. + double omega = casa::C::_2pi * freq; + double k = omega / casa::C::c; + + double C = k * length; + double D = inv_sin_alpha * cos(C); + double E = k * height * cos_theta; + + dcomplex term1 = makedcomplex(cos(E), sin(E)); + + double term2_F_phase = F * C * sin_alpha; + double term2_F_re = cos(term2_F_phase) * inv_sin_alpha - D; + double term2_F_im = + sin(term2_F_phase) * inv_sin_alpha - F * sin(C); + dcomplex term2_F = makedcomplex(term2_F_re, term2_F_im); + // k-term vanishes when computing E_phi/E_theta. + double term3_F = F * F - inv_sin_alpha_sqr; + + double term2_G_phase = G * C * sin_alpha; + double term2_G_re = cos(term2_G_phase) * inv_sin_alpha - D; + double term2_G_im = + sin(term2_G_phase) * inv_sin_alpha - G * sin(C); + dcomplex term2_G = makedcomplex(term2_G_re, term2_G_im); + // k-term vanishes when computing E_phi/E_theta. + double term3_G = G * G - inv_sin_alpha_sqr; + + dcomplex Gamma1 = (-term1 * term2_G) / term3_G; + dcomplex Gamma2 = (-term1 * term2_F) / term3_F; + dcomplex Gamma3 = (-conj(term1) * term2_G) / term3_G; + dcomplex Gamma4 = (-conj(term1) * term2_F) / term3_F; + + // mu = 1e-7 * 4.0 * pi --> mu / (4 * pi) = 1e-7 + double H = (1e-7 * inv_sin_alpha) * omega; + dcomplex E_phi = + H * (N * Gamma1 - M * Gamma2 - N * Gamma3 + M * Gamma4); + dcomplex E_theta = H * I * (Gamma1 + Gamma2 - Gamma3 - Gamma4); + + *(E_theta_re) = real(E_theta); + *(E_theta_im) = imag(E_theta); + ++E_theta_re; + ++E_theta_im; + + *(E_phi_re) = real(E_phi); + *(E_phi_im) = imag(E_phi); + ++E_phi_re; + ++E_phi_im; + + freq += request.stepX(); + } + } + ++az; ++el; + } +} + + +} //# namespace BBS +} //# namespace LOFAR diff --git a/CEP/BB/BBSKernel/src/MNS/MeqExpr.cc b/CEP/BB/BBSKernel/src/MNS/MeqExpr.cc index adc4826e0c766d2cd4473193ce69da67db47526e..b50fe54528c789397b10c3642454f6e33931da3c 100644 --- a/CEP/BB/BBSKernel/src/MNS/MeqExpr.cc +++ b/CEP/BB/BBSKernel/src/MNS/MeqExpr.cc @@ -80,6 +80,12 @@ void MeqExprRep::removeChild(MeqExpr child) itsChildren.erase(it); } +MeqExpr MeqExprRep::getChild(size_t index) +{ + ASSERT(index < itsChildren.size()); + return itsChildren[index]; +} + int MeqExprRep::setLevel (int level) { if (level < itsMinLevel) itsMinLevel = level; diff --git a/CEP/BB/BBSKernel/src/MNS/MeqRequest.cc b/CEP/BB/BBSKernel/src/MNS/MeqRequest.cc index 96748f66cf7f8d37b1a1f0b7e92a9b771a682afe..de0a9fc44c83d473ca29ec397ca8f62bb7925b44 100644 --- a/CEP/BB/BBSKernel/src/MNS/MeqRequest.cc +++ b/CEP/BB/BBSKernel/src/MNS/MeqRequest.cc @@ -35,9 +35,9 @@ MeqRequestId MeqRequest::theirRequestId = 0; MeqRequest::MeqRequest (const MeqDomain& domain, int nx, int ny, int nrSpid) : itsRequestId (theirRequestId++), - itsOffset (0, 0), itsSourceNr (0), - itsNspids (nrSpid) + itsNspids (nrSpid), + itsOffset (0, 0) { setDomain (domain, nx, ny); } @@ -46,9 +46,9 @@ MeqRequest::MeqRequest (const MeqDomain& domain, int nx, const vector<double>& y, int nrSpid) : itsRequestId (theirRequestId++), - itsOffset (0, 0), itsSourceNr (0), - itsNspids (nrSpid) + itsNspids (nrSpid), + itsOffset (0, 0) { setDomain (domain, nx, y); } @@ -57,9 +57,9 @@ MeqRequest::MeqRequest (const MeqRequest& req, uint stx, uint nrx, uint sty, uint nry) : itsRequestId (req.itsRequestId), itsStepX (req.itsStepX), - itsOffset (req.itsOffset), itsSourceNr (req.itsSourceNr), - itsNspids (req.itsNspids) + itsNspids (req.itsNspids), + itsOffset (req.itsOffset) { ASSERT (int(stx+nrx) <= req.itsNx && int(sty+nry) <= req.itsNy); itsNx = nrx; @@ -78,9 +78,9 @@ MeqRequest::MeqRequest (const MeqRequest& req) itsStepX (req.itsStepX), itsY (req.itsY), itsYP (req.itsYP), - itsOffset (req.itsOffset), itsSourceNr (req.itsSourceNr), - itsNspids (req.itsNspids) + itsNspids (req.itsNspids), + itsOffset (req.itsOffset) { if (itsY.size() > 0) { itsYP = &itsY[0]; @@ -97,9 +97,9 @@ MeqRequest& MeqRequest::operator= (const MeqRequest& req) itsStepX = req.itsStepX; itsY = req.itsY; itsYP = req.itsYP; - itsOffset = req.itsOffset; itsSourceNr = req.itsSourceNr; itsNspids = req.itsNspids; + itsOffset = req.itsOffset; if (itsY.size() > 0) { itsYP = &itsY[0]; } diff --git a/CEP/BB/BBSKernel/src/Makefile.am b/CEP/BB/BBSKernel/src/Makefile.am index f7832b58d49f93d3cf66c27a1deb1ee844e0ebec..dbbc452f318cb9a3597d585ea8506c4c84823cc7 100644 --- a/CEP/BB/BBSKernel/src/Makefile.am +++ b/CEP/BB/BBSKernel/src/Makefile.am @@ -8,10 +8,12 @@ libbbskernel_la_SOURCES = \ Prediffer.cc \ VisData.cc \ VisSelection.cc \ + MNS/MeqAzEl.cc \ MNS/MeqBaseDFTPS.cc \ MNS/MeqBaseLinPS.cc \ MNS/MeqDFTPS.cc \ MNS/MeqDiag.cc \ + MNS/MeqDipoleBeam.cc \ MNS/MeqDomain.cc \ MNS/MeqExpr.cc \ MNS/MeqFunklet.cc \ diff --git a/CEP/BB/BBSKernel/src/Model.cc b/CEP/BB/BBSKernel/src/Model.cc index 81388df57d58bc0a282f61a4d8c824d20c2c9c00..bd5fa25e4dd6b18289d6c8f35025fdf9a99f644f 100644 --- a/CEP/BB/BBSKernel/src/Model.cc +++ b/CEP/BB/BBSKernel/src/Model.cc @@ -35,6 +35,8 @@ #include <BBSKernel/MNS/MeqJonesCMul3.h> #include <BBSKernel/MNS/MeqJonesSum.h> #include <BBSKernel/MNS/MeqJonesVisData.h> +#include <BBSKernel/MNS/MeqAzEl.h> +#include <BBSKernel/MNS/MeqDipoleBeam.h> #include <BBSKernel/MNS/MeqStation.h> #include <BBSKernel/MNS/MeqStatUVW.h> @@ -89,17 +91,14 @@ void Model::makeEquations(EquationType type, const vector<string> &components, mask[GAIN] = true; else if(*it == "DIRECTIONAL_GAIN") mask[DIRECTIONAL_GAIN] = true; + else if(*it == "DIPOLE_BEAM") + mask[DIPOLE_BEAM] = true; else if(*it == "BANDPASS") mask[BANDPASS] = true; else if(*it == "PHASORS") mask[PHASORS] = true; } -/* - if(mask{GAIN] && mask[DIRECTIONAL_GAIN]) - LOG_WARN("Model components GAIN and DIRECTIONAL_GAIN are mutually" - " exclusive; using GAIN only."); -*/ - + string part1("real:"); string part2("imag:"); if(mask[PHASORS]) @@ -121,19 +120,42 @@ void Model::makeEquations(EquationType type, const vector<string> &components, size_t nStations = itsStationNodes.size(); size_t nSources = itsSourceNodes.size(); + ASSERT(nStations > 0 && nSources > 0); + + vector<MeqExpr> azel(nSources); vector<MeqExpr> dft(nStations * nSources); - vector<MeqJonesExpr> gain, inv_gain, bandpass; + vector<MeqJonesExpr> bandpass, gain, dir_gain, dipole_beam; if(mask[BANDPASS]) + { bandpass.resize(nStations); + } + + if(mask[GAIN]) + { + gain.resize(nStations); + } + + if(mask[DIRECTIONAL_GAIN]) + { + dir_gain.resize(nStations * nSources); + } - if(mask[GAIN] || mask[DIRECTIONAL_GAIN]) + if(mask[DIPOLE_BEAM]) { - inv_gain.resize(nStations); - if(mask[GAIN]) - gain.resize(nStations); - else - gain.resize(nStations * nSources); + // Make an E-jones expression per source. For now, we use the instrument + // position as reference position on earth. In the future, we will need + // an E-jones expression per source, _per station_. + azel.resize(nSources); + dipole_beam.resize(nSources); + for(size_t i = 0; i < nSources; ++i) + { + azel[i] = + new MeqAzEl(*(itsSourceNodes[i]), *(itsStationNodes[i].get())); + + dipole_beam[i] = new MeqDipoleBeam(azel[i], 1.706, 1.38, + casa::C::pi / 4.001, -casa::C::pi_4); + } } for(size_t i = 0; i < nStations; ++i) @@ -153,13 +175,13 @@ void Model::makeEquations(EquationType type, const vector<string> &components, MeqExpr B22(MeqParmFunklet::create("bandpass:22:" + suffix, parmGroup, instrumentDBase)); - bandpass[i] = new MeqDiag(MeqExpr(B11), MeqExpr(B22)); + bandpass[i] = new MeqDiag(B11, B22); } // Make a complex gain expression per station and possibly per source. if(mask[GAIN]) { - MeqExprRep *J11, *J12, *J21, *J22; + MeqExpr J11, J12, J21, J22; string suffix = itsStationNodes[i]->getName(); // Make a J-jones expression per station @@ -195,17 +217,17 @@ void Model::makeEquations(EquationType type, const vector<string> &components, J22 = new MeqExprToComplex(J22_part1, J22_part2); } - gain[i] = new MeqJonesNode(MeqExpr(J11), MeqExpr(J12), - MeqExpr(J21), MeqExpr(J22)); - inv_gain[i] = new MeqJonesInvert(gain[i]); + gain[i] = new MeqJonesNode(J11, J12, J21, J22); +// inv_gain[i] = new MeqJonesInvert(gain[i]); } - else if(mask[DIRECTIONAL_GAIN]) + + if(mask[DIRECTIONAL_GAIN]) { // Make a J-jones expression per station per source. Eventually, // patches of several sources will be supported as well. for(size_t j = 0; j < nSources; ++j) { - MeqExprRep *J11, *J12, *J21, *J22; + MeqExpr J11, J12, J21, J22; string suffix = itsStationNodes[i]->getName() + ":" + itsSourceNodes[j]->getName(); @@ -241,32 +263,96 @@ void Model::makeEquations(EquationType type, const vector<string> &components, J22 = new MeqExprToComplex(J22_part1, J22_part2); } - gain[i * nSources + j] = new MeqJonesNode(MeqExpr(J11), - MeqExpr(J12), MeqExpr(J21), MeqExpr(J22)); + dir_gain[i * nSources + j] = + new MeqJonesNode(J11, J12, J21, J22); // Gain correction is always performed with respect to the // direction of the first source (patch). - if(j == 0) - inv_gain[i] = new MeqJonesInvert(gain[i * nSources]); +// if(j == 0) +// inv_gain[i] = new MeqJonesInvert(gain[i * nSources]); } } } if(type == CORRECT) { + ASSERTSTR(mask[GAIN] || mask[DIRECTIONAL_GAIN] || mask[DIPOLE_BEAM], + "Need at least one of GAIN, DIRECTIONAL_GAIN, or DIPOLE_BEAM to" + " correct for."); + + vector<MeqJonesExpr> inv_bandpass, inv_gain, inv_dir_gain; + MeqJonesExpr inv_dipole_beam; + + if(mask[BANDPASS]) + { + inv_bandpass.resize(nStations); + for(size_t i = 0; i < nStations; ++i) + { + inv_bandpass[i] = new MeqJonesInvert(bandpass[i]); + } + } + + if(mask[GAIN]) + { + inv_gain.resize(nStations); + for(size_t i = 0; i < nStations; ++i) + { + inv_gain[i] = new MeqJonesInvert(gain[i]); + } + } + + if(mask[DIRECTIONAL_GAIN]) + { + inv_dir_gain.resize(nStations); + for(size_t i = 0; i < nStations; ++i) + { + // Always correct for the first source (direction). + inv_dir_gain[i] = new MeqJonesInvert(dir_gain[i * nSources]); + } + } + + if(mask[DIPOLE_BEAM]) + { + // Always correct for the first source (direction). + inv_dipole_beam = new MeqJonesInvert(dipole_beam[0]); + } + for(set<baseline_t>::const_iterator it = baselines.begin(); it != baselines.end(); ++it) { const baseline_t &baseline = *it; - itsEquations[baseline] = new MeqJonesCMul3(inv_gain[baseline.first], - new MeqJonesVisData(buffer, baseline), + + MeqJonesExpr vis = new MeqJonesVisData(buffer, baseline); + + if(mask[BANDPASS]) + { + vis = new MeqJonesCMul3(inv_bandpass[baseline.first], vis, + inv_bandpass[baseline.second]); + } + + if(mask[GAIN]) + { + vis = new MeqJonesCMul3(inv_gain[baseline.first], vis, inv_gain[baseline.second]); + } + + if(mask[DIRECTIONAL_GAIN]) + { + vis = new MeqJonesCMul3(inv_dir_gain[baseline.first], vis, + inv_dir_gain[baseline.second]); + } + + if(mask[DIPOLE_BEAM]) + { + vis = new MeqJonesCMul3(inv_dipole_beam, vis, inv_dipole_beam); + } + + itsEquations[baseline] = vis; } } else { - for(set<baseline_t>::const_iterator it = baselines.begin(); it != baselines.end(); ++it) @@ -276,23 +362,33 @@ void Model::makeEquations(EquationType type, const vector<string> &components, vector<MeqJonesExpr> terms; for(size_t j = 0; j < nSources; ++j) { - MeqExpr base + // Phase shift (incorporates geometry and fringe stopping). + MeqExpr shift (new MeqBaseDFTPS(dft[baseline.first * nSources + j], dft[baseline.second * nSources + j], itsLMNNodes[j])); + // Point source. MeqPointSource *source = dynamic_cast<MeqPointSource*>(itsSourceNodes[j]); - MeqJonesExpr sourceTerm(new MeqBaseLinPS(base, source)); + MeqJonesExpr sourceExpr = new MeqBaseLinPS(shift, source); + + // Apply image plane effects if required. + if(mask[DIPOLE_BEAM]) + { + sourceExpr = new MeqJonesCMul3(dipole_beam[j], sourceExpr, + dipole_beam[j]); + } if(mask[DIRECTIONAL_GAIN]) { - terms.push_back - (new MeqJonesCMul3(gain[baseline.first * nSources + j], - sourceTerm, gain[baseline.second * nSources + j])); + sourceExpr = new MeqJonesCMul3 + (dir_gain[baseline.first * nSources + j], + sourceExpr, + dir_gain[baseline.second * nSources + j]); } - else - terms.push_back(sourceTerm); + + terms.push_back(sourceExpr); } MeqJonesExpr sum; @@ -301,6 +397,7 @@ void Model::makeEquations(EquationType type, const vector<string> &components, else sum = MeqJonesExpr(new MeqJonesSum(terms)); + // Apply UV-plane effects if required. if(mask[GAIN]) { sum = new MeqJonesCMul3(gain[baseline.first], sum, @@ -312,6 +409,7 @@ void Model::makeEquations(EquationType type, const vector<string> &components, sum = new MeqJonesCMul3(bandpass[baseline.first], sum, bandpass[baseline.second]); } + itsEquations[baseline] = sum; } }