diff --git a/CEP/BB/BBSControl/include/BBSControl/CommandExecutor.h b/CEP/BB/BBSControl/include/BBSControl/CommandExecutor.h index 4c491bfe26b1cf759e404369bb876849db4dae1a..11775f9eaed6f88f00b706e32167f56e6e728355 100644 --- a/CEP/BB/BBSControl/include/BBSControl/CommandExecutor.h +++ b/CEP/BB/BBSControl/include/BBSControl/CommandExecutor.h @@ -78,14 +78,11 @@ namespace LOFAR // @} // Get result of the last executed command. - const CommandResult &getResult() - { - return itsResult; - } + const CommandResult &getResult() const + { return itsResult; } - private: - bool convertTime(string in, double &out); + private: // Kernel. scoped_ptr<Prediffer> itsKernel; @@ -95,14 +92,6 @@ namespace LOFAR // Connection to the solver. shared_ptr<BlobStreamableConnection> itsSolverConnection; - // Region of interest. - int32 itsROIFrequency[2]; - double itsROITime[2]; - - // Chunk size and position (in time). - double itsChunkSize; - double itsChunkPosition; - // Result of the last executed command. CommandResult itsResult; }; diff --git a/CEP/BB/BBSControl/include/BBSControl/DomainRegistrationRequest.h b/CEP/BB/BBSControl/include/BBSControl/DomainRegistrationRequest.h index ed69ff0972353d0ffc4cbf7c07dd7b9ac3389840..b6eb8770793bc920345b9717d4840ffdcb765d7c 100644 --- a/CEP/BB/BBSControl/include/BBSControl/DomainRegistrationRequest.h +++ b/CEP/BB/BBSControl/include/BBSControl/DomainRegistrationRequest.h @@ -25,7 +25,8 @@ #define LOFAR_BBSCONTROL_DOMAINREGISTRATIONREQUEST_H // \file -// Request sent from kernel to solver to register a solve domain and set the initial values of the unknowns. +// Request sent from kernel to solver to register a solve domain and set the +// initial values of the unknowns. #include <Blob/BlobStreamable.h> @@ -34,63 +35,74 @@ namespace LOFAR { - class BlobIStream; - class BlobOStream; +class BlobIStream; +class BlobOStream; namespace BBS { // \addtogroup BBSControl // @{ - // Request sent from kernel to solver to register a solve domain and set the initial values of the - // unknowns. + // Request sent from kernel to solver to register a solve domain and set the + // initial values of the unknowns. // - // Note that the initial values are not necessary for computing a solution, because a single iteration consists - // of computing the solution to a set of linear (normal) equations (see AIPS++ note 224). However, they seem to - // be needed to check for convergence (inside LSQFit). + // Note that the initial values are not necessary for computing a solution, + // because a single iteration consists of computing the solution to a + // set of linear (normal) equations (see AIPS++ note 224). However, they + // seem to be needed to check for convergence (inside LSQFit). class DomainRegistrationRequest : public BlobStreamable { public: DomainRegistrationRequest(uint32 domainIndex = 0) : itsDomainIndex(domainIndex), + itsMaxIter(0), itsEpsilon(1e-8), - itsMaxIter(0) + itsColFactor(1e-8), + itsLMFactor(1.0), + itsBalancedEq(false) { } - - DomainRegistrationRequest(uint32 domainIndex, double epsilon, uint32 maxIter, const vector<double> &unknowns) + + DomainRegistrationRequest(uint32 domainIndex, + const vector<double> &unknowns, uint32 maxIter = 0, + double epsilon = 1e-8, double colFactor = 1e-8, + double lmFactor = 1.0, bool balancedEq = false) : itsDomainIndex(domainIndex), - itsEpsilon(epsilon), itsMaxIter(maxIter), + itsEpsilon(epsilon), + itsColFactor(colFactor), + itsLMFactor(lmFactor), + itsBalancedEq(balancedEq), itsUnknowns(unknowns) { } - + uint32 getDomainIndex() const - { - return itsDomainIndex; - } - - double getEpsilon() const - { - return itsEpsilon; - } - + { return itsDomainIndex; } + uint32 getMaxIter() const - { - return itsMaxIter; - } - + { return itsMaxIter; } + + double getEpsilon() const + { return itsEpsilon; } + + double getColFactor() const + { return itsColFactor; } + + double getLMFactor() const + { return itsLMFactor; } + + bool getBalancedEq() const + { return itsBalancedEq; } + const vector<double> &getUnknowns() const - { - return itsUnknowns; - } + { return itsUnknowns; } static const string theirClassType; - + private: - //# -------- BlobStreamable interface implementation -------- - + //# -------- BlobStreamable interface implementation -------- + // Write the contents of \c *this into the blob output stream \a bos. virtual void write(BlobOStream& bos) const; @@ -99,11 +111,14 @@ namespace BBS // Return the type of \c *this as a string. virtual const string& classType() const; - - //# -------- Attributes -------- + + //# -------- Attributes -------- uint32 itsDomainIndex; - double itsEpsilon; uint32 itsMaxIter; + double itsEpsilon; + double itsColFactor; + double itsLMFactor; + bool itsBalancedEq; vector<double> itsUnknowns; }; diff --git a/CEP/BB/BBSControl/include/BBSControl/SolverProcessControl.h b/CEP/BB/BBSControl/include/BBSControl/SolverProcessControl.h index 7f5191a591a91ae708fbb1eb131255dcc440ff9d..50f0bebcc161502c81ec9268120676402e372929 100644 --- a/CEP/BB/BBSControl/include/BBSControl/SolverProcessControl.h +++ b/CEP/BB/BBSControl/include/BBSControl/SolverProcessControl.h @@ -80,11 +80,8 @@ namespace BBS uint32 index; vector<double> unknowns; casa::LSQFit solver; - //# this attribute is only temporary, until the problems with - //# the latest version of LSQFit have been solved. - double epsilon; }; - + bool dispatch(const BlobStreamable *message); bool handle(const DomainRegistrationRequest *request); bool handle(const BlobStreamableVector<DomainRegistrationRequest> *request); @@ -93,12 +90,12 @@ namespace BBS bool registerDomain(const DomainRegistrationRequest *request); IterationResult *performIteration(const IterationRequest *request); - + // Parameter set for this process controller. ACC::APS::ParameterSet itsParameterSet; scoped_ptr<BlobStreamableConnection> itsKernelConnection; - + map<uint32, Domain> itsRegisteredDomains; }; // @} diff --git a/CEP/BB/BBSControl/src/CommandExecutor.cc b/CEP/BB/BBSControl/src/CommandExecutor.cc index fd8baac2f7592d3616ca7d39bd78e2699fa7a68f..3a7a78d1db295bddf2bc56a13983d7d6bfa147db 100644 --- a/CEP/BB/BBSControl/src/CommandExecutor.cc +++ b/CEP/BB/BBSControl/src/CommandExecutor.cc @@ -52,8 +52,21 @@ #include <Common/LofarLogger.h> #include <Common/Timer.h> -#include <casa/Quanta/Quantum.h> -#include <casa/Quanta/MVTime.h> +//#include <casa/Quanta/Quantum.h> +//#include <casa/Quanta/MVTime.h> + +#if 0 +#define NONREADY casa::LSQFit::NONREADY +#define SOLINCREMENT casa::LSQFit::SOLINCREMENT +#define DERIVLEVEL casa::LSQFit::DERIVLEVEL +#define N_ReadyCode casa::LSQFit::N_ReadyCode +#else +#define NONREADY 0 +#define SOLINCREMENT 1 +#define DERIVLEVEL 2 +#define N_ReadyCode 999 +#endif + namespace LOFAR { @@ -73,20 +86,6 @@ CommandExecutor::~CommandExecutor() } -bool CommandExecutor::convertTime(string in, double &out) -{ - //# TODO: Convert from default epoch to MS epoch (as it may differ from - //# the default!) - casa::Quantum<casa::Double> time; - - if(in.empty() || !casa::MVTime::read(time, in)) - return false; - - out = static_cast<double>(time.getValue("s")); - return true; -} - - void CommandExecutor::visit(const InitializeCommand &/*command*/) { LOG_TRACE_FLOW(AUTO_FUNCTION_NAME); @@ -98,72 +97,48 @@ void CommandExecutor::visit(const InitializeCommand &/*command*/) try { - //# Create a new kernel. + // Create a new kernel. itsKernel.reset(new Prediffer(strategy->dataSet(), +// strategy->subband(), + 0, strategy->inputData(), strategy->parmDB().localSky, strategy->parmDB().instrument, strategy->parmDB().history, - 0, +// strategy->readUVW())); false)); } - catch(Exception& e) + catch(Exception &ex) { - LOG_WARN_STR(e); + // TODO: get exception msg and put into result msg. + itsResult = CommandResult(CommandResult::ERROR, "Could not create" + " kernel."); } - //# Select stations and correlations. - if(!itsKernel->setSelection(strategy->stations(), strategy->correlation())) - { - itsResult = CommandResult(CommandResult::ERROR, - "Data selection is empty."); - return; - } - - //# Store chunk size. - itsChunkSize = strategy->domainSize().timeInterval; - - LOG_DEBUG_STR("ChunkSize: " << itsChunkSize); - - //# Get Region Of Interest. + // Create selection from information in strategy. RegionOfInterest roi = strategy->regionOfInterest(); + Correlation correlation = strategy->correlation(); - //# Get Local Data Domain. - MeqDomain ldd = itsKernel->getLocalDataDomain(); - - //# Parse and validate time selection. - bool start = false, end = false; + VisSelection selection; + if(!strategy->stations().empty()) + selection.setStations(strategy->stations()); - start = (roi.time.size() >= 1) && convertTime(roi.time[0], itsROITime[0]); - end = (roi.time.size() >= 2) && convertTime(roi.time[1], itsROITime[1]); + if(!correlation.type.empty()) + selection.setCorrelations(correlation.type); - if(start && end && itsROITime[0] > itsROITime[1]) + if(correlation.selection == "AUTO") { - LOG_WARN("Specified start/end times are incorrect; All times will" - " be selected."); - start = end = false; + selection.setBaselineFilter(VisSelection::AUTO); } + else if(correlation.selection == "CROSS") + { + selection.setBaselineFilter(VisSelection::CROSS); + } + itsKernel->setSelection(selection); - if(!start || itsROITime[0] <= ldd.startY()) - itsROITime[0] = ldd.startY(); - - if(!end || itsROITime[1] >= ldd.endY()) - itsROITime[1] = ldd.endY(); - - //# Get frequency (channel) selection. - itsROIFrequency[0] = itsROIFrequency[0] = -1; - if(roi.frequency.size() >= 1) - itsROIFrequency[0] = roi.frequency[0]; - if(roi.frequency.size() >= 2) - itsROIFrequency[1] = roi.frequency[1]; - - //# Reset chunk iteration. - itsChunkPosition = itsROITime[0]; - - LOG_DEBUG_STR("Region Of Interest:" << endl - << " + Channels: " << itsROIFrequency[0] << " - " << itsROIFrequency[1] - << endl - << " + Time: " << itsROITime[0] << " - " << itsROITime[1] << endl); + size_t size = strategy->domainSize().timeInterval; + LOG_DEBUG_STR("Chunk size: " << size << " timeslot(s)"); + itsKernel->setChunkSize(size); itsResult = CommandResult(CommandResult::OK, "Ok."); } @@ -186,33 +161,14 @@ void CommandExecutor::visit(const NextChunkCommand &/*command*/) LOG_DEBUG("Handling a NextChunkCommand"); - //# Iteration should be moved to the kernel code. Ideally, we would only - //# issue an itsKernel->nextChunk() here. However, as this is entangled with - //# the new MS interface, we'll emulate it by setting a new local work - //# domain for now. - if(itsChunkPosition >= itsROITime[1]) + if(itsKernel->nextChunk()) { - LOG_DEBUG_STR("NextChunk: OUT_OF_DATA"); - itsResult = CommandResult(CommandResult::OUT_OF_DATA); - return; - } - - double size = itsChunkSize; - if(itsChunkPosition + itsChunkSize > itsROITime[1]) - size = itsROITime[1] - itsChunkPosition; - - if(!itsKernel->setWorkDomain(static_cast<int>(itsROIFrequency[0]), - static_cast<int>(itsROIFrequency[1]), - itsChunkPosition, - size)) - { - itsResult = CommandResult(CommandResult::ERROR, - "Could not set work domain."); + itsResult = CommandResult(CommandResult::OK, "Ok."); } else { - itsChunkPosition += itsChunkSize; - itsResult = CommandResult(CommandResult::OK, "Ok."); + LOG_DEBUG_STR("NextChunk: OUT_OF_DATA"); + itsResult = CommandResult(CommandResult::OUT_OF_DATA); } } @@ -280,7 +236,7 @@ void CommandExecutor::visit(const BBSPredictStep &command) } // Execute predict. - itsKernel->predictVisibilities(); + itsKernel->predict(); itsResult = CommandResult(CommandResult::OK, "Ok."); } @@ -310,7 +266,7 @@ void CommandExecutor::visit(const BBSSubtractStep &command) } // Execute subtract. - itsKernel->subtractVisibilities(); + itsKernel->subtract(); itsResult = CommandResult(CommandResult::OK, "Ok."); } @@ -340,7 +296,7 @@ void CommandExecutor::visit(const BBSCorrectStep &command) } // Execute correct. - itsKernel->correctVisibilities(); + itsKernel->correct(); itsResult = CommandResult(CommandResult::OK, "Ok."); } @@ -365,50 +321,23 @@ void CommandExecutor::visit(const BBSSolveStep &command) context.unknowns = command.parms(); context.excludedUnknowns = command.exclParms(); - // Create solve domains. For now this just splits the work domain in a - // rectangular grid, with cells of size command.itsDomainSize. Should - // become more interesting in the near future. - const MeqDomain &workDomain = itsKernel->getWorkDomain(); - - const int freqCount = (int) ceil((workDomain.endX() - - workDomain.startX()) / command.domainSize().bandWidth); - const int timeCount = (int) ceil((workDomain.endY() - - workDomain.startY()) / command.domainSize().timeInterval); +/* + pair<size_t, size_t> domainSize(command.domainSize().bandWidth, + command.domainSize().timeInterval); - double timeOffset = workDomain.startY(); - double timeSize = command.domainSize().timeInterval; - - int time = 0; - while(time < timeCount) + if (domainSize.first != 0) { - double freqOffset = workDomain.startX(); - double freqSize = command.domainSize().bandWidth; - - if(timeOffset + timeSize > workDomain.endY()) - { - timeSize = workDomain.endY() - timeOffset; - } - - int freq = 0; - while(freq < freqCount) - { - if(freqOffset + freqSize > workDomain.endX()) - { - freqSize = workDomain.endX() - freqOffset; - } - - context.solveDomains.push_back(MeqDomain(freqOffset, - freqOffset + freqSize, - timeOffset, - timeOffset + timeSize)); + LOG_WARN_STR("Subdividing in frequency not support yet; setting" + " will be ignored."); + domainSize.first = 0; + } - freqOffset += freqSize; - freq++; - } + context.domainSize = domainSize; +*/ - timeOffset += timeSize; - time++; - } + LOG_WARN_STR("Subdivision specfication not yet implemented; using domains" + " of 1 timeslot."); + context.domainSize = make_pair(0, 1); // Set context. if(!itsKernel->setContext(context)) @@ -418,154 +347,198 @@ void CommandExecutor::visit(const BBSSolveStep &command) return; } - // Register all solve domains with the solver. - BlobStreamableVector<DomainRegistrationRequest> request; + // Get domain descriptors. const vector<SolveDomainDescriptor> &descriptors = itsKernel->getSolveDomainDescriptors(); - for(size_t i = 0; i < descriptors.size(); ++i) - { - request.getVector().push_back(new DomainRegistrationRequest( - i, - command.epsilon(), - command.maxIter(), - descriptors[i].unknowns)); - } - itsSolverConnection->sendObject(request); - // Main iteration loop. - bool finished = false; - unsigned int iteration = 1; - while(!finished) + size_t blockSize = 1; + size_t nBlocks = + ceil(descriptors.size() / static_cast<double>(blockSize)); + + vector<double> solution(descriptors.front().unknowns); + vector<casa::LSQFit> solvers(blockSize); + size_t convergedTotal = 0, stoppedTotal = 0; + for(size_t block = 0; block < nBlocks; ++block) { - LOG_DEBUG_STR("[START] Iteration: " << iteration); + pair<size_t, size_t> domainRange(block * blockSize, + (block + 1) * blockSize - 1); + if(domainRange.second >= descriptors.size()) + domainRange.second = descriptors.size() - 1; + size_t nDomains = domainRange.second - domainRange.first + 1; + + LOG_DEBUG_STR("Processing domain(s) " << domainRange.first << " - " + << domainRange.second << " (" << descriptors.size() + << " domain(s) in total)"); + LOG_DEBUG_STR("Initial values: " << solution); + + // Register all solve domains with the solver. + BlobStreamableVector<DomainRegistrationRequest> request; + for(size_t i = domainRange.first; i <= domainRange.second; ++i) + { + itsKernel->updateSolvableParms(i, solution); + request.getVector().push_back(new DomainRegistrationRequest(i, + solution, + command.maxIter(), + command.epsilon())); + } + itsSolverConnection->sendObject(request); - LOG_DEBUG_STR("[START] Generating normal equations..."); - timer.reset(); - timer.start(); + // Main iteration loop. + bool finished = false; + size_t iteration = 1, converged = 0, stopped = 0; + while(!finished) + { + LOG_DEBUG_STR("[START] Iteration: " << iteration); + LOG_DEBUG_STR("[START] Generating normal equations..."); + timer.reset(); + timer.start(); - // Generate normal equations. - vector<casa::LSQFit> equations; - itsKernel->generateEquations(equations); + // Generate normal equations. + itsKernel->generate(make_pair(0, domainRange.first), + make_pair(0, domainRange.second), solvers); - timer.stop(); - LOG_DEBUG_STR("[END ] Generating normal equations; " << timer); + timer.stop(); + LOG_DEBUG_STR("[ END ] Generating normal equations; " << timer); - LOG_DEBUG_STR("[START] Sending equations to solver and waiting for" - " results..."); - timer.reset(); - timer.start(); - // Send iteration requests to the solver in one go. - BlobStreamableVector<IterationRequest> iterationRequests; - for(size_t i = 0; i < equations.size(); ++i) - { - iterationRequests.getVector().push_back(new IterationRequest(i, - equations[i])); - } - itsSolverConnection->sendObject(iterationRequests); + LOG_DEBUG_STR("[START] Sending equations to solver and waiting" + " for results..."); + timer.reset(); + timer.start(); - BlobStreamableVector<IterationResult> *resultv = - dynamic_cast<BlobStreamableVector<IterationResult>*>( - itsSolverConnection->recvObject()); - ASSERT(resultv); + // Send iteration requests to the solver in one go. + BlobStreamableVector<IterationRequest> iterationRequests; + for(size_t i = 0; i < nDomains; ++i) + { + iterationRequests.getVector().push_back( + new IterationRequest(domainRange.first + i, + solvers[i])); + } + itsSolverConnection->sendObject(iterationRequests); - timer.stop(); - LOG_DEBUG_STR("[END ] Sending/waiting; " << timer); + BlobStreamableVector<IterationResult> *resultv = + dynamic_cast<BlobStreamableVector<IterationResult>*>( + itsSolverConnection->recvObject()); - LOG_DEBUG_STR("[START] Processing results..."); - timer.reset(); - timer.start(); + ASSERT(resultv); - const vector<IterationResult*> &results = resultv->getVector(); + timer.stop(); + LOG_DEBUG_STR("[ END ] Sending/waiting; " << timer); + LOG_DEBUG_STR("[START] Processing results..."); + timer.reset(); + timer.start(); - // For each solve domain: - // - wait for result - // - check for convergence - // - update cached values of the unknowns - unsigned int converged = 0/*, stopped = 0*/; - for(size_t i = 0; i < results.size(); ++i) - { - const IterationResult *result = results[i]; - - // Check for convergence. - if(result->getResultCode() != 0) - converged++; - -// if(result->getResultCode() != casa::LSQFit::NONREADY) -// { -// if(result->getResultCode() == casa::LSQFit::SOLINCREMENT -//|| -// result->getResultCode() == casa::LSQFit::DERIVLEVEL) -// { -// converged++; -// } -// else -// stopped++; -// } - -// LOG_DEBUG_STR("+ Domain: " << result->getDomainIndex()); - //LOG_DEBUG_STR(" + result: " << result->getResultCode() << - // ", " << result->getResultText()); -// LOG_DEBUG_STR(" + rank: " << result->getRank() << -// ", chi^2: " << result->getChiSquared() << -// ", LM factor: " << result->getLMFactor()); -// LOG_DEBUG_STR(" + unknowns: " << result->getUnknowns()); - - if(result->getResultCode() != 2) + const vector<IterationResult*> &results = resultv->getVector(); + + // For each solve domain: + // - check for convergence + // - update cached values of the unknowns + converged = stopped = 0; + for(size_t i = 0; i < results.size(); ++i) { + const IterationResult *result = results[i]; + size_t resultCode = result->getResultCode(); + + if(resultCode == NONREADY) + { + // Update cached values of the unknowns. + itsKernel->updateSolvableParms( + result->getDomainIndex(), + result->getUnknowns()); +/* + // Log the updated unknowns. + itsKernel->logIteration( + command.getName(), + startDomain + i, + result->getRank(), + result->getChiSquared(), + result->getLMFactor()); +*/ + #ifdef LOG_SOLVE_DOMAIN_STATS - LOG_DEBUG_STR("Domain: " << result->getDomainIndex() - << ", Rank: " << result->getRank() - << ", Chi^2: " << result->getChiSquared() - << ", LM factor: " << result->getLMFactor()); + LOG_DEBUG_STR("Domain: " << result->getDomainIndex() + << ", Rank: " << result->getRank() + << ", Chi^2: " << result->getChiSquared() + << ", LM factor: " << result->getLMFactor() + << ", Message: " << result->getResultText()); #endif - // Update cached values of the unknowns. - itsKernel->updateSolvableParms(i, result->getUnknowns()); - - // Log the updated unknowns. - itsKernel->logIteration( - command.getName(), - i, - result->getRank(), - result->getChiSquared(), - result->getLMFactor()); + } + else if(resultCode == SOLINCREMENT + || resultCode == DERIVLEVEL + || resultCode == N_ReadyCode) + { + converged++; + } + else + { + stopped++; + } } -#ifdef LOG_SOLVE_DOMAIN_STATS - else - LOG_DEBUG_STR("Domain: " << result->getDomainIndex() - << " - Already converged"); -#endif + + if(results.back()->getResultCode() == NONREADY) + { + // Save solution of last solve domain in this block. + solution = results.back()->getUnknowns(); + } + + delete resultv; + + timer.stop(); + LOG_DEBUG_STR("[ END ] Processing results; " << timer); + + LOG_DEBUG_STR("[ END ] Iteration: " << iteration); + + + ostringstream oss; + oss << "Block statistics: " << endl; + oss << " converged: " << converged << "/" << nDomains + << " (" << (((double) converged) / nDomains * 100.0) << "%)" + << endl; + oss << " stopped : " << stopped << "/" << nDomains + << " (" << (((double) stopped) / nDomains * 100.0) << "%)"; + LOG_DEBUG(oss.str()); + //finished = (converged + stopped == + // context.solveDomains.size()) || (converged>= + //(command.minConverged() * + //context.solveDomains.size()) / 100.0); + + finished = ((converged + stopped) == nDomains) + || (iteration == command.maxIter()); + iteration++; } - timer.stop(); - LOG_DEBUG_STR("[END ] Processing results; " << timer); - - LOG_DEBUG_STR("[END ] Iteration: " << iteration - << ", Solve domains converged: " << converged << "/" - << context.solveDomains.size() - << " (" << (((double) converged) / context.solveDomains.size() * - 100.0) << "%)"); - //LOG_INFO_STR("Solve domains stopped: " << stopped << "/" << - //context.solveDomains.size() << " (" << (((double) stopped) / - //context.solveDomains.size() * 100.0) << "%)"); - - delete resultv; - //finished = (converged + stopped == context.solveDomains.size()) || - // (converged>= (command.minConverged() * - // context.solveDomains.size()) / 100.0); - finished = (converged == context.solveDomains.size()) - || (iteration == command.maxIter()); - iteration++; - } - LOG_DEBUG_STR("[START] Writing solutions into parameter databases..."); - timer.reset(); - timer.start(); + convergedTotal += converged; + stoppedTotal += stopped; + + ostringstream oss; + oss << "Global statistics: " << endl; + oss << " converged: " << convergedTotal << "/" + << descriptors.size() << " (" + << (((double) convergedTotal) / descriptors.size() * 100.0) + << "%)" << endl; + oss << " stopped : " << stoppedTotal << "/" + << descriptors.size() << " (" + << (((double) stoppedTotal) / descriptors.size() * 100.0) + << "%)"; + LOG_DEBUG(oss.str()); + + LOG_DEBUG_STR("[START] Writing solutions into parameter" + " databases..."); + timer.reset(); + timer.start(); - itsKernel->writeParms(); + for(size_t i = domainRange.first; i <= domainRange.second; ++i) + { + itsKernel->writeParms(i); + } + + timer.stop(); + LOG_DEBUG_STR("[ END ] Writing solutions; " << timer); + } - timer.stop(); - LOG_DEBUG_STR("[END ] Writing solutions; " << timer); + // Try to force log4cplus to flush its buffers. + cout << "DONE." << endl; itsResult = CommandResult(CommandResult::OK, "Ok."); } diff --git a/CEP/BB/BBSControl/src/DomainRegistrationRequest.cc b/CEP/BB/BBSControl/src/DomainRegistrationRequest.cc index 96f9ea2bb510b7cd95943429185f873e05a4bed4..0736f89f1aa38f853a775123f2ee2fc470cfd021 100644 --- a/CEP/BB/BBSControl/src/DomainRegistrationRequest.cc +++ b/CEP/BB/BBSControl/src/DomainRegistrationRequest.cc @@ -38,7 +38,7 @@ namespace BBS using LOFAR::operator>>; const string DomainRegistrationRequest::theirClassType = "DomainRegistrationRequest"; - + // Register DomainRegistrationRequest with the BlobStreamableFactory. Use an anonymous // namespace. This ensures that the variable `dummy' gets its own private // storage area and is only visible in this compilation unit. @@ -47,14 +47,17 @@ namespace BBS bool dummy = BlobStreamableFactory::instance().registerClass<DomainRegistrationRequest>("DomainRegistrationRequest"); bool dummy_vector = BlobStreamableFactory::instance().registerClass<BlobStreamableVector<DomainRegistrationRequest> >("BlobStreamableVector<" + DomainRegistrationRequest::theirClassType + ">"); } - + void DomainRegistrationRequest::write(BlobOStream& bos) const { LOG_TRACE_LIFETIME(TRACE_LEVEL_RTTI, ""); - + bos << itsDomainIndex - << itsEpsilon << itsMaxIter + << itsEpsilon + << itsColFactor + << itsLMFactor + << itsBalancedEq << itsUnknowns; } @@ -62,10 +65,13 @@ namespace BBS void DomainRegistrationRequest::read(BlobIStream& bis) { LOG_TRACE_LIFETIME(TRACE_LEVEL_RTTI, ""); - + bis >> itsDomainIndex - >> itsEpsilon >> itsMaxIter + >> itsEpsilon + >> itsColFactor + >> itsLMFactor + >> itsBalancedEq >> itsUnknowns; } diff --git a/CEP/BB/BBSControl/src/GlobalProcessControl.cc b/CEP/BB/BBSControl/src/GlobalProcessControl.cc index eb86b36fd36fa13e36351aa51473ccf68627e45e..5dcc96e505eda13b03b266448e597f5dc7174de1 100644 --- a/CEP/BB/BBSControl/src/GlobalProcessControl.cc +++ b/CEP/BB/BBSControl/src/GlobalProcessControl.cc @@ -98,10 +98,13 @@ namespace LOFAR LOG_INFO("GlobalProcessControl::init()"); try { - // Create a new CommandQueue. This will open a connection to the - // blackboard database. - itsCommandQueue.reset - (new CommandQueue(globalParameterSet()->getString("BBDB.DBName"))); + // Create a new CommandQueue. This will open a connection to the + // blackboard database. + itsCommandQueue.reset + (new CommandQueue(globalParameterSet()->getString("BBDB.DBName"), + globalParameterSet()->getString("BBDB.UserName"), + globalParameterSet()->getString("BBDB.Host"), + globalParameterSet()->getString("BBDB.Port"))); // Register for the "result" trigger, which fires when a new result is // posted to the blackboard database. diff --git a/CEP/BB/BBSControl/src/KernelProcessControl.cc b/CEP/BB/BBSControl/src/KernelProcessControl.cc index 61f5f91fccfe2cbf389ed2cd8447b734af304f26..bf0c5ba98bd805dd37caf4dc9ed146858608767a 100644 --- a/CEP/BB/BBSControl/src/KernelProcessControl.cc +++ b/CEP/BB/BBSControl/src/KernelProcessControl.cc @@ -126,7 +126,10 @@ namespace BBS // Create a new CommandQueue. This will open a connection to the // blackboard database. itsCommandQueue.reset(new CommandQueue( - globalParameterSet()->getString("BBDB.DBName"))); + globalParameterSet()->getString("BBDB.DBName"), + globalParameterSet()->getString("BBDB.UserName"), + globalParameterSet()->getString("BBDB.Host"), + globalParameterSet()->getString("BBDB.Port"))); // Register for the "command" trigger, which fires when a new // command is posted to the blackboard database. diff --git a/CEP/BB/BBSControl/src/SolverProcessControl.cc b/CEP/BB/BBSControl/src/SolverProcessControl.cc index 9874903653982073de712c5ea2d07998414e9de3..103e42484a4bf4f5623fc5eb10a912780462379b 100644 --- a/CEP/BB/BBSControl/src/SolverProcessControl.cc +++ b/CEP/BB/BBSControl/src/SolverProcessControl.cc @@ -39,326 +39,326 @@ #include <stdlib.h> +#if 0 + #define NONREADY casa::LSQFit::NONREADY + #define N_ReadyCode casa::LSQFit::N_ReadyCode + #define SUMLL casa::LSQFit::SUMLL + #define NC casa::LSQFit::NC +#else + #define NONREADY 0 + #define N_ReadyCode 999 + #define NC 0 + #define SUMLL 2 +#endif + using namespace LOFAR::ACC::APS; -namespace LOFAR +namespace LOFAR { -namespace BBS +namespace BBS { - using LOFAR::operator<<; - using boost::scoped_ptr; +using LOFAR::operator<<; +using boost::scoped_ptr; +//# Ensure classes are registered with the ObjectFactory. +template class BlobStreamableVector<DomainRegistrationRequest>; +template class BlobStreamableVector<IterationRequest>; +template class BlobStreamableVector<IterationResult>; - //# Ensure classes are registered with the ObjectFactory. - template class BlobStreamableVector<DomainRegistrationRequest>; - template class BlobStreamableVector<IterationRequest>; - template class BlobStreamableVector<IterationResult>; +//##---- P u b l i c m e t h o d s ----##// +SolverProcessControl::SolverProcessControl() + : ProcessControl() +{ + LOG_TRACE_FLOW(AUTO_FUNCTION_NAME); +} - //##---- P u b l i c m e t h o d s ----##// - SolverProcessControl::SolverProcessControl() : - ProcessControl() - { - LOG_TRACE_FLOW(AUTO_FUNCTION_NAME); - } +SolverProcessControl::~SolverProcessControl() +{ + LOG_TRACE_FLOW(AUTO_FUNCTION_NAME); +} - SolverProcessControl::~SolverProcessControl() - { - LOG_TRACE_FLOW(AUTO_FUNCTION_NAME); - } +tribool SolverProcessControl::define() +{ + LOG_TRACE_FLOW(AUTO_FUNCTION_NAME); - tribool SolverProcessControl::define() + try { - LOG_INFO("SolverProcessControl::define()"); - - try - { - char *user = getenv("USER"); - ASSERT(user); - string userString(user); - - itsKernelConnection.reset(new BlobStreamableConnection( - "=Solver_" + userString, - Socket::LOCAL)); - } - catch(Exception& e) - { - LOG_ERROR_STR(e); - return false; - } - - return true; - } - + char *user = getenv("USER"); + ASSERT(user); + string userString(user); - tribool SolverProcessControl::init() + itsKernelConnection.reset(new BlobStreamableConnection( + "=Solver_" + userString, + Socket::LOCAL)); + } + catch(Exception& e) { - LOG_INFO("SolverProcessControl::init()"); - try - { - LOG_INFO("Starting to listen at solver@localhost"); - if(!itsKernelConnection->connect()) - { - LOG_ERROR("+ listen failed"); - return false; - } - LOG_INFO("+ ok"); - } - catch(Exception& e) - { - LOG_ERROR_STR(e); - return false; - } - - // All went well. - return true; + LOG_ERROR_STR(e); + return false; } + return true; +} - tribool SolverProcessControl::run() - { - LOG_INFO("SolverProcessControl::run()"); - try - { - // Receive the next message - scoped_ptr<BlobStreamable> message(itsKernelConnection->recvObject()); - if(message) - return dispatch(message.get()); - else - return false; - } - catch(Exception& e) +tribool SolverProcessControl::init() +{ + LOG_TRACE_FLOW(AUTO_FUNCTION_NAME); + + try + { + LOG_INFO("Listening at solver@localhost"); + if(!itsKernelConnection->connect()) { - LOG_ERROR_STR(e); + LOG_ERROR("+ listen failed"); return false; } + LOG_INFO("+ ok"); } - - - tribool SolverProcessControl::pause(const string& /*condition*/) + catch(Exception& e) { - LOG_TRACE_FLOW(AUTO_FUNCTION_NAME); - LOG_WARN("Not supported"); + LOG_ERROR_STR(e); return false; } + // All went well. + return true; +} - tribool SolverProcessControl::quit() - { - LOG_INFO("SolverProcessControl::quit()"); - return true; - } +tribool SolverProcessControl::run() +{ + LOG_TRACE_FLOW(AUTO_FUNCTION_NAME); - tribool SolverProcessControl::snapshot(const string& /*destination*/) + try { - LOG_TRACE_FLOW(AUTO_FUNCTION_NAME); - LOG_WARN("Not supported"); - return false; + // Receive the next message + scoped_ptr<BlobStreamable> message(itsKernelConnection->recvObject()); + if(message) + return dispatch(message.get()); + else + return false; } - - - tribool SolverProcessControl::recover(const string& /*source*/) + catch(Exception& e) { - LOG_TRACE_FLOW(AUTO_FUNCTION_NAME); - LOG_WARN("Not supported"); + LOG_ERROR_STR(e); return false; } +} - tribool SolverProcessControl::reinit(const string& /*configID*/) - { - LOG_TRACE_FLOW(AUTO_FUNCTION_NAME); - LOG_WARN("Not supported"); - return false; - } +tribool SolverProcessControl::pause(const string& /*condition*/) +{ + LOG_TRACE_FLOW(AUTO_FUNCTION_NAME); + LOG_WARN("Not supported"); + return false; +} - std::string SolverProcessControl::askInfo(const string& /*keylist*/) - { - LOG_TRACE_FLOW(AUTO_FUNCTION_NAME); - return std::string(""); - } +tribool SolverProcessControl::quit() +{ + LOG_TRACE_FLOW(AUTO_FUNCTION_NAME); + return true; +} + + +tribool SolverProcessControl::snapshot(const string& /*destination*/) +{ + LOG_TRACE_FLOW(AUTO_FUNCTION_NAME); + LOG_WARN("Not supported"); + return false; +} + + +tribool SolverProcessControl::recover(const string& /*source*/) +{ + LOG_TRACE_FLOW(AUTO_FUNCTION_NAME); + LOG_WARN("Not supported"); + return false; +} + + +tribool SolverProcessControl::reinit(const string& /*configID*/) +{ + LOG_TRACE_FLOW(AUTO_FUNCTION_NAME); + LOG_WARN("Not supported"); + return false; +} + + +std::string SolverProcessControl::askInfo(const string& /*keylist*/) +{ + LOG_TRACE_FLOW(AUTO_FUNCTION_NAME); + return std::string(""); +} - bool SolverProcessControl::dispatch(const BlobStreamable *message) +bool SolverProcessControl::dispatch(const BlobStreamable *message) +{ { - { - const DomainRegistrationRequest *request = dynamic_cast<const DomainRegistrationRequest*>(message); - if(request) - return handle(request); - } - - { - const BlobStreamableVector<DomainRegistrationRequest> *request = dynamic_cast<const BlobStreamableVector<DomainRegistrationRequest>*>(message); - if(request) - return handle(request); - } - - { - const IterationRequest *request = dynamic_cast<const IterationRequest*>(message); - if(request) - return handle(request); - } - - { - const BlobStreamableVector<IterationRequest> *request = dynamic_cast<const BlobStreamableVector<IterationRequest>*>(message); - if(request) - return handle(request); - } - - // We received a message we can't handle - LOG_WARN_STR("Received message of unsupported type"); - return false; + const DomainRegistrationRequest *request = + dynamic_cast<const DomainRegistrationRequest*>(message); + if(request) + return handle(request); } - - - bool SolverProcessControl::handle(const DomainRegistrationRequest *request) + { - return registerDomain(request); + const BlobStreamableVector<DomainRegistrationRequest> *request = + dynamic_cast<const BlobStreamableVector<DomainRegistrationRequest>*> + (message); + if(request) + return handle(request); } - - bool SolverProcessControl::handle(const BlobStreamableVector<DomainRegistrationRequest> *request) { - bool result = true; - for(vector<DomainRegistrationRequest*>::const_iterator it = request->getVector().begin(); - it != request->getVector().end() && result; - ++it) - { - result = result && registerDomain(*it); - } - return result; + const IterationRequest *request = + dynamic_cast<const IterationRequest*>(message); + if(request) + return handle(request); } - - - bool SolverProcessControl::handle(const IterationRequest *request) + { - scoped_ptr<IterationResult> result(performIteration(request)); - return itsKernelConnection->sendObject(*result.get()); + const BlobStreamableVector<IterationRequest> *request = + dynamic_cast<const BlobStreamableVector<IterationRequest>*> + (message); + if(request) + return handle(request); } + // We received a message we can't handle + LOG_WARN_STR("Received message of unsupported type"); + return false; +} + + +bool SolverProcessControl::handle(const DomainRegistrationRequest *request) +{ + return registerDomain(request); +} + - bool SolverProcessControl::handle(const BlobStreamableVector<IterationRequest> *request) +bool SolverProcessControl::handle + (const BlobStreamableVector<DomainRegistrationRequest> *request) +{ + bool result = true; + + for(vector<DomainRegistrationRequest*>::const_iterator it = + request->getVector().begin(); + it != request->getVector().end() && result; + ++it) { - BlobStreamableVector<IterationResult> result; - - for(vector<IterationRequest*>::const_iterator it = request->getVector().begin(); - it != request->getVector().end(); - ++it) - { - result.getVector().push_back(performIteration(*it)); - } - - return itsKernelConnection->sendObject(result); + result = result && registerDomain(*it); } - - - bool SolverProcessControl::registerDomain(const DomainRegistrationRequest *request) + return result; +} + + +bool SolverProcessControl::handle(const IterationRequest *request) +{ + scoped_ptr<IterationResult> result(performIteration(request)); + return itsKernelConnection->sendObject(*result.get()); +} + + +bool SolverProcessControl::handle + (const BlobStreamableVector<IterationRequest> *request) +{ + BlobStreamableVector<IterationResult> result; + + for(vector<IterationRequest*>::const_iterator it = + request->getVector().begin(); + it != request->getVector().end(); + ++it) { - LOG_DEBUG_STR("DomainRegistrationRequest: index: " << request->getDomainIndex() << " #unknowns: " << request->getUnknowns().size()); - LOG_DEBUG_STR("+ unknowns: " << request->getUnknowns()); - - Domain &domain = itsRegisteredDomains[request->getDomainIndex()]; - domain.index = request->getDomainIndex(); - domain.unknowns = request->getUnknowns(); - domain.solver.set(casa::uInt(domain.unknowns.size())); - domain.epsilon = request->getEpsilon(); - // Set new value solution test - //domain.solver.setEpsValue(request->getEpsilon()); - // Set new 'derivative' test (actually, the inf norm of the known - // vector is checked). - //domain.solver.setEpsDerivative(request->getEpsilon()); - // Set maximum number of iterations - //domain.solver.setMaxIter(request->getMaxIter()); - // Set new factors (collinearity factor, and Levenberg-Marquardt LMFactor) - // void set(Double factor=1e-6, Double LMFactor=1e-3); - return true; + result.getVector().push_back(performIteration(*it)); } - - IterationResult *SolverProcessControl::performIteration(const IterationRequest *request) - { - map<uint32, Domain>::iterator it = itsRegisteredDomains.find(request->getDomainIndex()); - //ASSERT(it != itsRegisteredDomains.end()); - if(it == itsRegisteredDomains.end()) - { - // Artifact of the current implementation: equations are still being generated - // and send even if the solve domain has already converged. So, we'll just return - // a result with resultCode 2 (i.e. already converged). - return new IterationResult( - request->getDomainIndex(), - 2, - "", - vector<double>(), - 0, - -1.0, - -1.0); - } + return itsKernelConnection->sendObject(result); +} - // Set the new normal equations. - Domain &domain = it->second; - domain.solver.merge(request->getNormalEquations()); - - // Get some statistics from the solver. Note that the chi squared is - // valid for the _previous_ iteration. The solver cannot compute the - // chi squared directly after an iteration, because it needs the new - // condition equations for that and these are computed by the kernel. - double chiSquared, lmFactor; - casa::uInt rank, nun, np, ncon, ner, *piv; -// casa::Double *nEq, *known, *constr, *er, *sEq, *sol, prec, nonlin; - casa::Double *nEq, *known, *constr, *er, *sEq, *sol, prec, nonlin, fit; - - domain.solver.debugIt(nun, np, ncon, ner, rank, nEq, known, constr, er, piv, sEq, sol, prec, nonlin); -// ASSERT(er && ner > casa::LSQFit::NC && ner > casa::LSQFit::SUMLL); - ASSERT(er && ner > 2); - //# It's weird that er[casa::LSQFit::SUMLL] contains chi squared while - //# er[casa::LSQFit::CHI2] does not. ?? - //chiSquared = (er[casa::LSQFit::NC] > 0 ? er[casa::LSQFit::SUMLL] / er[casa::LSQFit::NC] : er[casa::LSQFit::SUMLL]); -// chiSquared = er[casa::LSQFit::SUMLL]; - chiSquared = er[2]; - lmFactor = nonlin; - - //LOG_DEBUG_STR("before " << domain.unknowns); - - // Solve the normal equations. -// domain.solver.solveLoop(rank, &(domain.unknowns[0]), true); - domain.solver.solveLoop(fit, rank, &(domain.unknowns[0]), true); - - //LOG_DEBUG_STR("after " << domain.unknowns); - - uint32 resultCode = 0; - if(fit < 0.0 && abs(fit) < domain.epsilon) - //# Force convergence (BBSKernelProcessControl is already geared - //# towards the new interface) - resultCode = 1; - - // Send the result to the kernel. - IterationResult *result = new IterationResult( - request->getDomainIndex(), -// domain.solver.isReady(), -// domain.solver.readyText(), - resultCode, - "", - domain.unknowns, - rank, - chiSquared, - lmFactor); - - - // If we're done with this domain, unregister it. -// if(domain.solver.isReady() != casa::LSQFit::NONREADY) - if(resultCode != 0) - { - LOG_DEBUG_STR("Unregistering domain " << request->getDomainIndex()); - itsRegisteredDomains.erase(request->getDomainIndex()); - } - return result; +bool SolverProcessControl::registerDomain + (const DomainRegistrationRequest *request) +{ + LOG_DEBUG_STR("DomainRegistrationRequest: index: " + << request->getDomainIndex() << " #unknowns: " + << request->getUnknowns().size()); + LOG_DEBUG_STR("+ unknowns: " << request->getUnknowns()); + + Domain &domain = itsRegisteredDomains[request->getDomainIndex()]; + domain.index = request->getDomainIndex(); + domain.unknowns = request->getUnknowns(); + domain.solver.set(casa::uInt(domain.unknowns.size())); + // Set new value solution test + domain.solver.setEpsValue(request->getEpsilon()); + // Set new 'derivative' test (actually, the inf norm of the known + // vector is checked). + domain.solver.setEpsDerivative(request->getEpsilon()); + // Set maximum number of iterations + domain.solver.setMaxIter(request->getMaxIter()); + // Set new factors (collinearity factor, and Levenberg-Marquardt LMFactor) + domain.solver.set(request->getColFactor(), request->getLMFactor()); + domain.solver.setBalanced(request->getBalancedEq()); + return true; +} + + +IterationResult* SolverProcessControl::performIteration + (const IterationRequest *request) +{ + map<uint32, Domain>::iterator it = + itsRegisteredDomains.find(request->getDomainIndex()); + + if(it == itsRegisteredDomains.end()) + { + // Artifact of the current implementation: equations are still being + // generated and send even if the solve domain has already + // converged. So, we'll just return a result with resultCode N_ReadyCode + // (i.e. already converged). + return new IterationResult(request->getDomainIndex(), + N_ReadyCode, "", vector<double>(), 0, -1.0, -1.0); + } + + // Set the new normal equations. + Domain &domain = it->second; + domain.solver.merge(request->getNormalEquations()); + + // Get some statistics from the solver. Note that the chi squared is + // valid for the _previous_ iteration. The solver cannot compute the + // chi squared directly after an iteration, because it needs the new + // condition equations for that and these are computed by the kernel. + casa::uInt rank, nun, np, ncon, ner, *piv; + casa::Double *nEq, *known, *constr, *er, *sEq, *sol, prec, nonlin; + domain.solver.debugIt(nun, np, ncon, ner, rank, nEq, known, constr, er, + piv, sEq, sol, prec, nonlin); + ASSERT(er && ner > SUMLL); + + double lmFactor = nonlin; + double chiSquared = er[SUMLL] / std::max(er[NC] + nun, 1.0); + + // Solve the normal equations. + domain.solver.solveLoop(rank, &(domain.unknowns[0]), true); + + // Construct a result. + IterationResult *result = new IterationResult(domain.index, + domain.solver.isReady(), + domain.solver.readyText(), + domain.unknowns, + rank, + chiSquared, + lmFactor); + + // If we're done with this domain, unregister it. + if(domain.solver.isReady() != NONREADY) + { + itsRegisteredDomains.erase(request->getDomainIndex()); } + return result; +} + } // namespace BBS } // namespace LOFAR diff --git a/CEP/BB/BBSKernel/include/BBSKernel/Axis.h b/CEP/BB/BBSKernel/include/BBSKernel/Axis.h new file mode 100644 index 0000000000000000000000000000000000000000..950d16de617d0101788f5bdce0b41ae0d550b204 --- /dev/null +++ b/CEP/BB/BBSKernel/include/BBSKernel/Axis.h @@ -0,0 +1,181 @@ +//# Axis.h: +//# +//# 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$ + +#ifndef LOFAR_BBS_BBSKERNEL_GRID_H +#define LOFAR_BBS_BBSKERNEL_GRID_H + +#include <Common/lofar_vector.h> +#include <algorithm> +#include <functional> +#include <utility> + +namespace LOFAR +{ +namespace BBS +{ +using std::unary_function; +using std::pair; +using std::make_pair; +using std::max; +using std::min; + +/* +template <typename T> +class BoundingBox +{ + BoundingBox(T minx, T miny, T maxx, T maxy) + : min(minx, miny), + max(maxx, maxy) + {} + + pair<T, T> min; + pair<T, T> max; +} + +template <typename T> +BoudingBox union(const BoundingBox<T> &a, const BoundingBox<T> &b) +{ + return BoundingBox(min(a.min.first, b.min.first), + min(a.min.second, b.min.second), + max(a.max.first, b.max.first), + max(a.max.second, b.max.second)); +} +*/ + +class regular_series: public unary_function<size_t, double> +{ +public: + regular_series() + : m_begin(0.0), + m_delta(1.0) + {} + + regular_series(result_type begin, result_type delta) + : m_begin(begin), + m_delta(delta) + {} + + result_type operator()(argument_type n) const + { return m_begin + n * m_delta; } + +private: + result_type m_begin, m_delta; +}; + + +class irregular_series: public unary_function<size_t, double> +{ +public: + irregular_series() + {} + + irregular_series(const vector<result_type> &terms) + : m_terms(terms) + {} + + result_type operator()(argument_type n) const + { return m_terms[n]; } + +private: + vector<result_type> m_terms; +}; + + +template <typename SeriesType> +class cell_centered_axis +{ +public: + cell_centered_axis() + : m_series(SeriesType()), + m_size(0) + {} + + cell_centered_axis(SeriesType series, size_t size) + : m_series(series), + m_size(size) + {} + + double operator()(size_t n) const + { return 0.5 * (m_series(n) + m_series(n + 1)); } + + double lower(size_t n) const + { return m_series(n); } + + double upper(size_t n) const + { return m_series(n + 1); } + + double width(size_t n) const + { return m_series(n + 1) - m_series(n); } + + size_t size() const + { return m_size; } + + pair<double, double> range() const + { return make_pair(lower(0), upper(size() - 1)); } + +private: + SeriesType m_series; + size_t m_size; +}; + + +template <typename SeriesType> +class node_centered_axis +{ +public: + node_centered_axis() + : m_series(SeriesType()), + m_size(0) + {} + + node_centered_axis(SeriesType series, size_t size) + : m_series(series), + m_size(size) + {} + + double operator()(size_t n) const + { return m_series(n); } + + double lower(size_t n) const + { return m_series(n); } + + double upper(size_t n) const + { return m_series(n); } + + double width(size_t n) const + { return 0.0; } + + size_t size() const + { return m_size; } + + pair<double, double> range() const + { return make_pair(lower(0), upper(size() - 1)); } + +private: + SeriesType m_series; + size_t m_size; +}; + +} //# namespace BBS +} //# namespace LOFAR + +#endif diff --git a/CEP/BB/BBSKernel/include/BBSKernel/BBSKernelStructs.h b/CEP/BB/BBSKernel/include/BBSKernel/BBSKernelStructs.h index adbf309bec04ac4a7de071487be2e0ea1964fae5..11298ef8c17e24011f039ca9734f650b222b76c8 100644 --- a/CEP/BB/BBSKernel/include/BBSKernel/BBSKernelStructs.h +++ b/CEP/BB/BBSKernel/include/BBSKernel/BBSKernelStructs.h @@ -26,9 +26,12 @@ #include <Common/lofar_vector.h> #include <Common/lofar_string.h> #include <Common/lofar_iosfwd.h> +#include <utility> namespace LOFAR { + using std::pair; + //# Forward declarations class BlobIStream; class BlobOStream; @@ -79,7 +82,7 @@ namespace LOFAR Baselines baselines; Correlation correlation; vector<string> sources; - vector<string> instrumentModel; + vector<string> instrumentModel; }; @@ -103,9 +106,9 @@ namespace LOFAR struct GenerateContext: Context { - vector<string> unknowns; - vector<string> excludedUnknowns; - vector<MeqDomain> solveDomains; + vector<string> unknowns; + vector<string> excludedUnknowns; + pair<size_t, size_t> domainSize; }; // I/O stream methods diff --git a/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqJonesVisData.h b/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqJonesVisData.h new file mode 100644 index 0000000000000000000000000000000000000000..8f4dadaddff22f6d15e1c4dd85d8d851728d4fd3 --- /dev/null +++ b/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqJonesVisData.h @@ -0,0 +1,56 @@ +//# MeqJonesVisData.h: +//# +//# 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$ + +#ifndef MNS_MEQJONESVISDATA_H +#define MNS_MEQJONESVISDATA_H + +#include <BBSKernel/MNS/MeqJonesExpr.h> +#include <BBSKernel/VisData.h> + +namespace LOFAR +{ +namespace BBS +{ + +class MeqJonesVisData: public MeqJonesExprRep +{ +public: + MeqJonesVisData(VisData::Pointer vdata, baseline_t baseline); + + ~MeqJonesVisData() + {} + + // Get the result of the expression for the given domain. + virtual MeqJonesResult getJResult (const MeqRequest&); + +private: + void copy(double *re, double *im, + const boost::multi_array<sample_t, 4>::const_array_view<2>::type &src); + + VisData::Pointer itsVisData; + size_t itsBaselineIndex; +}; + +} // namespace BBS +} // namespace LOFAR + +#endif diff --git a/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqParm.h b/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqParm.h index 3d995cd917439fa11f6f34b0e4e7341e34699377..797634886b9fbab9dbeeeef02d1e6de8a50e80f6 100644 --- a/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqParm.h +++ b/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqParm.h @@ -99,6 +99,7 @@ public: // Make the new value persistent (for the given domain). virtual void save(); + virtual void save(size_t domainIndex); // Functions needed for MeqParmFunklet. // By default they throw an exception. @@ -160,6 +161,8 @@ public: { return itsParmPtr->getFunklets(); } void save() { itsParmPtr->save(); } + void save(size_t domainIndex) + { itsParmPtr->save(domainIndex); } void update (const ParmData& values) { itsParmPtr->update (values); } void update (const vector<double>& value) diff --git a/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqParmFunklet.h b/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqParmFunklet.h index b350a4589106091a695157e12b7a76b06f59f904..fc7ad17975d2d8a8e9ff62d2c69258c285f9f060 100644 --- a/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqParmFunklet.h +++ b/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqParmFunklet.h @@ -103,6 +103,7 @@ public: // Make the new value persistent (for the given domain). virtual void save(); + virtual void save(size_t domainIndex); // Update the solvable parameter with the new value. virtual void update (const ParmData& values); diff --git a/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqRequest.h b/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqRequest.h index dcaa9b001c849af84e8ae682cf902b0cabb581c0..4cc2869aa9204d6ebe1ef2ff1ff02381081a3bd8 100644 --- a/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqRequest.h +++ b/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqRequest.h @@ -31,11 +31,13 @@ #include <BBSKernel/MNS/MeqDomain.h> #include <BBSKernel/MNS/MeqMatrix.h> #include <Common/lofar_vector.h> +#include <utility> namespace LOFAR { namespace BBS { +using std::pair; // \ingroup BBSKernel // \addtogroup MNS @@ -106,12 +108,18 @@ public: // Set or get the first X-value (i.e. first channel). // <group> - void setFirstX (int firstX) - { itsFirstX = firstX; } - int firstX() const - { return itsFirstX; } +// void setFirstX (int firstX) +// { itsFirstX = firstX; } +// int firstX() const +// { return itsFirstX; } // </group> + void setOffset(pair<size_t, size_t> offset) + { itsOffset = offset; } + + pair<size_t, size_t> offset() const + { return itsOffset; } + // Get the request id. MeqRequestId getId() const { return itsRequestId; } @@ -128,9 +136,10 @@ private: double itsStepX; vector<double> itsY; //# The vector of Y values. double* itsYP; //# The pointer to itsY for a partial request - int itsFirstX; +// int itsFirstX; int itsSourceNr; int itsNspids; + pair<size_t, size_t> itsOffset; static MeqRequestId theirRequestId; }; diff --git a/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqStatUVW.h b/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqStatUVW.h index d3f533a175690e01221984a4c149ef0dc138b1bc..013c1c580bd14f6f016379cd480317837c84537c 100644 --- a/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqStatUVW.h +++ b/CEP/BB/BBSKernel/include/BBSKernel/MNS/MeqStatUVW.h @@ -56,7 +56,8 @@ public: MeqStatUVW() {}; //# MeqStatUVW (MeqStation*, const MeqPhaseRef*); - MeqStatUVW(MeqStation* station, const pair<double, double> &phaseCenter, const vector<double> &arrayPosition); + MeqStatUVW(MeqStation *station, const casa::MDirection &phaseCenter, + const casa::MPosition &arrayPosition); void calculate (const MeqRequest&); diff --git a/CEP/BB/BBSKernel/include/BBSKernel/Makefile.am b/CEP/BB/BBSKernel/include/BBSKernel/Makefile.am index 137226951b6e37108018aedd63acbbfc1de4923e..d74ded1e593429da5db2cc3fcd6528aa91b754c3 100644 --- a/CEP/BB/BBSKernel/include/BBSKernel/Makefile.am +++ b/CEP/BB/BBSKernel/include/BBSKernel/Makefile.am @@ -1,20 +1,16 @@ pkginclude_MNSdir = $(pkgincludedir)/MNS pkginclude_HEADERS = \ + Axis.h \ BBSKernelStructs.h \ BBSStatus.h \ Exceptions.h \ - FlagsMap.h \ - MMap.h \ - MMapMSInfo.h \ - ParmData.h \ - ParmWriter.h \ + Measurement.h \ + MeasurementAIPS.h \ + Model.h \ Prediffer.h \ - Quality.h \ - SolveProp.h \ - Solver.h \ - StepProp.h \ - StrategyProp.h + VisData.h \ + VisSelection.h pkginclude_MNS_HEADERS = \ MNS/MeqBaseDFTPS.h \ @@ -29,12 +25,12 @@ pkginclude_MNS_HEADERS = \ MNS/MeqJonesCMul3.h \ MNS/MeqJonesExpr.h \ MNS/MeqJonesInvert.h \ - MNS/MeqJonesMMap.h \ MNS/MeqJonesMul2.h \ MNS/MeqJonesMul3.h \ MNS/MeqJonesNode.h \ MNS/MeqJonesResult.h \ MNS/MeqJonesSum.h \ + MNS/MeqJonesVisData.h \ MNS/MeqLMN.h \ MNS/MeqMatrixComplexArr.h \ MNS/MeqMatrixComplexSca.h \ diff --git a/CEP/BB/BBSKernel/include/BBSKernel/Measurement.h b/CEP/BB/BBSKernel/include/BBSKernel/Measurement.h new file mode 100644 index 0000000000000000000000000000000000000000..19da4aa400c7ae5f9208e9d9cd80779f1cbed906 --- /dev/null +++ b/CEP/BB/BBSKernel/include/BBSKernel/Measurement.h @@ -0,0 +1,116 @@ +//# Measurement.h: Interface class for measurement I/O. +//# +//# 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$ + +#ifndef LOFAR_BBS_BBSKERNEL_MEASUREMENT_H +#define LOFAR_BBS_BBSKERNEL_MEASUREMENT_H + +#include <BBSKernel/VisSelection.h> +#include <BBSKernel/VisData.h> + +#include <Common/lofar_string.h> +#include <Common/lofar_vector.h> +#include <Common/lofar_set.h> +#include <utility> + +#include <measures/Measures/MDirection.h> +#include <measures/Measures/MEpoch.h> +#include <measures/Measures/MPosition.h> + +namespace LOFAR +{ +namespace BBS +{ + +struct Station +{ + string name; + casa::MPosition position; +}; + +class Instrument +{ +public: + size_t getStationCount() const + { return stations.size(); } + + string name; + casa::MPosition position; + vector<Station> stations; + map<string, size_t> stationIndex; +}; + +class Measurement +{ +public: + typedef shared_ptr<Measurement> Pointer; + + virtual ~Measurement() + { + } + + const Instrument &getInstrument() const + { return itsInstrument; } + + const casa::MDirection &getPhaseCenter() const + { return itsPhaseCenter; } + + const vector<string> &getCorrelations() const + { return itsCorrelationProducts; } + + size_t getCorrelationCount() const + { return itsCorrelationProducts.size(); } + + size_t getChannelCount() const + { return itsSpectrum.size(); } + + const cell_centered_axis<regular_series> &getSpectrum() const + { return itsSpectrum; } + + pair<double, double> getFreqRange() const + { return itsSpectrum.range(); } + + pair<casa::MEpoch, casa::MEpoch> getTimeRange() const + { return itsTimeRange; } + + virtual VisGrid grid(const VisSelection &selection) const = 0; + + virtual VisData::Pointer read(const VisSelection &selection, + const string &column = "DATA", + bool readUVW = true) const = 0; + + virtual void write(const VisSelection &selection, + VisData::Pointer buffer, + const string &column = "CORRECTED_DATA", + bool writeFlags = true) const = 0; + +protected: + Instrument itsInstrument; + casa::MDirection itsPhaseCenter; + pair<casa::MEpoch, casa::MEpoch> itsTimeRange; + cell_centered_axis<regular_series> itsSpectrum; + vector<string> itsCorrelationProducts; +}; + +} //# namespace BBS +} //# namespace LOFAR + +#endif diff --git a/CEP/BB/BBSKernel/include/BBSKernel/MeasurementAIPS.h b/CEP/BB/BBSKernel/include/BBSKernel/MeasurementAIPS.h new file mode 100644 index 0000000000000000000000000000000000000000..ab1fcea7e1ecd33cee8ad6853602b1cc8a4ac5e4 --- /dev/null +++ b/CEP/BB/BBSKernel/include/BBSKernel/MeasurementAIPS.h @@ -0,0 +1,93 @@ +//# MeasurementAIPS.h: +//# +//# 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$ + +#ifndef LOFAR_BBS_BBSKERNEL_MEASUREMENTAIPS_H +#define LOFAR_BBS_BBSKERNEL_MEASUREMENTAIPS_H + +#include <BBSKernel/Measurement.h> +#include <Common/LofarTypes.h> +#include <Common/lofar_string.h> + +#include <casa/Arrays/Slicer.h> +#include <ms/MeasurementSets/MeasurementSet.h> + +namespace LOFAR +{ +namespace BBS +{ +class VisSelection; + +class MeasurementAIPS: public Measurement +{ +public: + MeasurementAIPS(string filename, + uint observationId = 0, + uint dataDescriptionId = 0, + uint fieldId = 0); + + ~MeasurementAIPS(); + + virtual VisGrid grid(const VisSelection &selection) const; + + virtual VisData::Pointer read(const VisSelection &selection, + const string &column = "DATA", + bool readUVW = true) const; + + virtual void write(const VisSelection &selection, + VisData::Pointer buffer, + const string &column = "CORRECTED_DATA", + bool writeFlags = true) const; + +private: + Instrument readInstrumentInfo + (const casa::MSAntenna &tab_antenna, + const casa::MSObservation &tab_observation, + uint id); + + vector<string> readPolarizationInfo + (const casa::MSPolarization &tab_polarization, uint id); + + void readSpectralInfo + (const casa::MSSpectralWindow &tab_spectralWindow, uint id); + + casa::MDirection readFieldInfo(const casa::MSField &tab_field, uint id); + + casa::TableExprNode getTAQLExpression(const VisSelection &selection) const; + + casa::Slicer getCellSlicer(const VisSelection &selection) const; + + VisGrid getGrid(const casa::Table tab_selection, const casa::Slicer slicer) + const; + + VisData::Pointer allocate(const VisGrid &grid) const; + + string itsFilename; + casa::MeasurementSet itsMS; + + casa::Int itsObservationId, itsDataDescriptionId, + itsFieldId; +}; + +} //# namespace BBS +} //# namespace LOFAR + +#endif diff --git a/CEP/BB/BBSKernel/include/BBSKernel/Model.h b/CEP/BB/BBSKernel/include/BBSKernel/Model.h new file mode 100644 index 0000000000000000000000000000000000000000..a9f2280e50206dd367b33ed07d763d005db7fccf --- /dev/null +++ b/CEP/BB/BBSKernel/include/BBSKernel/Model.h @@ -0,0 +1,104 @@ +//# Model.h: +//# +//# 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$ + + +#ifndef LOFAR_BBS_BBSKERNEL_MODEL_H +#define LOFAR_BBS_BBSKERNEL_MODEL_H + +#include <Common/lofar_smartptr.h> +#include <Common/lofar_vector.h> +#include <Common/lofar_string.h> +#include <Common/lofar_map.h> +#include <Common/lofar_set.h> + +#include <BBSKernel/VisData.h> +#include <BBSKernel/MNS/MeqJonesResult.h> +#include <BBSKernel/MNS/MeqSourceList.h> + +#include <ParmDB/ParmDB.h> + + +namespace LOFAR +{ +namespace BBS +{ +class Instrument; +class MeqParmGroup; +class MeqPhaseRef; +class MeqRequest; +class MeqStation; +class MeqStatUVW; +class MeqLMN; +class MeqJonesExpr; + +class Model +{ +public: + typedef shared_ptr<Model> Pointer; + + enum ModelComponent + { + GAIN = 0, + DIRECTIONAL_GAIN, + BANDPASS, + PHASORS, + N_ModelComponent + }; + + enum EquationType + { + PREDICT = 0, + CORRECT, + N_EquationType + }; + + Model(const Instrument &instrument, MeqParmGroup &parmGroup, + ParmDB::ParmDB *skyDBase, MeqPhaseRef *phaseRef); + + void setStationUVW(const Instrument &instrument, VisData::Pointer data); + + void makeEquations(EquationType type, const vector<string> &components, + const set<baseline_t> &baselines, const vector<string> &sources, + MeqParmGroup &parmGroup, ParmDB::ParmDB *instrumentDBase, + MeqPhaseRef *phaseRef, VisData::Pointer data); + + void precalculate(const MeqRequest& request); + MeqJonesResult evaluate(baseline_t baseline, const MeqRequest& request); + +private: + void makeStationNodes(const Instrument &instrument, + const MeqPhaseRef &phaseRef); + + void makeSourceNodes(const vector<string> &names, MeqPhaseRef *phaseRef); + + scoped_ptr<MeqSourceList> itsSourceList; + vector<shared_ptr<MeqStation> > itsStationNodes; + vector<shared_ptr<MeqStatUVW> > itsUVWNodes; + vector<MeqSource*> itsSourceNodes; + vector<MeqLMN*> itsLMNNodes; + map<baseline_t, MeqJonesExpr> itsEquations; +}; + +} //# namespace BBS +} //# namespace LOFAR + +#endif diff --git a/CEP/BB/BBSKernel/include/BBSKernel/Prediffer.h b/CEP/BB/BBSKernel/include/BBSKernel/Prediffer.h index 45d5ed5255ea3567bece41751bdb83f459c24cc0..865fd117652652f7124d89c3976be19be792dda6 100644 --- a/CEP/BB/BBSKernel/include/BBSKernel/Prediffer.h +++ b/CEP/BB/BBSKernel/include/BBSKernel/Prediffer.h @@ -26,60 +26,45 @@ // \file // Read and predict read visibilities -#include <casa/BasicSL/Complex.h> -#include <casa/Arrays/Matrix.h> -#include <scimath/Fitting/LSQFit.h> +//#include <casa/BasicSL/Complex.h> +//#include <casa/Arrays/Matrix.h> + +#include <BBSKernel/Measurement.h> +#include <BBSKernel/Model.h> +#include <BBSKernel/VisSelection.h> +#include <BBSKernel/VisData.h> #include <BBSKernel/BBSKernelStructs.h> -#include <BBSKernel/StrategyProp.h> -#include <BBSKernel/StepProp.h> -#include <BBSKernel/SolveProp.h> -#include <BBSKernel/ParmData.h> -#include <BBSKernel/MMapMSInfo.h> +//#include <BBSKernel/ParmData.h> #include <BBSKernel/MNS/MeqDomain.h> #include <BBSKernel/MNS/MeqJonesExpr.h> -#include <BBSKernel/MNS/MeqJonesNode.h> #include <BBSKernel/MNS/MeqMatrix.h> #include <BBSKernel/MNS/MeqParm.h> #include <BBSKernel/MNS/MeqPhaseRef.h> -#include <BBSKernel/MNS/MeqSourceList.h> #include <BBSKernel/MNS/MeqRequest.h> -#include <BBSKernel/MNS/MeqStation.h> -#include <BBSKernel/MNS/MeqStatUVW.h> -#include <BBSKernel/MNS/MeqLMN.h> -#include <BBSKernel/MNS/MeqDFTPS.h> #include <ParmDB/ParmDB.h> #include <ParmDB/ParmValue.h> #include <ParmDB/ParmDomain.h> -#include <MS/MSDesc.h> #include <Common/Timer.h> -#include <Common/LofarTypes.h> #include <Common/lofar_string.h> #include <Common/lofar_vector.h> -#include <Common/lofar_iomanip.h> +#include <Common/lofar_map.h> -#include <map> #include <utility> -namespace casa { - class Table; +namespace casa +{ + class LSQFit; } namespace LOFAR { namespace BBS { - // \addtogroup BBSKernel // @{ -//# Forward Declarations -class MMap; -class FlagsMap; -class MeqJonesMMap; - - // Prediffer calculates the equations for the solver. // It reads the measured data and predicts the data from the model. // It subtracts them from each other and calculates the derivatives. @@ -92,444 +77,207 @@ struct SolveDomainDescriptor vector<size_t> unknownIndex; vector<double> unknowns; }; - + + +struct ProcessingContext +{ + ProcessingContext() + : derivativeCount(0), + domainSize(0, 0), + domainCount(0, 0) + {} + + set<baseline_t> baselines; + set<pair<size_t, size_t> > polarizations; + + // Sum of the maximal number (over all solve domains) of partial derivatives + // of each parameter. + size_t derivativeCount; + + // Nominal solve domain size along each axis in #channels, #timeslots. + std::pair<size_t, size_t> domainSize; + // Number of solve domains along each axis (frequency, time). + std::pair<size_t, size_t> domainCount; + vector<SolveDomainDescriptor> domains; +}; + class Prediffer { public: - // NOTE: new constructor to comply with BBSStep interface. - Prediffer(const string &measurementSet, - const string &inputColumn, - const string &skyParameterDB, - const string &instrumentParameterDB, - const string &historyDB, - uint subbandID, - bool calcUVW); - - // Destructor - ~Prediffer(); - - // Lock and unlock the parm database tables. - // The user does not need to lock/unlock, but it can increase performance - // if many small accesses have to be done. - // <group> - void lock (bool lockForWrite = true) - { itsMEP->lock (lockForWrite); itsGSMMEP->lock (lockForWrite); } - void unlock() - { itsMEP->unlock(); itsGSMMEP->unlock(); } - - bool setSelection(const vector<string> &stations, const Correlation &correlation); - - // Set the work domain. - // The work domain (in frequency and time) is adjusted to the - // observation domain of the MS used. - // It reads all parms in the given domain. - // It returns false if the given work domain has no overlap with the - // MS part handled by this Prediffer - // <group> - bool setWorkDomain(const MeqDomain& domain); - bool setWorkDomain(double startFreq, double endFreq, double startTime, double endTime); - bool setWorkDomain(int startChan, int endChan, double startTime, double lengthTime); - // </group> - - bool setContext(const PredictContext &context); - bool setContext(const SubtractContext &context); - bool setContext(const CorrectContext &context); - bool setContext(const GenerateContext &context); - - void predictVisibilities(); - void subtractVisibilities(); - void correctVisibilities(); - void generateEquations(vector<casa::LSQFit> &equations); - - - // Get the actual work domain for this MS (after a setStrategy). - const MeqDomain &getWorkDomain() const - { return itsWorkDomain; } - - // Get the local data domain. - MeqDomain getLocalDataDomain() const; - - // Return the solvable parms. - // The parms are in ascending order of spidnr. - const ParmDataInfo& getSolvableParmData() const - { return itsParmData; } - - // There are three ways to update the solvable parms after the solver - // found a new solution. - // <group> - // Update the values of solvable parms. - // Using its spid index each parm takes its values from the vector. - void updateSolvableParms (const vector<double>& values); - - // Update the given values (for the current domain) of solvable parms - // matching the corresponding parm name in the vector. - // Vector values with a name matching no solvable parm are ignored. - void updateSolvableParms (const ParmDataInfo& parmData); - - // Update the solvable parm values (reread from table). - void updateSolvableParms(); - - void updateSolvableParms(size_t solveDomainIndex, - const vector<double> unknowns); - - // Log the updated values of a single solve domain. - void logIteration( - const string &stepName, - size_t solveDomainIndex, - double rank, - double chiSquared, - double LMFactor); - - // Write the solved parms. - void writeParms(); + Prediffer(const string &measurement, size_t subband, + const string &inputColumn, + const string &skyDBase, const string &instrumentDBase, + const string &historyDBase, bool readUVW); + + // Destructor + ~Prediffer(); + + // Lock and unlock the parm database tables. + // The user does not need to lock/unlock, but it can increase performance + // if many small accesses have to be done. + // <group> + void lock(bool lockForWrite = true) + { + itsInstrumentDBase->lock(lockForWrite); + itsSkyDBase->lock(lockForWrite); + } + + void unlock() + { + itsInstrumentDBase->unlock(); + itsSkyDBase->unlock(); + } + + void setSelection(VisSelection selection); + void setChunkSize(size_t time); + bool nextChunk(); + + bool setContext(const PredictContext &context); + bool setContext(const SubtractContext &context); + bool setContext(const CorrectContext &context); + bool setContext(const GenerateContext &context); + + void predict(); + void subtract(); + void correct(); + void generate(pair<size_t, size_t> start, pair<size_t, size_t> end, + vector<casa::LSQFit> &solvers); + + // Get the actual work domain for this MS (after a setStrategy). + const MeqDomain &getWorkDomain() const + { return itsWorkDomain; } + + // Get the local data domain. + MeqDomain getLocalDataDomain() const; + + // There are three ways to update the solvable parms after the solver + // found a new solution. + // <group> + // Update the values of solvable parms. + // Using its spid index each parm takes its values from the vector. + void updateSolvableParms (const vector<double>& values); + + // Update the given values (for the current domain) of solvable parms + // matching the corresponding parm name in the vector. + // Vector values with a name matching no solvable parm are ignored. +// void updateSolvableParms (const ParmDataInfo& parmData); + + // Update the solvable parm values (reread from table). + void updateSolvableParms(); + + void updateSolvableParms(size_t solveDomainIndex, + const vector<double> unknowns); + + // Log the updated values of a single solve domain. + void logIteration(const string &stepName, size_t solveDomainIndex, + double rank, double chiSquared, double LMFactor); + + // Write the solved parms. + void writeParms(); + void writeParms(size_t solveDomainIndex); + + const vector<SolveDomainDescriptor> &getSolveDomainDescriptors() const + { + return itsContext.domains; + } #ifdef EXPR_GRAPH - void writeExpressionGraph(const string &fileName, int baselineIndex); + void writeExpressionGraph(const string &fileName, baseline_t baseline); #endif - // Show the settings of the Prediffer. - void showSettings() const; - - // Get the results instead of the equations. - // This is mainly used for test purposes. - vector<MeqResult> getResults (bool calcDeriv=true); - - // Get the data and flags for the time domain. - // This is mainly used for test purposes. - void getData (bool useTree, - casa::Array<casa::Complex>& data, - casa::Array<casa::Bool>& flags); - - const vector<SolveDomainDescriptor> &getSolveDomainDescriptors() const - { - return itsSolveDomainDescriptors; - } - - // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED - // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED - - // WARNING: DEPRECATED. Create Prediffer object for a specific - // MeaurementSet, MEQ model (with associated MEP database) and skymodel - // for the specified data descriptor (i.e. spectral window). - // The UVW coordinates can be calculated or taken from the MS. - Prediffer (const string& msName, - const LOFAR::ParmDB::ParmDBMeta& meqPtd, - const LOFAR::ParmDB::ParmDBMeta& skyPtd, - uint ddid, - bool calcUVW); - - // WARNING: DEPRECATED. Will be removed in the next release. - // Old interface to set strategy and steps. - // Set the strategy properties. - // It returns false if no antennas are to be used in this MS part. - bool setStrategyProp (const StrategyProp&); - - // Set the properties to be used in the step that will be performed. - // It selects the data to be used and it builds the expression tree using - // the given instrument and source model. - // It returns false if the selection is such that no data is left. - bool setStepProp (const StepProp&); - - // Initialize all solvable parameters in the MeqExpr tree for the - // given solve domains. - // It sets the scids of the solvable parms and fills itsParmData. - // It returns false if no solvable parameters are found for this MS. - bool setSolveProp (const SolveProp&); - - // Get the equations for all selected baselines and fill the - // fitter vector with them. - // The fitter vector is resized as needed. - // All fitter objects are initialized before being filled. - void fillFitters(vector<casa::LSQFit>& fitters); - - // Shift data to another phase reference position. - void shiftData(); - - // Apply corrections to the data. - void correctData(); - - // Subtract (corrupted) sources from the data. - void subtractData(); - - // Write the predicted data into the .res or .dat file. - void writePredictedData(); - - // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED - // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED - private: - // Copy constructor and assignment are not allowed. - // <group> - Prediffer (const Prediffer& other); - Prediffer& operator= (const Prediffer& other); - // </group> - - // Read measurement set meta data. - void readMeasurementSetMetaData(const string& fileName); - - // Get the name of the file that contains the data that belongs to the specified column. - string getFileForColumn(const string &column); - - // Process the MS description for the given dd (spectral window). - void processMSDesc (uint ddid); - - // Get the phase reference position of the first field. - void getPhaseRef (double ra, double dec, double startTime); - - bool setContext(const Context &context); - void updateCorrelationMask(vector<bool> &mask, const vector<string> &requestedCorrelations); - - // Get the station info (position and name). - void fillStations(); - - // Fill all UVW coordinates if they are not calculated. - void fillUVW(); - - // Get all sources from the sky model table. - // Also check the source groups. - void getSources(); - - // Make the entire tree. - void makeTree (const vector<string>& modelType, - const vector<string>& sourceNames); - - // Create the expressions for each baseline and source(group). - // The gains can be expressed as real/imag or ampl/phase. - // The station parameters are optionally taken into account. - void makeLOFARExprs (const vector<MeqSource*>& sources, - const map<string, vector<int> >& groups, - bool useTotalGain, bool usePatchGain, - bool asAP, - bool useDipole, bool useBandpass); - - // Find all nodes to be precalculated. - void setPrecalcNodes (vector<MeqJonesExpr>& nodes); - - // Fill the fitter with the equations for the given baseline. - void fillEquation (int threadnr, void* arg, - const fcomplex* dataIn, fcomplex* dummy, - const bool* flags, - const MeqRequest& request, int blindex, - bool showd=false); - - // Reset the loop variables for the getEquations loop. - void resetEqLoop(); - - // Map the correct data files (if not mapped yet). - // If a string is empty, the file is not mapped. - void mapDataFiles (const string& inFile, const string& outFile); - - // Add a data column to the table and create a symlink for it. -// void addDataColumn (casa::Table& tab, const string& columnName, -// const string& symlinkName); - void addDataColumn (casa::Table& tab, const string& columnName); - - // Define the signature of a function processing a baseline. - typedef void (Prediffer::*ProcessFuncBL) (int threadnr, void* arg, - const fcomplex* dataIn, - fcomplex* dataOut, - const bool* flags, - const MeqRequest& request, - int blindex, bool showd); - - // Loop through all data and process each baseline by ProcessFuncBL. - void processData (bool useFlags, bool preCalc, bool calcDeriv, - ProcessFuncBL func, void* arg); - - // Subtract the data of a baseline. - void subtractBL (int threadnr, void* arg, - const fcomplex* dataIn, fcomplex* dataOut, - const bool* flags, - const MeqRequest& request, int blindex, - bool showd); - - // Correct the data of a baseline. - void correctBL (int threadnr, void* arg, - const fcomplex* dataIn, fcomplex* dataOut, - const bool* flags, - const MeqRequest& request, int blindex, - bool showd); - - // Write the predicted data of a baseline. - void predictBL (int threadnr, void* arg, - const fcomplex* dummy, fcomplex* dataOut, - const bool* flags, - const MeqRequest& request, int blindex, - bool showd); - - // Get the data of a single baseline. - // <group> - void getBL (int threadnr, void* arg, - const fcomplex* data, fcomplex*, - const bool* flags, - const MeqRequest&, int blindex, - bool); - void getMapBL (int threadnr, void* arg, - const fcomplex* data, fcomplex*, - const bool* flags, - const MeqRequest& request, int blindex, - bool); - // </group> - - // Make all parameters non-solvable. - void clearSolvableParms(); - - // Read the polcs for all parameters for the current work domain. - void readParms(); - - // Get access to the next data chunk and fill in all pointers. - // The data pointers are filled in the MMapMSInfo object. - bool nextDataChunk (bool useFitters); - - // Do the precalculations for all lower level nodes. - void precalcNodes (const MeqRequest& request); - - // Show the data on cout. - void showData (int corr, int sdch, int inc, int nrchan, - const bool* flags, const fcomplex* data, - const double* realData, const double* imagData); - - // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED - // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED - - // Initialize all solvable parameters in the MeqExpr tree for the - // given solve domains. - // It sets the scids of the solvable parms and fills itsParmData. - void initSolvableParms (const vector<MeqDomain>& solveDomains); - - // Get measurement set description from file - // NB. DEPRECATED -- only use for debugging purposes, will - // be removed in the next release. - void readDescriptiveData (const string& fileName); - - // Select the stations for a strategy. - // False is returned if no stations/baselines are left. - bool selectStations (const vector<int>& antnrs, bool useAutoCorr); - - // Do the selection of baselines and correlations for a step. - bool selectStep (const vector<int>& ant1, - const vector<int>& ant2, - bool useAutoCorrelations, - const vector<bool>& corr); - - // Fill indices and count nr of baselines and correlations selected. - bool fillBaseCorr (const casa::Matrix<bool>& blSel); - - // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED - // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED - - uint itsSubbandID; - bool itsCalcUVW; - - string itsMSName; //# Measurement set name - LOFAR::ParmDB::ParmDB *itsMEP; //# Common parmtable - string itsMEPName; //# Common parmtable name - LOFAR::ParmDB::ParmDB *itsGSMMEP; //# parmtable for GSM parameters - string itsGSMMEPName; //# GSM parameters parmtable name - LOFAR::ParmDB::ParmDB *itsHistoryDB; //# parmtable for solve history - MeqParmGroup itsParmGroup; //# container for all parms - - MeqPhaseRef itsPhaseRef; //# Phase reference position in J2000 - - MeqSourceList* itsSources; - vector<MeqExpr> itsLMN; //# LMN for sources used - vector<MeqStation*> itsStations; //# All stations - vector<MeqStation*> itsSelStations; //# Subset of selected stations - vector<MeqStatUVW*> itsStatUVW; //# UVW values per station - vector<MeqJonesExpr> itsExpr; //# solve expression tree per baseline - vector<vector<MeqExprRep*> > itsPrecalcNodes; //# nodes to be precalculated - vector<MeqJonesExpr> itsCorrStat; //# Correct per station - vector<MeqJonesMMap*> itsCorrMMap; //# MMap for each baseline - vector<MeqJonesExpr> itsCorrExpr; //# Ampl/phase expressions (to correct) - - string itsInDataColumn; - string itsOutDataColumn; - - MSDesc itsMSDesc; //# description of the MS - map<string, string> itsColumns; //# mapping from column name to table file within MS. - double itsStartFreq; //# start frequency of observation - double itsEndFreq; - double itsStepFreq; - int itsNrChan; //# nr of channels in observation - int itsFirstChan; //# first channel of selected domain - int itsLastChan; //# last channel of selected domain - bool itsReverseChan; //# Channels are in reversed order - int itsDataFirstChan; //# First channel to use in data - //# (can be different if reversed order) - - MeqDomain itsWorkDomain; //# Current work domain - vector<int> itsNrScids; //# Nr of solvable coeff per solve domain - int itsNrPert; //# Nr of perturbed values in result - ParmDataInfo itsParmData; //# solvable parm info. - - vector<bool> itsSelectedCorr;//# Correlations selected in initial data selection (setSelection()) - vector<bool> itsCorr; //# Correlations to use (subset of itsSelectedCorr) - int itsNCorr; //# Number of correlations (XX, etc.) - int itsNSelCorr; //# Number of correlations selected - casa::Vector<double> itsTimes; //# All times in MS - casa::Vector<double> itsIntervals; //# All intervals in MS - - //# All baselines in the MS are numbered 0 to itsNrBl-1. - unsigned int itsNrBl; //# Total number of baselines in MS - //# Define the baselines that can be used (thus selected in strategy). - //# The seqnr is the sequence number of the baseline in the MS. - - map<pair<int, int>, int> itsSelectedBaselines; - - //# Define which baselines are selected in the select function. - vector<int> itsBLInx; //# Seqnrs of selected baselines - unsigned int itsTimeIndex; //# The index of the current time - unsigned int itsNrTimes; //# The number of times in the time domain - unsigned int itsNrTimesDone; //# Nr of times done after a setDomain - vector<double> itsChunkTimes; //# Times in current data chunk - - MMapMSInfo itsMSMapInfo; //# Info about mapped input and output file - MMap* itsInDataMap; //# Input data file mapped - MMap* itsOutDataMap; //# Output data file mapped (can same as in) - FlagsMap* itsFlagsMap; //# Flags file mapped - MMap* itsWeightMap; //# Weights file mapped - bool itsIsWeightSpec; //# true = weight per channel - - //# All parm values in current work domain. - map<string,LOFAR::ParmDB::ParmValueSet> itsParmValues; - - //# Fitter info set by initSolvableParms. - vector<int> itsFreqFitInx; //# Fitter for each freq in work domain - //# for the data in the MS resolution - vector<int> itsTimeFitInx; //# Fitter for each time in work domain - uint itsFreqNrFit; //# Nr of fitters in freq direction - - //# Thread private buffers. - int itsNthread; - vector<casa::Block<bool> > itsFlagVecs; - vector<vector<const double*> > itsResultVecs; - vector<vector<double> > itsDiffVecs; - vector<vector<uint> > itsIndexVecs; - // vector<casa::Block<bool> > itsOrdFlagVecs; - - //# Timers. - NSTimer itsPredTimer; - NSTimer itsEqTimer; - - vector<MeqDomain> itsSolveDomains; - - vector<SolveDomainDescriptor> itsSolveDomainDescriptors; - - void initializeSolveDomains(const vector<MeqDomain> &globalSolveDomains); - -#ifdef COMPUTE_SQUARED_ERROR - vector<double> itsSquaredErrorReal; - vector<double> itsSquaredErrorImag; -#endif - - // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED - // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED - - casa::Matrix<bool> itsBLSel; //# Antenna pair selected in strategy? - - // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED - // DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED + // Copy constructor and assignment are not allowed. + // <group> + Prediffer (const Prediffer& other); + Prediffer& operator= (const Prediffer& other); + // </group> + + bool setContext(const Context &context); + + void initializeSolveDomains(std::pair<size_t, size_t> size); + + // Make all parameters non-solvable. + void clearSolvableParms(); + + // Read the polcs for all parameters for the current work domain. + void readParms(); + + // Define the signature of a function processing a baseline. + typedef void (Prediffer::*BaselineProcessor) (int threadnr, void* arguments, + VisData::Pointer chunk, pair<size_t, size_t> offset, + const MeqRequest& request, baseline_t baseline, bool showd); + + // Loop through all data and process each baseline by ProcessFuncBL. + void process(bool useFlags, bool precalc, bool derivatives, + pair<size_t, size_t> start, pair<size_t, size_t> end, + BaselineProcessor processor, void *arguments); + + // Write the predicted data of a baseline. + void predictBaseline(int threadnr, void* arguments, VisData::Pointer chunk, + pair<size_t, size_t> offset, const MeqRequest& request, + baseline_t baseline, bool showd = false); + + // Subtract the data of a baseline. + void subtractBaseline(int threadnr, void* arguments, VisData::Pointer chunk, + pair<size_t, size_t> offset, const MeqRequest& request, + baseline_t baseline, bool showd = false); + + // Correct the data of a baseline. + void correctBaseline(int threadnr, void* arguments, VisData::Pointer chunk, + pair<size_t, size_t> offset, const MeqRequest& request, + baseline_t baseline, bool showd = false); + + // Generate equations for a baseline. + void generateBaseline(int threadnr, void* arguments, VisData::Pointer chunk, + pair<size_t, size_t> offset, const MeqRequest& request, + baseline_t baseline, bool showd = false); + + void testFlagsBaseline(int threadnr, void* arguments, + VisData::Pointer chunk, const MeqRequest& request, baseline_t baseline, + bool showd); + + + size_t itsSubband; + string itsInputColumn; + string itsOutputColumn; + bool itsReadUVW; + + scoped_ptr<ParmDB::ParmDB> itsInstrumentDBase; + scoped_ptr<ParmDB::ParmDB> itsSkyDBase; + scoped_ptr<ParmDB::ParmDB> itsHistoryDBase; + + //# Container for all parameters. + MeqParmGroup itsParmGroup; + //# Phase reference position in J2000 coordinates. + MeqPhaseRef itsPhaseRef; + + MeqDomain itsWorkDomain; + + //# All parm values in current work domain. + map<string,ParmDB::ParmValueSet> itsParmValues; + + //# Thread private buffers. + int itsNthread; + vector<casa::Block<bool> > itsFlagVecs; + vector<vector<const double*> > itsResultVecs; + vector<vector<double> > itsDiffVecs; + vector<vector<uint> > itsIndexVecs; + + NSTimer itsPredTimer, itsEqTimer; + + Measurement::Pointer itsMeasurement; + Model::Pointer itsModel; + VisGrid itsGrid; + VisSelection itsChunkSelection; + VisData::Pointer itsChunkData; + size_t itsChunkSize, itsChunkPosition; + ProcessingContext itsContext; + +#ifdef COMPUTE_SQUARED_ERROR + vector<double> itsSquaredErrorReal; + vector<double> itsSquaredErrorImag; +#endif }; // @} diff --git a/CEP/BB/BBSKernel/include/BBSKernel/VisData.h b/CEP/BB/BBSKernel/include/BBSKernel/VisData.h new file mode 100644 index 0000000000000000000000000000000000000000..4a76c8570cf49bcc6be75a117398ad535ed4deda --- /dev/null +++ b/CEP/BB/BBSKernel/include/BBSKernel/VisData.h @@ -0,0 +1,109 @@ +//# VisData.h: +//# +//# 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$ + +#ifndef LOFAR_BBS_BBSKERNEL_VISDATA_H +#define LOFAR_BBS_BBSKERNEL_VISDATA_H + +#include <Common/LofarTypes.h> +#include <Common/lofar_smartptr.h> +#include <Common/lofar_map.h> +#include <Common/lofar_set.h> +#include <Common/lofar_string.h> + +#include <BBSKernel/Axis.h> + +#include <boost/multi_array.hpp> +#include <utility> + +namespace LOFAR +{ +namespace BBS +{ +using std::pair; + +typedef fcomplex sample_t; +typedef bool flag_t; +typedef uint8 tslot_flag_t; +typedef pair<uint32, uint32> baseline_t; + +// TODO: Find an elegant way to unify VisGrid and VisData. + +class VisGrid +{ +public: + cell_centered_axis<regular_series> freq; + cell_centered_axis<irregular_series> time; + set<baseline_t> baselines; + set<string> polarizations; +}; + + +class VisData +{ +public: + typedef shared_ptr<VisData> Pointer; + + enum TimeslotFlag + { + UNAVAILABLE = 1<<1, + FLAGGED_IN_INPUT = 1<<2, + N_TimeslotFlag + }; + + VisData(uint32 nTimeslots, + uint32 nBaselines, + uint32 nChannels, + uint32 nPolarizations); + + size_t getPolarizationCount() const + { return polarizations.size(); } + + size_t getChannelCount() const + { return freq.size(); } + + size_t getTimeslotCount() const + { return time.size(); } + + size_t getBaselineCount() const + { return baselines.size(); } + + bool hasBaseline(baseline_t baseline) const; + size_t getBaselineIndex(baseline_t baseline) const; + + bool hasPolarization(const string &polarization) const; + size_t getPolarizationIndex(const string &polarization) const; + + cell_centered_axis<regular_series> freq; + cell_centered_axis<irregular_series> time; + map<baseline_t, size_t> baselines; + map<string, size_t> polarizations; + + boost::multi_array<double, 3> uvw; + boost::multi_array<tslot_flag_t, 2> tslot_flag; + boost::multi_array<flag_t, 4> vis_flag; + boost::multi_array<sample_t, 4> vis_data; +}; + +} //# namespace BBS +} //# namespace LOFAR + +#endif diff --git a/CEP/BB/BBSKernel/include/BBSKernel/VisSelection.h b/CEP/BB/BBSKernel/include/BBSKernel/VisSelection.h new file mode 100644 index 0000000000000000000000000000000000000000..1165b004d4ee253a02a922fddea40a886fdbe098 --- /dev/null +++ b/CEP/BB/BBSKernel/include/BBSKernel/VisSelection.h @@ -0,0 +1,119 @@ +//# VisSelection.h: +//# +//# 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$ + +#ifndef LOFAR_BBS_BBSKERNEL_VISSELECTION_H +#define LOFAR_BBS_BBSKERNEL_VISSELECTION_H + +#include <Common/LofarTypes.h> +#include <Common/LofarLogger.h> +#include <Common/lofar_set.h> +#include <Common/lofar_vector.h> +#include <Common/lofar_string.h> + +#include <utility> + +namespace LOFAR +{ +namespace BBS +{ +using std::pair; + +class VisSelection +{ +public: + enum FieldEnum + { +// FREQ_START = 0, +// FREQ_END, + CHANNEL_START = 0, + CHANNEL_END, +// CHANNEL_STEP, + TIME_START, + TIME_END, + STATIONS, + CORRELATIONS, + BASELINE_FILTER, + N_FieldEnum + }; + + enum BaselineFilter + { + AUTO = 0, + CROSS, + N_BaselineFilter + }; + + VisSelection(); + + void clear(FieldEnum field) + { itsFieldFlags[field] = false; } + + bool isSet(FieldEnum field) const + { return itsFieldFlags[field]; } + + void setChannelRange(size_t start, size_t end); + void setTimeRange(string start, string end); + void setTimeRange(double start, double end); + void setCorrelations(vector<string> correlations); + void setStations(vector<string> stations); + void setBaselineFilter(BaselineFilter filter); + + pair<size_t, size_t> getChannelRange() const + { return itsChannelRange; } + +// size_t getChannelStep() const +// { return itsChannelStep; } + + pair<double, double> getTimeRange() const + { return itsTimeRange; } + + set<string> getCorrelations() const + { return itsCorrelations; } + + set<string> getStations() const + { return itsStations; } + + BaselineFilter getBaselineFilter() const + { return itsBaselineFilter; } + +// void selectFreqRange(const pair<uint, uint> &range); +// void selectBaselines(const vector<string> &stations); +// void selectBaselines( +// const pair<vector<string>, vector<string> > &baselines); + +private: + bool convertTime(const string &in, double &out) const; + vector<bool> itsFieldFlags; + pair<size_t, size_t> itsChannelRange; +// size_t itsChannelStep; +// pair<double, double> itsFreqRange; + pair<double, double> itsTimeRange; +// set<pair<uint, uint> > itsBaselines; + set<string> itsCorrelations; + set<string> itsStations; + BaselineFilter itsBaselineFilter; +}; + +} //# namespace BBS +} //# namespace LOFAR + +#endif diff --git a/CEP/BB/BBSKernel/src/MNS/MeqBaseDFTPS.cc b/CEP/BB/BBSKernel/src/MNS/MeqBaseDFTPS.cc index 5a9e6ba2121ec008dbb1ef2fca70df442b0ac8a2..dc78008254dfa22ab1af6ff23ef4be2d05d1319f 100644 --- a/CEP/BB/BBSKernel/src/MNS/MeqBaseDFTPS.cc +++ b/CEP/BB/BBSKernel/src/MNS/MeqBaseDFTPS.cc @@ -23,8 +23,11 @@ #include <lofar_config.h> #include <BBSKernel/MNS/MeqBaseDFTPS.h> +#include <BBSKernel/MNS/MeqDFTPS.h> +#include <BBSKernel/MNS/MeqStatUVW.h> #include <BBSKernel/MNS/MeqMatrixTmp.h> #include <Common/LofarLogger.h> +#include <Common/lofar_iomanip.h> using namespace casa; @@ -105,20 +108,28 @@ MeqResult MeqBaseDFTPS::getResult (const MeqRequest& request) // complex numbers which can be turned into a cheaper multiplication. // exp(x)/exp(y) = (cos(x) + i.sin(x)) / (cos(y) + i.sin(y)) // = (cos(x) + i.sin(x)) * (cos(y) - i.sin(y)) - { - //const MeqResult& ul = itsLeft->uvw().getU(request); - //const MeqResult& vl = itsLeft->uvw().getV(request); - //const MeqResult& wl = itsLeft->uvw().getW(request); - //const MeqResult& ur = itsRight->uvw().getU(request); - //const MeqResult& vr = itsRight->uvw().getV(request); - //const MeqResult& wr = itsRight->uvw().getW(request); - //cout << "U: " << ur.getValue() - ul.getValue() << endl; - //cout << "V: " << vr.getValue() - vl.getValue() << endl; - //cout << "W: " << wr.getValue() - wl.getValue() << endl; - //LOG_TRACE_FLOW ("U: " << ur.getValue() - ul.getValue()); - //LOG_TRACE_FLOW ("V: " << vr.getValue() - vl.getValue()); - //LOG_TRACE_FLOW ("W: " << wr.getValue() - wl.getValue()); - } +/* { + + MeqDFTPS *dftpsl = dynamic_cast<MeqDFTPS*>(itsLeft.rep()); + MeqDFTPS *dftpsr = dynamic_cast<MeqDFTPS*>(itsRight.rep()); + + const MeqResult& ul = dftpsl->uvw()->getU(request); + const MeqResult& vl = dftpsl->uvw()->getV(request); + const MeqResult& wl = dftpsl->uvw()->getW(request); + const MeqResult& ur = dftpsr->uvw()->getU(request); + const MeqResult& vr = dftpsr->uvw()->getV(request); + const MeqResult& wr = dftpsr->uvw()->getW(request); + cout << "U: " << setprecision(20) << ur.getValue() - ul.getValue() + << endl; + cout << "V: " << setprecision(20) << vr.getValue() - vl.getValue() + << endl; + cout << "W: " << setprecision(20) << wr.getValue() - wl.getValue() + << endl;*/ +// LOG_TRACE_FLOW ("U: " << ur.getValue() - ul.getValue()); +// LOG_TRACE_FLOW ("V: " << vr.getValue() - vl.getValue()); +// LOG_TRACE_FLOW ("W: " << wr.getValue() - wl.getValue()); +// } + MeqMatrix res(makedcomplex(0,0), request.nx(), request.ny(), false); for (int iy=0; iy<request.ny(); ++iy) { dcomplex tmpl = left.getValue().getDComplex(0,iy); @@ -126,7 +137,8 @@ MeqResult MeqBaseDFTPS::getResult (const MeqRequest& request) // We have to divide by N. // However, we divide by 2N to get the factor 0.5 needed in (I+Q)/2, etc. // in MeqBaseLinPS. - double tmpnk = 2. * nk.getValue().getDouble(0,iy); +// double tmpnk = 2. * nk.getValue().getDouble(0,iy); + double tmpnk = 2.0; dcomplex factor; if (multFreq) { dcomplex deltal = leftDelta.getValue().getDComplex(0,iy); @@ -137,6 +149,9 @@ MeqResult MeqBaseDFTPS::getResult (const MeqRequest& request) } result.setValue (res); +// cout << "DFT:" << endl; +// cout << setprecision(20) << res << endl; + // Evaluate (if needed) for the perturbed parameter values. // Note that we do not have to test for perturbed values in nk, // because the left and right value already depend on nk. @@ -155,7 +170,8 @@ MeqResult MeqBaseDFTPS::getResult (const MeqRequest& request) for (int iy=0; iy<request.ny(); ++iy) { dcomplex tmpl = left.getPerturbedValue(spinx).getDComplex(0,iy); dcomplex tmpr = right.getPerturbedValue(spinx).getDComplex(0,iy); - double tmpnk = 2. * nk.getPerturbedValue(spinx).getDouble(0,iy); +// double tmpnk = 2. * nk.getPerturbedValue(spinx).getDouble(0,iy); + double tmpnk = 2.0; dcomplex factor; if (multFreq) { dcomplex deltal = leftDelta.getPerturbedValue(spinx).getDComplex(0,iy); diff --git a/CEP/BB/BBSKernel/src/MNS/MeqExpr.cc b/CEP/BB/BBSKernel/src/MNS/MeqExpr.cc index 92af4b8ccf48f54562d1bb88a1760ae774aedd0f..adc4826e0c766d2cd4473193ce69da67db47526e 100644 --- a/CEP/BB/BBSKernel/src/MNS/MeqExpr.cc +++ b/CEP/BB/BBSKernel/src/MNS/MeqExpr.cc @@ -261,11 +261,12 @@ void MeqExprRep::writeExpressionGraph(std::ostream &os) { os << "id" << std::hex << this << " [label=\"" << getLabel() << "\"];" << std::endl; - std::vector<MeqExprRep*>::const_iterator it; + std::vector<MeqExpr>::iterator it; for(it = itsChildren.begin(); it != itsChildren.end(); ++it) { - os << "id" << std::hex << (*it) << " -> " << "id" << std::hex << this << ";" << std::endl; - (*it)->writeExpressionGraph(os); + os << "id" << std::hex << it->rep() << " -> " << "id" << std::hex + << this << ";" << std::endl; + it->writeExpressionGraph(os); } } #endif diff --git a/CEP/BB/BBSKernel/src/MNS/MeqJonesVisData.cc b/CEP/BB/BBSKernel/src/MNS/MeqJonesVisData.cc new file mode 100644 index 0000000000000000000000000000000000000000..08757f853feed91ed70a41fc1acb69fe0ddc990d --- /dev/null +++ b/CEP/BB/BBSKernel/src/MNS/MeqJonesVisData.cc @@ -0,0 +1,167 @@ +//# MeqJonesVisData.cc: +//# +//# 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/Exceptions.h> +#include <BBSKernel/MNS/MeqJonesVisData.h> +#include <Common/LofarLogger.h> + +namespace LOFAR +{ +namespace BBS +{ + +MeqJonesVisData::MeqJonesVisData(VisData::Pointer vdata, baseline_t baseline) + : itsVisData(vdata) +{ + itsBaselineIndex = itsVisData->getBaselineIndex(baseline); +} + +MeqJonesResult MeqJonesVisData::getJResult (const MeqRequest& request) +{ + typedef boost::multi_array<sample_t, 4>::index_range range; + + size_t nChannels = request.nx(); + size_t nTimeslots = request.ny(); + pair<size_t, size_t> offset = request.offset(); + range freqRange(offset.first, offset.first + nChannels); + range timeRange(offset.second, offset.second + nTimeslots); + + // Allocate the result matrices. + size_t pol; + double *re, *im; + MeqJonesResult result(request.nspid()); + MeqMatrix& m11 = result.result11().getValueRW(); + MeqMatrix& m12 = result.result12().getValueRW(); + MeqMatrix& m21 = result.result21().getValueRW(); + MeqMatrix& m22 = result.result22().getValueRW(); + m11.setDCMat(nChannels, nTimeslots); + m12.setDCMat(nChannels, nTimeslots); + m21.setDCMat(nChannels, nTimeslots); + m22.setDCMat(nChannels, nTimeslots); + + // Copy 11 elements if available. + if(itsVisData->hasPolarization("XX") || itsVisData->hasPolarization("LL")) + { + m11.dcomplexStorage(re, im); + + try + { + pol = itsVisData->getPolarizationIndex("XX"); + } + catch(BBSKernelException &ex) + { + pol = itsVisData->getPolarizationIndex("LL"); + } + + copy(re, im, itsVisData->vis_data[boost::indices[itsBaselineIndex] + [timeRange][freqRange][pol]]); + } + else + m11 = MeqMatrix(makedcomplex(0,0), nChannels, nTimeslots); + + + // Copy 12 elements if available. + if(itsVisData->hasPolarization("XY") || itsVisData->hasPolarization("LR")) + { + m12.dcomplexStorage(re, im); + + try + { + pol = itsVisData->getPolarizationIndex("XY"); + } + catch(BBSKernelException &ex) + { + pol = itsVisData->getPolarizationIndex("LR"); + } + + copy(re, im, itsVisData->vis_data[boost::indices[itsBaselineIndex] + [timeRange][freqRange][pol]]); + } + else + m12 = MeqMatrix(makedcomplex(0,0), nChannels, nTimeslots); + + + // Copy 21 elements if available. + if(itsVisData->hasPolarization("YX") || itsVisData->hasPolarization("RL")) + { + m21.dcomplexStorage(re, im); + + try + { + pol = itsVisData->getPolarizationIndex("YX"); + } + catch(BBSKernelException &ex) + { + pol = itsVisData->getPolarizationIndex("RL"); + } + + copy(re, im, itsVisData->vis_data[boost::indices[itsBaselineIndex] + [timeRange][freqRange][pol]]); + } + else + m21 = MeqMatrix(makedcomplex(0,0), nChannels, nTimeslots); + + + // Copy 22 elements if available. + if(itsVisData->hasPolarization("YY") || itsVisData->hasPolarization("RR")) + { + m22.dcomplexStorage(re, im); + + try + { + pol = itsVisData->getPolarizationIndex("YY"); + } + catch(BBSKernelException &ex) + { + pol = itsVisData->getPolarizationIndex("RR"); + } + + copy(re, im, itsVisData->vis_data[boost::indices[itsBaselineIndex] + [timeRange][freqRange][pol]]); + } + else + m22 = MeqMatrix(makedcomplex(0,0), nChannels, nTimeslots); + + return result; +} + + +void MeqJonesVisData::copy(double *re, double *im, + const boost::multi_array<sample_t, 4>::const_array_view<2>::type &src) +{ + for(size_t tslot = 0; tslot < src.shape()[0]; ++tslot) + { + for(size_t chan = 0; chan < src.shape()[1]; ++chan) + { + re[chan] = real(src[tslot][chan]); + im[chan] = imag(src[tslot][chan]); + } + re += src.shape()[1]; + im += src.shape()[1]; + } +} + + +} // namespace BBS +} // namespace LOFAR diff --git a/CEP/BB/BBSKernel/src/MNS/MeqParm.cc b/CEP/BB/BBSKernel/src/MNS/MeqParm.cc index d6ff1e65acd15e97ede08814aea406811bda15fa..d6b07958054cba56b09ccd911cc598b5fdee1641 100644 --- a/CEP/BB/BBSKernel/src/MNS/MeqParm.cc +++ b/CEP/BB/BBSKernel/src/MNS/MeqParm.cc @@ -66,6 +66,9 @@ int MeqParm::initDomain (const vector<MeqDomain>&, int&, vector<int>&) void MeqParm::save() {} +void MeqParm::save(size_t domainIndex) +{} + void MeqParm::update (const ParmData&) { throw Exception("MeqParm::update ParmData should not be called"); diff --git a/CEP/BB/BBSKernel/src/MNS/MeqParmFunklet.cc b/CEP/BB/BBSKernel/src/MNS/MeqParmFunklet.cc index 0ba80879c54e11022f2111bbf20e2ed614ac2d99..d0c88f4084ae93fab280225e4abddb83560b7af9 100644 --- a/CEP/BB/BBSKernel/src/MNS/MeqParmFunklet.cc +++ b/CEP/BB/BBSKernel/src/MNS/MeqParmFunklet.cc @@ -409,5 +409,14 @@ void MeqParmFunklet::update(size_t domainIndex, size_t unknownIndex, const vecto itsFunklets[domainIndex]->update(unknownIndex, unknowns); } +void MeqParmFunklet::save(size_t domainIndex) +{ + ASSERT(domainIndex < itsFunklets.size()); + //itsTable->lock(); + LOFAR::ParmDB::ParmValue pval = itsFunklets[domainIndex]->getParmValue(); + itsTable->putValue(getName(), pval); + //itsTable->unlock(); +} + } // namespace BBS } // namespace LOFAR diff --git a/CEP/BB/BBSKernel/src/MNS/MeqRequest.cc b/CEP/BB/BBSKernel/src/MNS/MeqRequest.cc index 0dff4f6a3a2466d1989b3729956b816752145f22..96748f66cf7f8d37b1a1f0b7e92a9b771a682afe 100644 --- a/CEP/BB/BBSKernel/src/MNS/MeqRequest.cc +++ b/CEP/BB/BBSKernel/src/MNS/MeqRequest.cc @@ -35,7 +35,7 @@ MeqRequestId MeqRequest::theirRequestId = 0; MeqRequest::MeqRequest (const MeqDomain& domain, int nx, int ny, int nrSpid) : itsRequestId (theirRequestId++), - itsFirstX (0), + itsOffset (0, 0), itsSourceNr (0), itsNspids (nrSpid) { @@ -46,7 +46,7 @@ MeqRequest::MeqRequest (const MeqDomain& domain, int nx, const vector<double>& y, int nrSpid) : itsRequestId (theirRequestId++), - itsFirstX (0), + itsOffset (0, 0), itsSourceNr (0), itsNspids (nrSpid) { @@ -57,7 +57,7 @@ MeqRequest::MeqRequest (const MeqRequest& req, uint stx, uint nrx, uint sty, uint nry) : itsRequestId (req.itsRequestId), itsStepX (req.itsStepX), - itsFirstX (req.itsFirstX), + itsOffset (req.itsOffset), itsSourceNr (req.itsSourceNr), itsNspids (req.itsNspids) { @@ -78,7 +78,7 @@ MeqRequest::MeqRequest (const MeqRequest& req) itsStepX (req.itsStepX), itsY (req.itsY), itsYP (req.itsYP), - itsFirstX (req.itsFirstX), + itsOffset (req.itsOffset), itsSourceNr (req.itsSourceNr), itsNspids (req.itsNspids) { @@ -97,7 +97,7 @@ MeqRequest& MeqRequest::operator= (const MeqRequest& req) itsStepX = req.itsStepX; itsY = req.itsY; itsYP = req.itsYP; - itsFirstX = req.itsFirstX; + itsOffset = req.itsOffset; itsSourceNr = req.itsSourceNr; itsNspids = req.itsNspids; if (itsY.size() > 0) { diff --git a/CEP/BB/BBSKernel/src/MNS/MeqStatUVW.cc b/CEP/BB/BBSKernel/src/MNS/MeqStatUVW.cc index f4cf064113ddc3f01dd89bd4f57430c790c59780..dc5652312dfae1f4ea210be61c352c31b27adc0d 100644 --- a/CEP/BB/BBSKernel/src/MNS/MeqStatUVW.cc +++ b/CEP/BB/BBSKernel/src/MNS/MeqStatUVW.cc @@ -31,10 +31,10 @@ #include <measures/Measures/MBaseline.h> #include <measures/Measures/MEpoch.h> -#include <measures/Measures/MCBaseline.h> #include <measures/Measures/MeasConvert.h> #include <measures/Measures/MeasFrame.h> #include <casa/Quanta/MVuvw.h> +#include <stdint.h> using namespace casa; @@ -62,11 +62,11 @@ MeqStatUVW::MeqStatUVW (MeqStation* station, } */ - -MeqStatUVW::MeqStatUVW(MeqStation* station, const pair<double, double> &phaseCenter, const vector<double> &arrayPosition) -: itsStation (station), - itsPhaseCenter(MVDirection(phaseCenter.first, phaseCenter.second), MDirection::J2000), - itsArrayPosition(MVPosition(arrayPosition[0], arrayPosition[1], arrayPosition[2]), MPosition::ITRF), +MeqStatUVW::MeqStatUVW(MeqStation *station, const casa::MDirection &phaseCenter, + const casa::MPosition &arrayPosition) + : itsStation(station), + itsPhaseCenter(phaseCenter), + itsArrayPosition(arrayPosition), itsU (0), itsV (0), itsW (0), @@ -82,7 +82,7 @@ void MeqStatUVW::calculate (const MeqRequest& request) double* uptr = itsU.setDoubleFormat (1, ntime); double* vptr = itsV.setDoubleFormat (1, ntime); double* wptr = itsW.setDoubleFormat (1, ntime); - + //# Use the UVW coordinates if already calculated for a time. int ndone = 0; for (int i=0; i<ntime; ++i) { @@ -100,59 +100,64 @@ void MeqStatUVW::calculate (const MeqRequest& request) itsLastReqId = request.getId(); return; } - + //# Calculate the other UVW coordinates using the AIPS++ code. //# First form the time-independent stuff. ASSERTSTR (itsStation, "UVW coordinates cannot be calculated"); - + //# Get station coordinates in ITRF coordinates MeqResult posx = itsStation->getPosX().getResult (request); MeqResult posy = itsStation->getPosY().getResult (request); MeqResult posz = itsStation->getPosZ().getResult (request); - + LOG_TRACE_FLOW_STR ("posx" << posx.getValue()); LOG_TRACE_FLOW_STR ("posy" << posy.getValue()); LOG_TRACE_FLOW_STR ("posz" << posz.getValue()); - + //# Get position relative to center to keep values small. //# const MVPosition& mvcpos = itsPhaseRef->earthPosition().getValue(); const MVPosition& mvcpos = itsArrayPosition.getValue(); MVPosition mvpos(posx.getValue().getDouble() - mvcpos(0), posy.getValue().getDouble() - mvcpos(1), posz.getValue().getDouble() - mvcpos(2)); - - MVBaseline mvbl(mvpos); - MBaseline mbl(mvbl, MBaseline::ITRF); - LOG_TRACE_FLOW_STR ("mbl " << mbl); - - Quantum<double> qepoch(0, "s"); -//# ?? qepoch.setValue(time(0)) ?? - MEpoch mepoch(qepoch, MEpoch::UTC); -//# itsFrame.set (mepoch); - MeasFrame frame(itsArrayPosition); - frame.set(itsPhaseCenter); - frame.set(mepoch); - + +// LOG_TRACE_FLOW_STR ("mbl " << mbl); //# mbl.getRefPtr()->set(itsFrame); // attach frame - mbl.getRefPtr()->set(frame); // attach frame - - MBaseline::Convert mcvt(mbl, MBaseline::J2000); - + + for (int i=0; i<ntime; ++i) { double time = request.y(i); +// cout << "Time: " << setprecision(25) << time << endl; map<MeqTime,MeqUVW>::iterator pos = itsUVW.find (MeqTime(time)); if (pos == itsUVW.end()) { - qepoch.setValue(time); - mepoch.set(qepoch); - frame.set(mepoch); - LOG_TRACE_FLOW_STR ("frame " << mbl.getRefPtr()->getFrame()); + Quantum<double> qepoch(time, "s"); + MEpoch mepoch(qepoch, MEpoch::UTC); + MeasFrame frame(itsArrayPosition); + frame.set(itsPhaseCenter); + frame.set(mepoch); + +// cout << "Frame: " << setprecision(25) << frame << endl; +// LOG_TRACE_FLOW_STR ("frame " << mbl.getRefPtr()->getFrame()); + + MVBaseline mvbl(mvpos); +// cout << "mvbl: " << setprecision(25) << mvbl << endl; + MBaseline mbl(mvbl, MBaseline::ITRF); +// cout << "mbl: " << setprecision(25) << mbl << endl; + mbl.getRefPtr()->set(frame); // attach frame +// cout << "mbl (after set frame): " << setprecision(25) << mbl << endl; + MBaseline::Convert mcvt(mbl, MBaseline::J2000); +// cout << "mcvt: " << setprecision(25) << mcvt << endl; const MVBaseline& bas2000 = mcvt().getValue(); - LOG_TRACE_FLOW_STR (bas2000); +// cout << "bas2000: " << setprecision(25) << bas2000 << endl; + +// LOG_TRACE_FLOW_STR (bas2000); //# LOG_TRACE_FLOW_STR (itsPhaseRef->direction().getValue()); - LOG_TRACE_FLOW_STR (itsPhaseCenter.getValue()); +// LOG_TRACE_FLOW_STR (itsPhaseCenter.getValue()); //# MVuvw uvw2000 (bas2000, itsPhaseRef->direction().getValue()); + + MVuvw uvw2000 (bas2000, itsPhaseCenter.getValue()); const Vector<double>& xyz = uvw2000.getValue(); @@ -161,6 +166,15 @@ void MeqStatUVW::calculate (const MeqRequest& request) *uptr++ = xyz(0); *vptr++ = xyz(1); *wptr++ = xyz(2); +/* + cout << "Baseline: " << hex +<< *reinterpret_cast<unsigned long long int*>(const_cast<double*>(&(xyz(0)))) +<< " " << hex +<< *reinterpret_cast<unsigned long long int*>(const_cast<double*>(&(xyz(1)))) +<< " " << hex +<< *reinterpret_cast<unsigned long long int*>(const_cast<double*>(&(xyz(2)))) +<< dec << endl; +*/ // Save the UVW coordinates in the map. itsUVW[MeqTime(time)] = MeqUVW(xyz(0), xyz(1), xyz(2)); } @@ -168,6 +182,13 @@ void MeqStatUVW::calculate (const MeqRequest& request) LOG_TRACE_FLOW_STR ('U' << itsU.getValue()); LOG_TRACE_FLOW_STR ('V' << itsV.getValue()); LOG_TRACE_FLOW_STR ('W' << itsW.getValue()); + +/* + cout << "Station: " << itsStation->getName() << endl; + cout << "U: " << setprecision(25) << itsU.getValue() << endl; + cout << "V: " << setprecision(25) << itsV.getValue() << endl; + cout << "W: " << setprecision(25) << itsW.getValue() << endl; +*/ itsLastReqId = request.getId(); } diff --git a/CEP/BB/BBSKernel/src/Makefile.am b/CEP/BB/BBSKernel/src/Makefile.am index be007320c9b14ace88260d3c339824d33d90bfd3..f7832b58d49f93d3cf66c27a1deb1ee844e0ebec 100644 --- a/CEP/BB/BBSKernel/src/Makefile.am +++ b/CEP/BB/BBSKernel/src/Makefile.am @@ -3,17 +3,11 @@ lib_LTLIBRARIES = libbbskernel.la libbbskernel_la_SOURCES = \ BBSKernelStructs.cc \ BBSStatus.cc \ - BBSTestLogger.cc \ - FlagsMap.cc \ - MMap.cc \ - MMapMSInfo.cc \ - ParmData.cc \ - ParmWriter.cc \ + MeasurementAIPS.cc \ + Model.cc \ Prediffer.cc \ - Quality.cc \ - Solver.cc \ - StepProp.cc \ - StrategyProp.cc \ + VisData.cc \ + VisSelection.cc \ MNS/MeqBaseDFTPS.cc \ MNS/MeqBaseLinPS.cc \ MNS/MeqDFTPS.cc \ @@ -26,11 +20,11 @@ libbbskernel_la_SOURCES = \ MNS/MeqJonesCMul3.cc \ MNS/MeqJonesExpr.cc \ MNS/MeqJonesInvert.cc \ - MNS/MeqJonesMMap.cc \ MNS/MeqJonesMul2.cc \ MNS/MeqJonesMul3.cc \ MNS/MeqJonesNode.cc \ MNS/MeqJonesSum.cc \ + MNS/MeqJonesVisData.cc \ MNS/MeqLMN.cc \ MNS/MeqMatrix.cc \ MNS/MeqMatrixComplexArr.cc \ @@ -57,10 +51,4 @@ libbbskernel_la_SOURCES = \ MNS/MeqStatUVW.cc \ MNS/MeqTabular.cc -bin_PROGRAMS = BBSrun - -BBSrun_SOURCES = BBSrun.cc -BBSrun_LDADD = libbbskernel.la -BBSrun_DEPENDENCIES = libbbskernel.la $(LOFAR_DEPEND) - include $(top_srcdir)/Makefile.common diff --git a/CEP/BB/BBSKernel/src/MeasurementAIPS.cc b/CEP/BB/BBSKernel/src/MeasurementAIPS.cc new file mode 100644 index 0000000000000000000000000000000000000000..cdd7e653fdbd8297ce0af9d9877d7045cab4ab0d --- /dev/null +++ b/CEP/BB/BBSKernel/src/MeasurementAIPS.cc @@ -0,0 +1,750 @@ +//# MeasurementAIPS.cc: +//# +//# 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/MeasurementAIPS.h> + +#include <cstring> +#include <Common/Timer.h> +#include <Common/lofar_algorithm.h> +#include <Common/LofarLogger.h> +#include <Common/StreamUtil.h> + +//#include <casa/Arrays/Slicer.h> +//#include <casa/Arrays/Vector.h> +// Vector2.cc: necessary to instantiate .tovector() +//#include <casa/Arrays/Vector2.cc> + +#include <measures/Measures/MeasTable.h> +#include <measures/Measures/MeasConvert.h> + +#include <tables/Tables/Table.h> +#include <tables/Tables/ExprNode.h> +#include <tables/Tables/ExprNodeSet.h> +#include <tables/Tables/TableIter.h> +#include <tables/Tables/ScalarColumn.h> +#include <tables/Tables/ArrayColumn.h> + +//#include <tables/Tables/TableDesc.h> +//#include <tables/Tables/ScalarColumn.h> +#include <tables/Tables/ArrColDesc.h> +#include <tables/Tables/TiledColumnStMan.h> + +//#include <tables/Tables/ArrColDesc.h> +//#include <tables/Tables/TiledColumnStMan.h> +#include <casa/Arrays/ArrayLogical.h> +#include <casa/Arrays/Matrix.h> +#include <casa/Arrays/Cube.h> + +#include <ms/MeasurementSets/MSAntenna.h> +#include <ms/MeasurementSets/MSAntennaColumns.h> +#include <ms/MeasurementSets/MSDataDescription.h> +#include <ms/MeasurementSets/MSDataDescColumns.h> +#include <ms/MeasurementSets/MSField.h> +#include <ms/MeasurementSets/MSFieldColumns.h> +#include <ms/MeasurementSets/MSObservation.h> +#include <ms/MeasurementSets/MSObsColumns.h> +#include <ms/MeasurementSets/MSPolarization.h> +#include <ms/MeasurementSets/MSPolColumns.h> +#include <ms/MeasurementSets/MSSpectralWindow.h> +#include <ms/MeasurementSets/MSSpWindowColumns.h> + +#include <casa/Utilities/GenSort.h> + +#include <Common/lofar_iomanip.h> + +using namespace casa; +using namespace std; + +namespace LOFAR +{ +namespace BBS +{ + +MeasurementAIPS::MeasurementAIPS(string filename, + uint observationId, + uint dataDescriptionId, + uint fieldId) + : itsFilename(filename), + itsObservationId(observationId), + itsDataDescriptionId(dataDescriptionId), + itsFieldId(fieldId) +{ + itsMS = casa::MeasurementSet(itsFilename); + + itsInstrument = readInstrumentInfo(itsMS.antenna(), itsMS.observation(), + itsObservationId); + + // Read time range. + MSObservation observation(itsMS.observation()); + ROMSObservationColumns observationCols(observation); + + ASSERT(observation.nrow() > observationId); + ASSERT(!observationCols.flagRow()(observationId)); + + const Vector<MEpoch> timeRange = + observationCols.timeRangeMeas()(observationId); + + itsTimeRange = make_pair(timeRange(0), timeRange(1)); + + // Read polarization id and spectral window id. + ROMSDataDescColumns dataDescription(itsMS.dataDescription()); + ASSERT(itsMS.dataDescription().nrow() > dataDescriptionId); + ASSERT(!dataDescription.flagRow()(dataDescriptionId)); + + Int polarizationId = + dataDescription.polarizationId()(dataDescriptionId); + + Int spectralWindowId = + dataDescription.spectralWindowId()(dataDescriptionId); + + itsCorrelationProducts = + readPolarizationInfo(itsMS.polarization(), polarizationId); + + readSpectralInfo(itsMS.spectralWindow(), spectralWindowId); + itsPhaseCenter = readFieldInfo(itsMS.field(), itsFieldId); + + // Select all rows that match the specified observation. + itsMS = itsMS(itsMS.col("OBSERVATION_ID") == itsObservationId + && itsMS.col("DATA_DESC_ID") == itsDataDescriptionId + && itsMS.col("FIELD_ID") == itsFieldId); + + // Sort MS on TIME. + itsMS.sort("TIME"); + + LOG_DEBUG_STR("Measurement " << itsObservationId << " contains " + << itsMS.nrow() << " row(s)."); +} + + +MeasurementAIPS::~MeasurementAIPS() +{ + itsMS = MeasurementSet(); +} + + +VisGrid MeasurementAIPS::grid(const VisSelection &selection) const +{ + TableExprNode taqlExpr = getTAQLExpression(selection); + Slicer slicer = getCellSlicer(selection); + + Table tab_selection = itsMS(taqlExpr); + ASSERTSTR(tab_selection.nrow() > 0, "Data selection empty!"); + + return getGrid(tab_selection, slicer); +} + + +VisData::Pointer MeasurementAIPS::read(const VisSelection &selection, + const string &column, + bool readUVW) const +{ + NSTimer readTimer, copyTimer; + + TableExprNode taqlExpr = getTAQLExpression(selection); + Slicer slicer = getCellSlicer(selection); + + Table tab_selection = itsMS(taqlExpr); + ASSERTSTR(tab_selection.nrow() > 0, "Data selection empty!"); + + VisGrid grid = getGrid(tab_selection, slicer); + VisData::Pointer buffer = allocate(grid); + + size_t nChannels = buffer->freq.size(); + size_t nCorrelations = getCorrelationCount(); + + TableIterator tslotIterator(tab_selection, "TIME"); + + Table tslot; + uint32 tslotIdx = 0; + while(!tslotIterator.pastEnd()) + { + ASSERT(tslotIdx < buffer->getTimeslotCount()); + + // Get next timeslot. + tslot = tslotIterator.table(); + + // Declare all the columns we want to read. + ROScalarColumn<Int> c_antenna1(tslot, "ANTENNA1"); + ROScalarColumn<Int> c_antenna2(tslot, "ANTENNA2"); + ROScalarColumn<Bool> c_flag_row(tslot, "FLAG_ROW"); + ROArrayColumn<Double> c_uvw(tslot, "UVW"); + ROArrayColumn<Complex> c_data(tslot, column); + ROArrayColumn<Bool> c_flag(tslot, "FLAG"); + + // Read data from the MS. + readTimer.start(); + Vector<Int> aips_antenna1 = c_antenna1.getColumn(); + Vector<Int> aips_antenna2 = c_antenna2.getColumn(); + Vector<Bool> aips_flag_row = c_flag_row.getColumn(); + Matrix<Double> aips_uvw; + if(readUVW) + aips_uvw = c_uvw.getColumn(); + + Cube<Complex> aips_data = c_data.getColumn(slicer); + Cube<Bool> aips_flag = c_flag.getColumn(slicer); + readTimer.stop(); + + // Validate shapes. + ASSERT(aips_antenna1.shape().isEqual(IPosition(1,tslot.nrow()))); + ASSERT(aips_antenna2.shape().isEqual(IPosition(1,tslot.nrow()))); + ASSERT(aips_flag_row.shape().isEqual(IPosition(1, tslot.nrow()))); + ASSERT(!readUVW + || aips_uvw.shape().isEqual(IPosition(2, 3, tslot.nrow()))); + IPosition shape = IPosition(3, nCorrelations, nChannels, tslot.nrow()); + ASSERT(aips_data.shape().isEqual(shape)); + ASSERT(aips_flag.shape().isEqual(shape)); + + ASSERT(aips_data.contiguousStorage()); + ASSERT(aips_flag.contiguousStorage()); + + // The const_cast<>() call below is needed becase multi_array_ref + // expects a non-const pointer. This does not break the const semantics + // as we never write to the array. + Complex *ptr_data = const_cast<Complex*>(aips_data.data()); + boost::multi_array_ref<sample_t, 3> + data(reinterpret_cast<sample_t*>(ptr_data), + boost::extents[tslot.nrow()][nChannels][nCorrelations]); + + Bool *ptr_flag = const_cast<Bool*>(aips_flag.data()); + boost::multi_array_ref<flag_t, 3> flag(ptr_flag, + boost::extents[tslot.nrow()][nChannels][nCorrelations]); + + copyTimer.start(); + for(uInt i = 0; i < tslot.nrow(); ++i) + { + // Get time sequence for this baseline. + map<baseline_t, size_t>::iterator it = + buffer->baselines.find(baseline_t(aips_antenna1[i], + aips_antenna2[i])); + + ASSERTSTR(it != buffer->baselines.end(), "Unknown baseline!"); + size_t baseline = it->second; + + // Flag timeslot as available. + buffer->tslot_flag[baseline][tslotIdx] = 0; + + // Copy row (timeslot) flag. + if(aips_flag_row(i)) + buffer->tslot_flag[baseline][tslotIdx] |= + VisData::FLAGGED_IN_INPUT; + + // Copy UVW. + if(readUVW) + { + buffer->uvw[baseline][tslotIdx][0] = aips_uvw(0, i); + buffer->uvw[baseline][tslotIdx][1] = aips_uvw(1, i); + buffer->uvw[baseline][tslotIdx][2] = aips_uvw(2, i); + } + + // Copy visibilities. + buffer->vis_data[baseline][tslotIdx] = data[i]; + // Copy flags. + buffer->vis_flag[baseline][tslotIdx] = flag[i]; + } + copyTimer.stop(); + + // Proceed to the next timeslot. + ++tslotIdx; + ++tslotIterator; + } + + LOG_DEBUG_STR("Read time: " << readTimer); + LOG_DEBUG_STR("Copy time: " << copyTimer); + + return buffer; +} + + + +void MeasurementAIPS::write(const VisSelection &selection, + VisData::Pointer buffer, + const string &column, + bool writeFlags) const +{ + NSTimer readTimer, writeTimer; + + ASSERTSTR(!writeFlags, "Flag writing not implemented yet!"); + + // TODO: The addition of a column is not noted by the MeasurementSet + // class. + Table out(itsFilename); + out.reopenRW(); + + Slicer slicer = getCellSlicer(selection); + size_t nChannels = buffer->freq.size(); + size_t nCorrelations = getCorrelationCount(); + + // Add column if it does not exist. + // TODO: Check why the AIPS++ imager does not recognize these columns. + if(!out.tableDesc().isColumn(column)) + { + LOG_INFO_STR("Adding column '" << column << "'."); + + ArrayColumnDesc<Complex> descriptor(column, + IPosition(2, nCorrelations, nChannels), + ColumnDesc::FixedShape); + TiledColumnStMan storageManager("Tiled_" + column, + IPosition(3, nCorrelations, nChannels, 1)); + + out.addColumn(descriptor, storageManager); + out.flush(); + } + + LOG_DEBUG_STR("Writing to column: " << column); + + TableExprNode taqlExpr = getTAQLExpression(selection); + Table tab_selection = itsMS(taqlExpr); + ASSERTSTR(tab_selection.nrow() > 0, "Data selection empty!"); + + Table tslot; + size_t tslotIdx = 0; + bool mismatch = false; + TableIterator tslotIterator(tab_selection, "TIME"); + while(!tslotIterator.pastEnd()) + { + ASSERTSTR(tslotIdx < buffer->getTimeslotCount(), + "Timeslot out of range!"); + + // Extract next timeslot. + tslot = tslotIterator.table(); +// LOG_DEBUG_STR("No. of rows in timeslot " << tslotIdx << ": " +// << tslot.nrow()); + + // TODO: Should use TIME_CENTROID here (centroid of exposure)? + // NOTE: TIME_CENTROID may be different for each baseline! + ROScalarColumn<Double> c_time(tslot, "TIME"); + ROScalarColumn<Int> c_antenna1(tslot, "ANTENNA1"); + ROScalarColumn<Int> c_antenna2(tslot, "ANTENNA2"); + ArrayColumn<Complex> c_data(tslot, column); + ArrayColumn<Bool> c_flag(tslot, "FLAG"); + + // Read meta data. + readTimer.start(); + Vector<Double> aips_time = c_time.getColumn(); + Vector<Int> aips_antenna1 = c_antenna1.getColumn(); + Vector<Int> aips_antenna2 = c_antenna2.getColumn(); + readTimer.stop(); + + // Validate shapes. + ASSERT(aips_antenna1.shape().isEqual(IPosition(1, tslot.nrow()))); + ASSERT(aips_antenna2.shape().isEqual(IPosition(1, tslot.nrow()))); + ASSERT(aips_time.shape().isEqual(IPosition(1, tslot.nrow()))); + + mismatch = mismatch && (buffer->time(tslotIdx) == aips_time(0)); + + writeTimer.start(); + for(uInt i = 0; i < tslot.nrow(); ++i) + { + // Get time sequence for this baseline. + map<baseline_t, size_t>::iterator it = + buffer->baselines.find(baseline_t(aips_antenna1[i], + aips_antenna2[i])); + + ASSERTSTR(it != buffer->baselines.end(), "Unknown baseline!"); + size_t baseline = it->second; + + // Write visibilities. + Array<Complex> vis_data(IPosition(2, nCorrelations, nChannels), + reinterpret_cast<Complex*> + (&(buffer->vis_data[baseline][tslotIdx][0][0])), + SHARE); + c_data.putSlice(i, slicer, vis_data); + } + writeTimer.stop(); + + ++tslotIdx; + ++tslotIterator; + } + tab_selection.flush(); + + if(mismatch) + LOG_WARN_STR("Time mismatches detected while writing data."); + + LOG_DEBUG_STR("Read time (meta data): " << readTimer); + LOG_DEBUG_STR("Write time: " << writeTimer); +} + + +Instrument +MeasurementAIPS::readInstrumentInfo(const casa::MSAntenna &tab_antenna, + const casa::MSObservation &tab_observation, + uint id) +{ + // Get station names and positions in ITRF coordinates. + ROMSAntennaColumns antenna(tab_antenna); + ROMSObservationColumns observation(tab_observation); + ASSERT(tab_observation.nrow() > id); + ASSERT(!observation.flagRow()(id)); + + Instrument instrument; + instrument.name = observation.telescopeName()(id); + instrument.stations.resize(tab_antenna.nrow()); + + MVPosition stationCentroid; + for(size_t i = 0; i < instrument.stations.size(); ++i) + { + // Store station name and update index. + instrument.stations[i].name = antenna.name()(i); + instrument.stationIndex[antenna.name()(i)] = i; + + // Store station position. + MPosition position = antenna.positionMeas()(i); + instrument.stations[i].position = + MPosition::Convert(position, MPosition::ITRF)(); + + // Update centroid. + stationCentroid += instrument.stations[i].position.getValue(); + } + + // Get the instrument position in ITRF coordinates, or use the centroid + // of the station positions if the instrument position is unknown. + MPosition instrumentPosition; + if(MeasTable::Observatory(instrumentPosition, instrument.name)) + { + instrument.position = + MPosition::Convert(instrumentPosition, MPosition::ITRF)(); + } + else + { + LOG_WARN("Instrument position unknown; will use centroid of stations."); + stationCentroid *= (1.0 / (double) instrument.stations.size()); + instrument.position = MPosition(stationCentroid, MPosition::ITRF); + } + + return instrument; +} + +void MeasurementAIPS::readSpectralInfo(const casa::MSSpectralWindow &tab_window, + uint id) +{ + ROMSSpWindowColumns window(tab_window); + ASSERT(tab_window.nrow() > id); + ASSERT(!window.flagRow()(id)); + + Int nChannels = window.numChan()(id); + ASSERT(nChannels > 0); + + Vector<Double> frequency = window.chanFreq()(id); + Vector<Double> width = window.chanWidth()(id); + + ASSERT(frequency.nelements() == nChannels); + ASSERT(width.nelements() == nChannels); + ASSERTSTR(frequency(0) <= frequency(nChannels - 1), + "Channels are in reverse order. This is not supported yet."); + // TODO: Technically, checking for equal channel widths is not enough, + // because there could still be gaps between channels even though the + // widths are still equal (this is not prevented by the MS 2.0 standard). + ASSERTSTR(allEQ(width, width(0)), + "Channels width is not the same for all channels. This is not supported" + " yet."); + + double lower = frequency(0) - 0.5 * width(0); + double upper = frequency(nChannels - 1) + 0.5 * width(nChannels - 1); + regular_series series(lower, (upper - lower) / nChannels); + itsSpectrum = cell_centered_axis<regular_series>(series, nChannels); +} + + +vector<string> +MeasurementAIPS::readPolarizationInfo(const MSPolarization &tab_polarization, + uint id) +{ + ROMSPolarizationColumns polarization(tab_polarization); + ASSERT(tab_polarization.nrow() > id); + ASSERT(!polarization.flagRow()(id)); + + Vector<Int> products = polarization.corrType()(id); + + vector<string> result; + for(size_t i = 0; i < products.nelements(); ++i) + result.push_back(Stokes::name(Stokes::type(products(i)))); + + return result; +} + + +casa::MDirection MeasurementAIPS::readFieldInfo(const MSField &tab_field, + uint id) +{ + /* + Get phase center as RA and DEC (J2000). + + From AIPS++ note 229 (MeasurementSet definition version 2.0): + --- + FIELD: Field positions for each source + Notes: + The FIELD table defines a field position on the sky. For interferometers, + this is the correlated field position. For single dishes, this is the + nominal pointing direction. + --- + + In LOFAR/CEP/BB/MS/src/makemsdesc.cc the following line can be found: + MDirection phaseRef = mssubc.phaseDirMeasCol()(0)(IPosition(1,0)); + This should be equivalent to: + MDirection phaseRef = mssubc.phaseDirMeas(0); + as used in the code below. + */ + ROMSFieldColumns field(tab_field); + ASSERT(tab_field.nrow() > id); + ASSERT(!field.flagRow()(id)); + + return MDirection::Convert(field.phaseDirMeas(id), MDirection::J2000)(); +} + +/* +void Measurement::readTimeInfo(const Table &selection) +{ + ROScalarColumn<double> time(selection, "TIME"); + ROScalarColumn<double> interval(selection, "INTERVAL"); + + ASSERT(time.nrow() == interval.nrow() && time.nrow() > 0); + + uint nTimes = time.nrow(); + itsTimeRange[0] = time(0) - interval(0) / 2.0; + itsTimeRange[1] = time(nTimes - 1) + interval(nTimes - 1) / 2.0; +} +*/ + + +// OPTIMIZATION OPPORTUNITY: Cache implementation specific selection within +// a specialization of VisSelection or VisData. +TableExprNode +MeasurementAIPS::getTAQLExpression(const VisSelection &selection) const +{ + TableExprNode filter(true); + + const pair<double, double> &timeRange = selection.getTimeRange(); + if(selection.isSet(VisSelection::TIME_START)) + { + filter = filter && + itsMS.col("TIME") >= timeRange.first; + } + + if(selection.isSet(VisSelection::TIME_END)) + { + filter = filter + && itsMS.col("TIME") <= timeRange.second; + } + + if(selection.isSet(VisSelection::STATIONS)) + { + set<string> stations = selection.getStations(); + ASSERT(stations.size() > 0); + + set<size_t> selection; + for(set<string>::const_iterator it = stations.begin(); + it != stations.end(); + ++it) + { + casa::Regex regex = casa::Regex::fromPattern(*it); + + // If the name of a station matches the pattern, add it to the + // selection. + for(size_t i = 0; i < itsInstrument.getStationCount(); ++i) + { + casa::String name(itsInstrument.stations[i].name); + if(name.matches(regex)) + selection.insert(i); + } + } + + TableExprNodeSet selectionExpr; + for(set<size_t>::const_iterator it = selection.begin(); + it != selection.end(); + ++it) + { + selectionExpr.add( + TableExprNodeSetElem(static_cast<casa::Int>(*it))); + } + + filter = filter && itsMS.col("ANTENNA1").in(selectionExpr) + && itsMS.col("ANTENNA2").in(selectionExpr); + } + + if(selection.isSet(VisSelection::BASELINE_FILTER)) + { + if(selection.getBaselineFilter() == VisSelection::AUTO) + filter = filter && (itsMS.col("ANTENNA1") == itsMS.col("ANTENNA2")); + else if(selection.getBaselineFilter() == VisSelection::CROSS) + filter = filter && (itsMS.col("ANTENNA1") != itsMS.col("ANTENNA2")); + } + + if(selection.isSet(VisSelection::CORRELATIONS)) + { + LOG_WARN_STR("Correlation selection not yet implemented; all available" + " correlations will be used."); + } + + return filter; +} + + +// NOTE: Optimization opportunity: when reading all channels, do not use a +// slicer at all. +Slicer MeasurementAIPS::getCellSlicer(const VisSelection &selection) const +{ + // Construct slicer with default setting. + IPosition start(2, 0, 0); + size_t lastChannel = getChannelCount() - 1; + size_t lastCorrelation = getCorrelationCount() - 1; + IPosition end(2, lastCorrelation, lastChannel); + + // Validate and set selection. + pair<size_t, size_t> range = selection.getChannelRange(); + if(selection.isSet(VisSelection::CHANNEL_START)) + start = IPosition(2, 0, range.first); + + if(selection.isSet(VisSelection::CHANNEL_END)) + if(range.second > lastChannel) + LOG_WARN("Invalid end channel specified; using last channel" + " instead."); + else + end = IPosition(2, lastCorrelation, range.second); + + return Slicer(start, end, Slicer::endIsLast); +} + + +VisGrid MeasurementAIPS::getGrid(const casa::Table tab_selection, + const casa::Slicer slicer) const +{ + VisGrid grid; + + IPosition shape = slicer.length(); + size_t nCorrelations = shape[0]; + size_t nChannels = shape[1]; + + // Extract time grid based on TIME column (mid-point of integration + // interval). + // TODO: Should use TIME_CENTROID here (centroid of exposure)? + // NOTE: UVW is given of the TIME_CENTROID, not for TIME! + // NOTE: TIME_CENTROID may be different for each baseline! + ROScalarColumn<Double> c_time(tab_selection, "TIME"); + Vector<Double> time = c_time.getColumn(); + + // Find all unique timeslots. + Vector<uInt> timeIndex; + uInt nTimeslots = GenSortIndirect<double>::sort(timeIndex, time, + Sort::Ascending, Sort::InsSort + Sort::NoDuplicates); + + // Find all unique baselines. + Block<String> sortColumns(2); + sortColumns[0] = "ANTENNA1"; + sortColumns[1] = "ANTENNA2"; + Table baselines = tab_selection.sort(sortColumns, Sort::Ascending, + Sort::QuickSort + Sort::NoDuplicates); + uInt nBaselines = baselines.nrow(); + + LOG_DEBUG_STR("Selection contains " << nBaselines << " baseline(s), " + << nTimeslots << " timeslot(s), " << nChannels << " channel(s), and " + << nCorrelations << " correlation(s)."); + + // Initialize baseline axis. + ROScalarColumn<Int> c_antenna1(baselines, "ANTENNA1"); + ROScalarColumn<Int> c_antenna2(baselines, "ANTENNA2"); + Vector<Int> antenna1 = c_antenna1.getColumn(); + Vector<Int> antenna2 = c_antenna2.getColumn(); + for(uInt i = 0; i < nBaselines; ++i) + grid.baselines.insert(baseline_t(antenna1[i], antenna2[i])); + + // Initialize time axis. + ROScalarColumn<Double> c_interval(tab_selection, "INTERVAL"); + Vector<Double> interval = c_interval.getColumn(); + + vector<double> times(nTimeslots + 1); + for(uInt i = 0; i < nTimeslots; ++i) + // Compute _lower border_ of each integration cell. + times[i] = time[timeIndex[i]] - interval[timeIndex[i]] / 2.0; + + times[nTimeslots] = time[timeIndex[nTimeslots - 1]] + + interval[timeIndex[nTimeslots - 1]] / 2.0; + + grid.time = cell_centered_axis<irregular_series>(irregular_series(times), + nTimeslots); + + // Initialize frequency axis. + double lower = itsSpectrum.lower(slicer.start()[1]); + double upper = itsSpectrum.upper(slicer.end()[1]); + double delta = (upper - lower) / nChannels; + grid.freq = cell_centered_axis<regular_series>(regular_series(lower, + delta), nChannels); + + // Initialize polarization axis. + for(size_t i = 0; i < itsCorrelationProducts.size(); ++i) + grid.polarizations.insert(itsCorrelationProducts[i]); + + return grid; +} + + +VisData::Pointer MeasurementAIPS::allocate(const VisGrid &grid) const +{ + size_t nTimeslots = grid.time.size(); + size_t nBaselines = grid.baselines.size(); + size_t nChannels = grid.freq.size(); + size_t nPolarizations = grid.polarizations.size(); + + LOG_DEBUG_STR("Allocate: " << nBaselines << " baseline(s), " + << nTimeslots << " timeslot(s), " << nChannels << " channel(s), and " + << nPolarizations << " polarization(s)."); + + VisData::Pointer buffer(new VisData(nTimeslots, nBaselines, nChannels, + nPolarizations)); + + // Initially flag all timeslots as UNAVAILABLE. + for(size_t i = 0; i < nBaselines; ++i) + for(size_t j = 0; j < nTimeslots; ++j) + buffer->tslot_flag[i][j] = VisData::UNAVAILABLE; + + // Copy time and frequency axis. + buffer->time = grid.time; + buffer->freq = grid.freq; + + size_t index; + + // Initialize baseline index. + index = 0; + for(set<baseline_t>::const_iterator it = grid.baselines.begin(); + it != grid.baselines.end(); + ++it) + { + buffer->baselines[*it] = index; + ++index; + } + + // Initialize polarizations index. + index = 0; + for(set<string>::const_iterator it = grid.polarizations.begin(); + it != grid.polarizations.end(); + ++it) + { + buffer->polarizations[*it] = index; + ++index; + } + + return buffer; +} + + +} //# namespace BBS +} //# namespace LOFAR diff --git a/CEP/BB/BBSKernel/src/Model.cc b/CEP/BB/BBSKernel/src/Model.cc new file mode 100644 index 0000000000000000000000000000000000000000..bebe238efcf8ed7097cc58344bfff0b0a0635496 --- /dev/null +++ b/CEP/BB/BBSKernel/src/Model.cc @@ -0,0 +1,529 @@ +//# Model.cc: +//# +//# 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/Model.h> + +#include <BBSKernel/Measurement.h> + +#include <BBSKernel/MNS/MeqPhaseRef.h> +#include <BBSKernel/MNS/MeqParmFunklet.h> +#include <BBSKernel/MNS/MeqParmSingle.h> +#include <BBSKernel/MNS/MeqDiag.h> +#include <BBSKernel/MNS/MeqJonesInvert.h> +#include <BBSKernel/MNS/MeqBaseDFTPS.h> +#include <BBSKernel/MNS/MeqBaseLinPS.h> +#include <BBSKernel/MNS/MeqJonesCMul3.h> +#include <BBSKernel/MNS/MeqJonesSum.h> +#include <BBSKernel/MNS/MeqJonesVisData.h> + +#include <BBSKernel/MNS/MeqStation.h> +#include <BBSKernel/MNS/MeqStatUVW.h> +#include <BBSKernel/MNS/MeqLMN.h> +#include <BBSKernel/MNS/MeqDFTPS.h> +#include <BBSKernel/MNS/MeqJonesNode.h> +#include <BBSKernel/MNS/MeqRequest.h> +#include <BBSKernel/MNS/MeqJonesExpr.h> + +#include <Common/LofarLogger.h> +#include <Common/StreamUtil.h> +#include <Common/lofar_string.h> +#include <Common/lofar_vector.h> +#include <Common/lofar_map.h> + +#include <measures/Measures/MDirection.h> +#include <casa/Quanta/Quantum.h> +#include <casa/Arrays/Vector.h> + +#include <ParmDB/ParmDB.h> + +namespace LOFAR +{ +namespace BBS +{ +using LOFAR::ParmDB::ParmDB; +using std::max; + +Model::Model(const Instrument &instrument, MeqParmGroup &parmGroup, + ParmDB *skyDBase, MeqPhaseRef *phaseRef) +{ + // Construct source list. + itsSourceList.reset(new MeqSourceList(*skyDBase, parmGroup)); + + // Make nodes for all stations. + makeStationNodes(instrument, *phaseRef); +} + + +void Model::makeEquations(EquationType type, const vector<string> &components, + const set<baseline_t> &baselines, const vector<string> &sources, + MeqParmGroup &parmGroup, ParmDB *instrumentDBase, MeqPhaseRef *phaseRef, + VisData::Pointer data) +{ + // Parse component names. + vector<bool> mask(N_ModelComponent, false); + for(vector<string>::const_iterator it = components.begin(); + it != components.end(); + ++it) + { + if(*it == "GAIN") + mask[GAIN] = true; + else if(*it == "DIRECTIONAL_GAIN") + mask[DIRECTIONAL_GAIN] = 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]) + { + part1 = "ampl:"; + part2 = "phase:"; + } + + // Clear all equations. + itsEquations.clear(); + + // Make nodes for all specified sources (use all if none specified). + if(sources.empty()) + makeSourceNodes(itsSourceList->getSourceNames(), phaseRef); + else + makeSourceNodes(sources, phaseRef); + + // Make baseline equations. + size_t nStations = itsStationNodes.size(); + size_t nSources = itsSourceNodes.size(); + + vector<MeqExpr> dft(nStations * nSources); + vector<MeqJonesExpr> gain, inv_gain, bandpass; + + if(mask[BANDPASS]) + bandpass.resize(nStations); + + if(mask[GAIN] || mask[DIRECTIONAL_GAIN]) + { + inv_gain.resize(nStations); + if(mask[GAIN]) + gain.resize(nStations); + else + gain.resize(nStations * nSources); + } + + for(size_t i = 0; i < nStations; ++i) + { + // Make a phase term per station per source. + for(size_t j = 0; j < nSources; ++j) + dft[i * nSources + j] = MeqExpr(new MeqDFTPS(itsLMNNodes[j], + itsUVWNodes[i].get())); + + // Make a bandpass expression per station. + if(mask[BANDPASS]) + { + string suffix = itsStationNodes[i]->getName(); + + MeqExpr B11(MeqParmFunklet::create("bandpass:11:" + suffix, + parmGroup, instrumentDBase)); + MeqExpr B22(MeqParmFunklet::create("bandpass:22:" + suffix, + parmGroup, instrumentDBase)); + + bandpass[i] = new MeqDiag(MeqExpr(B11), MeqExpr(B22)); + } + + // Make a complex gain expression per station and possibly per source. + if(mask[GAIN]) + { + MeqExprRep *J11, *J12, *J21, *J22; + string suffix = itsStationNodes[i]->getName(); + + // Make a J-jones expression per station + MeqExpr J11_part1(MeqParmFunklet::create("gain:11:" + part1 + + suffix, parmGroup, instrumentDBase)); + MeqExpr J11_part2(MeqParmFunklet::create("gain:11:" + part2 + + suffix, parmGroup, instrumentDBase)); + MeqExpr J12_part1(MeqParmFunklet::create("gain:12:" + part1 + + suffix, parmGroup, instrumentDBase)); + MeqExpr J12_part2(MeqParmFunklet::create("gain:12:" + part2 + + suffix, parmGroup, instrumentDBase)); + MeqExpr J21_part1(MeqParmFunklet::create("gain:21:" + part1 + + suffix, parmGroup, instrumentDBase)); + MeqExpr J21_part2(MeqParmFunklet::create("gain:21:" + part2 + + suffix, parmGroup, instrumentDBase)); + MeqExpr J22_part1(MeqParmFunklet::create("gain:22:" + part1 + + suffix, parmGroup, instrumentDBase)); + MeqExpr J22_part2(MeqParmFunklet::create("gain:22:" + part2 + + suffix, parmGroup, instrumentDBase)); + + if(mask[PHASORS]) + { + J11 = new MeqExprAPToComplex(J11_part1, J11_part2); + J12 = new MeqExprAPToComplex(J12_part1, J12_part2); + J21 = new MeqExprAPToComplex(J21_part1, J21_part2); + J22 = new MeqExprAPToComplex(J22_part1, J22_part2); + } + else + { + J11 = new MeqExprToComplex(J11_part1, J11_part2); + J12 = new MeqExprToComplex(J12_part1, J12_part2); + J21 = new MeqExprToComplex(J21_part1, J21_part2); + 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]); + } + else 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; + string suffix = itsStationNodes[i]->getName() + ":" + + itsSourceNodes[j]->getName(); + + MeqExpr J11_part1(MeqParmFunklet::create("gain:11:" + part1 + + suffix, parmGroup, instrumentDBase)); + MeqExpr J11_part2(MeqParmFunklet::create("gain:11:" + part2 + + suffix, parmGroup, instrumentDBase)); + MeqExpr J12_part1(MeqParmFunklet::create("gain:12:" + part1 + + suffix, parmGroup, instrumentDBase)); + MeqExpr J12_part2(MeqParmFunklet::create("gain:12:" + part2 + + suffix, parmGroup, instrumentDBase)); + MeqExpr J21_part1(MeqParmFunklet::create("gain:21:" + part1 + + suffix, parmGroup, instrumentDBase)); + MeqExpr J21_part2(MeqParmFunklet::create("gain:21:" + part2 + + suffix, parmGroup, instrumentDBase)); + MeqExpr J22_part1(MeqParmFunklet::create("gain:22:" + part1 + + suffix, parmGroup, instrumentDBase)); + MeqExpr J22_part2(MeqParmFunklet::create("gain:22:" + part2 + + suffix, parmGroup, instrumentDBase)); + + if(mask[PHASORS]) + { + J11 = new MeqExprAPToComplex(J11_part1, J11_part2); + J12 = new MeqExprAPToComplex(J12_part1, J12_part2); + J21 = new MeqExprAPToComplex(J21_part1, J21_part2); + J22 = new MeqExprAPToComplex(J22_part1, J22_part2); + } + else + { + J11 = new MeqExprToComplex(J11_part1, J11_part2); + J12 = new MeqExprToComplex(J12_part1, J12_part2); + J21 = new MeqExprToComplex(J21_part1, J21_part2); + J22 = new MeqExprToComplex(J22_part1, J22_part2); + } + + gain[i * nSources + j] = new MeqJonesNode(MeqExpr(J11), + MeqExpr(J12), MeqExpr(J21), MeqExpr(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(type == CORRECT) + { + 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(data, baseline), + inv_gain[baseline.second]); + } + } + else + { + + for(set<baseline_t>::const_iterator it = baselines.begin(); + it != baselines.end(); + ++it) + { + const baseline_t &baseline = *it; + + vector<MeqJonesExpr> terms; + for(size_t j = 0; j < nSources; ++j) + { + MeqExpr base + (new MeqBaseDFTPS(dft[baseline.first * nSources + j], + dft[baseline.second * nSources + j], itsLMNNodes[j])); + + MeqPointSource *source = + dynamic_cast<MeqPointSource*>(itsSourceNodes[j]); + + MeqJonesExpr sourceTerm(new MeqBaseLinPS(base, source)); + + if(mask[DIRECTIONAL_GAIN]) + { + terms.push_back + (new MeqJonesCMul3(gain[baseline.first * nSources + j], + sourceTerm, gain[baseline.second * nSources + j])); + } + else + terms.push_back(sourceTerm); + } + + MeqJonesExpr sum; + if(terms.size() == 1) + sum = terms.front(); + else + sum = MeqJonesExpr(new MeqJonesSum(terms)); + + if(mask[GAIN]) + { + sum = new MeqJonesCMul3(gain[baseline.first], sum, + gain[baseline.second]); + } + + if(mask[BANDPASS]) + { + sum = new MeqJonesCMul3(bandpass[baseline.first], sum, + bandpass[baseline.second]); + } + itsEquations[baseline] = sum; + } + } +} + + +void Model::precalculate(const MeqRequest& request) +{ + if(itsEquations.empty()) + return; + + // First clear the levels of all nodes in the tree. + for(map<baseline_t, MeqJonesExpr>::iterator it = itsEquations.begin(); + it != itsEquations.end(); + ++it) + { + MeqJonesExpr &expr = it->second; + if(!expr.isNull()) + expr.clearDone(); + } + + // Now set the levels of all nodes in the tree. + // The top nodes have level 0; lower nodes have 1, 2, etc.. + int nrLev = -1; + for(map<baseline_t, MeqJonesExpr>::iterator it = itsEquations.begin(); + it != itsEquations.end(); + ++it) + { + MeqJonesExpr &expr = it->second; + if(!expr.isNull()) + nrLev = max(nrLev, expr.setLevel(0)); + } + nrLev++; + ASSERT(nrLev > 0); + + // Find the nodes to be precalculated at each level. + // That is not needed for the root nodes (the baselines). + // The nodes used by the baselines are always precalculated (even if + // having one parent). + // It may happen that a station is used by only one baseline. Calculating + // such a baseline is much more work if the station was not precalculated. + vector<vector<MeqExprRep*> > precalcNodes(nrLev); + for(size_t level = 1; level < nrLev; ++level) + { + vector<MeqExprRep*> &nodes = precalcNodes[level]; + nodes.resize(0); + + for(map<baseline_t, MeqJonesExpr>::iterator it = itsEquations.begin(); + it != itsEquations.end(); + ++it) + { + MeqJonesExpr &expr = it->second; + if(!expr.isNull()) + expr.getCachingNodes(nodes, level, false); + } + } + +/************ DEBUG DEBUG DEBUG ************/ + LOG_TRACE_FLOW_STR("#levels=" << nrLev); + for(size_t i = 0; i < nrLev; ++i) + { + LOG_TRACE_FLOW_STR("#expr on level " << i << " is " + << precalcNodes[i].size()); + } +/************ DEBUG DEBUG DEBUG ************/ + +#pragma omp parallel + { + // Loop through expressions to be precalculated. + // At each level the expressions can be executed in parallel. + // Level 0 is formed by itsExpr which are not calculated here. + for(size_t level = precalcNodes.size(); --level > 0;) + { + vector<MeqExprRep*> &nodes = precalcNodes[level]; + if(!nodes.empty()) +#pragma omp for schedule(dynamic) + for(size_t i=0; i < nodes.size(); ++i) + nodes[i]->precalculate(request); + } + } // omp parallel +} + + +MeqJonesResult Model::evaluate(baseline_t baseline, const MeqRequest& request) +{ + map<baseline_t, MeqJonesExpr>::iterator it = + itsEquations.find(baseline); + ASSERTSTR(it != itsEquations.end(), "Result requested for unknown" + " baseline " << baseline.first << " - " << baseline.second); + + return it->second.getResult(request); +} + + +void Model::makeStationNodes(const Instrument &instrument, + const MeqPhaseRef &phaseRef) +{ + // Workaround to facilitate comparison with earlier versions of BBS + // and with MeqTree. + casa::Quantum<casa::Vector<casa::Double> > angles = + phaseRef.direction().getAngle(); + casa::MDirection phaseRef2(casa::MVDirection(angles.getBaseValue()(0), + angles.getBaseValue()(1)), casa::MDirection::J2000); + LOG_WARN_STR("Superfluous conversion of phase center from/to" + " casa::MDirection to allow comparison with earlier version of BBS and" + " with MeqTree. Should be removed after validation."); + + itsStationNodes.resize(instrument.getStationCount()); + itsUVWNodes.resize(instrument.getStationCount()); + for(size_t i = 0; i < instrument.getStationCount(); ++i) + { + const casa::MVPosition &position = + instrument.stations[i].position.getValue(); + + MeqParmSingle *x = new MeqParmSingle("position:x:" + + instrument.stations[i].name, position(0)); + MeqParmSingle *y = new MeqParmSingle("position:y:" + + instrument.stations[i].name, position(1)); + MeqParmSingle *z = new MeqParmSingle("position:z:" + + instrument.stations[i].name, position(2)); + + itsStationNodes[i].reset(new MeqStation(x, y, z, + instrument.stations[i].name)); + + itsUVWNodes[i].reset(new MeqStatUVW(itsStationNodes[i].get(), + phaseRef2, instrument.position)); + } +} + + +void Model::makeSourceNodes(const vector<string> &names, MeqPhaseRef *phaseRef) +{ + itsSourceNodes.resize(names.size()); + itsLMNNodes.resize(names.size()); + for(size_t i = 0; i < names.size(); ++i) + { + MeqSource *source = itsSourceList->getSource(names[i]); + itsSourceNodes[i] = source; + + // Create an LMN node for the source. + itsLMNNodes[i] = new MeqLMN(source); + itsLMNNodes[i]->setPhaseRef(phaseRef); + } +} + + +void Model::setStationUVW(const Instrument &instrument, VisData::Pointer data) +{ + size_t nStations = instrument.getStationCount(); + vector<bool> statDone(nStations); + vector<double> statUVW(3 * nStations); + + // Step through the MS by timeslot. + for (size_t tslot = 0; tslot < data->time.size(); ++tslot) + { + double time = data->time(tslot); + fill(statDone.begin(), statDone.end(), false); + + // Set UVW of first station used to 0 (UVW coordinates are relative!). + size_t station0 = data->baselines.begin()->first.first; + statUVW[3 * station0] = 0.0; + statUVW[3 * station0 + 1] = 0.0; + statUVW[3 * station0 + 2] = 0.0; + itsUVWNodes[station0]->set(time, 0.0, 0.0, 0.0); + statDone[station0] = true; + + size_t nDone; + do + { + nDone = 0; + for (map<baseline_t, size_t>::const_iterator it = + data->baselines.begin(); + it != data->baselines.end(); + ++it) + { + size_t blindex = it->second; + if(data->tslot_flag[blindex][tslot]) + continue; + + size_t statA = it->first.first; + size_t statB = it->first.second; + if (statDone[statA] && !statDone[statB]) + { + statUVW[3 * statB] = + data->uvw[blindex][tslot][0] - statUVW[3 * statA]; + statUVW[3 * statB + 1] = + data->uvw[blindex][tslot][1] - statUVW[3 * statA + 1]; + statUVW[3 * statB + 2] = + data->uvw[blindex][tslot][2] - statUVW[3 * statA + 2]; + statDone[statB] = true; + itsUVWNodes[statB]->set(time, statUVW[3 * statB], + statUVW[3 * statB + 1], statUVW[3 * statB + 2]); + ++nDone; + } + else if (statDone[statB] && !statDone[statA]) + { + statUVW[3 * statA] = + statUVW[3 * statB] - data->uvw[blindex][tslot][0]; + statUVW[3 * statA + 1] = + statUVW[3 * statB + 1] - data->uvw[blindex][tslot][1]; + statUVW[3 * statA + 2] = + statUVW[3 * statB + 2] - data->uvw[blindex][tslot][2]; + statDone[statA] = true; + itsUVWNodes[statA]->set(time, statUVW[3 * statA], + statUVW[3 * statA + 1], statUVW[3 * statA + 2]); + ++nDone; + } + } + } + while(nDone > 0); + } +} + +} //# namespace BBS +} //# namespace LOFAR diff --git a/CEP/BB/BBSKernel/src/Prediffer.cc b/CEP/BB/BBSKernel/src/Prediffer.cc index f0d01da2c4d30e3f7a173b7da63e88b885463256..db7d4c180b7ffb5f03add9acb725b6df26ebe542 100644 --- a/CEP/BB/BBSKernel/src/Prediffer.cc +++ b/CEP/BB/BBSKernel/src/Prediffer.cc @@ -23,135 +23,68 @@ #include <lofar_config.h> #include <BBSKernel/Prediffer.h> -#include <BBSKernel/MMap.h> -#include <BBSKernel/FlagsMap.h> +#include <BBSKernel/MeasurementAIPS.h> #include <BBSKernel/Exceptions.h> -#include <BBSKernel/MNS/MeqLMN.h> -#include <BBSKernel/MNS/MeqDFTPS.h> -#include <BBSKernel/MNS/MeqDiag.h> -#include <BBSKernel/MNS/MeqBaseDFTPS.h> -#include <BBSKernel/MNS/MeqBaseLinPS.h> -#include <BBSKernel/MNS/MeqStatExpr.h> -#include <BBSKernel/MNS/MeqJonesSum.h> -#include <BBSKernel/MNS/MeqMatrixTmp.h> -#include <BBSKernel/MNS/MeqMatrixComplexArr.h> + +#include <BBSKernel/MNS/MeqDomain.h> +#include <BBSKernel/MNS/MeqRequest.h> +#include <BBSKernel/MNS/MeqResult.h> +#include <BBSKernel/MNS/MeqJonesResult.h> + +#include <BBSKernel/MNS/MeqMatrix.h> #include <BBSKernel/MNS/MeqMatrixRealArr.h> -#include <BBSKernel/MNS/MeqParmFunklet.h> -#include <BBSKernel/MNS/MeqParmSingle.h> -#include <BBSKernel/MNS/MeqPointSource.h> -#include <BBSKernel/MNS/MeqJonesCMul3.h> -#include <BBSKernel/MNS/MeqJonesInvert.h> -#include <BBSKernel/MNS/MeqJonesMMap.h> +#include <BBSKernel/MNS/MeqMatrixComplexArr.h> + +#include <BBSKernel/MNS/MeqParm.h> +#include <BBSKernel/MNS/MeqFunklet.h> +#include <BBSKernel/MNS/MeqPhaseRef.h> #include <Common/Timer.h> #include <Common/LofarLogger.h> -#include <Blob/BlobIStream.h> -#include <Blob/BlobIBufStream.h> -#include <Blob/BlobArray.h> #include <Common/StreamUtil.h> #include <Common/DataConvert.h> -#include <Common/LofarLogger.h> +#include <Common/lofar_algorithm.h> +#include <Common/lofar_fstream.h> +#include <Common/lofar_iostream.h> +#include <Common/lofar_iomanip.h> -#include <casa/Arrays/ArrayIO.h> -#include <casa/Arrays/ArrayMath.h> -#include <casa/Arrays/ArrayLogical.h> -#include <casa/Arrays/Matrix.h> -#include <casa/Arrays/Slice.h> -#include <casa/Arrays/Slicer.h> -#include <casa/Arrays/Vector.h> -// Vector2.cc: necessary to instantiate .tovector() -#ifdef AIPS_NO_TEMPLATE_SRC -#include <casa/Arrays/Vector2.cc> -#endif -#include <casa/Quanta/MVBaseline.h> -#include <casa/Quanta/MVPosition.h> -#include <casa/OS/Timer.h> -#include <casa/OS/RegularFile.h> -//#include <casa/OS/SymLink.h> -#include <casa/Containers/Record.h> -#include <casa/IO/AipsIO.h> -#include <casa/IO/MemoryIO.h> #include <casa/Exceptions/Error.h> #include <casa/Utilities/Regex.h> #include <casa/Utilities/GenSort.h> +#include <casa/Quanta/MVTime.h> +#include <scimath/Fitting/LSQFit.h> -#include <measures/Measures/MeasConvert.h> -#include <measures/Measures/MeasTable.h> -#include <measures/Measures/MPosition.h> -#include <measures/Measures/MDirection.h> -#include <measures/Measures/Stokes.h> - -#include <tables/Tables/Table.h> -#include <tables/Tables/TableDesc.h> -#include <tables/Tables/ScalarColumn.h> -#include <tables/Tables/ArrColDesc.h> -#include <tables/Tables/TiledColumnStMan.h> - -#include <ms/MeasurementSets/MeasurementSet.h> -#include <ms/MeasurementSets/MSAntenna.h> -#include <ms/MeasurementSets/MSAntennaColumns.h> -#include <ms/MeasurementSets/MSDataDescription.h> -#include <ms/MeasurementSets/MSDataDescColumns.h> -#include <ms/MeasurementSets/MSField.h> -#include <ms/MeasurementSets/MSFieldColumns.h> -#include <ms/MeasurementSets/MSObservation.h> -#include <ms/MeasurementSets/MSObsColumns.h> -#include <ms/MeasurementSets/MSPolarization.h> -#include <ms/MeasurementSets/MSPolColumns.h> -#include <ms/MeasurementSets/MSSpectralWindow.h> -#include <ms/MeasurementSets/MSSpWindowColumns.h> +#include <measures/Measures.h> +#include <functional> #include <stdexcept> -#include <iostream> -#include <iomanip> -#include <fstream> -//#include <malloc.h> -#include <unistd.h> -#include <algorithm> - -//#include <BBSKernel/BBSTestLogger.h> #if defined _OPENMP #include <omp.h> #endif -using namespace casa; -using namespace std; +#ifdef EXPR_GRAPH +#include <BBSKernel/MNS/MeqJonesExpr.h> +#endif namespace LOFAR { -namespace BBS +namespace BBS { using LOFAR::operator<<; -using std::max; - -Prediffer::Prediffer( const string &measurementSet, - const string &inputColumn, - const string &skyParameterDB, - const string &instrumentParameterDB, - const string &historyDB, - uint subbandID, - bool calcUVW) - : itsSubbandID (subbandID), - itsCalcUVW (calcUVW), - itsMEP (0), - itsGSMMEP (0), - itsHistoryDB (0), - itsSources (0), - itsInDataColumn (inputColumn), - itsNrPert (0), - itsNCorr (0), - itsNrBl (0), - itsTimeIndex (0), - itsNrTimes (0), - itsNrTimesDone (0), - itsInDataMap (0), - itsOutDataMap (0), - itsFlagsMap (0), - itsWeightMap (0), - itsIsWeightSpec (false) +using LOFAR::ParmDB::ParmDB; +using LOFAR::ParmDB::ParmDBMeta; + +Prediffer::Prediffer(const string &measurement, size_t subband, + const string &inputColumn, const string &skyDBase, + const string &instrumentDBase, const string &historyDBase, bool readUVW) + : itsSubband (subband), + itsInputColumn (inputColumn), + itsReadUVW (readUVW), + itsChunkSize (0), + itsChunkPosition (0) { - LOG_INFO("Prediffer was compiled with the following options:"); + LOG_INFO("Compile time options:"); #ifdef _OPENMP LOG_INFO(" _OPENMP: yes"); @@ -164,76 +97,86 @@ Prediffer::Prediffer( const string &measurementSet, #else LOG_INFO(" EXPR_GRAPH: no"); #endif - + #ifdef COMPUTE_SQUARED_ERROR LOG_INFO(" COMPUTE_SQUARED_ERROR: yes"); #else LOG_INFO(" COMPUTE_SQUARED_ERROR: no"); #endif - - // Get path to measurement set. - itsMSName = Path(measurementSet).absoluteName(); - LOG_INFO_STR("Input: " << itsMSName << "::" << itsInDataColumn); - - // Read meta data (needed to know for instance the number of available - // correlations). + + // Open measurement. try { - readMeasurementSetMetaData(itsMSName); + LOG_INFO_STR("Input: " << measurement << "::" << itsInputColumn); + itsMeasurement.reset(new MeasurementAIPS(measurement, 0, subband, 0)); } - catch (AipsError &_ex) + catch(casa::AipsError &_ex) { - THROW(BBSKernelException, "Failed to read input meta data (AipsError: " << _ex.what() << ")"); + THROW(BBSKernelException, "Failed to open measurement: " + << measurement << endl << "(AipsError: " + << _ex.what() << ")"); } - - // Amongst other things, processMSDesc() calls fillStations(), which - // sets itsStations. Eventually it may make sense to remove MSDesc from - // the Prediffer. - processMSDesc(itsSubbandID); - - // Open sky parmdb. + + // Open sky model parmdb. try { - LOFAR::ParmDB::ParmDBMeta skyParameterDBMeta("aips", skyParameterDB); - itsGSMMEP = new LOFAR::ParmDB::ParmDB(skyParameterDBMeta); - itsGSMMEPName = skyParameterDBMeta.getTableName(); - LOG_INFO_STR("Sky model ParmDB: " << itsGSMMEPName); + ParmDBMeta skyDBaseMeta("aips", skyDBase); + LOG_INFO_STR("Sky model database: " << skyDBaseMeta.getTableName()); + itsSkyDBase.reset(new ParmDB(skyDBaseMeta)); } - catch (AipsError &_ex) + catch(casa::AipsError &_ex) { - THROW(BBSKernelException, "Failed to open sky parameter db: " << skyParameterDB << endl << "(AipsError: " << _ex.what() << ")"); + THROW(BBSKernelException, "Failed to open sky parameter db: " + << skyDBase << endl << "(AipsError: " << _ex.what() << ")"); } - // Open instrument parmdb. + // Open instrument model parmdb. try { - LOFAR::ParmDB::ParmDBMeta instrumentParameterDBMeta("aips", instrumentParameterDB); - itsMEP = new LOFAR::ParmDB::ParmDB(instrumentParameterDBMeta); - itsMEPName = instrumentParameterDBMeta.getTableName(); - LOG_INFO_STR("Instrument model ParmDB: " << itsMEPName); + ParmDBMeta instrumentDBaseMeta("aips", instrumentDBase); + LOG_INFO_STR("Instrument model database: " + << instrumentDBaseMeta.getTableName()); + itsInstrumentDBase.reset(new ParmDB(instrumentDBaseMeta)); } - catch (AipsError &_ex) + catch(casa::AipsError &_ex) { - THROW(BBSKernelException, "Failed to open instrument parameter db: " << instrumentParameterDB << endl << "(AipsError: " << _ex.what() << ")"); + THROW(BBSKernelException, "Failed to open instrument parameter db: " + << instrumentDBase << endl << "(AipsError: " << _ex.what() << ")"); } - + // Open history db. - if(!historyDB.empty()) + if(!historyDBase.empty()) { try { - LOFAR::ParmDB::ParmDBMeta historyDBMeta("aips", historyDB); - itsHistoryDB = new LOFAR::ParmDB::ParmDB(historyDBMeta); - LOG_INFO_STR("History DB: " << historyDBMeta.getTableName()); + ParmDBMeta historyDBaseMeta("aips", historyDBase); + LOG_INFO_STR("History DB: " << historyDBaseMeta.getTableName()); + itsHistoryDBase.reset(new ParmDB(historyDBaseMeta)); } - catch (AipsError &_ex) + catch (casa::AipsError &_ex) { - THROW(BBSKernelException, "Failed to open history db: " << historyDB << endl << "(AipsError: " << _ex.what() << ")"); + THROW(BBSKernelException, "Failed to open history db: " + << historyDBase << endl << "(AipsError: " << _ex.what() << ")"); } } else LOG_INFO_STR("History DB: -"); + LOG_INFO_STR("UVW source: " << (readUVW ? "read" : "computed")); + LOG_INFO_STR("UVW convention: " << (readUVW ? "as recorded in the input" + " measurement" : "ANTENNA2 - ANTENNA1 (AIPS++ convention)")); +// ASSERTSTR(computeUVW, "Reading of UVW coordinates from the input" +// " measurement temporarily disabled."); + + // Initialize model. + casa::MEpoch startTimeMeas = itsMeasurement->getTimeRange().first; + casa::Quantum<casa::Double> startTime = startTimeMeas.get("s"); + itsPhaseRef = MeqPhaseRef(itsMeasurement->getPhaseCenter(), + startTime.getValue("s")); + + itsModel.reset(new Model(itsMeasurement->getInstrument(), itsParmGroup, + itsSkyDBase.get(), &itsPhaseRef)); + // Allocate thread private buffers. #if defined _OPENMP itsNthread = omp_get_max_threads(); @@ -251,266 +194,231 @@ Prediffer::~Prediffer() { LOG_TRACE_FLOW( "Prediffer destructor" ); - delete itsSources; - for (vector<MeqStatUVW*>::iterator iter = itsStatUVW.begin(); - iter != itsStatUVW.end(); - iter++) { - delete *iter; - } - for (vector<MeqStation*>::iterator iter = itsStations.begin(); - iter != itsStations.end(); - iter++) { - delete *iter; - } - - delete itsMEP; - delete itsGSMMEP; -// delete itsHistoryDB; - - delete itsInDataMap; - delete itsOutDataMap; - delete itsFlagsMap; - delete itsWeightMap; - // clear up the matrix pool MeqMatrixComplexArr::poolDeactivate(); MeqMatrixRealArr::poolDeactivate(); } -void Prediffer::updateCorrelationMask(vector<bool> &mask, const vector<string> &requestedCorrelations) +void Prediffer::setSelection(VisSelection selection) { - if(requestedCorrelations.empty()) return; - - const vector<string> &availableCorrelations = itsMSDesc.corrTypes; - for(int i = 0; i < availableCorrelations.size(); ++i) - { - if(mask[i]) - { - mask[i] = false; - for(int j = 0; j < requestedCorrelations.size(); ++j) - { - if(requestedCorrelations[j] == availableCorrelations[i]) - { - mask[i] = true; - break; - } - } - } - } + itsChunkSelection = selection; + itsGrid = itsMeasurement->grid(selection); } -bool Prediffer::setSelection(const vector<string> &stations, const Correlation &correlation) -{ - // Select correlations. - const vector<string> &availableCorrelations = itsMSDesc.corrTypes; - const vector<string> &requestedCorrelations = correlation.type; - LOG_INFO_STR("Available correlation(s): " << availableCorrelations); - LOG_INFO_STR("Requested correlation(s): " << requestedCorrelations); - - // Initially select all correlations. - fill(itsSelectedCorr.begin(), itsSelectedCorr.end(), true); - - // Deselect all correlations _not_ present in requestedCorrelations. - updateCorrelationMask(itsSelectedCorr, requestedCorrelations); - - // Verify that at least one correlations is still selected. - if(count(itsSelectedCorr.begin(), itsSelectedCorr.end(), true) == 0) - { - LOG_ERROR("At least one correlation should be selected."); +void Prediffer::setChunkSize(size_t size) +{ + itsChunkSize = size; + itsChunkPosition = 0; +} + + +bool Prediffer::nextChunk() +{ + // Exit if the MS has no overlap in frequency with the specified work + // domain. +// if(startChannel >= itsMeasurement->getChannelCount()) +// return false; + ASSERT(itsChunkPosition <= itsGrid.time.size()); + + if(itsChunkPosition == itsGrid.time.size()) return false; - } - - // Output selected correlations (inform the user). - ostringstream os; - os << "Selected correlation(s):"; - for(unsigned int i = 0; i < availableCorrelations.size(); ++i) - { - if(itsSelectedCorr[i]) - { - os << " " << availableCorrelations[i]; - } - } - LOG_INFO_STR(os.str()); - - // Select stations. - const vector<string> &availableStations = itsMSDesc.antNames; - const vector<string> &requestedStations = stations; - LOG_INFO_STR("Available station(s): " << availableStations); - LOG_INFO_STR("Requested station(s): " << requestedStations); - - vector<string> debugSelectedStations; - if(requestedStations.empty()) + + // Clear time selection. + itsChunkSelection.clear(VisSelection::TIME_START); + itsChunkSelection.clear(VisSelection::TIME_END); + + if(itsChunkSize == 0) { - // Select all available stations if none are requested explicitly. - itsSelStations = itsStations; - debugSelectedStations = availableStations; + itsChunkPosition = itsGrid.time.size(); } else { - itsSelStations = vector<MeqStation*>(availableStations.size(), (MeqStation*) 0); - - for(vector<string>::const_iterator it = requestedStations.begin(); - it != requestedStations.end(); - ++it) - { - casa::Regex regex = casa::Regex::fromPattern(*it); - - // If a names matches, add its antennanr to the vector. - for(uint i = 0; i < availableStations.size(); ++i) - { - String stationName(availableStations[i]); - if(stationName.matches(regex)) - { - itsSelStations[i] = itsStations[i]; - debugSelectedStations.push_back(availableStations[i]); - } - } - } - } - LOG_INFO_STR("Selected station(s): " << debugSelectedStations); - - // Select baselines. - LOG_INFO_STR("Requested baselines: " << correlation.selection); - - itsSelectedBaselines.clear(); - for(int i = 0; i < itsMSDesc.ant1.size(); ++i) - { - const pair<int, int> baseline(itsMSDesc.ant1[i], itsMSDesc.ant2[i]); - - if(itsSelStations[baseline.first] && itsSelStations[baseline.second]) + double start = itsGrid.time.lower(itsChunkPosition); + itsChunkPosition += itsChunkSize; + if(itsChunkPosition > itsGrid.time.size()) { - if( correlation.selection == "ALL" - || (baseline.first == baseline.second && correlation.selection == "AUTO") - || (baseline.first != baseline.second && correlation.selection == "CROSS")) - { - itsSelectedBaselines[baseline] = i; - } + itsChunkPosition = itsGrid.time.size(); } - } - LOG_INFO_STR("No. of selected baselines: " << itsSelectedBaselines.size()); - - // Map flags into memory. - string flagFile = getFileForColumn(MS::columnName(MS::FLAG)); - if(flagFile.empty()) - { - return false; - } - LOG_INFO_STR("Input column " << MS::columnName(MS::FLAG) << " maps to: " << flagFile); - itsFlagsMap = new FlagsMap(flagFile, MMap::Read); - - // Get all sources from the ParmDB. - itsSources = new MeqSourceList(*itsGSMMEP, itsParmGroup); - - // Create the UVW nodes and fill them with uvw-s from MS if not calculated. - fillUVW(); - - return (itsSelectedBaselines.size() > 0); + double end = itsGrid.time.upper(itsChunkPosition - 1); + itsChunkSelection.setTimeRange(start, end); + } + + // Read data. + LOG_DEBUG("Reading chunk..."); + itsChunkData = itsMeasurement->read(itsChunkSelection, itsInputColumn, + itsReadUVW); + if(itsReadUVW) + itsModel->setStationUVW(itsMeasurement->getInstrument(), itsChunkData); + +/* + LOG_DEBUG_STR("Times:"); + for(size_t i = 0; i < itsChunkData->time.size(); ++i) + LOG_DEBUG_STR("i: " << i << " " << setprecision(15) << + itsChunkData->time(i)); +*/ + + // Set work domain. + pair<double, double> freqRange = itsChunkData->freq.range(); + pair<double, double> timeRange = itsChunkData->time.range(); + itsWorkDomain = MeqDomain(freqRange.first, freqRange.second, + timeRange.first, timeRange.second); + + // Read all parameter values that are part of the work domain. + readParms(); + + // Display chunk meta data. + LOG_INFO_STR("Chunk: "); + LOG_INFO_STR(" Frequency: " + << setprecision(3) << freqRange.first / 1000.0 << " kHz" + << " - " + << setprecision(3) << freqRange.second / 1000.0 << " kHz"); + LOG_INFO_STR(" Bandwidth: " + << setprecision(3) << (freqRange.second - freqRange.first) / 1000.0 + << "kHz (" << itsChunkData->freq.size() << " channels of " + << setprecision(3) + << (freqRange.second - freqRange.first) / itsChunkData->freq.size() + << " Hz)"); + LOG_INFO_STR(" Time: " + << casa::MVTime::Format(casa::MVTime::YMD, 6) + << casa::MVTime(casa::Quantum<casa::Double>(timeRange.first, "s")) + << " - " + << casa::MVTime::Format(casa::MVTime::YMD, 6) + << casa::MVTime(casa::Quantum<casa::Double>(timeRange.second, "s"))); + LOG_INFO_STR(" Duration: " + << setprecision(3) << (timeRange.second - timeRange.first) / 3600.0 + << " hours (" << itsChunkData->time.size() << " samples of " + << setprecision(3) + << (timeRange.second - timeRange.first) / itsChunkData->time.size() + << " s on average)"); + + return true; } bool Prediffer::setContext(const Context &context) { - // Select correlations. - const vector<string> &availableCorrelations = itsMSDesc.corrTypes; - const vector<string> &requestedCorrelations = context.correlation.type; -// LOG_INFO_STR("Available correlation(s): " << availableCorrelations); - LOG_INFO_STR("Requested correlation(s): " << requestedCorrelations); - - - // Deselect all correlations _not_ present in requestedCorrelations. - itsCorr = itsSelectedCorr; - updateCorrelationMask(itsCorr, requestedCorrelations); - - // Verify that at least one correlations is still selected. - if(count(itsCorr.begin(), itsCorr.end(), true) == 0) - { - LOG_ERROR("At least one correlation should be selected."); - return false; - } - - // Output selected correlations (inform the user). - ostringstream os; - os << "Selected correlations(s):"; - for(unsigned int i = 0; i < availableCorrelations.size(); ++i) + // Clear context. + itsContext = ProcessingContext(); + + // Select polarizations. + vector<string> requested; + if(context.correlation.type.empty()) + requested = itsMeasurement->getCorrelations(); + else + requested = context.correlation.type; + + for(vector<string>::const_iterator it = requested.begin(); + it != requested.end(); + ++it) { - if(itsCorr[i]) + size_t idx; + + try + { + idx = itsChunkData->getPolarizationIndex(*it); + if(*it == "XX" || *it == "LL") + itsContext.polarizations.insert(make_pair(idx, 0)); + else if(*it == "XY" || *it == "LR") + itsContext.polarizations.insert(make_pair(idx, 1)); + else if(*it == "YX" || *it == "RL") + itsContext.polarizations.insert(make_pair(idx, 2)); + else if(*it == "YY" || *it == "RR") + itsContext.polarizations.insert(make_pair(idx, 3)); + else + LOG_WARN_STR("Don't know how to process polarization " << *it + << "; skipping"); + } + catch(BBSKernelException &ex) { - os << " " << availableCorrelations[i]; } } - LOG_INFO_STR(os.str()); - + + // Verify that at least one polarization is selected. + if(itsContext.polarizations.empty()) + { + LOG_ERROR("At least one polarization should be selected."); + return false; + } + // Select baselines. - itsBLInx.clear(); if(context.baselines.station1.empty()) { - // If no baselines are speficied, use all baselines selected in the strategy that - // match the correlation selection of this context. - map<pair<int, int>, int>::const_iterator it = itsSelectedBaselines.begin(); - while(it != itsSelectedBaselines.end()) + // If no baselines are speficied, use all baselines selected in the + // strategy that match the correlation selection of this context. + map<baseline_t, size_t>::const_iterator it = + itsChunkData->baselines.begin(); + + while(it != itsChunkData->baselines.end()) { - const pair<int, int> &baseline = it->first; - - if( context.correlation.selection == "ALL" - || (baseline.first == baseline.second && context.correlation.selection == "AUTO") - || (baseline.first != baseline.second && context.correlation.selection == "CROSS")) + const baseline_t &baseline = it->first; + + if(context.correlation.selection == "ALL" + || (baseline.first == baseline.second + && context.correlation.selection == "AUTO") + || (baseline.first != baseline.second + && context.correlation.selection == "CROSS")) { - itsBLInx.push_back(it->second); + itsContext.baselines.insert(it->first); } ++it; } } else { - vector<string>::const_iterator baseline_it1 = context.baselines.station1.begin(); - vector<string>::const_iterator baseline_it2 = context.baselines.station2.begin(); + const Instrument &instrument = itsMeasurement->getInstrument(); + + vector<string>::const_iterator baseline_it1 = + context.baselines.station1.begin(); + vector<string>::const_iterator baseline_it2 = + context.baselines.station2.begin(); while(baseline_it1 != context.baselines.station1.end()) - { - // Find the IDs of all the stations of which the name matches the regex - // specified in the context (Baselines.station1 and Baselines.station2). - vector<int> stationGroup1, stationGroup2; + { + // Find the indices of all the stations of which the name matches + // the regex specified in the context. + set<size_t> stationGroup1, stationGroup2; casa::Regex regex1 = casa::Regex::fromPattern(*baseline_it1); casa::Regex regex2 = casa::Regex::fromPattern(*baseline_it2); - for(int i = 0; i < itsMSDesc.antNames.size(); ++i) + for(size_t i = 0; i < instrument.getStationCount(); ++i) { - String stationName(itsMSDesc.antNames[i]); + casa::String stationName(instrument.stations[i].name); if(stationName.matches(regex1)) { - stationGroup1.push_back(i); + stationGroup1.insert(i); } if(stationName.matches(regex2)) { - stationGroup2.push_back(i); + stationGroup2.insert(i); } } - LOG_WARN_STR("Baseline specification " << *baseline_it1 << ", " << *baseline_it2 << " does not match any baseline in the measurement set."); - - // Generate all possible baselines (pairs) from the two groups of station IDs. If a baseline - // is selected in the current strategy _and_ matches the correlation selection of this context, - // select it for processing (by adding the ID of the _baseline_ to the itsBLInx vector). - for(vector<int>::const_iterator it1 = stationGroup1.begin(); it1 != stationGroup1.end(); ++it1) + // Generate all possible baselines (pairs) from the two groups of + // station indices. If a baseline is selected in the current + // strategy _and_ matches the correlation selection of this context, + // select it for processing. + for(set<size_t>::const_iterator it1 = stationGroup1.begin(); + it1 != stationGroup1.end(); + ++it1) { - for(vector<int>::const_iterator it2 = stationGroup2.begin(); it2 != stationGroup2.end(); ++it2) + for(set<size_t>::const_iterator it2 = stationGroup2.begin(); + it2 != stationGroup2.end(); + ++it2) { - if( context.correlation.selection == "ALL" - || (*it1 == *it2 && context.correlation.selection == "AUTO") - || (*it1 != *it2 && context.correlation.selection == "CROSS")) + if(context.correlation.selection == "ALL" + || ((*it1 == *it2) + && (context.correlation.selection == "AUTO")) + || ((*it1 != *it2) + && context.correlation.selection == "CROSS")) { - const pair<int, int> baseline(*it1, *it2); - - map<pair<int, int>, int>::const_iterator index = itsSelectedBaselines.find(baseline); - - if(index != itsSelectedBaselines.end()) - { - itsBLInx.push_back(index->second); - } + baseline_t baseline(*it1, *it2); + + if (itsChunkData->hasBaseline(baseline)) + itsContext.baselines.insert(baseline); } } } @@ -519,169 +427,63 @@ bool Prediffer::setContext(const Context &context) ++baseline_it2; } } - ASSERTSTR(itsBLInx.size() > 0, "No baselines selected in current context."); - - // Clear the solvable flag on all parameters (may still be set from the - // previous step. - clearSolvableParms(); - - // Create the measurement equation for each interferometer (baseline). - if(context.sources.empty()) - // If no sources are specified, use all available sources. - makeTree(context.instrumentModel, itsSources->getSourceNames()); - else - makeTree(context.instrumentModel, context.sources); - // Put funklets in parms which are not filled yet. (?) - for (MeqParmGroup::iterator it = itsParmGroup.begin(); - it != itsParmGroup.end(); - ++it) + if(itsContext.baselines.empty()) { - it->second.fillFunklets(itsParmValues, itsWorkDomain); + LOG_ERROR("At least one baseline should be selected."); + return false; } - + return true; } -MeqDomain Prediffer::getLocalDataDomain() const +bool Prediffer::setContext(const PredictContext &context) { - return MeqDomain(itsStartFreq, - itsEndFreq, - itsMSDesc.times.front() - itsMSDesc.exposures.front() / 2, - itsMSDesc.times.back() + itsMSDesc.exposures.back() / 2); -} + if(!setContext(dynamic_cast<const Context &>(context))) + { + return false; + } + // Create the measurement equation for each interferometer (baseline). + itsModel->makeEquations(Model::PREDICT, context.instrumentModel, + itsContext.baselines, context.sources, itsParmGroup, + itsInstrumentDBase.get(), &itsPhaseRef, itsChunkData); -bool Prediffer::setWorkDomain(const MeqDomain &domain) -{ - // Determine channel with lower border closest to specified start frequency. - int startChan = int(0.5 + (domain.startX() - itsStartFreq) / itsStepFreq); - - // Determine channel with upper border closest to specified end frequency. - int endChan = int(0.5 + (domain.endX() - itsStartFreq) / itsStepFreq) - 1; - - // Exit if the MS has no overlap in frequency with the specified work domain. - if(endChan < 0 || startChan >= itsNrChan) - return false; - - // Clip start/end channel against the MS domain. - if(startChan < 0) - itsFirstChan = 0; - else - itsFirstChan = startChan; - - if(endChan > itsNrChan - 1) - itsLastChan = itsNrChan - 1; - else - itsLastChan = endChan; - - ASSERT (itsFirstChan <= itsLastChan); - - // Find the times matching the given time interval. - double startTime = domain.startY(); - - // Usually the work domain is shifted sequentially in time, - // so we can start the search for the start of the specified - // work domain from the end of the previous work domain. - - // Compute the end of the previous work domain. - itsTimeIndex += itsNrTimes; - - // If necessary, restart the search at the beginning. - if(itsTimeIndex >= itsMSDesc.times.size() || startTime < itsMSDesc.times[itsTimeIndex]) - itsTimeIndex = 0; - - // Find the index of the time sample with lower border closest - // to the specified start time. - while(itsTimeIndex < itsMSDesc.times.size() && startTime > itsMSDesc.times[itsTimeIndex]) - ++itsTimeIndex; - - // Exit if the MS has no overlap in time with the specified work domain. - if(itsTimeIndex >= itsMSDesc.times.size()) - return false; - - // Compute the actual start time (i.e. the lower border of - // the selected time sample. - startTime = itsMSDesc.times[itsTimeIndex] - itsMSDesc.exposures[itsTimeIndex] / 2; - - // Find the index of the time sample with the upper bound closest - // to the specified end time. - itsNrTimes = 0; - double endTime = domain.endY(); - unsigned int endIndex = itsTimeIndex; - while(endIndex < itsMSDesc.times.size() && endTime >= itsMSDesc.times[endIndex]) + // Put funklets in parms which are not filled yet. (?) + for(MeqParmGroup::iterator it = itsParmGroup.begin(); + it != itsParmGroup.end(); + ++it) { - ++endIndex; - ++itsNrTimes; + it->second.fillFunklets(itsParmValues, itsWorkDomain); } - ASSERT(itsNrTimes > 0); - - // Compute the actual end time (i.e. the upper border of - // the selected time sample. - endTime = itsMSDesc.times[endIndex - 1] + itsMSDesc.exposures[endIndex - 1] / 2; - - itsWorkDomain = MeqDomain(itsStartFreq + itsFirstChan * itsStepFreq, - itsStartFreq + (itsLastChan + 1) * itsStepFreq, - startTime, - endTime); - - // Read all parameter values which are part of the work domain. - readParms(); - - // Display work domain. - LOG_INFO_STR("Work domain: " << setprecision(10) << itsWorkDomain); - LOG_INFO_STR(" + Bandwidth: " << setprecision(3) << (itsLastChan + 1 - itsFirstChan) * itsStepFreq / 1000.0 - << " kHz [Channel " << itsFirstChan << " - " << itsLastChan << ", " << itsStepFreq / 1000.0 - << " kHz/channel]"); - LOG_INFO_STR(" + Time: " << (endTime - startTime) / 60.0 << " minutes [Sample " << itsTimeIndex << " - " - << endIndex - 1 << ", " << (endTime - startTime) / itsNrTimes << " s/sample on average]"); - - return true; -} - -bool Prediffer::setWorkDomain(int startChan, int endChan, double tstart, double tlength) -{ - // Determine the first and last channel to process. - if (startChan < 0) { - startChan = 0; - } - if (endChan < 0 || endChan >= itsNrChan) { - endChan = itsNrChan-1; - } - return setWorkDomain (MeqDomain(itsStartFreq + startChan*itsStepFreq, - itsStartFreq + (endChan+1)*itsStepFreq, - tstart, - tstart+tlength)); + itsOutputColumn = context.outputColumn; + return true; } -bool Prediffer::setWorkDomain(double startFreq, double endFreq, double startTime, double endTime) -{ - return setWorkDomain(MeqDomain(startFreq, endFreq, startTime, endTime)); -} - -bool Prediffer::setContext(const PredictContext &context) +bool Prediffer::setContext(const SubtractContext &context) { if(!setContext(dynamic_cast<const Context &>(context))) { return false; } - - itsOutDataColumn = context.outputColumn; - return true; -} + // Create the measurement equation for each interferometer (baseline). + itsModel->makeEquations(Model::PREDICT, context.instrumentModel, + itsContext.baselines, context.sources, itsParmGroup, + itsInstrumentDBase.get(), &itsPhaseRef, itsChunkData); -bool Prediffer::setContext(const SubtractContext &context) -{ - if(!setContext(dynamic_cast<const Context &>(context))) + // Put funklets in parms which are not filled yet. (?) + for(MeqParmGroup::iterator it = itsParmGroup.begin(); + it != itsParmGroup.end(); + ++it) { - return false; + it->second.fillFunklets(itsParmValues, itsWorkDomain); } - - itsOutDataColumn = context.outputColumn; + + itsOutputColumn = context.outputColumn; return true; } @@ -692,8 +494,22 @@ bool Prediffer::setContext(const CorrectContext &context) { return false; } - - itsOutDataColumn = context.outputColumn; + + // Create the measurement equation for each interferometer (baseline). + itsModel->makeEquations(Model::CORRECT, context.instrumentModel, + itsContext.baselines, context.sources, itsParmGroup, + itsInstrumentDBase.get(), &itsPhaseRef, itsChunkData); + + // Put funklets in parms which are not filled yet. (?) + for(MeqParmGroup::iterator it = itsParmGroup.begin(); + it != itsParmGroup.end(); + ++it) + { + it->second.fillFunklets(itsParmValues, itsWorkDomain); + } + + + itsOutputColumn = context.outputColumn; return true; } @@ -704,1320 +520,836 @@ bool Prediffer::setContext(const GenerateContext &context) { return false; } - - const vector<string>& unknowns = context.unknowns; - const vector<string>& excludedUnknowns = context.excludedUnknowns; - - vector<casa::Regex> unknownsRegex; - vector<casa::Regex> excludedUnknownsRegex; + + // Create the measurement equation for each interferometer (baseline). + itsModel->makeEquations(Model::PREDICT, context.instrumentModel, + itsContext.baselines, context.sources, itsParmGroup, + itsInstrumentDBase.get(), &itsPhaseRef, itsChunkData); + + // Put funklets in parms which are not filled yet. (?) + for(MeqParmGroup::iterator it = itsParmGroup.begin(); + it != itsParmGroup.end(); + ++it) + { + it->second.fillFunklets(itsParmValues, itsWorkDomain); + } + + // Clear the solvable flag on all parameters (may still be set from the + // previous step. + clearSolvableParms(); + + // Convert patterns to AIPS++ regular expression objects. + vector<casa::Regex> included(context.unknowns.size()); + vector<casa::Regex> excluded(context.excludedUnknowns.size()); try { - // Convert patterns to aips++ regexes. - for(unsigned int i = 0; i < unknowns.size(); i++) - { - unknownsRegex.push_back(casa::Regex::fromPattern(unknowns[i])); - } - - for(unsigned int i = 0; i < excludedUnknowns.size(); i++) - { - excludedUnknownsRegex.push_back(casa::Regex::fromPattern(excludedUnknowns[i])); - } + transform(context.unknowns.begin(), context.unknowns.end(), + included.begin(), ptr_fun(casa::Regex::fromPattern)); + + transform(context.excludedUnknowns.begin(), + context.excludedUnknowns.end(), excluded.begin(), + ptr_fun(casa::Regex::fromPattern)); } - catch(exception &_ex) + catch(std::exception &_ex) { - LOG_ERROR_STR("Error parsing Parms/ExclParms regular expression (exception: " << _ex.what() << ")"); + LOG_ERROR_STR("Error parsing Parms/ExclParms pattern (exception: " + << _ex.what() << ")"); return false; } - + // Find all parms matching context.unknowns, exclude those that // match context.excludedUnknowns. - int unknownCount = 0; for(MeqParmGroup::iterator parameter_it = itsParmGroup.begin(); parameter_it != itsParmGroup.end(); ++parameter_it) { - String parameterName(parameter_it->second.getName()); + casa::String name(parameter_it->second.getName()); // Loop through all regex-es until a match is found. - for(vector<casa::Regex>::iterator included_it = unknownsRegex.begin(); - included_it != unknownsRegex.end(); - included_it++) + for(vector<casa::Regex>::iterator included_it = included.begin(); + included_it != included.end(); + ++included_it) { - if(parameterName.matches(*included_it)) + if(name.matches(*included_it)) { bool include = true; - + // Test if excluded. - for(vector<casa::Regex>::const_iterator excluded_it = excludedUnknownsRegex.begin(); - excluded_it != excludedUnknownsRegex.end(); - excluded_it++) + for(vector<casa::Regex>::const_iterator excluded_it = + excluded.begin(); + excluded_it != excluded.end(); + ++excluded_it) { - if(parameterName.matches(*excluded_it)) + if(name.matches(*excluded_it)) { include = false; break; } } - + if(include) - { - LOG_TRACE_OBJ_STR("setSolvable: " << parameter_it->second.getName()); parameter_it->second.setSolvable(true); - unknownCount++; - } - + break; } } } - - if(unknownCount == 0) - { - LOG_ERROR("No unknowns selected in this context."); - return false; - } - - itsSolveDomains = context.solveDomains; -// initSolvableParms(itsSolveDomains); - initializeSolveDomains(context.solveDomains); - - return itsNrPert>0; -} + // Initialize solve domain grid. + pair<size_t, size_t> domainSize(context.domainSize); + if(domainSize.first == 0 || domainSize.first > itsChunkData->freq.size()) + domainSize.first = itsChunkData->freq.size(); + if(domainSize.second == 0 || domainSize.second > itsChunkData->time.size()) + domainSize.second = itsChunkData->time.size(); -void Prediffer::predictVisibilities() -{ - writePredictedData(); -} + LOG_DEBUG_STR("Nominal solve domain size: " << domainSize.first + << " channels by " << domainSize.second << " timeslots."); + initializeSolveDomains(domainSize); -void Prediffer::subtractVisibilities() -{ - subtractData(); + return (itsContext.derivativeCount > 0); } -void Prediffer::correctVisibilities() +void Prediffer::predict() { - correctData(); -} + process(false, true, false, make_pair(0, 0), + make_pair(itsChunkData->freq.size() - 1, itsChunkData->time.size() - 1), + &Prediffer::predictBaseline, 0); + if(!itsOutputColumn.empty()) + itsMeasurement->write(itsChunkSelection, itsChunkData, itsOutputColumn, + false); -void Prediffer::generateEquations(vector<casa::LSQFit> &equations) -{ - fillFitters(equations); + LOG_DEBUG_STR("Predict: " << itsPredTimer); + LOG_DEBUG_STR("Copy: " << itsEqTimer); + itsPredTimer.reset(); + itsEqTimer.reset(); } -//-----------------------[ Model ]-----------------------// - - -void Prediffer::makeTree (const vector<string>& modelType, - const vector<string>& sourceNames) +void Prediffer::subtract() { - // Determine which parts of the model to use. - bool asAP = true; - bool useDipole = false; - bool usePatchGain = false; - bool useTotalGain = false; - bool useBandpass = false; - for (uint i=0; i<modelType.size(); ++i) { - if (modelType[i] != "") { - if (modelType[i] == "TOTALGAIN") { - useTotalGain = true; - } else if (modelType[i] == "PATCHGAIN") { - usePatchGain = true; - } else if (modelType[i] == "REALIMAG") { - asAP = false; - } else if (modelType[i] == "DIPOLE") { - useDipole = true; - } else if (modelType[i] == "BANDPASS") { - useBandpass = true; - } else { - ASSERTSTR (false, "Modeltype part " << modelType[i] << " is invalid; " - "valid are TOTALGAIN,PATCHGAIN,REALIMAG,DIPOLE,BANDPASS"); - } - } - } - - LOG_INFO_STR("Instrument model:" - << (asAP ? "" : " REALIMAG") - << (useDipole ? " DIPOLE" : "") - << (useTotalGain ? " TOTALGAIN" : "") - << (usePatchGain ? " PATCHGAIN" : "") - << (useBandpass ? " BANDPASS" : "")); - - // Find all sources and groups to use. - // Make an LMN node for each source used. - int nrsrc = sourceNames.size(); - vector<MeqSource*> sources; - map<string,vector<int> > groups; - itsLMN.clear(); - itsLMN.reserve (nrsrc); - for (int i=0; i<nrsrc; ++i) { - MeqSource* src = itsSources->getSource (sourceNames[i]); - // Add source to list. - sources.push_back (src); - // Add source index to group. - groups[src->getGroupName()].push_back (i); - MeqLMN* lmn = new MeqLMN(src); - lmn->setPhaseRef (&itsPhaseRef); - itsLMN.push_back (lmn); - } - // Set up the expression tree for all baselines. - makeLOFARExprs (sources, groups, - useTotalGain, usePatchGain, asAP, useDipole, useBandpass); -} + process(false, true, false, make_pair(0, 0), + make_pair(itsChunkData->freq.size() - 1, itsChunkData->time.size() - 1), + &Prediffer::subtractBaseline, 0); -void Prediffer::makeLOFARExprs (const vector<MeqSource*>& sources, - const map<string, vector<int> >& groups, - bool useTotalGain, bool usePatchGain, - bool asAP, - bool useDipole, bool useBandpass) -{ - // Allocate the vectors holding the expressions. - int nrstat = itsStations.size(); - int nrsrc = sources.size(); - int nrgrp = groups.size(); - // GJ is real/imag or ampl/phase - string gjname1 = "real:"; - string gjname2 = "imag:"; - if (asAP) { - gjname1 = "ampl:"; - gjname2 = "phase:"; - } - // Vector containing DipoleExpr-s. - vector<MeqJonesExpr> dipoleExpr(nrstat); - // Vector containing DFTPS-s. - vector<MeqExpr> pdfts(nrsrc*nrstat); - // Vector containing all gains per station per patch. - vector<MeqJonesExpr> patchGJ(nrgrp*nrstat); - // Vector containing all Gain-s per station. - vector<MeqJonesExpr> totalGJ(nrstat); - // Correction per station. - vector<MeqJonesExpr> corrStat(nrstat); - // Bandpass per station. - vector<MeqJonesExpr> bandpass(nrstat); - - // Fill the vectors for each station. - for (int stat=0; stat<nrstat; ++stat) { - // Do it only if the station is actually used. - if (itsSelStations[stat] != 0) { - // Do pure station parameters only if told so. - if (useDipole) { - MeqExpr frot (MeqParmFunklet::create ("frot:" + - itsStations[stat]->getName(), - itsParmGroup, itsMEP)); - MeqExpr drot (MeqParmFunklet::create ("drot:" + - itsStations[stat]->getName(), - itsParmGroup, itsMEP)); - MeqExpr dell (MeqParmFunklet::create ("dell:" + - itsStations[stat]->getName(), - itsParmGroup, itsMEP)); - MeqExpr gj11 (MeqParmFunklet::create ("dgain:X:" + - itsStations[stat]->getName(), - itsParmGroup, itsMEP)); - MeqExpr gj22 (MeqParmFunklet::create ("dgain:Y:" + - itsStations[stat]->getName(), - itsParmGroup, itsMEP)); - dipoleExpr[stat] = MeqJonesExpr(new MeqStatExpr (frot, drot, dell, - gj11, gj22)); - } - // Make a bandpass per station - if (useBandpass) { - string stationName = itsStations[stat]->getName(); - MeqExpr bandpassXX(MeqParmFunklet::create("bandpass:X:" + stationName, - itsParmGroup, itsMEP)); - MeqExpr bandpassYY(MeqParmFunklet::create("bandpass:Y:" + stationName, - itsParmGroup, itsMEP)); - - bandpass[stat] = new MeqDiag(MeqExpr(bandpassXX), MeqExpr(bandpassYY)); - } - // Make a DFT per station per source. - for (int src=0; src<nrsrc; ++src) { - pdfts[stat*nrsrc + src] = MeqExpr(new MeqDFTPS (itsLMN[src], - itsStatUVW[stat])); - } - // Make optionally GJones expressions. - MeqExprRep* gj11; - MeqExprRep* gj12; - MeqExprRep* gj21; - MeqExprRep* gj22; - if (useTotalGain) { - // Make a gain/phase expression per station. - string nm = itsStations[stat]->getName(); - MeqExpr gj11r (MeqParmFunklet::create ("gain:11:" + gjname1 + nm, - itsParmGroup, itsMEP)); - MeqExpr gj11i (MeqParmFunklet::create ("gain:11:" + gjname2 + nm, - itsParmGroup, itsMEP)); - MeqExpr gj12r (MeqParmFunklet::create ("gain:12:" + gjname1 + nm, - itsParmGroup, itsMEP)); - MeqExpr gj12i (MeqParmFunklet::create ("gain:12:" + gjname2 + nm, - itsParmGroup, itsMEP)); - MeqExpr gj21r (MeqParmFunklet::create ("gain:21:" + gjname1 + nm, - itsParmGroup, itsMEP)); - MeqExpr gj21i (MeqParmFunklet::create ("gain:21:" + gjname2 + nm, - itsParmGroup, itsMEP)); - MeqExpr gj22r (MeqParmFunklet::create ("gain:22:" + gjname1 + nm, - itsParmGroup, itsMEP)); - MeqExpr gj22i (MeqParmFunklet::create ("gain:22:" + gjname2 + nm, - itsParmGroup, itsMEP)); - if (asAP) { - gj11 = new MeqExprAPToComplex (gj11r, gj11i); - gj12 = new MeqExprAPToComplex (gj12r, gj12i); - gj21 = new MeqExprAPToComplex (gj21r, gj21i); - gj22 = new MeqExprAPToComplex (gj22r, gj22i); - } else { - gj11 = new MeqExprToComplex (gj11r, gj11i); - gj12 = new MeqExprToComplex (gj12r, gj12i); - gj21 = new MeqExprToComplex (gj21r, gj21i); - gj22 = new MeqExprToComplex (gj22r, gj22i); - } - totalGJ[stat] = new MeqJonesNode (MeqExpr(gj11), MeqExpr(gj12), - MeqExpr(gj21), MeqExpr(gj22)); - corrStat[stat] = new MeqJonesInvert (totalGJ[stat]); - } - if (usePatchGain) { - // Make a complex gain expression per station per patch. - int grp=0; - for (map<string,vector<int> >::const_iterator grpiter = groups.begin(); - grpiter != groups.end(); - grpiter++, grp++) { - string nm = itsStations[stat]->getName() + ":" + grpiter->first; - MeqExpr gj11r (MeqParmFunklet::create ("gain:11:" + gjname1 + nm, - itsParmGroup, itsMEP)); - MeqExpr gj11i (MeqParmFunklet::create ("gain:11:" + gjname2 + nm, - itsParmGroup, itsMEP)); - MeqExpr gj12r (MeqParmFunklet::create ("gain:12:" + gjname1 + nm, - itsParmGroup, itsMEP)); - MeqExpr gj12i (MeqParmFunklet::create ("gain:12:" + gjname2 + nm, - itsParmGroup, itsMEP)); - MeqExpr gj21r (MeqParmFunklet::create ("gain:21:" + gjname1 + nm, - itsParmGroup, itsMEP)); - MeqExpr gj21i (MeqParmFunklet::create ("gain:21:" + gjname2 + nm, - itsParmGroup, itsMEP)); - MeqExpr gj22r (MeqParmFunklet::create ("gain:22:" + gjname1 + nm, - itsParmGroup, itsMEP)); - MeqExpr gj22i (MeqParmFunklet::create ("gain:22:" + gjname2 + nm, - itsParmGroup, itsMEP)); - if (asAP) { - gj11 = new MeqExprAPToComplex (gj11r, gj11i); - gj12 = new MeqExprAPToComplex (gj12r, gj12i); - gj21 = new MeqExprAPToComplex (gj21r, gj21i); - gj22 = new MeqExprAPToComplex (gj22r, gj22i); - } else { - gj11 = new MeqExprToComplex (gj11r, gj11i); - gj12 = new MeqExprToComplex (gj12r, gj12i); - gj21 = new MeqExprToComplex (gj21r, gj21i); - gj22 = new MeqExprToComplex (gj22r, gj22i); - } - patchGJ[stat*nrgrp + grp] = new MeqJonesNode (MeqExpr(gj11), - MeqExpr(gj12), - MeqExpr(gj21), - MeqExpr(gj22)); - // Only AP of first group is used for correction. - if (grp == 0) { - corrStat[stat] = new MeqJonesInvert (patchGJ[stat*nrgrp + grp]); - } - } - } - } - } - // Make an expression for each baseline. - int nrusedbl = itsBLInx.size(); - itsExpr.resize (nrusedbl); - itsCorrExpr.resize (nrusedbl); - itsCorrMMap.resize (nrusedbl); - for (int blindex=0; blindex<nrusedbl; blindex++) { - int bl = itsBLInx[blindex]; - int ant1 = itsMSDesc.ant1[bl]; - int ant2 = itsMSDesc.ant2[bl]; - if (usePatchGain || useTotalGain) { - // Make correction expressions. - itsCorrMMap[blindex] = new MeqJonesMMap (itsMSMapInfo, bl); - itsCorrExpr[blindex] = new MeqJonesCMul3 (corrStat[ant1], - itsCorrMMap[blindex], - corrStat[ant2]); - } - // Predict expressions. - vector<MeqJonesExpr> vecPatch; - // Loop through all source groups. - int grp=0; - for (map<string,vector<int> >::const_iterator grpiter = groups.begin(); - grpiter != groups.end(); - grpiter++, grp++) { - const vector<int>& srcgrp = grpiter->second;; - vector<MeqJonesExpr> vecSrc; - vecSrc.reserve (srcgrp.size()); - for (uint j=0; j<srcgrp.size(); ++j) { - // Create the total DFT per source. - int src = srcgrp[j]; - MeqExpr expr1 (new MeqBaseDFTPS (pdfts[ant1*nrsrc + src], - pdfts[ant2*nrsrc + src], - itsLMN[src])); - // For the time being only point sources are supported. - MeqPointSource& mps = dynamic_cast<MeqPointSource&>(*sources[src]); - vecSrc.push_back (MeqJonesExpr (new MeqBaseLinPS(expr1, &mps))); - } - MeqJonesExpr sum; - // Sum all sources in the group. - if (vecSrc.size() == 1) { - sum = vecSrc[0]; - } else { - sum = MeqJonesExpr (new MeqJonesSum(vecSrc)); - } - // Multiply by ionospheric gain/phase per station per patch. - if (usePatchGain) { - vecPatch.push_back (new MeqJonesCMul3(patchGJ[ant1*nrgrp + grp], - sum, - patchGJ[ant2*nrgrp + grp])); - } else { - vecPatch.push_back (sum); - } - } - // Sum all patches. - MeqJonesExpr sumAll; - if (vecPatch.size() == 1) { - sumAll = vecPatch[0]; - } else { - sumAll = MeqJonesExpr (new MeqJonesSum(vecPatch)); - } - // Multiply by total gain/phase per station. - if (useTotalGain) { - sumAll = new MeqJonesCMul3(totalGJ[ant1], - sumAll, - totalGJ[ant2]); - } - if (useBandpass) { - sumAll = new MeqJonesCMul3(bandpass[ant1], - sumAll, - bandpass[ant2]); - } - if (useDipole) { - sumAll = new MeqJonesCMul3(dipoleExpr[ant1], - sumAll, - dipoleExpr[ant2]); - } - itsExpr[blindex] = sumAll; - } -} + if(!itsOutputColumn.empty()) + itsMeasurement->write(itsChunkSelection, itsChunkData, itsOutputColumn, + false); -void Prediffer::setPrecalcNodes (vector<MeqJonesExpr>& nodes) -{ - // First clear the levels of all nodes in the tree. - for (uint i=0; i<nodes.size(); ++i) { - if (! nodes[i].isNull()) { - nodes[i].clearDone(); - } - } - // Now set the levels of all nodes in the tree. - // The top nodes have level 0; lower nodes have 1, 2, etc.. - int nrLev = -1; - for (uint i=0; i<nodes.size(); ++i) { - if (! nodes[i].isNull()) { - nrLev = max (nrLev, nodes[i].setLevel(0)); - } - } - nrLev++; - ASSERT (nrLev > 0); - itsPrecalcNodes.resize (nrLev); - // Find the nodes to be precalculated at each level. - // That is not needed for the root nodes (the baselines). - // The nodes used by the baselines are always precalculated (even if - // having one parent). - // It may happen that a station is used by only one baseline. Calculating - // such a baseline is much more work if the station was not precalculated. - for (int level=1; level<nrLev; ++level) { - vector<MeqExprRep*>& pcnodes = itsPrecalcNodes[level]; - pcnodes.resize (0); - for (vector<MeqJonesExpr>::iterator iter=nodes.begin(); - iter != nodes.end(); - ++iter) { - if (! iter->isNull()) { - iter->getCachingNodes (pcnodes, level, false); - } - } - } - LOG_TRACE_FLOW_STR("#levels=" << nrLev); - for (int i=0; i<nrLev; ++i) { - LOG_TRACE_FLOW_STR("#expr on level " << i << " is " << itsPrecalcNodes[i].size()); - } + LOG_DEBUG_STR("Predict: " << itsPredTimer); + LOG_DEBUG_STR("Subtract: " << itsEqTimer); + itsPredTimer.reset(); + itsEqTimer.reset(); } -void Prediffer::precalcNodes (const MeqRequest& request) -{ -#pragma omp parallel - { - // Loop through expressions to be precalculated. - // At each level the expressions can be executed in parallel. - // Level 0 is formed by itsExpr which are not calculated here. - for (int level = itsPrecalcNodes.size(); --level > 0;) { - vector<MeqExprRep*>& exprs = itsPrecalcNodes[level]; - int nrExprs = exprs.size(); - if (nrExprs > 0) { -#pragma omp for schedule(dynamic) - for (int i=0; i<nrExprs; ++i) { - exprs[i]->precalculate (request); - } - } - } - } // end omp parallel -} - -//-----------------------[ MS Access ]-----------------------// -void Prediffer::readMeasurementSetMetaData(const string &fileName) +void Prediffer::correct() { - MeasurementSet ms(fileName); - - Path absolutePath = Path(fileName).absoluteName(); - itsMSDesc.msPath = absolutePath.dirName(); - itsMSDesc.msName = absolutePath.baseName(); - itsMSDesc.npart = 1; - - /* - Get baselines. - */ - Block<String> sortColumns(2); - sortColumns[0] = "ANTENNA1"; - sortColumns[1] = "ANTENNA2"; - Table uniqueBaselines = ms.sort(sortColumns, Sort::Ascending, Sort::QuickSort + Sort::NoDuplicates); - ROScalarColumn<Int> station1Column(uniqueBaselines, "ANTENNA1"); - ROScalarColumn<Int> station2Column(uniqueBaselines, "ANTENNA2"); - station1Column.getColumn().tovector(itsMSDesc.ant1); - station2Column.getColumn().tovector(itsMSDesc.ant2); - - /* - Get information about frequency grid. - */ - MSDataDescription dataDescription(ms.dataDescription()); - ROMSDataDescColumns dataDescriptionColumns(dataDescription); - MSSpectralWindow spectralWindow(ms.spectralWindow()); - ROMSSpWindowColumns spectralWindowColumns(spectralWindow); - int spectralWindowCount = dataDescription.nrow(); - - itsMSDesc.nchan.resize(spectralWindowCount); - itsMSDesc.startFreq.resize(spectralWindowCount); - itsMSDesc.endFreq.resize(spectralWindowCount); - - for(int i = 0; i < spectralWindowCount; i++) - { - // _Center_ frequencies for each channel - Vector<double> channelFrequency = spectralWindowColumns.chanFreq()(i); - // Channel width for each channel - Vector<double> channelWidth = spectralWindowColumns.chanWidth()(i); + process(false, true, false, make_pair(0, 0), + make_pair(itsChunkData->freq.size() - 1, itsChunkData->time.size() - 1), + &Prediffer::correctBaseline, 0); - // So far, only equal frequency spacings are possible. - ASSERTSTR(allEQ(channelWidth, channelWidth(0)), "Channels must have equal spacings"); + if(!itsOutputColumn.empty()) + itsMeasurement->write(itsChunkSelection, itsChunkData, itsOutputColumn, + false); - int channelCount = channelWidth.nelements(); - itsMSDesc.nchan[i] = channelCount; + LOG_DEBUG_STR("Correct: " << itsEqTimer); + LOG_DEBUG_STR("Copy: " << itsPredTimer); + itsPredTimer.reset(); + itsEqTimer.reset(); +} - double step = abs(channelWidth(0)); - if(channelFrequency(0) > channelFrequency(channelCount - 1)) - { - // Channels are in reverse order! NB: startFreq and endFreq are left - // in reverse order because they are swapped in processMSDesc(). - - // Upper border of last channel. - itsMSDesc.startFreq[i] = channelFrequency(0) + step / 2; - // Lower border of first channel. - itsMSDesc.endFreq[i] = itsMSDesc.startFreq[i] - channelCount * step; - } - else - { - // Lower border of first channel. - itsMSDesc.startFreq[i] = channelFrequency(0) - step / 2; - // Upper border of last channel. - itsMSDesc.endFreq[i] = itsMSDesc.startFreq[i] + channelCount * step; - } - } - /* - Get information about time grid. - */ - ROScalarColumn<double> timeColumn(ms, "TIME"); - Vector<double> time = timeColumn.getColumn(); - Vector<uInt> timeIndex; - uInt timeCount = GenSortIndirect<double>::sort(timeIndex, time, Sort::Ascending, Sort::InsSort + Sort::NoDuplicates); +void Prediffer::generate(pair<size_t, size_t> start, pair<size_t, size_t> end, + vector<casa::LSQFit> &solvers) +{ + ASSERT(start.first <= end.first + && end.first < itsContext.domainCount.first); + ASSERT(start.second <= end.second + && end.second < itsContext.domainCount.second); - itsMSDesc.times.resize(timeCount); - itsMSDesc.exposures.resize(timeCount); - ROScalarColumn<double> exposureColumn(ms, "EXPOSURE"); - Vector<double> exposure = exposureColumn.getColumn(); + size_t nFreqDomains = end.first - start.first + 1; + size_t nTimeDomains = end.second - start.second + 1; + size_t nDomains = nFreqDomains * nTimeDomains; + ASSERT(solvers.size() >= nDomains); - for(uInt i = 0; i < timeCount; i++) - { - // _Center_ of integration interval. - itsMSDesc.times[i] = time[timeIndex[i]]; - // Effective integration time. - itsMSDesc.exposures[i] = exposure[timeIndex[i]]; - } +#ifdef COMPUTE_SQUARED_ERROR + itsSquaredErrorReal.resize(nDomains); + itsSquaredErrorImag.resize(nDomains); + fill(itsSquaredErrorReal.begin(), itsSquaredErrorReal.end(), 0.0); + fill(itsSquaredErrorImag.begin(), itsSquaredErrorImag.end(), 0.0); +#endif - /* - Get phase center as RA and DEC (J2000). - - From AIPS++ note 229 (MeasurementSet definition version 2.0): - --- - FIELD: Field positions for each source - Notes: - The FIELD table defines a field position on the sky. For interferometers, - this is the correlated field position. For single dishes, this is the - nominal pointing direction. - --- - - In LOFAR/CEP/BB/MS/src/makemsdesc.cc the following line can be found: - MDirection phaseRef = mssubc.phaseDirMeasCol()(0)(IPosition(1,0)); - which should be equivalent to: - MDirection phaseRef = mssubc.phaseDirMeas(0); - as used in the code below. - */ - MSField field(ms.field()); - ROMSFieldColumns fieldColumns(field); - MDirection phaseCenter = MDirection::Convert(fieldColumns.phaseDirMeas(0), MDirection::J2000)(); - Quantum<Vector<double> > phaseCenterAngles = phaseCenter.getAngle(); - itsMSDesc.ra = phaseCenterAngles.getBaseValue()(0); - itsMSDesc.dec = phaseCenterAngles.getBaseValue()(1); - - /* - Get correlation types. - */ - MSPolarization polarization(ms.polarization()); - ROMSPolarizationColumns polarizationColumn(polarization); - Vector<Int> correlationTypes = polarizationColumn.corrType()(0); - int correlationTypeCount = correlationTypes.nelements(); - itsMSDesc.corrTypes.resize(correlationTypeCount); - for(int i = 0; i < correlationTypeCount; i++) - { - itsMSDesc.corrTypes[i] = Stokes::name(Stokes::type(correlationTypes(i))); - } + // Create thread private fitters for parallel execution. + vector<vector<casa::LSQFit*> > threadPrivateSolvers(itsNthread); + for(size_t i = 0; i < itsNthread; ++i) + threadPrivateSolvers[i].resize(nDomains); - /* - Get station names and positions in ITRF coordinates. - */ - MSAntenna antenna(ms.antenna()); - ROMSAntennaColumns antennaColumns(antenna); - int antennaCount = antenna.nrow(); - - MVPosition sumVector; - itsMSDesc.antNames.resize(antennaCount); - itsMSDesc.antPos.resize(IPosition(2, 3, antennaCount)); - for(int i = 0; i < antennaCount; i++) + // Initialize the solver objects. + size_t solverIdx = 0; + size_t domainIdx = + start.second * itsContext.domainCount.first + start.first; + for(size_t i = 0; i < nTimeDomains; ++i) { - itsMSDesc.antNames[i] = antennaColumns.name()(i); - MPosition position = antennaColumns.positionMeas()(i); - position = MPosition::Convert(position, MPosition::ITRF)(); - const MVPosition& positionVector = position.getValue(); - sumVector += positionVector; - - for(int j = 0; j < 3; j++) + for(size_t j = 0; j < nFreqDomains; ++j) { - itsMSDesc.antPos(IPosition(2, j, i)) = positionVector(j); - } - } +// LOG_DEBUG_STR("Domain (" << j << ", " << i << ") -> " +// << domainIdx + j << endl); - /* - Get the array position in ITRF coordinates, or use the centroid - of the station positions if the array position is unknown. - */ - MSObservation observation(ms.observation()); - ROMSObservationColumns observationColumns(observation); + size_t nUnknowns = + itsContext.domains[domainIdx + j].unknowns.size(); + solvers[solverIdx].set(nUnknowns); + threadPrivateSolvers[0][solverIdx] = &solvers[solverIdx]; - MPosition position; - MVPosition positionVector; - if(observation.nrow() > 0 && MeasTable::Observatory(position, observationColumns.telescopeName()(0))) - { - position = MPosition::Convert(position, MPosition::ITRF)(); - positionVector = position.getValue(); - //LOG_TRACE_FLOW("Array position: " << position); - } - else - { - LOG_WARN("Array position unknown; will use centroid of stations."); - positionVector = sumVector * (1.0 / (double) antennaCount); - } + for(size_t j = 1; j < itsNthread; ++j) + { + threadPrivateSolvers[j][solverIdx] = + new casa::LSQFit(nUnknowns); + } - itsMSDesc.arrayPos.resize(3); - for(int i = 0; i < 3; i++) - { - itsMSDesc.arrayPos[i] = positionVector(i); + ++solverIdx; + } + domainIdx += itsContext.domainCount.first; } - /* - Determine the startTime and endTime of the observation. - */ - if(observation.nrow() > 0) + // Size the thread private buffers. + for(size_t i = 0; i < itsNthread; ++i) { - Vector<double> times = observationColumns.timeRange()(0); - itsMSDesc.startTime = times(0); - itsMSDesc.endTime = times(1); - } - else + itsResultVecs[i].resize(2 * itsContext.derivativeCount); + itsDiffVecs[i].resize(3 * itsContext.derivativeCount); + itsIndexVecs[i].resize(itsContext.derivativeCount); + } + + // Convert from solve domain 'coordinates' to sample numbers (i.e. channel + // number, timeslot number). + pair<size_t, size_t> vstart(start.first * itsContext.domainSize.first, + start.second * itsContext.domainSize.second); + pair<size_t, size_t> vend + ((end.first + 1) * itsContext.domainSize.first - 1, + (end.second + 1) * itsContext.domainSize.second - 1); + ASSERT(vstart.first < itsChunkData->freq.size()); + ASSERT(vstart.second < itsChunkData->time.size()); + + // Clip against data boundary. + if(vend.first >= itsChunkData->freq.size()) + vend.first = itsChunkData->freq.size() - 1; + if(vend.second >= itsChunkData->time.size()) + vend.second = itsChunkData->time.size() - 1; + +// LOG_DEBUG_STR("Processing visbility domain: " << vstart.first << ", " +// << vstart.second << " - " << vend.first << ", " << vend.second << +//endl); + + process(true, true, true, vstart, vend, &Prediffer::generateBaseline, + &threadPrivateSolvers); + + // Merge the thread-specific solvers into the main ones. + for(size_t j = 1; j < itsNthread; ++j) { - itsMSDesc.startTime = 0.0; - itsMSDesc.endTime = 0.0; + for(size_t i = 0; i < nDomains; ++i) + { + solvers[i].merge(*threadPrivateSolvers[j][i]); + delete threadPrivateSolvers[j][i]; + } } - if(itsMSDesc.startTime >= itsMSDesc.endTime) +#ifdef COMPUTE_SQUARED_ERROR + for(size_t i = 0; i < nDomains; ++i) { - /* - Invalid start / end times; derive from times and interval. - Difference between interval and exposure is startup time which - is taken into account. - */ - ASSERT(timeCount >= 2); - ROScalarColumn<double> interval(ms, "INTERVAL"); - itsMSDesc.startTime = itsMSDesc.times[0] - itsMSDesc.exposures[0] / 2 + (interval(0) - itsMSDesc.exposures[0]); - itsMSDesc.endTime = itsMSDesc.times[timeCount - 1] + interval(timeCount - 1) / 2; + LOG_DEBUG_STR("SquaredError: domain: " << domains.first + i + << " real: " << itsSquaredErrorReal[i] + << " imaginary: " << itsSquaredErrorImag[i]); } +#endif - /* - Create a map from column name to file on disk. - */ - Record info = ms.dataManagerInfo(); - for(unsigned int i = 0; i < info.nfields(); ++i) - { - const Record &dm = info.subRecord(i); - const Array<String> columns = dm.asArrayString("COLUMNS"); - - /* - BBS requires TiledColumnStMan/TiledShapeStMan (or another StorageManager that - stores data linearly on disk) and one column per DataManager. This is because - mmap is used to access the data. - */ - if((dm.asString("TYPE") == "TiledColumnStMan" || - dm.asString("TYPE") == "TiledShapeStMan") && - columns.size() == 1) - { - /* - The data bound to a TiledStMan is stored in a file called table.f<seqnr>_TSM<stman> where - <seqnr> is SPEC.SEQNR stored in the DataManager info record and <stman> indicates the - specific tiled storage manager. If several TiledStMan are used in one MS, they are numbered - sequentially. Because there is no easy way to determine which number belongs to which - TiledStMan, the mapping created here will not always be correct. However, it is guaranteed - to be correct for MSs created by Storage. - */ - unsigned int idx = i; - - try - { - const Record &spec = dm.asRecord("SPEC"); - idx = spec.asuInt("SEQNR"); - } - catch(AipsError &_ex) - { - LOG_WARN_STR("DataManager " << i + 1 << " has no SPEC.SEQNR. Please verify (e.g. with glish) that the columns bound to this DataManager are stored in " << fileName << "/table.f" << i << "_TSM" << (dm.asString("TYPE") == "TiledColumnStMan" ? "0" : "1") << "."); - } - - /* - Update the column map. - */ - ostringstream os; - if(dm.asString("TYPE") == "TiledColumnStMan") - os << itsMSName << "/table.f" << idx << "_TSM0"; - else - os << itsMSName << "/table.f" << idx << "_TSM1"; - - for(Array<String>::const_iterator it = columns.begin(); it != columns.end(); ++it) - { - itsColumns[static_cast<string>(*it)] = os.str(); - } - } - } + LOG_DEBUG_STR("Predict: " << itsPredTimer); + LOG_DEBUG_STR("Construct equations: " << itsEqTimer); + itsPredTimer.reset(); + itsEqTimer.reset(); } -string Prediffer::getFileForColumn(const string &column) -{ - map<string, string>::const_iterator it = itsColumns.find(column); - - if(it == itsColumns.end()) - return string(); - else - return it->second; -} -void Prediffer::processMSDesc (uint ddid) -{ - ASSERT (ddid < itsMSDesc.nchan.size()); - // Set the observation info. - itsNCorr = itsMSDesc.corrTypes.size(); - itsSelectedCorr.resize(itsNCorr); - itsCorr.resize(itsNCorr); - itsNrChan = itsMSDesc.nchan[ddid]; - itsStartFreq = itsMSDesc.startFreq[ddid]; - itsEndFreq = itsMSDesc.endFreq[ddid]; - itsStepFreq = (itsEndFreq - itsStartFreq)/itsNrChan; - itsNrBl = itsMSDesc.ant1.size(); - itsReverseChan = itsStartFreq > itsEndFreq; - if (itsReverseChan) { - double tmp = itsEndFreq; - itsEndFreq = itsStartFreq; - itsStartFreq = tmp; - itsStepFreq = abs(itsStepFreq); - } - // Set the MS info. - itsMSMapInfo = MMapMSInfo (itsMSDesc, ddid, itsReverseChan); - // Set the phase center info. - getPhaseRef (itsMSDesc.ra, itsMSDesc.dec, itsMSDesc.startTime); - // Set station info. - fillStations(); -} +//-----------------------[ Parameter Access ]-----------------------// -void Prediffer::getPhaseRef(double ra, double dec, double startTime) +void Prediffer::readParms() { - // Use the phase reference of the given J2000 ra/dec. - MVDirection mvdir(ra, dec); - MDirection phaseRef(mvdir, MDirection::J2000); - itsPhaseRef = MeqPhaseRef (phaseRef, startTime); -} + vector<string> emptyvec; + // Clear all parameter values. + itsParmValues.clear(); -void Prediffer::fillStations() -{ - // Use the array as a 2D one. - Matrix<double> antPos (itsMSDesc.antPos); - uint nrant = antPos.ncolumn(); - itsStations = vector<MeqStation*>(nrant, (MeqStation*)0); - // Get all stations actually used. - for (uint ant=0; ant<nrant; ant++) { - // Store each position as a constant parameter. - // Use the antenna name as the parameter name. - Vector<double> antpos = antPos.column(ant); - const string& name = itsMSDesc.antNames[ant]; - MeqParmSingle* px = new MeqParmSingle("AntPosX." + name, - antpos(0)); - MeqParmSingle* py = new MeqParmSingle("AntPosY." + name, - antpos(1)); - MeqParmSingle* pz = new MeqParmSingle("AntPosZ." + name, - antpos(2)); - itsStations[ant] = new MeqStation(px, py, pz, name); - } -} + // Get all parameters that intersect the work domain. + LOFAR::ParmDB::ParmDomain pdomain(itsWorkDomain.startX(), + itsWorkDomain.endX(), itsWorkDomain.startY(), itsWorkDomain.endY()); + itsInstrumentDBase->getValues(itsParmValues, emptyvec, pdomain); + itsSkyDBase->getValues(itsParmValues, emptyvec, pdomain); -void Prediffer::mapDataFiles (const string& inColumnName, - const string& outColumnName) -{ - Table tab; - - if (! inColumnName.empty()) { - string inFile = getFileForColumn(inColumnName); - ASSERTSTR(!inFile.empty(), "Column " << inColumnName << " does not exist or has non-standard storage manager."); - - if (itsInDataMap == 0 || itsInDataMap->getFileName() != inFile) { - tab = Table(itsMSName); - ASSERTSTR (tab.tableDesc().isColumn(inColumnName), - "Column " << inColumnName << " does not exist"); - delete itsInDataMap; - itsInDataMap = 0; - // See if the input file is the previous output file. - if (itsOutDataMap && itsOutDataMap->getFileName() == inFile) { - itsInDataMap = itsOutDataMap; - itsOutDataMap = 0; - } else { - itsInDataMap = new MMap (inFile, MMap::Read); - } - LOG_INFO_STR("Input column " << inColumnName << " maps to: " << inFile); - } - } - - - if (! outColumnName.empty()) { - if (tab.isNull()) { - tab = Table(itsMSName); - } - - string outFile = getFileForColumn(outColumnName); - if (itsOutDataMap == 0 || outFile.empty() || itsOutDataMap->getFileName() != outFile) { - if (!tab.tableDesc().isColumn(outColumnName)) { -// addDataColumn (tab, outColumnName, outFile); - addDataColumn (tab, outColumnName); - outFile = getFileForColumn(outColumnName); - } - ASSERTSTR(!outFile.empty(), "Column " << outColumnName << " does not exist or has non-standard storage manager."); - - delete itsOutDataMap; - itsOutDataMap = 0; - itsOutDataMap = new MMap (outFile, MMap::ReWr); - - LOG_INFO_STR("Output column " << outColumnName << " maps to: " << outFile); + // Remove the funklets from all parms. + for (MeqParmGroup::iterator it = itsParmGroup.begin(); + it != itsParmGroup.end(); + ++it) + { + it->second.removeFunklets(); } - } } -void Prediffer::addDataColumn(Table& tab, const string& columnName) +void Prediffer::initializeSolveDomains(pair<size_t, size_t> size) { - ASSERT(itsColumns.find(columnName) == itsColumns.end()); - - ArrayColumnDesc<Complex> resCol(columnName, IPosition(2, itsNCorr, itsNrChan), ColumnDesc::FixedShape); - String stManName = "Tiled_"+columnName; - TiledColumnStMan tiledRes(stManName, IPosition(3, itsNCorr, itsNrChan, 1)); - - tab.reopenRW(); - tab.addColumn (resCol, tiledRes); - tab.flush(); - - /* - Find out which datamanager the new column is in. - */ - Record dminfo = tab.dataManagerInfo(); - for (uint i=0; i<dminfo.nfields(); ++i) - { - const Record& dm = dminfo.subRecord(i); - if (dm.asString("NAME") == stManName) + // Need to implement some way to select local solve domains + // from global solve domains, see initSolvableParms(). + size_t nFreqDomains = + ceil(itsChunkData->freq.size() / static_cast<double>(size.first)); + size_t nTimeDomains = + ceil(itsChunkData->time.size() / static_cast<double>(size.second)); + size_t nSolveDomains = nFreqDomains * nTimeDomains; + + cout << "freq.size(): " << itsChunkData->freq.size() << " #domains: " + << nFreqDomains << endl; + cout << "time.size(): " << itsChunkData->time.size() << " #domains: " + << nTimeDomains << endl; + + itsContext.domainSize = size; + itsContext.domainCount = make_pair(nFreqDomains, nTimeDomains); + itsContext.domains.resize(nSolveDomains); + + // Generate solve domains. + // TODO: Update interface of MeqParmFunklet so we can lose the solveDomains + // vector and the domainUnknownCount vector below. + vector<MeqDomain> solveDomains(nSolveDomains); + vector<int> domainUnknownCount(nSolveDomains, 0); + + size_t idx = 0, tstart = 0; + for(size_t tdomain = 0; tdomain < nTimeDomains; ++tdomain) { - ostringstream os; - os << itsMSName << "/table.f" << i << "_TSM0"; - itsColumns[columnName] = os.str(); - break; - } - } -} + size_t tend = tstart + size.second - 1; + if(tend >= itsChunkData->time.size()) + tend = itsChunkData->time.size() - 1; -//-----------------------[ Parameter Access ]-----------------------// + size_t fstart = 0; + for(size_t fdomain = 0; fdomain < nFreqDomains; ++fdomain) + { + size_t fend = fstart + size.first - 1; + if(fend >= itsChunkData->freq.size()) + fend = itsChunkData->freq.size() - 1; -void Prediffer::readParms() -{ - // Read all parms for this domain into a single map. - itsParmValues.clear(); - vector<string> emptyvec; - LOFAR::ParmDB::ParmDomain pdomain(itsWorkDomain.startX(), itsWorkDomain.endX(), - itsWorkDomain.startY(), itsWorkDomain.endY()); - itsMEP->getValues (itsParmValues, emptyvec, pdomain); - itsGSMMEP->getValues (itsParmValues, emptyvec, pdomain); - // Remove the funklets from all parms. - for (MeqParmGroup::iterator iter = itsParmGroup.begin(); - iter != itsParmGroup.end(); - ++iter) - { - iter->second.removeFunklets(); - } -} + itsContext.domains[idx].domain = + MeqDomain(itsChunkData->freq.lower(fstart), + itsChunkData->freq.upper(fend), + itsChunkData->time.lower(tstart), + itsChunkData->time.upper(tend)); + solveDomains[idx] = itsContext.domains[idx].domain; -void Prediffer::initializeSolveDomains(const vector<MeqDomain> &globalSolveDomains) -{ - // Need to implement some way to select local solve domains - // from global solve domains, see initSolvableParms(). - const vector<MeqDomain> solveDomains = globalSolveDomains; - itsSolveDomainDescriptors.clear(); - itsSolveDomainDescriptors.resize(solveDomains.size()); - - itsNrPert = 0; - itsNrScids.resize(solveDomains.size()); - fill(itsNrScids.begin(), itsNrScids.end(), 0); - for (MeqParmGroup::iterator iter = itsParmGroup.begin(); - iter != itsParmGroup.end(); - ++iter) + fstart += size.first; + ++idx; + } + tstart += size.second; + } + + // Initialize solve domain meta data (e.g. number of unknowns, unknown + // index, etc.) + int nDerivatives = 0; + for(MeqParmGroup::iterator it = itsParmGroup.begin(); + it != itsParmGroup.end(); + ++it) { - // Determine maximal number of solvable coefficients over all solve domains - // for this parameter. - int max = iter->second.initDomain(solveDomains, itsNrPert, itsNrScids); + // Determine maximal number of unknowns over all solve domains for this + // parameter. + int max = it->second.initDomain(solveDomains, nDerivatives, + domainUnknownCount); + if(max > 0) { - const vector<MeqFunklet*>& funklets = iter->second.getFunklets(); - ASSERT(funklets.size() == solveDomains.size()); - for(size_t i = 0; i < solveDomains.size(); ++i) + const vector<MeqFunklet*>& funklets = it->second.getFunklets(); + ASSERT(funklets.size() == nSolveDomains); + + for(size_t i = 0; i < nSolveDomains; ++i) { - itsSolveDomainDescriptors[i].domain = solveDomains[i]; - itsSolveDomainDescriptors[i].parameters.push_back(iter->second); - itsSolveDomainDescriptors[i].unknownIndex.push_back(itsSolveDomainDescriptors[i].unknowns.size()); + SolveDomainDescriptor &domain = itsContext.domains[i]; + domain.parameters.push_back(it->second); + domain.unknownIndex.push_back(domain.unknowns.size()); const MeqMatrix &coeff = funklets[i]->getCoeff(); const vector<bool> &mask = funklets[i]->getSolvMask(); - for(unsigned int j = 0; j < coeff.nelements(); j++) + for(size_t j = 0; j < coeff.nelements(); ++j) { if(mask[j]) - itsSolveDomainDescriptors[i].unknowns.push_back(coeff.doubleStorage()[j]); + domain.unknowns.push_back(coeff.doubleStorage()[j]); } } } } - - // Determine the fitter indices for the frequency and time axis. - // First check if the (local) solve domains are ordered and regular. - // Start with finding the number of frequency intervals. - for (itsFreqNrFit=1; itsFreqNrFit<solveDomains.size(); itsFreqNrFit++) { - if (solveDomains[itsFreqNrFit].startX() < - solveDomains[itsFreqNrFit-1].endX()) { - break; - } - } - // Now check if regular in frequency and time. - uint timeNrFit = solveDomains.size() / itsFreqNrFit; - ASSERT (timeNrFit*itsFreqNrFit == solveDomains.size()); - for (uint inxt=0; inxt<timeNrFit; inxt++) { - const MeqDomain& first = solveDomains[inxt*itsFreqNrFit]; - for (uint inxf=1; inxf<itsFreqNrFit; inxf++) { - const MeqDomain& cur = solveDomains[inxt*itsFreqNrFit + inxf]; - ASSERT (cur.startY() == first.startY() && cur.endY() == first.endY()); - } - } - for (uint inxf=0; inxf<itsFreqNrFit; inxf++) { - const MeqDomain& first = solveDomains[inxf]; - for (uint inxt=1; inxt<timeNrFit; inxt++) { - const MeqDomain& cur = solveDomains[inxt*itsFreqNrFit + inxf]; - ASSERT (cur.startX() == first.startX() && cur.endX() == first.endX()); - } - } - // Determine for each frequency point to which fitter it belongs. - // For the time axis it is determined by nextDataChunk. - int nrchan = itsLastChan-itsFirstChan+1; - itsFreqFitInx.resize (nrchan); - double step = itsWorkDomain.sizeX() / nrchan; - double freq = itsWorkDomain.startX() + step / 2; - int interv = 0; - for (int i=0; i<nrchan; i++) { - if (freq > solveDomains[interv].endX()) { - interv++; - } - itsFreqFitInx[i] = interv; - freq += step; + itsContext.derivativeCount = nDerivatives; +} + + +void Prediffer::clearSolvableParms() +{ + LOG_TRACE_FLOW( "clearSolvableParms" ); + for (MeqParmGroup::iterator it = itsParmGroup.begin(); + it != itsParmGroup.end(); + ++it) + { + it->second.setSolvable(false); } } -void Prediffer::initSolvableParms (const vector<MeqDomain>& solveDomains) +//-----------------------[ Computation ]-----------------------// +void Prediffer::process(bool useFlags, bool precalc, bool derivatives, + pair<size_t, size_t> start, pair<size_t, size_t> end, + BaselineProcessor processor, void *arguments) { - itsParmData.set (solveDomains, itsWorkDomain); - const vector<MeqDomain>& localSolveDomains = itsParmData.getDomains(); + // Determine if perturbed values have to be calculated. + int nPerturbedValues = derivatives ? itsContext.derivativeCount : 0; - itsSolveDomains = localSolveDomains; + // Get frequency / time grid information. + int nChannels = end.first - start.first + 1; + int nTimeslots = end.second - start.second + 1; - itsNrPert = 0; - itsNrScids.resize (localSolveDomains.size()); - fill (itsNrScids.begin(), itsNrScids.end(), 0); - for (MeqParmGroup::iterator iter = itsParmGroup.begin(); - iter != itsParmGroup.end(); - ++iter) - { - int nr = iter->second.initDomain (localSolveDomains, - itsNrPert, itsNrScids); - if (nr > 0) { - itsParmData.parms().push_back (ParmData(iter->second.getName(), - iter->second.getParmDBSeqNr(), - iter->second.getFunklets())); - } - } - // Determine the fitter indices for the frequency and time axis. - // First check if the (local) solve domains are ordered and regular. - // Start with finding the number of frequency intervals. - for (itsFreqNrFit=1; itsFreqNrFit<localSolveDomains.size(); itsFreqNrFit++) { - if (localSolveDomains[itsFreqNrFit].startX() < - localSolveDomains[itsFreqNrFit-1].endX()) { - break; - } - } - // Now check if regular in frequency and time. - uint timeNrFit = localSolveDomains.size() / itsFreqNrFit; - ASSERT (timeNrFit*itsFreqNrFit == localSolveDomains.size()); - for (uint inxt=0; inxt<timeNrFit; inxt++) { - const MeqDomain& first = localSolveDomains[inxt*itsFreqNrFit]; - for (uint inxf=1; inxf<itsFreqNrFit; inxf++) { - const MeqDomain& cur = localSolveDomains[inxt*itsFreqNrFit + inxf]; - ASSERT (cur.startY() == first.startY() && cur.endY() == first.endY()); - } - } - for (uint inxf=0; inxf<itsFreqNrFit; inxf++) { - const MeqDomain& first = localSolveDomains[inxf]; - for (uint inxt=1; inxt<timeNrFit; inxt++) { - const MeqDomain& cur = localSolveDomains[inxt*itsFreqNrFit + inxf]; - ASSERT (cur.startX() == first.startX() && cur.endX() == first.endX()); + // NOTE: Temporary vector should be removed after MNS overhaul. + vector<double> timeAxis(nTimeslots + 1); + for(size_t i = 0; i < nTimeslots; ++i) + timeAxis[i] = itsChunkData->time.lower(start.second + i); + timeAxis[nTimeslots] = itsChunkData->time.upper(end.second); + + // Initialize the ComplexArr pool with the most frequently used size. + uint64 defaultPoolSize = itsMeasurement->getChannelCount() * nTimeslots; + MeqMatrixComplexArr::poolDeactivate(); + MeqMatrixRealArr::poolDeactivate(); + MeqMatrixComplexArr::poolActivate(defaultPoolSize); + MeqMatrixRealArr::poolActivate(defaultPoolSize); + + // Create a request. + MeqDomain domain(itsChunkData->freq.lower(start.first), + itsChunkData->freq.upper(end.first), + itsChunkData->time.lower(start.second), + itsChunkData->time.upper(end.second)); + + MeqRequest request(domain, nChannels, timeAxis, nPerturbedValues); + request.setOffset(start); + + // Precalculate if required. + // TODO: Fix this when doing a correct! + if(precalc) + itsModel->precalculate(request); + +/************** DEBUG DEBUG DEBUG **************/ +/* + cout << "Processing correlations: "; + copy(itsContext.correlations.begin(), itsContext.correlations.end(), + ostream_iterator<size_t>(cout, " ")); + cout << endl; + + cout << "Processing baselines:" << endl; + for(set<baseline_t>::const_iterator it = itsContext.baselines.begin(); + it != itsContext.baselines.end(); + ++it) + { + cout << it->first << " - " << it->second << endl; } - } - // Determine for each frequency point to which fitter it belongs. - // For the time axis it is determined by nextDataChunk. - int nrchan = itsLastChan-itsFirstChan+1; - itsFreqFitInx.resize (nrchan); - double step = itsWorkDomain.sizeX() / nrchan; - double freq = itsWorkDomain.startX() + step / 2; - int interv = 0; - for (int i=0; i<nrchan; i++) { - if (freq > localSolveDomains[interv].endX()) { - interv++; +*/ +/************** DEBUG DEBUG DEBUG **************/ + +#pragma omp parallel + { +#pragma omp for schedule(dynamic) + // Process all selected baselines. + for(set<baseline_t>::const_iterator it = itsContext.baselines.begin(); + it != itsContext.baselines.end(); + ++it) + { +// LOG_DEBUG_STR("Processing baseline " << it->first << " - " +// << it->second); + +#if defined _OPENMP + size_t thread = omp_get_thread_num(); +#else + size_t thread = 0; +#endif + // Process baseline. + (this->*processor) + (thread, arguments, itsChunkData, start, request, *it, false); + } + } // omp parallel +} + + +void Prediffer::predictBaseline(int, void*, VisData::Pointer chunk, + pair<size_t, size_t> offset, const MeqRequest& request, baseline_t baseline, + bool showd) +{ + // Do the actual correct. + itsPredTimer.start(); + MeqJonesResult jresult = itsModel->evaluate(baseline, request); + itsPredTimer.stop(); + + itsEqTimer.start(); + // Put the results in a single array for easier handling. + const double *resultRe[4], *resultIm[4]; + jresult.getResult11().getValue().dcomplexStorage(resultRe[0], + resultIm[0]); + jresult.getResult12().getValue().dcomplexStorage(resultRe[1], + resultIm[1]); + jresult.getResult21().getValue().dcomplexStorage(resultRe[2], + resultIm[2]); + jresult.getResult22().getValue().dcomplexStorage(resultRe[3], + resultIm[3]); + + // Get information about request grid. + size_t nChannels = request.nx(); + size_t nTimeslots = request.ny(); + + // Get baseline index. + size_t basel = chunk->getBaselineIndex(baseline); + + // Copy the data to the right location. + for(size_t tslot = offset.second; + tslot < offset.second + nTimeslots; + ++tslot) + { + for(set<pair<size_t, size_t> >::const_iterator it = + itsContext.polarizations.begin(); + it != itsContext.polarizations.end(); + ++it) + { + size_t pol = it->first; + + const double* re = resultRe[it->second]; + const double* im = resultIm[it->second]; + + for(size_t chan = 0; chan < nChannels; ++chan) + { + chunk->vis_data[basel][tslot][offset.first + chan][pol] = + makefcomplex(re[chan], im[chan]); + } + + resultRe[pol] += nChannels; + resultIm[pol] += nChannels; + } } - itsFreqFitInx[i] = interv; - freq += step; - } + itsEqTimer.stop(); } -void Prediffer::clearSolvableParms() + +void Prediffer::subtractBaseline(int, void*, VisData::Pointer chunk, + pair<size_t, size_t> offset, const MeqRequest& request, baseline_t baseline, + bool showd) { - LOG_TRACE_FLOW( "clearSolvableParms" ); - for (MeqParmGroup::iterator iter = itsParmGroup.begin(); - iter != itsParmGroup.end(); - ++iter) - { - iter->second.setSolvable(false); - } -} + // Do the actual correct. + itsPredTimer.start(); + MeqJonesResult jresult = itsModel->evaluate(baseline, request); + itsPredTimer.stop(); + itsEqTimer.start(); + // Put the results in a single array for easier handling. + const double *resultRe[4], *resultIm[4]; + jresult.getResult11().getValue().dcomplexStorage(resultRe[0], + resultIm[0]); + jresult.getResult12().getValue().dcomplexStorage(resultRe[1], + resultIm[1]); + jresult.getResult21().getValue().dcomplexStorage(resultRe[2], + resultIm[2]); + jresult.getResult22().getValue().dcomplexStorage(resultRe[3], + resultIm[3]); + + // Get information about request grid. + size_t nChannels = request.nx(); + size_t nTimeslots = request.ny(); + + // Get baseline index. + size_t basel = chunk->getBaselineIndex(baseline); + + // Copy the data to the right location. + for(size_t tslot = offset.second; + tslot < offset.second + nTimeslots; + ++tslot) + { + for(set<pair<size_t, size_t> >::const_iterator it = + itsContext.polarizations.begin(); + it != itsContext.polarizations.end(); + ++it) + { + size_t pol = it->first; -//-----------------------[ Computation ]-----------------------// + const double* re = resultRe[it->second]; + const double* im = resultIm[it->second]; + for(size_t chan = 0; chan < nChannels; ++chan) + { + chunk->vis_data[basel][tslot][offset.first + chan][pol] -= + makefcomplex(re[chan], im[chan]); + } -// Currently this function always returns all data in the work domain. -// In the future it can be made smarter and process less if the work domain -// is very large. -bool Prediffer::nextDataChunk (bool useFitters) -{ - if (itsNrTimesDone >= itsNrTimes) { - return false; - } - /// For the time being all times of the work domain are mapped in. - int nt = itsNrTimes; - int st = itsNrTimesDone; - // Map the part of the file matching the given times. -// BBSTest::ScopedTimer mapTimer("P:file-mapping"); - - int64 nrValues = nt * itsMSMapInfo.timeSize(); - int64 startOffset = itsTimeIndex * itsMSMapInfo.timeSize(); - if (itsInDataMap) { - itsInDataMap->mapFile(startOffset*sizeof(fcomplex), - nrValues*sizeof(fcomplex)); - itsMSMapInfo.setInData(static_cast<fcomplex*>(itsInDataMap->getStart())); - } - if (itsOutDataMap) { - itsOutDataMap->mapFile(startOffset*sizeof(fcomplex), - nrValues*sizeof(fcomplex)); - itsMSMapInfo.setOutData(static_cast<fcomplex*>(itsOutDataMap->getStart())); - } - // Map the correct flags subset (this time interval). - itsFlagsMap->mapFile(startOffset, nrValues); - // Map the weights. - /// itsWeightMap->mapFile(..,..); - // Fill the time vector. - itsChunkTimes.resize (nt+1); - for (int i=0; i<nt; ++i) { - itsChunkTimes[i] = itsMSDesc.times[itsTimeIndex + st + i] - - itsMSDesc.exposures[itsTimeIndex + st + i] / 2; - } - itsChunkTimes[nt] = itsMSDesc.times[itsTimeIndex + st + nt-1] + - itsMSDesc.exposures[itsTimeIndex + st + nt-1] / 2; - itsMSMapInfo.setTimes (st, nt); - itsNrTimesDone += nt; - if (useFitters) { - // Determine for each time point to which fitter it belongs. -// const vector<MeqDomain>& localSolveDomains = itsParmData.getDomains(); - const vector<MeqDomain>& localSolveDomains = itsSolveDomains; - itsTimeFitInx.resize (nt); - uint interv = 0; - for (int i=0; i<nt; i++) { - double time = itsMSDesc.times[itsTimeIndex + st + i]; - while (time > localSolveDomains[interv*itsFreqNrFit].endY()) { - interv++; - DBGASSERT (interv < localSolveDomains.size()/itsFreqNrFit); - } - itsTimeFitInx[i] = interv; + resultRe[pol] += nChannels; + resultIm[pol] += nChannels; + } } - } - return true; + itsEqTimer.stop(); } -void Prediffer::processData (bool useFlags, bool preCalc, bool calcDeriv, - ProcessFuncBL pfunc, - void* arg) + +void Prediffer::correctBaseline(int, void*, VisData::Pointer chunk, + pair<size_t, size_t> offset, const MeqRequest& request, baseline_t baseline, + bool showd) { - // Map the correct input and output file (if needed). - mapDataFiles (itsInDataColumn, itsOutDataColumn); - // Calculate frequency axis info. - int nrchan = itsLastChan-itsFirstChan+1; - double startFreq = itsStartFreq + itsFirstChan*itsStepFreq; - double endFreq = itsStartFreq + (itsLastChan+1)*itsStepFreq; - // Add offset for dd (band) and channel. - unsigned int freqOffset = itsFirstChan*itsNCorr + itsMSMapInfo.ddOffset(); - // Determine if perturbed values have to be calculated. - int nrpert = calcDeriv ? itsNrPert:0; - // Loop through the domain of the data to be processed. - // Process as much data as possible (hopefully everything). - itsNrTimesDone = 0; - while (nextDataChunk(nrpert>0)) { - int nrtimes = itsMSMapInfo.nrTimes(); - // Initialize the ComplexArr pool with the most frequently used size - // itsNrChan is the number of frequency channels - MeqMatrixComplexArr::poolDeactivate(); - MeqMatrixRealArr::poolDeactivate(); - MeqMatrixComplexArr::poolActivate(itsNrChan * nrtimes); - MeqMatrixRealArr::poolActivate(itsNrChan * nrtimes); + // Do the actual correct. + itsPredTimer.start(); + MeqJonesResult jresult = itsModel->evaluate(baseline, request); + itsPredTimer.stop(); - // Size the thread private flag buffers. - if (useFlags) { - for (int i=0; i<itsNthread; ++i) { - itsFlagVecs[i].resize (nrtimes*nrchan*itsNCorr); - } - } - fcomplex* inDataStart = itsMSMapInfo.inData(); - fcomplex* outDataStart = itsMSMapInfo.outData(); - void* flagStart = itsFlagsMap->getStart(); - int flagStartBit = itsFlagsMap->getStartBit(); + itsEqTimer.start(); + // Put the results in a single array for easier handling. + const double *resultRe[4], *resultIm[4]; + jresult.getResult11().getValue().dcomplexStorage(resultRe[0], + resultIm[0]); + jresult.getResult12().getValue().dcomplexStorage(resultRe[1], + resultIm[1]); + jresult.getResult21().getValue().dcomplexStorage(resultRe[2], + resultIm[2]); + jresult.getResult22().getValue().dcomplexStorage(resultRe[3], + resultIm[3]); - // Create a request. - MeqDomain domain(startFreq, endFreq, itsChunkTimes[0], - itsChunkTimes[itsChunkTimes.size()-1]); - MeqRequest request(domain, nrchan, itsChunkTimes, nrpert); - request.setFirstX (itsFirstChan); - // Loop through all baselines. - //static NSTimer timer("Prediffer::fillFitters", true); - //timer.start(); - if (preCalc) { - precalcNodes (request); - } + // Get information about request grid. + size_t nChannels = request.nx(); + size_t nTimeslots = request.ny(); - // Loop through all baselines and fill its equations if selected. -#pragma omp parallel + // Get baseline index. + size_t basel = chunk->getBaselineIndex(baseline); + + // Copy the data to the right location. + for(size_t tslot = offset.second; + tslot < offset.second + nTimeslots; + ++tslot) { -#pragma omp for schedule(dynamic) - for (uint blindex=0; blindex<itsBLInx.size(); ++blindex) { - int bl = itsBLInx[blindex]; - // Get pointer to correct data part. - unsigned int offset = freqOffset + bl*itsNrChan*itsNCorr; - fcomplex* idata = inDataStart + offset; - fcomplex* odata = outDataStart + offset; - // Convert the flag bits to bools. - /// if (ant1==8&&ant2==11&&tStep<5) { - ///cout << "flagmap: start="<<flagStart<<" sbit="<<flagStartBit - /// << " offs="<<offset<<endl; - /// } -#if defined _OPENMP - int threadNr = omp_get_thread_num(); -#else - int threadNr = 0; -#endif - // If needed, convert flag bits to bools. - bool* flags = 0; - if (useFlags) { - flags = &itsFlagVecs[threadNr][0]; - for (int i=0; i<itsMSMapInfo.nrTimes(); ++i) { - bitToBool (flags+i*nrchan*itsNCorr, flagStart, nrchan*itsNCorr, - offset + flagStartBit); - offset += itsMSMapInfo.timeSize(); - } - } - // Call the given member function. - (this->*pfunc) (threadNr, arg, idata, odata, flags, - request, blindex, false); - ///request, blindex, itsAnt1[bl]==4&&itsAnt2[bl]==8); - } - } // end omp parallel - //timer.stop(); - } -} + for(set<pair<size_t, size_t> >::const_iterator it = + itsContext.polarizations.begin(); + it != itsContext.polarizations.end(); + ++it) + { + size_t pol = it->first; -void Prediffer::fillFitters (vector<casa::LSQFit>& fitters) -{ - // Find all nodes to be precalculated. - setPrecalcNodes (itsExpr); - // Initialize the fitters. - int nfitter = itsNrScids.size(); - fitters.resize (nfitter); - -#ifdef COMPUTE_SQUARED_ERROR - itsSquaredErrorReal.resize(nfitter); - itsSquaredErrorImag.resize(nfitter); - fill(itsSquaredErrorReal.begin(), itsSquaredErrorReal.end(), 0.0); - fill(itsSquaredErrorImag.begin(), itsSquaredErrorImag.end(), 0.0); -#endif - - // Create thread private fitters for parallel execution. - vector<vector<LSQFit*> > threadPrivateFitters(itsNthread); - for (int i=0; i<itsNthread; ++i) { - threadPrivateFitters[i].resize (nfitter); - } - for (int i=0; i<nfitter; ++i) { - fitters[i].set (itsNrScids[i]); - threadPrivateFitters[0][i] = &fitters[i]; - for (int j=1; j<itsNthread; j++) { - threadPrivateFitters[j][i] = new LSQFit(itsNrScids[i]); - } - } - // Size the thread private buffers. - ///int nrchan = itsLastChan-itsFirstChan+1; - for (int i=0; i<itsNthread; ++i) { - itsResultVecs[i].resize (2*itsNrPert); - itsDiffVecs[i].resize (3*itsNrPert); - itsIndexVecs[i].resize (itsNrPert); - /// itsOrdFlagVecs[i].resize (2*nrchan); - } - // Process the data and use the flags. - processData (true, true, true, - &Prediffer::fillEquation, &threadPrivateFitters); - // Merge the thread-specific fitters into the main ones. - for (int j=1; j<itsNthread; ++j) { - for (int i=0; i<nfitter; ++i) { - fitters[i].merge (*threadPrivateFitters[j][i]); - delete threadPrivateFitters[j][i]; + const double* re = resultRe[it->second]; + const double* im = resultIm[it->second]; + + for(size_t chan = 0; chan < nChannels; ++chan) + { + chunk->vis_data[basel][tslot][offset.first + chan][pol] = + makefcomplex(re[chan], im[chan]); + } + + resultRe[pol] += nChannels; + resultIm[pol] += nChannels; + } } - } - -#ifdef COMPUTE_SQUARED_ERROR - for(int i = 0; i < nfitter; ++i) - { - LOG_DEBUG_STR( - "SquaredError: domain: " << - i << - " real: " << - itsSquaredErrorReal[i] << - " imaginary: " << - itsSquaredErrorImag[i]); - } -#endif - - LOG_DEBUG_STR("Predict: " << itsPredTimer); - LOG_DEBUG_STR("Construct equations: " << itsEqTimer); - itsPredTimer.reset(); - itsEqTimer.reset(); -} + itsEqTimer.stop(); +} + + +void Prediffer::generateBaseline(int threadnr, void* arguments, + VisData::Pointer chunk, pair<size_t, size_t> offset, + const MeqRequest& request, baseline_t baseline, bool showd) +{ + // Check precondition. + ASSERT(offset.first % itsContext.domainSize.first == 0); + ASSERT(offset.second % itsContext.domainSize.second == 0); + + // Get the solver objects. + vector<casa::LSQFit*> &solvers = + (*static_cast<vector<vector<casa::LSQFit*> >*>(arguments))[threadnr]; + + // Get pointers to thread specific data structures. + // TODO: Get rid of ghastly pointer arithmetic. + uint* indices = &(itsIndexVecs[threadnr][0]); + const double** pertReal = &(itsResultVecs[threadnr][0]); + const double** pertImag = pertReal + itsContext.derivativeCount; + double* invPert = &(itsDiffVecs[threadnr][0]); + double* resultr = invPert + itsContext.derivativeCount; + double* resulti = resultr + itsContext.derivativeCount; + + // Do the actual predict. + itsPredTimer.start(); + MeqJonesResult jresult = itsModel->evaluate(baseline, request); + itsPredTimer.stop(); + + itsEqTimer.start(); + // Put the results in a single array for easier handling. + const MeqResult *predictResults[4]; + predictResults[0] = &(jresult.getResult11()); + predictResults[1] = &(jresult.getResult12()); + predictResults[2] = &(jresult.getResult21()); + predictResults[3] = &(jresult.getResult22()); + + // Get information about request grid. + size_t nChannels = request.nx(); + size_t nTimeslots = request.ny(); + + // Get baseline index. + size_t basel = chunk->getBaselineIndex(baseline); + + // To avoid having to use large temporary arrays, step through the + // data by timestep and correlation. + uint nreq=0; + for(set<pair<size_t, size_t> >::const_iterator it = + itsContext.polarizations.begin(); + it != itsContext.polarizations.end(); + ++it) + { + size_t pol = it->first; + + // Get the results for this correlation. + const MeqResult &tcres = *predictResults[it->second]; + + // Get pointers to the main data. + const MeqMatrix &val = tcres.getValue(); + const double *realVals; + const double *imagVals; + val.dcomplexStorage(realVals, imagVals); + + // Determine which parameters have derivatives and keep that info. + // E.g. when solving for station parameters, only a few parameters + // per baseline have derivatives. + // Note that this is the same for the entire work domain. + // Also get pointers to the perturbed values. + int nrParamsFound = 0; + for (int scinx = 0; scinx < itsContext.derivativeCount; ++scinx) + { + if (tcres.isDefined(scinx)) + { + indices[nrParamsFound] = scinx; + const MeqMatrix& valp = tcres.getPerturbedValue(scinx); + valp.dcomplexStorage (pertReal[nrParamsFound], + pertImag[nrParamsFound]); + invPert[nrParamsFound] = 1. / tcres.getPerturbation(scinx,0); + ++nrParamsFound; + } + } -void Prediffer::correctData() -{ - // Find all nodes to be precalculated. - setPrecalcNodes (itsCorrExpr); - processData (false, true, false, - &Prediffer::correctBL, 0); - /// if (flush) { - /// itsOutDataMap->flush(); - /// } - - LOG_DEBUG_STR("Read/Correct: " << itsPredTimer); - LOG_DEBUG_STR("Write: " << itsEqTimer); - itsPredTimer.reset(); - itsEqTimer.reset(); -} + if (nrParamsFound > 0) + { + for(size_t tslot = offset.second; + tslot < offset.second + nTimeslots; + ++tslot) + { +/************** DEBUG DEBUG DEBUG **************/ +// if (showd) +// { +// showData(corr, sdch, inc, nrchan, cflags, cdata, +// realVals, imagVals); +// } +/************** DEBUG DEBUG DEBUG **************/ + + // Compute relative solver index (time part). + size_t solverIndexTime = + ((tslot - offset.second) / itsContext.domainSize.second) + * itsContext.domainCount.first; + + // Loop through all channels. + // Form two equations for each unflagged data point. + for (int ch = offset.first; + ch < offset.first + nChannels; + ++ch) + { + // Compute relative solver index. + size_t solverIndex = solverIndexTime + + (ch - offset.first) / itsContext.domainSize.first; -void Prediffer::subtractData() -{ - // Find all nodes to be precalculated. - setPrecalcNodes (itsExpr); - processData (false, true, false, - &Prediffer::subtractBL, 0); - /// if (flush) { - /// itsOutDataMap->flush(); - /// } - - LOG_DEBUG_STR("Predict: " << itsPredTimer); - LOG_DEBUG_STR("Read/Subtract/Write: " << itsEqTimer); - itsPredTimer.reset(); - itsEqTimer.reset(); -} + if (!chunk->vis_flag[basel][tslot][ch][pol]) + { + // Compute right hand side of the equation pair. + double diffr = + real(chunk->vis_data[basel][tslot][ch][pol]) + - *realVals; + double diffi = + imag(chunk->vis_data[basel][tslot][ch][pol]) + - *imagVals; + + #ifdef COMPUTE_SQUARED_ERROR + itsSquaredErrorReal[solverIndex] += diffr*diffr; + itsSquaredErrorImag[solverIndex] += diffi*diffi; + #endif + + // Compute left hand side of the equation pair. + for(int scinx = 0; scinx < nrParamsFound; ++scinx) + { + // Approximate the derivative for real and imag + // part. + double invp = invPert[scinx]; + resultr[scinx] = (*pertReal[scinx] - *realVals) + * invp; + resulti[scinx] = (*pertImag[scinx] - *imagVals) + * invp; + } -void Prediffer::writePredictedData() -{ - // Find all nodes to be precalculated. - setPrecalcNodes (itsExpr); - processData (false, true, false, - &Prediffer::predictBL, 0); + // Now add the equations to the correct fitter + // object. + if (nrParamsFound != itsContext.derivativeCount) + { + solvers[solverIndex]->makeNorm( + itsContext.derivativeCount, indices, resultr, + 1.0, diffr); + + solvers[solverIndex]->makeNorm( + itsContext.derivativeCount, indices, resulti, + 1.0, diffi); + } + else + { + solvers[solverIndex]->makeNorm(resultr, 1.0, diffr); + solvers[solverIndex]->makeNorm(resulti, 1.0, diffi); + } + +/************** DEBUG DEBUG DEBUG **************/ +/* + if (showd) + { + cout << "eq"<<corr<<" ch " << 2*ch << " diff " + << diffr; + for (int ii=0; ii<nrParamsFound; ii++) + cout << ' '<<resultr[ii]; + + cout << endl; + cout << "eq"<<corr<<" ch " << 2*ch+1 << " diff " + << diffi; + + for (int ii=0; ii<nrParamsFound; ii++) + cout << ' '<<resulti[ii]; + + cout << endl; + } +*/ +/************** DEBUG DEBUG DEBUG **************/ + + nreq += 2; + } // !chunk->vis_flag[basel][tslot][ch][pol] + + // Move pointers to the next channel. + for (int scinx = 0; scinx < nrParamsFound; ++scinx) + { + pertReal[scinx]++; + pertImag[scinx]++; + } + realVals++; + imagVals++; + } + } + } + } - LOG_DEBUG_STR("Predict: " << itsPredTimer); - LOG_DEBUG_STR("Write: " << itsEqTimer); - itsPredTimer.reset(); - itsEqTimer.reset(); + //fillEquationTimer.stop(); + itsEqTimer.stop(); } + +/* void Prediffer::getData (bool useTree, Array<Complex>& dataArr, Array<Bool>& flagArr) { - int nrusedbl = itsBLInx.size(); + int nrusedbl = itsBaselineInx.size(); int nrchan = itsLastChan-itsFirstChan+1; dataArr.resize (IPosition(4, itsNCorr, nrchan, nrusedbl, itsNrTimes)); flagArr.resize (IPosition(4, itsNCorr, nrchan, nrusedbl, itsNrTimes)); @@ -2025,245 +1357,23 @@ void Prediffer::getData (bool useTree, p.first = dataArr.data(); p.second = flagArr.data(); if (!useTree) { - processData (true, false, false, &Prediffer::getBL, &p); + process (true, false, false, &Prediffer::getBaseline, &p); return; } vector<MeqJonesExpr> expr(nrusedbl); for (int i=0; i<nrusedbl; ++i) { - expr[i] = new MeqJonesMMap (itsMSMapInfo, itsBLInx[i]); + expr[i] = new MeqJonesMMap (itsMSMapInfo, itsBaselinenInx[i]); } pair<pair<Complex*,bool*>*, vector<MeqJonesExpr>*> p1; p1.first = &p; p1.second = &expr; - processData (true, false, false, &Prediffer::getMapBL, &p1); + process (true, false, false, &Prediffer::getMapBaseline, &p1); } +*/ -void Prediffer::fillEquation (int threadnr, void* arg, - const fcomplex* data, fcomplex*, - const bool* flags, - const MeqRequest& request, int blindex, - bool showd) -{ - ///int bl = itsBLInx[blindex]; - ///int ant1 = itsAnt1[bl]; - ///int ant2 = itsAnt2[bl]; - //static NSTimer fillEquationTimer("fillEquation", true); - //fillEquationTimer.start(); - // Get the fitter objects. - vector<LSQFit*>& fitters = - (*static_cast<vector<vector<LSQFit*> >*>(arg))[threadnr]; - - // Allocate temporary vectors. - // If needed, they can be pre-allocated per thread, so there is no - // malloc needed for each invocation. Currently it is believed that - // the work domains are so large, that the malloc overhead is negligible. - // ON the other hand, there are many baselines and the malloc is done - // for each of them. - uint* indices = &(itsIndexVecs[threadnr][0]); - const double** pertReal = &(itsResultVecs[threadnr][0]); - const double** pertImag = pertReal + itsNrPert; - double* invPert = &(itsDiffVecs[threadnr][0]); - double* resultr = invPert + itsNrPert; - double* resulti = resultr + itsNrPert; - // Get all equations. - itsPredTimer.start(); - MeqJonesExpr& expr = itsExpr[blindex]; - // Do the actual predict for the entire work domain. - MeqJonesResult jresult = expr.getResult (request); - itsPredTimer.stop(); - - itsEqTimer.start(); - int nrchan = request.nx(); - int nrtime = request.ny(); - int timeSize = itsMSMapInfo.timeSize(); - // Put the results in a single array for easier handling. - const MeqResult* predResults[4]; - predResults[0] = &(jresult.getResult11()); - if (itsNCorr == 2) { - predResults[1] = &(jresult.getResult22()); - } else if (itsNCorr == 4) { - predResults[1] = &(jresult.getResult12()); - predResults[2] = &(jresult.getResult21()); - predResults[3] = &(jresult.getResult22()); - } - - // Determine start and incr reflecting the order of the observed data. - int sdch = itsReverseChan ? itsNCorr * (nrchan - 1) : 0; - int inc = itsReverseChan ? -itsNCorr : itsNCorr; - // To avoid having to use large temporary arrays, step through the - // data by timestep and correlation. - uint nreq=0; - - for (int corr=0; corr<itsNCorr; corr++, data++, flags++) { - if (itsCorr[corr]) { - // Get the results for this correlation. - const MeqResult& tcres = *predResults[corr]; - - // Get pointers to the main data. - const MeqMatrix& val = tcres.getValue(); - const double* realVals; - const double* imagVals; - val.dcomplexStorage(realVals, imagVals); - - // Determine which parameters have derivatives and keep that info. - // E.g. when solving for station parameters, only a few parameters - // per baseline have derivatives. - // Note that this is the same for the entire work domain. - // Also get pointers to the perturbed values. - int nrParamsFound = 0; - for (int scinx=0; scinx<itsNrPert; ++scinx) { - if (tcres.isDefined(scinx)) { - indices[nrParamsFound] = scinx; - const MeqMatrix& valp = tcres.getPerturbedValue(scinx); - valp.dcomplexStorage (pertReal[nrParamsFound], - pertImag[nrParamsFound]); - invPert[nrParamsFound] = 1. / tcres.getPerturbation(scinx, 0); - nrParamsFound++; - } - } - - if (nrParamsFound > 0) { - const fcomplex* cdata = data; - const bool* cflags = flags; - if (fitters.size() == 1) { - - // No fitter indexing needed if only one fitter. - for (int tim=0; tim<nrtime; tim++) { - // Loop through all channels. - if (showd) { - showData (corr, sdch, inc, nrchan, cflags, cdata, - realVals, imagVals); - } - // Form two equations for each unflagged data point. - int dch = sdch; - for (int ch=0; ch<nrchan; ++ch, dch+=inc) { - if (! cflags[dch]) { - double diffr = real(cdata[dch]) - *realVals; - double diffi = imag(cdata[dch]) - *imagVals; - -#ifdef COMPUTE_SQUARED_ERROR - itsSquaredErrorReal[0] += diffr*diffr; - itsSquaredErrorImag[0] += diffi*diffi; -#endif - - for (int scinx=0; scinx<nrParamsFound; ++scinx) { - // Calculate the derivative for real and imag part. - double invp = invPert[scinx]; - resultr[scinx] = (*pertReal[scinx]++ - *realVals) * invp; - resulti[scinx] = (*pertImag[scinx]++ - *imagVals) * invp; - } - // Now add the equations to the correct fitter object. - if (nrParamsFound != itsNrPert) { - fitters[0]->makeNorm (nrParamsFound, indices, - resultr, 1., diffr); - fitters[0]->makeNorm (nrParamsFound, indices, - resulti, 1., diffi); - } else { - fitters[0]->makeNorm (resultr, 1., diffr); - fitters[0]->makeNorm (resulti, 1., diffi); - } - if (showd) { - cout << "eq"<<corr<<" ch " << 2*ch << " diff " << diffr; - for (int ii=0; ii<nrParamsFound; ii++) { - cout << ' '<<resultr[ii]; - } - cout << endl; - cout << "eq"<<corr<<" ch " << 2*ch+1 << " diff " << diffi; - for (int ii=0; ii<nrParamsFound; ii++) { - cout << ' '<<resulti[ii]; - } - cout << endl; - } - nreq += 2; - } else { - for (int scinx=0; scinx<nrParamsFound; ++scinx) { - pertReal[scinx]++; - pertImag[scinx]++; - } - } - realVals++; - imagVals++; - } - cdata += timeSize; // next observed data time step - cflags += nrchan*itsNCorr; - } - } else { - // Multiple fitters, so for each point the correct fitter - // has to be determined. - for (int tim=0; tim<nrtime; tim++) { - // Loop through all channels. - if (showd) { - showData (corr, sdch, inc, nrchan, cflags, cdata, - realVals, imagVals); - } - // Get first fitter index for this time line. - int fitInxT = itsTimeFitInx[tim] * itsFreqNrFit; - // Form two equations for each unflagged data point. - int dch = sdch; - for (int ch=0; ch<nrchan; ++ch, dch+=inc) { - if (! cflags[dch]) { - int fitInx = fitInxT + itsFreqFitInx[ch]; - double diffr = real(cdata[dch]) - *realVals; - double diffi = imag(cdata[dch]) - *imagVals; - -#ifdef COMPUTE_SQUARED_ERROR - itsSquaredErrorReal[fitInx] += diffr*diffr; - itsSquaredErrorImag[fitInx] += diffi*diffi; -#endif - - for (int scinx=0; scinx<nrParamsFound; ++scinx) { - // Calculate the derivative for real and imag part. - double invp = 1. / tcres.getPerturbation(indices[scinx], - fitInx); - resultr[scinx] = (*pertReal[scinx]++ - *realVals) * invp; - resulti[scinx] = (*pertImag[scinx]++ - *imagVals) * invp; - } - // Now add the equations to the correct fitter object. - if (nrParamsFound != itsNrPert) { - fitters[fitInx]->makeNorm (nrParamsFound, indices, - resultr, 1., diffr); - fitters[fitInx]->makeNorm (nrParamsFound, indices, - resulti, 1., diffi); - } else { - fitters[fitInx]->makeNorm (resultr, 1., diffr); - fitters[fitInx]->makeNorm (resulti, 1., diffi); - } - if (showd) { - cout << "eq"<<corr<<" ch " << 2*ch << " diff " << diffr; - for (int ii=0; ii<nrParamsFound; ii++) { - cout << ' '<<resultr[ii]; - } - cout << endl; - cout << "eq"<<corr<<" ch " << 2*ch+1 << " diff " << diffi; - for (int ii=0; ii<nrParamsFound; ii++) { - cout << ' '<<resulti[ii]; - } - cout << endl; - } - nreq += 2; - } else { - for (int scinx=0; scinx<nrParamsFound; ++scinx) { - pertReal[scinx]++; - pertImag[scinx]++; - } - } - realVals++; - imagVals++; - } - cdata += timeSize; // next observed data time step - cflags += nrchan*itsNCorr; - } - } - } - } - } - //fillEquationTimer.stop(); - itsEqTimer.stop(); - - /// cout << "nreq="<<nreq<<endl; -} -vector<MeqResult> Prediffer::getResults (bool calcDeriv) +/* +vector<MeqResult> Prediffer::getResults(bool calcDeriv) { // Find all nodes to be precalculated. setPrecalcNodes (itsExpr); @@ -2279,7 +1389,7 @@ vector<MeqResult> Prediffer::getResults (bool calcDeriv) MeqDomain domain(startFreq, endFreq, time-interv/2, time+interv/2); MeqRequest request(domain, nrchan, 1, 0); if (calcDeriv) { - request = MeqRequest(domain, nrchan, 1, itsNrPert); + request = MeqRequest(domain, nrchan, 1, itsContext.derivativeCount); } // Loop through expressions to be precalculated. // We can parallellize them at each level. @@ -2295,7 +1405,7 @@ vector<MeqResult> Prediffer::getResults (bool calcDeriv) } } // Evaluate for all selected baselines. - for (uint blindex=0; blindex<itsBLInx.size(); ++blindex) { + for (uint blindex=0; blindex<itsBaselineInx.size(); ++blindex) { // Get the result for this baseline. MeqJonesExpr& expr = itsExpr[blindex]; // This is the actual predict. @@ -2308,12 +1418,12 @@ vector<MeqResult> Prediffer::getResults (bool calcDeriv) } return results; } +*/ -void Prediffer::getBL (int, void* arg, - const fcomplex* data, fcomplex*, - const bool* flags, - const MeqRequest&, int blindex, - bool) + +/* +void Prediffer::getBaseline(int, void* arguments, const fcomplex* data, + fcomplex*, const bool* flags, const MeqRequest&, int blindex, bool) { Complex* datap = static_cast<pair<Complex*,bool*>*>(arg)->first; bool* flagp = static_cast<pair<Complex*,bool*>*>(arg)->second; @@ -2323,12 +1433,11 @@ void Prediffer::getBL (int, void* arg, memcpy (flagp+blindex*nrchan*itsNCorr, flags, nrchan*itsNCorr*sizeof(bool)); } +*/ -void Prediffer::getMapBL (int, void* arg, - const fcomplex*, fcomplex*, - const bool* flags, - const MeqRequest& request, int blindex, - bool) +/* +void Prediffer::getMapBaseline (int, void* arguments, const fcomplex*, + fcomplex*, const bool* flags, const MeqRequest& request, int blindex, bool) { pair<pair<Complex*,bool*>*, vector<MeqJonesExpr>*>* p1 = static_cast<pair<pair<Complex*,bool*>*, vector<MeqJonesExpr>*>*>(arg); @@ -2375,245 +1484,45 @@ void Prediffer::getMapBL (int, void* arg, } } } +*/ -void Prediffer::subtractBL (int, void*, - const fcomplex* dataIn, fcomplex* dataOut, - const bool*, - const MeqRequest& request, int blindex, - bool) -{ - itsPredTimer.start(); - MeqJonesExpr& expr = itsExpr[blindex]; - // Do the actual predict. - MeqJonesResult jresult = expr.getResult (request); - itsPredTimer.stop(); - - itsEqTimer.start(); - int nrchan = request.nx(); - int nrtime = request.ny(); - int timeSize = itsMSMapInfo.timeSize(); - const double* predReal[4]; - const double* predImag[4]; - jresult.getResult11().getValue().dcomplexStorage(predReal[0], predImag[0]); - if (itsNCorr == 2) { - jresult.getResult22().getValue().dcomplexStorage(predReal[1], predImag[1]); - } else if (itsNCorr == 4) { - jresult.getResult12().getValue().dcomplexStorage(predReal[1], predImag[1]); - jresult.getResult21().getValue().dcomplexStorage(predReal[2], predImag[2]); - jresult.getResult22().getValue().dcomplexStorage(predReal[3], predImag[3]); - } - // Loop through the times and correlations. - for (int tim=0; tim<nrtime; tim++) { - const fcomplex* idata = dataIn; - fcomplex* odata = dataOut; - for (int corr=0; corr<itsNCorr; corr++, idata++, odata++) { - if (itsCorr[corr]) { - const double* realVals = predReal[corr]; - const double* imagVals = predImag[corr]; - // Subtract predicted from the data. - int dch = itsReverseChan ? itsNCorr * (nrchan - 1) : 0; - int inc = itsReverseChan ? -itsNCorr : itsNCorr; - if (idata == odata) { - for (int ch=0; ch<nrchan; ch++, dch+=inc) { - odata[dch] -= makefcomplex(realVals[ch], imagVals[ch]); - } - } else { - for (int ch=0; ch<nrchan; ch++, dch+=inc) { - odata[dch] = idata[dch] - makefcomplex(realVals[ch], - imagVals[ch]); - } - } - predReal[corr] += nrchan; - predImag[corr] += nrchan; - } - } - dataIn += timeSize; - dataOut += timeSize; - } - itsEqTimer.stop(); -} -void Prediffer::correctBL (int, void*, - const fcomplex*, fcomplex*, - const bool*, - const MeqRequest& request, int blindex, - bool) -{ - itsPredTimer.start(); - MeqJonesResult res = itsCorrExpr[blindex].getResult (request); - itsPredTimer.stop(); - itsEqTimer.start(); - itsCorrMMap[blindex]->putJResult (res, request); - itsEqTimer.stop(); -} -void Prediffer::predictBL (int, void*, - const fcomplex*, fcomplex* dataOut, - const bool*, - const MeqRequest& request, int blindex, - bool) +/* +void Prediffer::testFlagsBaseline(int, void*, VisData::Pointer chunk, + const MeqRequest& request, baseline_t baseline, bool showd) { - itsPredTimer.start(); - MeqJonesExpr& expr = itsExpr[blindex]; - // Do the actual predict. - MeqJonesResult jresult = expr.getResult (request); - itsPredTimer.stop(); - - itsEqTimer.start(); - int nrchan = request.nx(); - int nrtime = request.ny(); - int timeSize = itsMSMapInfo.timeSize(); - // Put the results in a single array for easier handling. - const double* predReal[4]; - const double* predImag[4]; - jresult.getResult11().getValue().dcomplexStorage(predReal[0], predImag[0]); - if (itsNCorr == 2) { - jresult.getResult22().getValue().dcomplexStorage(predReal[1], predImag[1]); - } else if (itsNCorr == 4) { - jresult.getResult12().getValue().dcomplexStorage(predReal[1], predImag[1]); - jresult.getResult21().getValue().dcomplexStorage(predReal[2], predImag[2]); - jresult.getResult22().getValue().dcomplexStorage(predReal[3], predImag[3]); - } - - // Loop through the times and correlations. - for (int tim=0; tim<nrtime; tim++) { - fcomplex* data = dataOut; - for (int corr=0; corr<itsNCorr; corr++, data++) { - if (itsCorr[corr]) { - const double* realVals = predReal[corr]; - const double* imagVals = predImag[corr]; - // Store the predict in data. - int dch = itsReverseChan ? itsNCorr * (nrchan - 1) : 0; - int inc = itsReverseChan ? -itsNCorr : itsNCorr; - for (int ch=0; ch<nrchan; ch++, dch+=inc) { - data[dch] = makefcomplex(realVals[ch], imagVals[ch]); - } - predReal[corr] += nrchan; - predImag[corr] += nrchan; - } - } - dataOut += timeSize; - } - itsEqTimer.stop(); -} + itsEqTimer.start(); + int nrchan = request.nx(); + int nrtime = request.ny(); + map<baseline_t, size_t>::iterator it = chunk->baselines.find(baseline); + ASSERT(it != chunk->baselines.end()); + size_t basel = it->second; -void Prediffer::fillUVW() -{ - // Create the UVW nodes. - int nrstat = itsStations.size(); - itsStatUVW.reserve (nrstat); - for (int i=0; i<nrstat; ++i) { - MeqStatUVW* uvw = 0; - // Do it only if the station is actually used. - if (itsStations[i] != 0) { - // Expression to calculate UVW per station - uvw = new MeqStatUVW(itsStations[i], pair<double, double>(itsMSDesc.ra, itsMSDesc.dec), itsMSDesc.arrayPos); - } - itsStatUVW.push_back (uvw); - } - if (itsCalcUVW) { - return; - } - // Fill the UVW objects with the uvw-s from the MS. - LOG_TRACE_RTTI( "get UVW coordinates from MS" ); - int nant = itsStatUVW.size(); - vector<bool> statFnd (nant); - vector<bool> statDone (nant); - vector<double> statuvw(3*nant); - - // Determine the number of stations (found) - statFnd.assign (statFnd.size(), false); - int nStatFnd = 0; - for (unsigned int bl=0; bl<itsNrBl; bl++) { - int a1 = itsMSDesc.ant1[bl]; - int a2 = itsMSDesc.ant2[bl]; - if (!statFnd[a1]) { - nStatFnd++; - statFnd[a1] = true; - } - if (!statFnd[a2]) { - nStatFnd++; - statFnd[a2] = true; - } - } - // Map uvw data into memory - size_t nrBytes = itsMSDesc.times.size() * itsNrBl * 3 * sizeof(double); - double* uvwDataPtr = 0; - string UVWFile = getFileForColumn(MS::columnName(MS::UVW)); - LOG_INFO_STR("Input column " << MS::columnName(MS::UVW) << " maps to: " << UVWFile); - MMap* mapPtr = new MMap(UVWFile, MMap::Read); - mapPtr->mapFile(0, nrBytes); - uvwDataPtr = (double*)mapPtr->getStart(); - - // Step time by time through the MS. - for (unsigned int tStep=0; tStep < itsMSDesc.times.size(); tStep++) { - // Set uvw pointer to beginning of this time - unsigned int tOffset = tStep * itsNrBl * 3; - double* uvw = uvwDataPtr + tOffset; - double time = itsMSDesc.times[tStep]; - - // Set UVW of first station used to 0 (UVW coordinates are relative!). - statDone.assign (statDone.size(), false); - int ant0 = itsMSDesc.ant1[0]; - statuvw[3*ant0] = 0; - statuvw[3*ant0+1] = 0; - statuvw[3*ant0+2] = 0; - statDone[ant0] = true; - itsStatUVW[ant0]->set (time, 0, 0, 0); - -// cout << "itsStatUVW[" << itsAnt1Data[0] << "] time: " << time << " 0, 0, 0" << endl; - - int ndone = 1; - // Loop until all found stations are handled. This is necessary when not all - // stations can be calculated in one loop (depends on the order) - while (ndone < nStatFnd) { - int nd = 0; - // Loop over baselines - for (unsigned int bl=0; bl<itsNrBl; bl++) { - int a1 = itsMSDesc.ant1[bl]; - int a2 = itsMSDesc.ant2[bl]; - if (!statDone[a2]) { - if (statDone[a1]) { - statuvw[3*a2] = uvw[3*bl] - statuvw[3*a1]; - statuvw[3*a2+1] = uvw[3*bl+1] - statuvw[3*a1+1]; - statuvw[3*a2+2] = uvw[3*bl+2] - statuvw[3*a1+2]; - statDone[a2] = true; - itsStatUVW[a2]->set (time, statuvw[3*a2], statuvw[3*a2+1], - statuvw[3*a2+2]); - -// cout << "itsStatUVW[" << a2 << "] time: " << time << statuvw[3*a2] << " ," << statuvw[3*a2+1] << " ," << statuvw[3*a2+2] << endl; - - ndone++; - nd++; - } - } else if (!statDone[a1]) { - if (statDone[a2]) { - statuvw[3*a1] = statuvw[3*a2] - uvw[3*bl]; - statuvw[3*a1+1] = statuvw[3*a2+1] - uvw[3*bl+1]; - statuvw[3*a1+2] = statuvw[3*a2+2] - uvw[3*bl+2]; - statDone[a1] = true; - itsStatUVW[a1]->set (time, statuvw[3*a1], statuvw[3*a1+1], - statuvw[3*a1+2]); -// cout << "itsStatUVW[" << a1 << "] time: " << time << statuvw[3*a1] << " ," << statuvw[3*a1+1] << " ," << statuvw[3*a1+2] << endl; - - ndone++; - nd++; - } - } - if (ndone == nStatFnd) { - break; - } - } // End loop baselines - // ASSERT (nd > 0); - } // End loop stations found - } // End loop time + // Loop through the times and correlations. + for(size_t tslot = 0; tslot < nrtime; ++tslot) + { + for(set<size_t>::const_iterator it = itsContext.correlations.begin(); + it != itsContext.correlations.end(); + ++it) + { + size_t correlation = *it; - // Finished with map - delete mapPtr; + for(size_t ch=0; ch < nrchan; ++ch) + { + chunk->vis_data[basel][tslot][ch][correlation] = + (chunk->vis_flag[basel][tslot][ch][correlation] ? + makefcomplex(0.0, 0.0) : makefcomplex(1.0, 1.0)); + } + } + } + itsEqTimer.stop(); } +*/ -void Prediffer::updateSolvableParms (const vector<double>& values) + +void Prediffer::updateSolvableParms(const vector<double>& values) { // Iterate through all parms. for (MeqParmGroup::iterator iter = itsParmGroup.begin(); @@ -2624,13 +1533,12 @@ void Prediffer::updateSolvableParms (const vector<double>& values) iter->second.update (values); } } - resetEqLoop(); } void Prediffer::updateSolvableParms(size_t solveDomainIndex, const vector<double> unknowns) { SolveDomainDescriptor &descriptor = - itsSolveDomainDescriptors[solveDomainIndex]; + itsContext.domains[solveDomainIndex]; for(size_t i = 0; i < descriptor.parameters.size(); ++i) { @@ -2639,6 +1547,7 @@ void Prediffer::updateSolvableParms(size_t solveDomainIndex, const vector<double } +/* void Prediffer::updateSolvableParms (const ParmDataInfo& parmDataInfo) { const vector<ParmData>& parmData = parmDataInfo.parms(); @@ -2661,8 +1570,8 @@ void Prediffer::updateSolvableParms (const ParmDataInfo& parmDataInfo) } } } - resetEqLoop(); } +*/ void Prediffer::updateSolvableParms() { @@ -2681,26 +1590,16 @@ void Prediffer::updateSolvableParms() // cout.precision (prec); } } - resetEqLoop(); -} - -void Prediffer::resetEqLoop() -{ } - // Log the values of the solvable parameters and the quality indicators of the // last iteration to a ParmDB. The type of the parameters is set to 'history' // to ensure that they cannot accidentily be used as input for BBSkernel. Also, // ParmFacade::getHistory() checks on this type. -void Prediffer::logIteration( - const string &stepName, - size_t solveDomainIndex, - double rank, - double chiSquared, - double LMFactor) +void Prediffer::logIteration(const string &stepName, size_t solveDomainIndex, + double rank, double chiSquared, double LMFactor) { - if(!itsHistoryDB) + if(!itsHistoryDBase) return; ostringstream os; @@ -2713,7 +1612,7 @@ void Prediffer::logIteration( vector<int> shape(2, 1); const SolveDomainDescriptor &descriptor = - itsSolveDomainDescriptors[solveDomainIndex]; + itsContext.domains[solveDomainIndex]; // For each solve domain, log the solver quality indicators and the values of the // coefficients of each solvable parameter. @@ -2729,24 +1628,28 @@ void Prediffer::logIteration( string stepPrefix = stepName + ":"; string domainSuffix; - if(itsSolveDomains.size() > 1) + if(itsContext.domains.size() > 1) { os.str(""); - os << ":domain" << setw(((int) log10(double(itsSolveDomains.size())) + 1)) << solveDomainIndex; + os << ":domain" + << setw(((int) log10(double(itsContext.domains.size())) + 1)) + << solveDomainIndex; domainSuffix = os.str(); } value.setNewParm(); valueRep.setCoeff(&rank, &solvable, shape); - itsHistoryDB->putValue(stepPrefix + "solver:rank" + domainSuffix, value); + itsHistoryDBase->putValue(stepPrefix + "solver:rank" + domainSuffix, value); value.setNewParm(); valueRep.setCoeff(&chiSquared, &solvable, shape); - itsHistoryDB->putValue(stepPrefix + "solver:chi_squared" + domainSuffix, value); + itsHistoryDBase->putValue(stepPrefix + "solver:chi_squared" + domainSuffix, +value); value.setNewParm(); valueRep.setCoeff(&LMFactor, &solvable, shape); - itsHistoryDB->putValue(stepPrefix + "solver:lm_factor" + domainSuffix, value); + itsHistoryDBase->putValue(stepPrefix + "solver:lm_factor" + domainSuffix, +value); // Log each solvable parameter. Each combinaton of coefficient // and solve domain is logged separately. Otherwise, one would @@ -2771,13 +1674,25 @@ void Prediffer::logIteration( valueRep.setCoeff(&data[j], &solvable, shape); os.str(""); os << stepPrefix << descriptor.parameters[i].getName() << ":c" << setw(indexWidth) << j << domainSuffix; - itsHistoryDB->putValue(os.str(), value); + itsHistoryDBase->putValue(os.str(), value); } } } } +void Prediffer::writeParms(size_t solveDomainIndex) +{ + lock(); + SolveDomainDescriptor &descriptor = itsContext.domains[solveDomainIndex]; + for(size_t i = 0; i < descriptor.parameters.size(); ++i) + { + descriptor.parameters[i].save(solveDomainIndex); + } + unlock(); +} + + void Prediffer::writeParms() { // BBSTest::ScopedTimer saveTimer("P:write-parm"); @@ -2792,361 +1707,25 @@ void Prediffer::writeParms() } // saveTimer.stop(); // BBSTest::Logger::log("write-parm", saveTimer); - cout << "wrote timeIndex=" << itsTimeIndex - << " nrTimes=" << itsNrTimes << endl; +// cout << "wrote timeIndex=" << itsTimeIndex + //<< " nrTimes=" << itsNrTimes << endl; } #ifdef EXPR_GRAPH -void Prediffer::writeExpressionGraph(const string &fileName, int baselineIndex) +void Prediffer::writeExpressionGraph(const string &fileName, + baseline_t baseline) { - ASSERT(baselineIndex >= 0 && baselineIndex < itsExpr.size()); + MeqJonesExpr& expr = itsExpr[baseline]; + ASSERTSTR(!expr.isNull(), "Trying to process an unknown baseline."); ofstream os(fileName.c_str()); os << "digraph MeasurementEquation" << endl; os << "{" << endl; os << "node [shape=box];" << endl; - itsExpr[baselineIndex].writeExpressionGraph(os); + expr.writeExpressionGraph(os); os << "}" << endl; } #endif -void Prediffer::showSettings() const -{ - cout << "Prediffer settings:" << endl; - cout << " msname: " << itsMSName << endl; - cout << " mepname: " << itsMEPName << endl; - cout << " gsmname: " << itsGSMMEPName << endl; - cout << " solvparms: " << itsParmData << endl; - if (itsReverseChan) { - cout << " stchan: " << itsNrChan - 1 - itsFirstChan << endl; - cout << " endchan: " << itsNrChan - 1 - itsLastChan << endl; - cout << " Note: channels are in reversed order" << endl; - } else { - cout << " stchan: " << itsFirstChan << endl; - cout << " endchan: " << itsLastChan << endl; - } - cout << " corr : " << itsNCorr << " " << itsCorr[0]; - for (int i=1; i<itsNCorr; ++i) { - cout << ',' << itsCorr[i]; - } - cout << endl; - cout << " calcuvw : " << itsCalcUVW << endl; - cout << endl; -} - -void Prediffer::showData (int corr, int sdch, int inc, int nrchan, - const bool* flags, const fcomplex* data, - const double* realVals, const double* imagVals) -{ - cout << "flag=" << corr << "x "; - int dch = sdch; - for (int ch=0; ch<nrchan; ch++, dch+=inc) { - cout << flags[dch]<< ' '; - } - cout << endl; - cout << "cor=" << corr << "x "; - dch = sdch; - for (int ch=0; ch<nrchan; ch++, dch+=inc) { - cout << '(' << setprecision(12) - << real(data[dch]) - << ',' << setprecision(12) - << imag(data[dch])<< ')'; - } - cout << endl; - cout << "corr=" << corr << "x "; - for (int ch=0; ch<nrchan; ch++) { - cout << '(' << setprecision(12) - << realVals[ch] - << ',' << setprecision(12) - << imagVals[ch]<< ')'; - } - cout << endl; -} - - -// DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED -// DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED - -Prediffer::Prediffer(const string& msName, - const LOFAR::ParmDB::ParmDBMeta& meqPdm, - const LOFAR::ParmDB::ParmDBMeta& skyPdm, - uint ddid, - bool calcUVW) -: itsCalcUVW (calcUVW), - itsMEPName (meqPdm.getTableName()), - itsGSMMEPName (skyPdm.getTableName()), - itsHistoryDB (0), - itsSources (0), - itsNrPert (0), - itsNCorr (0), - itsNrBl (0), - itsTimeIndex (0), - itsNrTimes (0), - itsNrTimesDone (0), - itsInDataMap (0), - itsOutDataMap (0), - itsFlagsMap (0), - itsWeightMap (0), - itsIsWeightSpec (false), - itsPredTimer ("P:predict", false), - itsEqTimer ("P:eq|save", false) -{ - // Get absolute path name for MS. - itsMSName = Path(msName).absoluteName(); - LOG_INFO_STR( "Prediffer constructor (" - << "'" << itsMSName << "', " - << "'" << meqPdm.getTableName() << "', " - << "'" << skyPdm.getTableName() << "', " - << itsCalcUVW << ")" ); - // Read the meta data and map the flags file. - //readDescriptiveData(msName); - readMeasurementSetMetaData(itsMSName); - processMSDesc(ddid); - - itsGSMMEP = new LOFAR::ParmDB::ParmDB(skyPdm); - itsMEP = new LOFAR::ParmDB::ParmDB(meqPdm); - - itsFlagsMap = new FlagsMap(getFileForColumn(MS::columnName(MS::FLAG)), MMap::Read); - // Get all sources from the ParmDB. - itsSources = new MeqSourceList(*itsGSMMEP, itsParmGroup); - // Create the UVW nodes and fill them with uvw-s from MS if not calculated. - fillUVW(); - // Allocate thread private buffers. -#if defined _OPENMP - itsNthread = omp_get_max_threads(); -#else - itsNthread = 1; -#endif - itsFlagVecs.resize (itsNthread); - itsResultVecs.resize (itsNthread); - itsDiffVecs.resize (itsNthread); - itsIndexVecs.resize (itsNthread); -} - -bool Prediffer::setStrategyProp (const StrategyProp& strat) -{ - itsInDataColumn = strat.getInColumn(); - // Initially use all correlations. - for (int i=0; i<itsNCorr; ++i) { - itsCorr[i] = true; - } - strat.expandPatterns (itsMSDesc.antNames); - return selectStations (strat.getAntennas(), // Available antennas - strat.getAutoCorr()); -} - -bool Prediffer::setStepProp (const StepProp& stepProp) -{ - itsOutDataColumn = stepProp.getOutColumn(); - stepProp.expandPatterns (itsMSDesc.antNames); - if (!selectStep (stepProp.getAnt1(), stepProp.getAnt2(), - stepProp.getAutoCorr(), - stepProp.getCorr())) { - return false; - } - // If no sources given, use all sources. - if (stepProp.getSources().empty()) { - makeTree (stepProp.getModel(), itsSources->getSourceNames()); - } else { - makeTree (stepProp.getModel(), stepProp.getSources()); - } - // Put funklets in parms which are not filled yet. - for (MeqParmGroup::iterator iter = itsParmGroup.begin(); - iter != itsParmGroup.end(); - ++iter) - { - iter->second.fillFunklets (itsParmValues, itsWorkDomain); - } - return true; -} - -bool Prediffer::setSolveProp (const SolveProp& solveProp) -{ - LOG_INFO_STR( "setSolveProp"); - const vector<string>& parms = solveProp.getParmPatterns(); - const vector<string>& excludePatterns = solveProp.getExclPatterns(); - // Convert patterns to regexes. - vector<Regex> parmRegex; - for (unsigned int i=0; i<parms.size(); i++) { - parmRegex.push_back (Regex::fromPattern(parms[i])); - } - vector<Regex> excludeRegex; - for (unsigned int i=0; i<excludePatterns.size(); i++) { - excludeRegex.push_back (Regex::fromPattern(excludePatterns[i])); - } - // Find all parms matching the parms. - // Exclude them if matching an excludePattern - int nrsolv = 0; - for (MeqParmGroup::iterator iter = itsParmGroup.begin(); - iter != itsParmGroup.end(); - ++iter) - { - String parmName (iter->second.getName()); - // Loop through all regex-es until a match is found. - for (vector<Regex>::iterator incIter = parmRegex.begin(); - incIter != parmRegex.end(); - incIter++) { - if (parmName.matches(*incIter)) { - bool parmExc = false; - // Test if not excluded. - for (vector<Regex>::const_iterator excIter = excludeRegex.begin(); - excIter != excludeRegex.end(); - excIter++) { - if (parmName.matches(*excIter)) { - parmExc = true; - break; - } - } - if (!parmExc) { - LOG_TRACE_OBJ_STR( "setSolvable: " << iter->second.getName()); - iter->second.setSolvable (true); - nrsolv++; - } - break; - } - } - } - if (nrsolv == 0) { - return false; - } - initSolvableParms (solveProp.getDomains()); - return itsNrPert>0; -} - -void Prediffer::readDescriptiveData (const string& fileName) -{ - ASSERTSTR(false, "DEPRECATED -- will be removed in next release. Use Prediffer::readMeasurementSetMetaData instead."); - - // Get meta data from description file. - string name(fileName+"/vis.des"); - ifstream istr(name.c_str()); - ASSERTSTR (istr, "File " << fileName << "/vis.des could not be opened"); - BlobIBufStream bbs(istr); - BlobIStream bis(bbs); - bis >> itsMSDesc; -} - -bool Prediffer::selectStations (const vector<int>& antnrs, bool useAutoCorr) -{ - int nrant = itsStations.size(); - // Get all stations actually used. - // Default is all stations. - if (antnrs.empty()) { - itsSelStations = itsStations; - } else { - // Set given stations. - itsSelStations = vector<MeqStation*>(nrant, (MeqStation*)0); - for (uint i=0; i<antnrs.size(); i++) { - int ant = antnrs[i]; - if (ant >= 0 && ant < nrant) { - itsSelStations[ant] = itsStations[ant]; - } - } - } - // Fill a a matrix telling for each antenna pair where contained in the MS. - // First initialize to not contained. - itsBLSel.resize (nrant, nrant); - itsBLSel = false; - // Set if selected for each baseline in the MS. - int nr = 0; - for (uint i=0; i<itsMSDesc.ant1.size(); ++i) { - int a1 = itsMSDesc.ant1[i]; - int a2 = itsMSDesc.ant2[i]; - if (itsSelStations[a1] && itsSelStations[a2]) { - if (useAutoCorr || a1 != a2) { - itsBLSel(a1,a2) = true; - nr++; - } - } - } - return nr>0; -} - -bool Prediffer::selectStep (const vector<int>& ant1, - const vector<int>& ant2, - bool useAutoCorrelations, - const vector<bool>& corr) -{ - int nrant = itsBLSel.nrow(); - ASSERT (ant1.size() == ant2.size()); - Matrix<bool> blSel; - if (ant1.size() == 0) { - // No baselines specified, select all baselines in strategy. - blSel = itsBLSel; - } else { - blSel.resize (nrant, nrant); - blSel = false; - for (uint i=0; i<ant1.size(); i++) { - int a1 = ant1[i]; - int a2 = ant2[i]; - if (a1 < nrant && a2 < nrant) { - blSel(a1, a2) = itsBLSel(a1, a2); - } - } - } - // Unset auto-correlations if needed. - if (!useAutoCorrelations) { - for (int i=0; i<nrant; i++) { - blSel(i,i) = false; - } - } - // Fill the correlations to use. Use all if vector is empty. - for (int i=0; i<itsNCorr; ++i) { - itsCorr[i] = corr.empty(); - } - if (corr.size() > 0) { - // Some values given; first one is always XX (or LL, etc.) - itsCorr[0] = corr[0]; - if (corr.size() > 1 && itsNCorr > 1) { - if (corr.size() == 2) { - // Two values given; last one is always YY (or RR, etc.) - itsCorr[itsNCorr-1] = corr[1]; - } else { - // More than 2 must be 4 values. - ASSERTSTR (corr.size()==4, - "Correlation selection vector must have 1, 2 or 4 flags"); - if (itsNCorr == 2) { - itsCorr[1] = corr[3]; - } else { - itsCorr[1] = corr[1]; - itsCorr[2] = corr[2]; - itsCorr[3] = corr[3]; - } - } - } - } - - cout << blSel << endl; - - return fillBaseCorr (blSel); -} - -bool Prediffer::fillBaseCorr (const Matrix<bool>& blSel) -{ - // Count the nr of baselines actually used for this step. - // Store the seqnr of all selected baselines. - itsBLInx.clear(); - for (uint i=0; i<itsMSDesc.ant1.size(); ++i) { - int a1 = itsMSDesc.ant1[i]; - int a2 = itsMSDesc.ant2[i]; - if (blSel(a1,a2)) { - itsBLInx.push_back (i); - } - } - // Count the nr of selecteed correlations. - int nSelCorr = 0; - for (int i=0; i<itsNCorr; ++i) { - if (itsCorr[i]) { - nSelCorr++; - } - } - return (itsBLInx.size() > 0 && nSelCorr > 0); -} - -// DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED -// DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED - - - } // namespace BBS } // namespace LOFAR diff --git a/CEP/BB/BBSKernel/src/VisData.cc b/CEP/BB/BBSKernel/src/VisData.cc new file mode 100644 index 0000000000000000000000000000000000000000..e510e09f52fd4f499ba35ee668c8673a409a6956 --- /dev/null +++ b/CEP/BB/BBSKernel/src/VisData.cc @@ -0,0 +1,92 @@ +//# VisData.cc: +//# +//# 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/VisData.h> +#include <BBSKernel/Exceptions.h> +#include <Common/LofarLogger.h> + +namespace LOFAR +{ +namespace BBS +{ + +VisData::VisData(uint32 nTimeslots, + uint32 nBaselines, + uint32 nChannels, + uint32 nPolarizations) + : + uvw(boost::extents[nBaselines][nTimeslots][3]), + tslot_flag(boost::extents[nBaselines][nTimeslots]), + vis_flag(boost::extents[nBaselines][nTimeslots][nChannels][nPolarizations]), + vis_data(boost::extents[nBaselines][nTimeslots][nChannels][nPolarizations]) +{ + LOG_DEBUG_STR("Chunk size: " + << (nBaselines * nTimeslots * 3 * sizeof(double) + + nBaselines * nTimeslots * sizeof(tslot_flag_t) + + nBaselines * nTimeslots * nChannels * nPolarizations + * sizeof(flag_t) + + nBaselines * nTimeslots * nChannels * nPolarizations + * sizeof(sample_t)) + / (1024.0 * 1024.0) + << " Mb."); +} + + +bool VisData::hasBaseline(baseline_t baseline) const +{ + map<baseline_t, size_t>::const_iterator it = baselines.find(baseline); + return it != baselines.end(); +} + + +size_t VisData::getBaselineIndex(baseline_t baseline) const +{ + map<baseline_t, size_t>::const_iterator it = baselines.find(baseline); + if(it != baselines.end()) + return it->second; + else + THROW(BBSKernelException, "Request for index of unknown baseline " + << baseline.first << " - " << baseline.second); +} + + +bool VisData::hasPolarization(const string &polarization) const +{ + map<string, size_t>::const_iterator it = polarizations.find(polarization); + return it != polarizations.end(); +} + + +size_t VisData::getPolarizationIndex(const string &polarization) const +{ + map<string, size_t>::const_iterator it = polarizations.find(polarization); + + if(it != polarizations.end()) + return it->second; + else + THROW(BBSKernelException, "Request for index of unknown polarization " + << polarization); +} + +} //# namespace BBS +} //# namespace LOFAR diff --git a/CEP/BB/BBSKernel/src/VisSelection.cc b/CEP/BB/BBSKernel/src/VisSelection.cc new file mode 100644 index 0000000000000000000000000000000000000000..d75de8505cb0524b36c0f88e409ca0272aed79f2 --- /dev/null +++ b/CEP/BB/BBSKernel/src/VisSelection.cc @@ -0,0 +1,186 @@ +//# VisSelection.cc: +//# +//# 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/VisSelection.h> + +#include <casa/Quanta/Quantum.h> +#include <casa/Quanta/MVTime.h> + + +namespace LOFAR +{ +namespace BBS +{ +using casa::Quantum; +using casa::MVTime; +using casa::Double; + + +VisSelection::VisSelection() +{ + itsFieldFlags.resize(N_FieldEnum, false); +} + + +void VisSelection::setChannelRange(size_t start, size_t end) +{ + if(!isSet(CHANNEL_START) + && (!isSet(CHANNEL_END) || start <= itsChannelRange.second)) + { + itsFieldFlags[CHANNEL_START] = true; + itsChannelRange.first = start; + } + else if(start < itsChannelRange.first) + itsChannelRange.first = start; + + if(!isSet(CHANNEL_END) + && (!isSet(CHANNEL_START) || end >= itsChannelRange.first)) + { + itsFieldFlags[CHANNEL_END] = true; + itsChannelRange.second = end; + } + else if(end > itsChannelRange.second) + itsChannelRange.second = end; +} + + +bool VisSelection::convertTime(const string &in, double &out) const +{ + //# TODO: Convert from default epoch to MS epoch (as it may differ from + //# the default!) + casa::Quantity time; + + if(in.empty() || !casa::MVTime::read(time, in)) + return false; + + out = time.getValue("s"); + return true; +} + + +void VisSelection::setTimeRange(string start, string end) +{ + double time; + + if(convertTime(start, time)) + { + if(!isSet(TIME_START) + && (!isSet(TIME_END) || time <= itsTimeRange.second)) + { + itsFieldFlags[TIME_START] = true; + itsTimeRange.first = time; + } + else if(time < itsTimeRange.first) + itsTimeRange.first = time; + } + + if(convertTime(end, time)) + { + if(!isSet(TIME_END) + && (!isSet(TIME_START) || time >= itsTimeRange.first)) + { + itsFieldFlags[TIME_END] = true; + itsTimeRange.second = time; + } + else if(time > itsTimeRange.second) + itsTimeRange.second = time; + } +} + + +void VisSelection::setTimeRange(double start, double end) +{ + if(!isSet(TIME_START) + && (!isSet(TIME_END) || start <= itsTimeRange.second)) + { + itsFieldFlags[TIME_START] = true; + itsTimeRange.first = start; + } + else if(start < itsTimeRange.first) + itsTimeRange.first = start; + + if(!isSet(TIME_END) + && (!isSet(TIME_START) || end >= itsTimeRange.first)) + { + itsFieldFlags[TIME_END] = true; + itsTimeRange.second = end; + } + else if(end > itsTimeRange.second) + itsTimeRange.second = end; +} + + +void VisSelection::setCorrelations(vector<string> correlations) +{ + set<string> selection(correlations.begin(), correlations.end()); + + if(!isSet(CORRELATIONS)) + { + itsCorrelations = selection; + itsFieldFlags[CORRELATIONS] = true; + } + else + { + set<string>::const_iterator it = itsCorrelations.begin(); + while(it != itsCorrelations.end()) + { + if(selection.count(*it)) + ++it; + else + itsCorrelations.erase(it++); + } + } +} + + +void VisSelection::setStations(vector<string> stations) +{ + set<string> selection(stations.begin(), stations.end()); + + if(!isSet(STATIONS)) + { + itsStations = selection; + itsFieldFlags[STATIONS] = true; + } + else + { + set<string>::const_iterator it = itsStations.begin(); + while(it != itsStations.end()) + { + if(selection.count(*it)) + ++it; + else + itsStations.erase(it++); + } + } +} + + +void VisSelection::setBaselineFilter(BaselineFilter filter) +{ + itsFieldFlags[BASELINE_FILTER] = true; + itsBaselineFilter = filter; +} + +} //# namespace BBS +} //# namespace LOFAR