diff --git a/.gitattributes b/.gitattributes index 8549437bf284fe4d17ae8dac853ee6e1f4808b1e..0952b9460ea8a922714acad2d698dc0ee1e39b59 100644 --- a/.gitattributes +++ b/.gitattributes @@ -760,7 +760,6 @@ CEP/DP3/DPPP/src/ComplexMedianFlagger2.cc -text CEP/DP3/DPPP/src/DataBuffer.cc -text CEP/DP3/DPPP/src/DataSquasher.cc -text CEP/DP3/DPPP/src/EstimateMixed.cc -text -CEP/DP3/DPPP/src/EstimateNDPPP.cc -text CEP/DP3/DPPP/src/FrequencyFlagger.cc -text CEP/DP3/DPPP/src/GaussianSource.cc -text CEP/DP3/DPPP/src/IDPPP.cc -text diff --git a/CEP/DP3/DPPP/include/DPPP/Demixer.h b/CEP/DP3/DPPP/include/DPPP/Demixer.h index 6fc90536be860b4692c9fc5267affa75a7f3bbbf..25b8258a8d695b16cbd46553d4fd2de653c07650 100644 --- a/CEP/DP3/DPPP/include/DPPP/Demixer.h +++ b/CEP/DP3/DPPP/include/DPPP/Demixer.h @@ -193,7 +193,7 @@ namespace LOFAR { casa::Vector<double> itsFreqDemix; casa::Vector<double> itsFreqSubtr; vector<double> itsUnknowns; - vector<double> itsLastKnowns; + vector<double> itsPrevSolution; uint itsTimeIndex; uint itsNConverged; diff --git a/CEP/DP3/DPPP/src/DPInfo.cc b/CEP/DP3/DPPP/src/DPInfo.cc index 3901be35654abb9bd7eae13c23d688d07156e9c5..d1b9496ef08586af93bba2e299d680ade867d503 100644 --- a/CEP/DP3/DPPP/src/DPInfo.cc +++ b/CEP/DP3/DPPP/src/DPInfo.cc @@ -129,9 +129,9 @@ namespace LOFAR { itsAntUsed.reserve (itsAntNames.size()); for (uint i=0; i<itsAntMap.size(); ++i) { if (itsAntMap[i] == 0) { - itsAntMap[i] = itsAntUsed.size(); + itsAntMap[i] = itsAntUsed.size(); itsAntUsed.push_back (i); - } + } } } diff --git a/CEP/DP3/DPPP/src/Demixer.cc b/CEP/DP3/DPPP/src/Demixer.cc index 390664d89184392a0ceae60b6ca7380768e1ba74..abb217c53443bbe892c1773e95ec560772174f6b 100644 --- a/CEP/DP3/DPPP/src/Demixer.cc +++ b/CEP/DP3/DPPP/src/Demixer.cc @@ -268,18 +268,26 @@ namespace LOFAR { // Handle possible data selection. itsFilter.setInfo (infoIn); const DPInfo& infoSel = itsFilter.getInfo(); + // NB. The number of baselines and stations refer to the number of + // selected baselines and the number of unique stations that participate + // in the selected baselines. itsNBl = infoSel.nbaselines(); + itsNStation = infoSel.antennaUsed().size(); + + // Re-number the station IDs in the selected baselines, removing gaps in + // the numbering due to unused stations. + const vector<int> &antennaMap = infoSel.antennaMap(); + for (uint i=0; i<itsNBl; ++i) { + itsBaselines.push_back(Baseline(antennaMap[infoSel.getAnt1()[i]], + antennaMap[infoSel.getAnt2()[i]])); + } + + // Allocate buffers used to compute the smearing factors. itsFactorBuf.resize (IPosition(4, itsNCorr, itsNChanIn, itsNBl, itsNDir*(itsNDir-1)/2)); itsFactorBufSubtr.resize (IPosition(4, itsNCorr, itsNChanIn, itsNBl, itsNDir*(itsNDir-1)/2)); - for (uint i=0; i<itsNBl; ++i) { - itsBaselines.push_back (Baseline(infoSel.getAnt1()[i], - infoSel.getAnt2()[i])); - } - // Get nr of stations actually used. - ///itsNStation = infoSel.antennaUsed().size(); - itsNStation = infoSel.antennaNames().size(); + // Adapt averaging to available nr of channels and times. // Use a copy of the DPInfo, otherwise it is updated multiple times. DPInfo infoDemix(infoSel); @@ -321,9 +329,9 @@ namespace LOFAR { // Intialize the unknowns. itsUnknowns.resize(itsNTimeDemix * itsNModel * itsNStation * 8); - itsLastKnowns.resize(itsNModel * itsNStation * 8); - vector<double>::iterator it = itsLastKnowns.begin(); - vector<double>::iterator it_end = itsLastKnowns.end(); + itsPrevSolution.resize(itsNModel * itsNStation * 8); + vector<double>::iterator it = itsPrevSolution.begin(); + vector<double>::iterator it_end = itsPrevSolution.end(); while(it != it_end) { *it++ = 1.0; @@ -344,11 +352,11 @@ namespace LOFAR { os << " instrumentmodel: " << itsInstrumentName << std::endl; itsSelBL.show (os); if (itsSelBL.hasSelection()) { - os << " demixing " << itsFilter.getInfo().nbaselines() - << " out of " << getInfo().nbaselines() << " baselines (" - << itsFilter.getInfo().antennaUsed().size() - << " out of " << getInfo().antennaUsed().size() - << " stations)" << std::endl; + os << " demixing " << itsFilter.getInfo().nbaselines() + << " out of " << getInfo().nbaselines() << " baselines (" + << itsFilter.getInfo().antennaUsed().size() + << " out of " << getInfo().antennaUsed().size() + << " stations)" << std::endl; } os << " targetsource: " << itsTargetSource << std::endl; os << " subtractsources: " << itsSubtrSources << std::endl; @@ -463,51 +471,12 @@ namespace LOFAR { // Estimate gains and subtract source contributions when sufficient time // slots have been collected. if (itsNTimeOut == itsNTimeChunk) { - handleDemix(); + handleDemix(); } itsTimer.stop(); return true; } - void Demixer::handleDemix() - { - if(itsNModel > 0) { - itsTimerSolve.start(); - demix(); - itsTimerSolve.stop(); - // If selection was done, merge the subtract results back into the - // buffer. - if (itsSelBL.hasSelection()) { - mergeSubtractResult(); - } - } - - // Clear the input buffers. - for (size_t i=0; i<itsAvgResults.size(); ++i) { - itsAvgResults[i]->clear(); - } - // Let the next step process the data. - for (uint i=0; i<itsNTimeOutSubtr; ++i) { - itsTimer.stop(); - if (itsSelBL.hasSelection()) { - getNextStep()->process (itsAvgResultFull->get()[i]); - } else { - getNextStep()->process (itsAvgResultSubtr->get()[i]); - } - itsTimer.start(); - } - - // Clear the output buffer. - itsAvgResultFull->clear(); - itsAvgResultSubtr->clear(); - - // Reset counters. - itsNTimeIn = 0; - itsNTimeOut = 0; - itsNTimeOutSubtr = 0; - itsTimeIndex += itsNTimeChunk; - } - void Demixer::finish() { itsTimer.start(); @@ -544,7 +513,7 @@ namespace LOFAR { itsFactorsSubtr.resize(itsNTimeOutSubtr); // Demix the source directions. - handleDemix(); + handleDemix(); } // Write solutions to disk in ParmDB format. @@ -558,6 +527,45 @@ namespace LOFAR { getNextStep()->finish(); } + void Demixer::handleDemix() + { + if(itsNModel > 0) { + itsTimerSolve.start(); + demix(); + itsTimerSolve.stop(); + // If selection was done, merge the subtract results back into the + // buffer. + if (itsSelBL.hasSelection()) { + mergeSubtractResult(); + } + } + + // Clear the input buffers. + for (size_t i=0; i<itsAvgResults.size(); ++i) { + itsAvgResults[i]->clear(); + } + // Let the next step process the data. + for (uint i=0; i<itsNTimeOutSubtr; ++i) { + itsTimer.stop(); + if (itsSelBL.hasSelection()) { + getNextStep()->process (itsAvgResultFull->get()[i]); + } else { + getNextStep()->process (itsAvgResultSubtr->get()[i]); + } + itsTimer.start(); + } + + // Clear the output buffer. + itsAvgResultFull->clear(); + itsAvgResultSubtr->clear(); + + // Reset counters. + itsNTimeIn = 0; + itsNTimeOut = 0; + itsNTimeOutSubtr = 0; + itsTimeIndex += itsNTimeChunk; + } + void Demixer::mergeSubtractResult() { // Merge the selected baselines from the subtract buffer into the @@ -824,24 +832,20 @@ namespace LOFAR { const size_t nCr = 4; const size_t nSamples = nBl * nCh * nCr; - ///for (uint j=0; j<nTimeSubtr; ++j) { - ///cout << itsAvgResultSubtr->get()[j].getData()<<endl; - /// cout << itsAvgResultSubtr->get()[j].getFlags()<<endl; - /// cout << itsAvgResultSubtr->get()[j].getWeights()<<endl; - /// cout << itsAvgResultSubtr->get()[j].getUVW()<<endl; - ///} - ///for (uint i=0; i<itsFactors.size(); ++i) { - /// cout << itsFactors[i] << endl; - ///} - ///for (uint i=0; i<itsFactorsSubtr.size(); ++i) { - /// cout << itsFactorsSubtr[i] << endl; - ///} - vector<ThreadPrivateStorage> threadStorage(nThread); for(vector<ThreadPrivateStorage>::iterator it = threadStorage.begin(), end = threadStorage.end(); it != end; ++it) { initThreadPrivateStorage(*it, nDr, nSt, nBl, nCh, nChSubtr); + + // Copy the previous solution to the thread private vectors of unknowns. + // When solution propagation is disabled, itsPrevSolution is never + // updated. It then contains 1.0+0.0i for the diagonal terms and + // 0.0+0.0i for the off-diagonal terms. Thus, when solution propagation + // is disabled this statement effectively re-initializes the thread + // private vectors of unknowns. + copy(itsPrevSolution.begin(), itsPrevSolution.end(), + it->unknowns.begin()); } const_cursor<double> cr_freq = casa_const_cursor(itsFreqDemix); @@ -853,11 +857,14 @@ namespace LOFAR { { const size_t thread = OpenMP::threadNum(); ThreadPrivateStorage &storage = threadStorage[thread]; - // Copy solutions from global solution array to thread private solution - // array (solution propagation between chunks). - if (!itsPropagateSolutions || ts==0) { - copy(itsLastKnowns.begin(), itsLastKnowns.end(), storage.unknowns.begin()); - } + + // If solution propagation is disabled, re-initialize the thread-private + // vector of unknowns. + if(!itsPropagateSolutions) + { + copy(itsPrevSolution.begin(), itsPrevSolution.end(), + storage.unknowns.begin()); + } // Simulate. // @@ -1009,7 +1016,7 @@ namespace LOFAR { { copy(&(itsUnknowns[(itsTimeIndex + nTime - 1) * nDr * nSt * 8]), &(itsUnknowns[(itsTimeIndex + nTime) * nDr * nSt * 8]), - itsLastKnowns.begin()); + itsPrevSolution.begin()); } // Update convergence count. @@ -1041,30 +1048,40 @@ namespace LOFAR { resolution[1] = itsTimeIntervalAvg; parmDB.setDefaultSteps(resolution); + // Map station indices in the solution array to the corresponding antenna + // names. This is required because solutions are only produced for + // stations that participate in one or more baselines. Due to the baseline + // selection or missing baselines, solutions may be available for less + // than the total number of station available in the observation. + const DPInfo &info = itsFilter.getInfo(); + const vector<int> &antennaUsed = info.antennaUsed(); + const Vector<String> &antennaNames = info.antennaNames(); + vector<BBS::Parm> parms; for(size_t dr = 0; dr < itsNModel; ++dr) { - for(size_t st = 0; st < getInfo().antennaNames().size(); ++st) { - string suffix (string(getInfo().antennaNames()[st]) + ':' + - itsAllSources[dr]); - parms.push_back(BBS::Parm(parmCache, parmSet.addParm(parmDB, - "DirectionalGain:0:0:Real:" + suffix))); - parms.push_back(BBS::Parm(parmCache, parmSet.addParm(parmDB, - "DirectionalGain:0:0:Imag:" + suffix))); - - parms.push_back(BBS::Parm(parmCache, parmSet.addParm(parmDB, - "DirectionalGain:0:1:Real:" + suffix))); - parms.push_back(BBS::Parm(parmCache, parmSet.addParm(parmDB, - "DirectionalGain:0:1:Imag:" + suffix))); - - parms.push_back(BBS::Parm(parmCache, parmSet.addParm(parmDB, - "DirectionalGain:1:0:Real:" + suffix))); - parms.push_back(BBS::Parm(parmCache, parmSet.addParm(parmDB, - "DirectionalGain:1:0:Imag:" + suffix))); - - parms.push_back(BBS::Parm(parmCache, parmSet.addParm(parmDB, - "DirectionalGain:1:1:Real:" + suffix))); - parms.push_back(BBS::Parm(parmCache, parmSet.addParm(parmDB, - "DirectionalGain:1:1:Imag:" + suffix))); + for(size_t st = 0; st < itsNStation; ++st) { + string suffix(string(antennaNames[antennaUsed[st]]) + ':' + + itsAllSources[dr]); + + parms.push_back(BBS::Parm(parmCache, parmSet.addParm(parmDB, + "DirectionalGain:0:0:Real:" + suffix))); + parms.push_back(BBS::Parm(parmCache, parmSet.addParm(parmDB, + "DirectionalGain:0:0:Imag:" + suffix))); + + parms.push_back(BBS::Parm(parmCache, parmSet.addParm(parmDB, + "DirectionalGain:0:1:Real:" + suffix))); + parms.push_back(BBS::Parm(parmCache, parmSet.addParm(parmDB, + "DirectionalGain:0:1:Imag:" + suffix))); + + parms.push_back(BBS::Parm(parmCache, parmSet.addParm(parmDB, + "DirectionalGain:1:0:Real:" + suffix))); + parms.push_back(BBS::Parm(parmCache, parmSet.addParm(parmDB, + "DirectionalGain:1:0:Imag:" + suffix))); + + parms.push_back(BBS::Parm(parmCache, parmSet.addParm(parmDB, + "DirectionalGain:1:1:Real:" + suffix))); + parms.push_back(BBS::Parm(parmCache, parmSet.addParm(parmDB, + "DirectionalGain:1:1:Imag:" + suffix))); } } diff --git a/CEP/DP3/DPPP/src/EstimateNDPPP.cc b/CEP/DP3/DPPP/src/EstimateNDPPP.cc deleted file mode 100644 index a2cad2d85462ba8cbc1df02b2e797b3782248ac1..0000000000000000000000000000000000000000 --- a/CEP/DP3/DPPP/src/EstimateNDPPP.cc +++ /dev/null @@ -1,860 +0,0 @@ -//# EstimateNDPPP.cc: NDPPP specific variant of BBS estimation routines. -//# -//# Copyright (C) 2012 -//# 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 <DPPP/EstimateNDPPP.h> -#include <BBSKernel/EstimateUtil.h> - -namespace LOFAR -{ -namespace DPPP -{ -using namespace BBS; - -namespace -{ - // State kept for a single cell in the solution grid. - struct Cell - { - // LSQ solver and current estimates for the coefficients. - casa::LSQFit solver; - vector<double> coeff; - }; - - template <typename T_SAMPLE_MODIFIER> - struct SampleProcessorComplex; - - JonesMatrix mix(const vector<JonesMatrix> &in, - const vector<casa::Array<casa::DComplex> > &coeff, - unsigned int target, - unsigned int nsources, - unsigned int baseline); - - void mix(const vector<JonesMatrix> &in, vector<JonesMatrix> &out, - const vector<casa::Array<casa::DComplex> > &coeff, - const Location &start, const Location &end, unsigned int baseline); - - FlagArray mergeFlags(const vector<JonesMatrix> &in); - void mixAndMerge(const Matrix &factor, const Element &in, Element &out); - - Matrix makeMixingFactor(const vector<casa::Array<casa::DComplex> > &coeff, - const Location &start, const Location &end, unsigned int baseline, - unsigned int correlation, unsigned int row, unsigned int column); - - void subtract2(vector<DPPP::DPBuffer> &buffer, - const vector<MeasurementExpr::Ptr> &models, - const vector<casa::Array<casa::DComplex> > &coeff, - unsigned int target, - unsigned int nsources, - const vector<pair<size_t, size_t> > &baselineMap, - const vector<pair<size_t, size_t> > &correlationMap); - - template <typename T_SAMPLE_PROCESSOR> - void equate(const Location &start, const Location &end, - const vector<vector<DPPP::DPBuffer> > &buffers, - const vector<MeasurementExpr::Ptr> &models, - const vector<casa::Array<casa::DComplex> > &coeff, - const vector<pair<size_t, size_t> > &baselineMap, - const vector<pair<size_t, size_t> > &correlationMap, - const vector<Interval<size_t> > (&cellMap)[2], - const map<PValueKey, unsigned int> &coeffMap, - vector<Cell> &cells); - - template <typename T_SAMPLE_PROCESSOR> - void equate2(const Location &start, const Location &end, size_t blIndex, - const vector<DPPP::DPBuffer> &obs, const JonesMatrix &sim, - const vector<pair<size_t, size_t> > &correlationMap, - const vector<Interval<size_t> > (&cellMap)[2], - const map<PValueKey, unsigned int> &coeffMap, - vector<Cell> &cells); - - void initCells(const Location &start, const Location &end, - const ParmGroup &solvables, size_t nCoeff, - const EstimateOptions &options, - vector<Cell> &cells); - - // Perform a single iteration for all cells in the range [\p start, \p end) - // that have not yet converged or failed, updating the coefficient values - // to the new estimates found. - // \pre The range starting at \p cell should contain exactly one Cell - // instance for each cell in the range [\p start, \p end]. - bool iterate(const Location &start, const Location &end, - const ParmGroup &solvables, const EstimateOptions &options, - vector<Cell> &cells); -} // unnamed namespace - -void estimate(const vector<vector<DPPP::DPBuffer> > &buffers, - const vector<MeasurementExpr::Ptr> &models, - const vector<casa::Array<dcomplex> > &coeff, - const BaselineSeq &baselines, - const CorrelationSeq &correlations, - const BaselineMask &baselineMask, - const CorrelationMask &correlationMask, - const Grid &visGrid, - const Grid &solGrid, - const EstimateOptions &options) -{ - // ========================================================================= - // CHECK PRECONDITIONS - // ========================================================================= - const size_t nDirections = buffers.size(); - const size_t nModels = models.size(); - { - ASSERT(nDirections >= nModels && nModels > 0); - ASSERT(int(nDirections) == coeff[0].shape()[0]); - ASSERT(int(nModels) == coeff[0].shape()[1]); - - CorrelationSeq tmp; - tmp.append(Correlation::XX); - tmp.append(Correlation::XY); - tmp.append(Correlation::YX); - tmp.append(Correlation::YY); - - for(size_t i = 0; i < nModels; ++i) - { - ASSERT(models[i]->baselines() == models.front()->baselines()); - ASSERT(models[i]->correlations() == tmp); - ASSERT(models[i]->domain().contains(visGrid.getBoundingBox())); - } - } - // ========================================================================= - - // Construct a sequence of pairs of indices of matching baselines (i.e. - // baselines common to both buffer and model). - vector<pair<size_t, size_t> > blMap; - makeIndexMap(baselines, models.front()->baselines(), baselineMask, - back_inserter(blMap)); - - // Construct a sequence of pairs of indices of matching correlations - // (i.e. correlations known by both buffer and model). - vector<pair<size_t, size_t> > crMap; - makeIndexMap(correlations, models.front()->correlations(), correlationMask, - back_inserter(crMap)); - - // Compute a mapping from cells of the solution grid to cell intervals - // in the evaluation grid. - vector<Interval<size_t> > cellMap[2]; - Interval<size_t> domain[2]; - domain[FREQ] = makeAxisMap(solGrid[FREQ], visGrid[FREQ], - back_inserter(cellMap[FREQ])); - domain[TIME] = makeAxisMap(solGrid[TIME], visGrid[TIME], - back_inserter(cellMap[TIME])); - - ParmGroup solvables; - for(size_t i = 0; i < nModels; ++i) - { - ParmGroup tmp = models[i]->solvables(); - solvables.insert(tmp.begin(), tmp.end()); - } - - // Make coefficient map. - map<PValueKey, unsigned int> coeffMap; - makeCoeffMap(solvables, inserter(coeffMap, coeffMap.begin())); - LOG_DEBUG_STR("No. of coefficients to estimate: " << coeffMap.size()); - - // Assign solution grid to solvables. - ParmManager::instance().setGrid(solGrid, solvables); - - // --------------------------------------------------------------------- - // Process each chunk of cells in a loop. - // --------------------------------------------------------------------- - - // Clip chunk size to the size of the solution grid. - size_t chunkSize = options.chunkSize() == 0 ? solGrid[TIME]->size() - : std::min(options.chunkSize(), solGrid[TIME]->size()); - - // Allocate cells. - vector<Cell> cells(solGrid[FREQ]->size() * chunkSize); - - // Compute the number of cell chunks to process. - size_t nChunks = (solGrid[TIME]->size() + chunkSize - 1) / chunkSize; - - // Process the solution grid in chunks. - for(size_t chunk = 0; chunk < nChunks; ++chunk) - { - NSTimer timerChunk, timerEquate, timerIterate; - timerChunk.start(); - - // Compute cell chunk boundaries in solution grid coordinates. - Location chunkStart(0, chunk * chunkSize); - Location chunkEnd(solGrid[FREQ]->size() - 1, - std::min(chunkStart.second + chunkSize - 1, - solGrid[TIME]->size() - 1)); - - // Adjust cell chunk boundaries to exclude those cells for which no - // visibility data is available. - chunkStart = - Location(std::max(chunkStart.first, domain[FREQ].start), - std::max(chunkStart.second, domain[TIME].start)); - chunkEnd = - Location(std::min(chunkEnd.first, domain[FREQ].end), - std::min(chunkEnd.second, domain[TIME].end)); - - // If there are no cells for which visibility data is available, - // skip the chunk. - if(chunkStart.first > chunkEnd.first - || chunkStart.second > chunkEnd.second) - { - timerChunk.stop(); - continue; - } - - // Ensure a model value is computed for all the visibility samples - // within the chunk. - Location reqStart(cellMap[FREQ][chunkStart.first].start, - cellMap[TIME][chunkStart.second].start); - Location reqEnd(cellMap[FREQ][chunkEnd.first].end, - cellMap[TIME][chunkEnd.second].end); - for(size_t i = 0; i < nModels; ++i) - { - models[i]->setEvalGrid(visGrid.subset(reqStart, reqEnd)); - } - - // Initialize a cell instance for each cell in [chunkEnd, - // chunkStart]. - initCells(chunkStart, chunkEnd, solvables, coeffMap.size(), options, - cells); - - typedef SampleProcessorComplex<SampleModifierComplex> SampleProcessor; - - bool done = false; - unsigned int nIterations = 0; - while(!done) - { - // Construct normal equations from the data and an evaluation of - // the model based on the current coefficient values. - timerEquate.start(); - equate<SampleProcessor>(chunkStart, chunkEnd, buffers, models, - coeff, blMap, crMap, cellMap, coeffMap, cells); - timerEquate.stop(); - - // Perform a single iteration. - timerIterate.start(); - done = iterate(chunkStart, chunkEnd, solvables, options, cells); - timerIterate.stop(); - - // Notify model that solvables have changed. - for(size_t i = 0; i < nModels; ++i) - { - models[i]->solvablesChanged(); - } - - // Update iteration count. - ++nIterations; - } - timerChunk.stop(); - - // Output statistics and timers. - const size_t nCells = (chunkEnd.second - chunkStart.second + 1) - * (chunkEnd.first - chunkStart.first + 1); - LOG_DEBUG_STR("chunk: " << (chunk + 1) << "/" << nChunks - << " cells: " << nCells << " iterations: " << nIterations); - LOG_DEBUG_STR("\ttimers: all: " << toString(timerChunk) - << " equate: " << toString(timerEquate) << " iterate: " - << toString(timerIterate) << " total/count/average"); - - // Propagate solutions to the next chunk if required. - if(options.propagate() && (chunk + 1) < nChunks) - { - Location srcStart(0, chunk * chunkSize); - Location srcEnd(solGrid[FREQ]->size() - 1, - srcStart.second + chunkSize - 1); - - Location destStart(0, (chunk + 1) * chunkSize); - Location destEnd(solGrid[FREQ]->size() - 1, - std::min(destStart.second + chunkSize - 1, - solGrid[TIME]->size() - 1)); - - passCoeff(solvables, srcStart, srcEnd, destStart, destEnd); - } - } -} - -void subtract(vector<DPPP::DPBuffer> &buffer, - const vector<BBS::MeasurementExpr::Ptr> &models, - const vector<casa::Array<casa::DComplex> > &coeff, - const BBS::BaselineSeq &baselines, - const BBS::CorrelationSeq &correlations, - const BBS::BaselineMask &baselineMask, - const BBS::CorrelationMask &correlationMask, - const BBS::Grid &visGrid, - unsigned int target, - unsigned int nsources) -{ - // ========================================================================= - // CHECK PRECONDITIONS - // ========================================================================= - { - ASSERT(nsources <= models.size()); - ASSERT(buffer.size() > 0); - ASSERT(int(target) < coeff[0].shape()[1]); - - CorrelationSeq tmp; - tmp.append(Correlation::XX); - tmp.append(Correlation::XY); - tmp.append(Correlation::YX); - tmp.append(Correlation::YY); - - for(size_t i = 0; i < nsources; ++i) - { - ASSERT(models[i]->baselines() == models.front()->baselines()); - ASSERT(models[i]->correlations() == tmp); - ASSERT(models[i]->domain().contains(visGrid.getBoundingBox())); - } - } - // ========================================================================= - - // Construct a sequence of pairs of indices of matching baselines (i.e. - // baselines common to both buffer and model). - vector<pair<size_t, size_t> > blMap; - makeIndexMap(baselines, models.front()->baselines(), baselineMask, - back_inserter(blMap)); - - // Construct a sequence of pairs of indices of matching correlations - // (i.e. correlations known by both buffer and model). - vector<pair<size_t, size_t> > crMap; - makeIndexMap(correlations, models.front()->correlations(), correlationMask, - back_inserter(crMap)); - - for(size_t i = 0; i < nsources; ++i) - { - models[i]->setEvalGrid(visGrid); - } - - subtract2(buffer, models, coeff, target, nsources, blMap, crMap); -} - - -namespace -{ - -template <typename T_SAMPLE_PROCESSOR> -void equate(const Location &start, const Location &end, - const vector<vector<DPPP::DPBuffer> > &buffers, - const vector<MeasurementExpr::Ptr> &models, - const vector<casa::Array<casa::DComplex> > &coeff, - const vector<pair<size_t, size_t> > &baselineMap, - const vector<pair<size_t, size_t> > &correlationMap, - const vector<Interval<size_t> > (&cellMap)[2], - const map<PValueKey, unsigned int> &coeffMap, - vector<Cell> &cells) - -{ - ASSERT(buffers.size() >= models.size()); - - const size_t nDirections = buffers.size(); - const size_t nModels = models.size(); - - vector<JonesMatrix> sim(nModels); - vector<JonesMatrix> mixed(nDirections); - - typedef vector<pair<size_t, size_t> >::const_iterator bl_iterator; - for(bl_iterator it = baselineMap.begin(), it_end = baselineMap.end(); - it != it_end; ++it) - { - // Evaluate models. - for(size_t i = 0; i < nModels; ++i) - { - sim[i] = models[i]->evaluate(it->second); - } - - // Mix - Location visStart(cellMap[FREQ][start.first].start, - cellMap[TIME][start.second].start); - Location visEnd(cellMap[FREQ][end.first].end, - cellMap[TIME][end.second].end); - mix(sim, mixed, coeff, visStart, visEnd, it->first); - - // Flags will be equal for all mixed simulations. Skip baseline if all - // grid points are flagged. - if(sim.front().hasFlags()) - { - FlagArray flags(sim.front().flags()); - if(flags.rank() == 0 && (*flags.begin() != 0)) - { - continue; - } - } - - // Equate. - for(size_t i = 0; i < nDirections; ++i) - { - equate2<T_SAMPLE_PROCESSOR>(start, end, it->first, buffers[i], mixed[i], correlationMap, - cellMap, coeffMap, cells); - } - } // baselines -} - -template <typename T_SAMPLE_PROCESSOR> -void equate2(const Location &start, const Location &end, size_t blIndex, - const vector<DPPP::DPBuffer> &obs, const JonesMatrix &sim, - const vector<pair<size_t, size_t> > &correlationMap, - const vector<Interval<size_t> > (&cellMap)[2], - const map<PValueKey, unsigned int> &coeffMap, - vector<Cell> &cells) -{ -// // can we somehow properly clear() if nUnkowns does not change? -// // instead of using set() which reallocates? - - const unsigned int nFreq = cellMap[FREQ][end.first].end - - cellMap[FREQ][start.first].start + 1; - const unsigned int nTime = cellMap[TIME][end.second].end - - cellMap[TIME][start.second].start + 1; - - double *reSim = 0, *imSim = 0; - vector<unsigned int> coeffIndex(coeffMap.size()); - vector<double> reDerivative(coeffMap.size()); - vector<double> imDerivative(coeffMap.size()); - vector<double*> reSimDerivative(coeffMap.size(), 0); - vector<double*> imSimDerivative(coeffMap.size(), 0); - - typedef vector<pair<size_t, size_t> >::const_iterator cr_iterator; - for(cr_iterator cr_it = correlationMap.begin(), cr_end = correlationMap.end(); - cr_it != cr_end; ++cr_it) - { - const Element element = sim.element(cr_it->second); - if(element.size() <= 1) - { - continue; - } - - const size_t nCoeff = element.size() - 1; - - // ----------------------------------------------------------------- - // Setup pointers and strides to access the model value and - // derivatives. - // ----------------------------------------------------------------- - Matrix sim(element.value()); - ASSERT(sim.isComplex() && sim.isArray() - && static_cast<unsigned int>(sim.nx()) == nFreq - && static_cast<unsigned int>(sim.ny()) == nTime); - sim.dcomplexStorage(reSim, imSim); - - size_t i = 0; - for(Element::const_iterator el_it = element.begin(), - el_end = element.end(); el_it != el_end; ++el_it, ++i) - { - // Look-up coefficient index for this coefficient. - map<PValueKey, unsigned int>::const_iterator coeff_it = - coeffMap.find(el_it->first); - ASSERT(coeff_it != coeffMap.end()); - coeffIndex[i] = coeff_it->second; - - // Get pointers to the real and imaginary part of the partial - // derivarive of the model with respect to this coefficient. - Matrix derivative(el_it->second); - ASSERT(derivative.isComplex() && derivative.isArray() - && static_cast<unsigned int>(derivative.nx()) == nFreq - && static_cast<unsigned int>(derivative.ny()) == nTime); - derivative.dcomplexStorage(reSimDerivative[i], imSimDerivative[i]); - } - - size_t offset[2]; - offset[FREQ] = cellMap[FREQ][start.first].start; - offset[TIME] = cellMap[TIME][start.second].start; - - vector<Cell>::iterator cell = cells.begin(); - for(CellIterator it(start, end); !it.atEnd(); ++it, ++cell) - { - if(cell->solver.isReady()) - { - // Skip cell if it is inactive (converged or failed). - continue; - } - - const Interval<size_t> &freqInterval = cellMap[FREQ][it->first]; - const Interval<size_t> &timeInterval = cellMap[TIME][it->second]; - - size_t index = (timeInterval.start - offset[TIME]) * nFreq - + (freqInterval.start - offset[FREQ]); - - for(size_t t = timeInterval.start; t <= timeInterval.end; ++t) - { - const DPPP::DPBuffer &buffer = obs[t]; - - for(size_t f = freqInterval.start; f <= freqInterval.end; ++f) - { - const bool &flagged = buffer.getFlags()(cr_it->first, f, blIndex); - if(!flagged) - { - for(size_t i = 0; i < nCoeff; ++i) - { - reDerivative[i] = reSimDerivative[i][index]; - imDerivative[i] = imSimDerivative[i][index]; - } - - const fcomplex &vis = buffer.getData()(cr_it->first, f, blIndex); - const float &weight = buffer.getWeights()(cr_it->first, f, blIndex); - - T_SAMPLE_PROCESSOR::process(*cell, weight, real(vis), - imag(vis), reSim[index], imSim[index], nCoeff, - &(reDerivative[0]), &(imDerivative[0]), - &(coeffIndex[0])); - } - - ++index; - } - - index -= (freqInterval.end - freqInterval.start + 1); - index += nFreq; - } - } - } -} - -void subtract2(vector<DPPP::DPBuffer> &buffer, - const vector<MeasurementExpr::Ptr> &models, - const vector<casa::Array<casa::DComplex> > &coeff, - unsigned int target, - unsigned int nsources, - const vector<pair<size_t, size_t> > &baselineMap, - const vector<pair<size_t, size_t> > &correlationMap) -{ - vector<JonesMatrix> sim(nsources); - - typedef vector<pair<size_t, size_t> >::const_iterator - index_map_iterator; - - for(index_map_iterator bl_it = baselineMap.begin(), - bl_end = baselineMap.end(); bl_it != bl_end; ++bl_it) - { - // Evaluate models. - for(unsigned int i = 0; i < nsources; ++i) - { - sim[i] = models[i]->evaluate(bl_it->second); - } - - // Mix - JonesMatrix mixed = mix(sim, coeff, target, nsources, bl_it->first); - - // Subtract. - for(index_map_iterator cr_it = correlationMap.begin(), - cr_end = correlationMap.end(); cr_it != cr_end; ++cr_it) - { - Matrix crMixed = mixed.element(cr_it->second).value(); - ASSERT(!crMixed.isNull()); - - const unsigned int nFreq = crMixed.nx(); - const unsigned int nTime = crMixed.ny(); - ASSERT(crMixed.isComplex() && crMixed.isArray()); - ASSERTSTR(nTime == buffer.size(), "nTime: " << nTime << " buffer size: " << buffer.size()); - - const double *mixed_re = 0, *mixed_im = 0; - crMixed.dcomplexStorage(mixed_re, mixed_im); - - for(vector<DPBuffer>::iterator buffer_it = buffer.begin(), - buffer_end = buffer.end(); buffer_it != buffer_end; - ++buffer_it) - { - casa::Cube<casa::Complex> &data = buffer_it->getData(); - ASSERT(data.shape()(1) == int(nFreq)); - - for(size_t i = 0; i < nFreq; ++i) - { - data(cr_it->first, i, bl_it->first) -= - makedcomplex(*mixed_re++, *mixed_im++); - } // frequency - } // time - } // correlations - } // baselines -} - -JonesMatrix mix(const vector<JonesMatrix> &in, - const vector<casa::Array<casa::DComplex> > &coeff, - unsigned int target, - unsigned int nsources, - unsigned int baseline) -{ - const unsigned int nFreq = coeff.front().shape()(3); - const unsigned int nTime = coeff.size(); - - ASSERT(nFreq >= 1 && nTime >= 1); - const Location start(0, 0); - const Location end(nFreq - 1, nTime - 1); - - Matrix out[4]; - for(unsigned int i = 0; i < nsources; ++i) - { - for(unsigned int correlation = 0; correlation < 4; ++correlation) - { - // Exchanged target and i, because we want the effect of - // direction i on the target direction. - Matrix weight = makeMixingFactor(coeff, start, end, baseline, - correlation, target, i); - - const Matrix sim = in[i].element(correlation).value(); - - ASSERTSTR(sim.nx() == weight.nx(), "sim: " << sim.nx() << " weight: " << weight.nx()); - ASSERTSTR(sim.ny() == weight.ny(), "sim: " << sim.ny() << " weight: " << weight.ny()); - if(out[correlation].isNull()) - { - out[correlation] = weight * sim; - } - else - { - out[correlation] += weight * sim; - } - } // correlations - } // nsources - - JonesMatrix result(out[0], out[1], out[2], out[3]); - result.setFlags(mergeFlags(in)); - return result; -} - -void mix(const vector<JonesMatrix> &in, vector<JonesMatrix> &out, - const vector<casa::Array<casa::DComplex> > &coeff, - const Location &start, const Location &end, unsigned int baseline) -{ - // dims array: ndir x nmodel x ncorr x nchan x nbl (minor -> major). - // better dims: nbl x ncorr x ndir x nmodel x nchan ??? - - const unsigned int nModels = in.size(); - const unsigned int nDirections = coeff[0].shape()[0]; - ASSERT(nDirections == out.size()); - ASSERT(int(nModels) == coeff[0].shape()[1]); - - FlagArray flags = mergeFlags(in); - - for(unsigned int i = 0; i < nDirections; ++i) - { - Element element[4]; - for(unsigned int j = 0; j < nModels; ++j) - { - for(unsigned int k = 0; k < 4; ++k) - { - Matrix factor = makeMixingFactor(coeff, start, end, - baseline, k, i, j); - - mixAndMerge(factor, in[j].element(k), element[k]); - } - } - - out[i] = JonesMatrix(element[0], element[1], element[2], - element[3]); - out[i].setFlags(flags); - } -} - -FlagArray mergeFlags(const vector<JonesMatrix> &in) -{ - vector<JonesMatrix>::const_iterator first = in.begin(); - vector<JonesMatrix>::const_iterator last = in.end(); - - for(; first != last && !first->hasFlags(); ++first) - { - } - - if(first == last) - { - return FlagArray(); - } - - FlagArray flags = first->flags().clone(); - ++first; - - for(; first != last; ++first) - { - if(first->hasFlags()) - { - flags |= first->flags(); - } - } - - return flags; -} - -void mixAndMerge(const Matrix &factor, const Element &in, Element &out) -{ - // Update value. - Matrix value = out.value(); - if(value.isNull()) - { - out.assign(factor * in.value()); - } - else - { - value += factor * in.value(); - } - - // Update partial derivatives. - Element::const_iterator inIter = in.begin(); - Element::const_iterator inEnd = in.end(); - - Element::iterator outIter = out.begin(); - Element::iterator outEnd = out.end(); - - while(inIter != inEnd && outIter != outEnd) - { - if(outIter->first == inIter->first) - { - outIter->second += factor * inIter->second; - ++inIter; - ++outIter; - } - else if(outIter->first < inIter->first) - { - ++outIter; - } - else - { - out.assign(inIter->first, factor * inIter->second); - ++inIter; - } - } - - while(inIter != inEnd) - { - out.assign(inIter->first, factor * inIter->second); - ++inIter; - } -} - -Matrix makeMixingFactor(const vector<casa::Array<casa::DComplex> > &coeff, - const Location &start, const Location &end, unsigned int baseline, - unsigned int correlation, unsigned int row, unsigned int column) -{ - const unsigned int nFreq = end.first - start.first + 1; - const unsigned int nTime = end.second - start.second + 1; - - Matrix factor(makedcomplex(0.0, 0.0), nFreq, nTime, false); - double *re = 0, *im = 0; - factor.dcomplexStorage(re, im); - - // dims coeff: ndir x nmodel x ncorr x nchan x nbl (minor -> major). - // nmodel = nr of directions with source model (thus excl. target) - casa::IPosition index(5, row, column, correlation, 0, baseline); - for(unsigned int t = start.second; t <= end.second; ++t) - { - const casa::Array<casa::DComplex> &tmp = coeff[t]; - ASSERTSTR(tmp.shape()(3) == int(nFreq), "nFreq: " - << nFreq << ' ' << tmp.shape()); - for(index(3) = start.first; index(3) <= static_cast<int>(end.first); - ++index(3)) - { - const casa::DComplex &weight = tmp(index); - *re++ = real(weight); - *im++ = imag(weight); - } - } - - return factor; -} - -template <typename T_SAMPLE_MODIFIER> -struct SampleProcessorComplex -{ - static inline void process(Cell &cell, double weight, double reObs, - double imObs, double reSim, double imSim, unsigned int nDerivative, - double *reDerivative, double *imDerivative, - const unsigned int *index) - { - // Modify the observed and simulated data depending on the solving - // mode (complex, phase only, amplitude only). - T_SAMPLE_MODIFIER::process(weight, reObs, imObs, reSim, imSim, - reDerivative, imDerivative, nDerivative); - - if(weight == 0.0) - { - return; - } - - // Compute the residual. - double reResidual = reObs - reSim; - double imResidual = imObs - imSim; - - // Update the normal equations. - cell.solver.makeNorm(nDerivative, index, reDerivative, weight, - reResidual); - cell.solver.makeNorm(nDerivative, index, imDerivative, weight, - imResidual); - } -}; - -void initCells(const Location &start, const Location &end, - const ParmGroup &solvables, size_t nCoeff, - const EstimateOptions &options, - vector<Cell> &cells) -{ - vector<Cell>::iterator cell = cells.begin(); - for(CellIterator it(start, end); !it.atEnd(); ++it, ++cell) - { - // Initalize LSQ solver. - cell->solver = casa::LSQFit(static_cast<casa::uInt>(nCoeff)); - configLSQSolver(cell->solver, options.lsqOptions()); - - // Initialize coefficients. - cell->coeff.resize(nCoeff); - loadCoeff(*it, solvables, cell->coeff.begin()); - } -} - -bool iterate(const Location &start, const Location &end, - const ParmGroup &solvables, const EstimateOptions &options, - vector<Cell> &cells) -{ - const size_t nCellFreq = end.first - start.first + 1; - const size_t nCellTime = end.second - start.second + 1; - const size_t nCell = nCellFreq * nCellTime; - - bool done = true; -#pragma omp parallel for - for(size_t i = 0; i < nCell; ++i) - { - Cell &cell = cells[i]; - - // If processing on the cell is already done, only update the status - // counts and continue to the next cell. - if(cell.solver.isReady()) - { - continue; - } - - // Perform a single iteration if the cell has not yet converged or - // failed. - // - // LSQFit::solveLoop() only returns false if the normal - // equations are singular. This can also be seen from the result - // of LSQFit::isReady(), so we don't update the iteration status - // here but do skip the update of the solvables. - casa::uInt rank; - if(cell.solver.solveLoop(rank, &(cell.coeff[0]), - options.lsqOptions().useSVD)) - { - // Store the updated coefficient values. - storeCoeff(Location(start.first + i % nCellFreq, start.second + i - / nCellFreq), solvables, cell.coeff.begin()); - } - - if(!cell.solver.isReady()) - { - done = false; - } - } - - return done; -} - -} // unnamed namespace - -} //# namespace BBS -} //# namespace LOFAR diff --git a/CEP/DP3/DPPP/src/Filter.cc b/CEP/DP3/DPPP/src/Filter.cc index 9ab9a6274772e99ddc9750aea4493f02ffdc8812..9b4bb455897a5cd11f483f02ef27d8ac38481ae4 100644 --- a/CEP/DP3/DPPP/src/Filter.cc +++ b/CEP/DP3/DPPP/src/Filter.cc @@ -134,8 +134,8 @@ namespace LOFAR { itsTimer.start(); if (!itsDoSelect) { itsBuf = buf; // uses reference semantics - itsTimer.stop(); - getNextStep()->process (itsBuf); + itsTimer.stop(); + getNextStep()->process (itsBuf); return true; } // Make sure no other object references the DATA and UVW arrays.