LCOV - code coverage report
Current view: top level - synthesis/MeasurementComponents - SolveDataBuffer.cc (source / functions) Hit Total Coverage
Test: ctest_coverage.info Lines: 0 403 0.0 %
Date: 2023-11-02 14:27:30 Functions: 0 44 0.0 %

          Line data    Source code
       1             : //# SolveDataBuffer.cc: Implementation of SolveDataBuffer.h
       2             : //# Copyright (C) 2008
       3             : //# Associated Universities, Inc. Washington DC, USA.
       4             : //#
       5             : //# This library is free software; you can redistribute it and/or modify it
       6             : //# under the terms of the GNU Library General Public License as published by
       7             : //# the Free Software Foundation; either version 2 of the License, or (at your
       8             : //# option) any later version.
       9             : //#
      10             : //# This library is distributed in the hope that it will be useful, but WITHOUT
      11             : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12             : //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
      13             : //# License for more details.
      14             : //#
      15             : //# You should have received a copy of the GNU Library General Public License
      16             : //# along with this library; if not, write to the Free Software Foundation,
      17             : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
      18             : //#
      19             : //# Correspondence concerning AIPS++ should be addressed as follows:
      20             : //#        Internet email: aips2-request@nrao.edu.
      21             : //#        Postal address: AIPS++ Project Office
      22             : //#                        National Radio Astronomy Observatory
      23             : //#                        520 Edgemont Road
      24             : //#                        Charlottesville, VA 22903-2475 USA
      25             : //#
      26             : //# $Id$
      27             : 
      28             : #include <synthesis/MeasurementComponents/SolveDataBuffer.h>
      29             : #include <msvis/MSVis/VisBuffer2.h>
      30             : #include <msvis/MSVis/VisBufferComponents2.h>
      31             : #include <casacore/casa/Arrays/ArrayMath.h>
      32             : #include <casacore/casa/Arrays/ArrayPartMath.h>
      33             : #include <casacore/casa/Arrays/MaskArrMath.h>
      34             : #include <casacore/casa/IO/ArrayIO.h>
      35             : #include <casacore/casa/iomanip.h>
      36             : #include <casacore/casa/Exceptions/Error.h>
      37             : #include <casacore/casa/Containers/Block.h>
      38             : #include <casacore/casa/Utilities/Assert.h>
      39             : #include <casacore/casa/Quanta/MVTime.h>
      40             : #include <casacore/casa/BasicSL/Constants.h>
      41             : #include <casacore/casa/BasicMath/Math.h>
      42             : 
      43             : using namespace casacore;
      44             : using namespace casa::vi;
      45             : 
      46             : 
      47             : using namespace casacore;
      48             : namespace casa { //# NAMESPACE CASA - BEGIN
      49             : 
      50           0 : SolveDataBuffer::SolveDataBuffer() : 
      51             :   vb_(0),
      52             :   nAnt_(0),
      53             :   freqs_(0),
      54             :   centroidFreq_(0.0),
      55             :   corrs_(0),
      56             :   feedPa_(0),
      57             :   focusChan_p(-1),
      58             :   infocusFlagCube_p(),
      59             :   infocusWtSpec_p(),
      60             :   infocusVisCube_p(),
      61             :   infocusModelVisCube_p(),
      62             :   workingFlagCube_p(),
      63             :   workingWtSpec_p(),
      64             :   residuals_p(),
      65             :   residFlagCube_p(),
      66           0 :   diffResiduals_p()
      67           0 : {}
      68             : 
      69           0 : SolveDataBuffer::SolveDataBuffer(const vi::VisBuffer2& vb) :
      70             :   vb_(0),
      71             :   nAnt_(0),
      72             :   freqs_(0),
      73             :   centroidFreq_(0.0),
      74             :   corrs_(0),
      75             :   feedPa_(0),
      76             :   focusChan_p(-1),
      77             :   infocusFlagCube_p(),
      78             :   infocusWtSpec_p(),
      79             :   infocusVisCube_p(),
      80             :   infocusModelVisCube_p(),
      81             :   workingFlagCube_p(),
      82             :   workingWtSpec_p(),
      83             :   residuals_p(),
      84             :   residFlagCube_p(),
      85           0 :   diffResiduals_p()
      86             : 
      87             : {
      88             :   
      89           0 :   vb_= vi::VisBuffer2::factory(VbRekeyable);
      90             : 
      91           0 :   initFromVB(vb);
      92           0 : }
      93             : 
      94           0 : SolveDataBuffer::SolveDataBuffer(const SolveDataBuffer& sdb) :
      95             :   vb_(),
      96             :   nAnt_(0),
      97             :   freqs_(0),
      98             :   centroidFreq_(0.0),
      99             :   corrs_(0),
     100             :   feedPa_(0),
     101             :   focusChan_p(-1),
     102             :   infocusFlagCube_p(),
     103             :   infocusWtSpec_p(),
     104             :   infocusVisCube_p(),
     105             :   infocusModelVisCube_p(),
     106             :   workingFlagCube_p(),
     107             :   workingWtSpec_p(),
     108             :   residuals_p(),
     109             :   residFlagCube_p(),
     110           0 :   diffResiduals_p()
     111             : {
     112             :   // Copy from the other's VB2
     113             :   // NB: that VB2 won't be attached!!
     114           0 :   initFromVB(*(sdb.vb_));
     115             : 
     116             :   // copy over freqs_, corrs_,feedPa, nAnt_
     117             :   //  (things that normally require being attached)
     118           0 :   freqs_.assign(sdb.freqs_);
     119           0 :   centroidFreq_=sdb.centroidFreq_;
     120           0 :   corrs_.assign(sdb.corrs_);
     121           0 :   feedPa_.assign(sdb.feedPa_);
     122           0 :   nAnt_=sdb.nAnt_;
     123           0 : }
     124             : 
     125           0 : SolveDataBuffer::~SolveDataBuffer()
     126             : {
     127           0 :   if (vb_) delete vb_;
     128           0 :   vb_=0;
     129             :  
     130           0 : }
     131             : 
     132             : //SolveDataBuffer& SolveDataBuffer::operator=(const VisBuffer& other)
     133             : 
     134             :   
     135           0 : Bool SolveDataBuffer::Ok() {
     136             :   // Ok if net unflagged weight is positive
     137           0 :   if (nfalse(flagCube())>0) {
     138           0 :     Float wtsum=sum(weightSpectrum()(!flagCube()));
     139           0 :     return (wtsum>0.0f);
     140             :   }
     141             :   else
     142           0 :     return false;
     143             : }
     144             : 
     145             : /*
     146             : // Divide corrected by model
     147             : void SolveDataBuffer::divideCorrByModel() {
     148             : 
     149             :   Int nCor(nCorrelations());
     150             :   Int nChan(nChannels());
     151             :   Int nRow(nRows());
     152             :   Float amp(1.0);
     153             :   Complex cor(1.0);
     154             :     
     155             :   Cube<Complex> vC; vC.reference(visCubeCorrected());
     156             :   Cube<Complex> vM; vM.reference(visCubeModel());
     157             :   Cube<Float> wS; wS.reference(weightSpectrum());
     158             : 
     159             :   for (Int irow=0;irow<nRow;++irow) {
     160             :     if (!flagRow()(irow)) {
     161             :       for (Int ich=0;ich<nChan;++ich) {
     162             :         for (Int icorr=0;icorr<nCor;icorr++) {
     163             :           if (!flagCube()(icorr,ich,irow)) {
     164             :             amp=abs(vM(icorr,ich,irow));
     165             :             if (amp>0.0f) {
     166             :               // Divide corr by model
     167             :               vC(icorr,ich,irow)/=vM(icorr,ich,irow);
     168             :               // Adjust weight by square of model amp
     169             :               wS(icorr,ich,irow)*=square(amp);
     170             :             }
     171             :           } // !*fl
     172             :           else {
     173             :             // zero data and weight
     174             :             vC(icorr,ich,irow)=Complex(0.0);
     175             :             wS(icorr,ich,irow)=0.0;
     176             :           }
     177             :           // model always unity after division
     178             :           vM(icorr,ich,irow)=Complex(1.0);
     179             :         } // icorr
     180             :       } // ich
     181             :     } // !*flR
     182             :   } // irow
     183             : }
     184             : */
     185             : 
     186           0 : void SolveDataBuffer::enforceAPonData(const String& apmode)
     187             : {
     188             : 
     189             :   // TBD:  apply to model, too?  (never matters, since we prob /modelVis already?
     190             : 
     191             :   // ONLY if something to do
     192           0 :   if (apmode=="A" || apmode=="P") {
     193           0 :     Int nCor(nCorrelations());
     194           0 :     Int nChan(nChannels());
     195           0 :     Int nRow(nRows());
     196           0 :     Float amp(1.0);
     197           0 :     Complex cor(1.0);
     198             :     
     199           0 :     Cube<Complex> vC; vC.reference(visCubeCorrected());
     200           0 :     Cube<Float> wS; wS.reference(weightSpectrum());
     201             : 
     202           0 :     for (Int irow=0;irow<nRow;++irow) {
     203           0 :       if (!flagRow()(irow)) {
     204           0 :         for (Int ich=0;ich<nChan;++ich) {
     205           0 :           for (Int icorr=0;icorr<nCor;icorr++) {
     206           0 :             if (!flagCube()(icorr,ich,irow)) {
     207             :               
     208           0 :               amp=abs(vC(icorr,ich,irow));
     209           0 :               if (amp>0.0f) {
     210             :                 
     211           0 :                 if (apmode=="P") {
     212             :                   // we will scale by amp to make data phase-only
     213           0 :                   cor=Complex(amp,0.0);
     214             :                   // Adjust weight by square of amp
     215           0 :                   wS(icorr,ich,irow)*=square(amp);
     216             :                 }
     217           0 :                 else if (apmode=="A")
     218             :                   // we will scale by "phase" to make data amp-only
     219             :                   //  no weight adjustment
     220           0 :                   cor=vC(icorr,ich,irow)/amp;
     221             :                 
     222             :                 // Apply the complex scaling
     223           0 :                 vC(icorr,ich,irow)/=cor;
     224             :               }
     225             :             } // !*fl
     226             :             else {
     227           0 :               vC(icorr,ich,irow)=Complex(0.0);
     228           0 :               wS(icorr,ich,irow)=0.0;
     229             :             }
     230             :           } // icorr
     231             :         } // ich
     232             :       } // !*flR
     233             :     } // irow
     234             : 
     235             :   } // phase- or amp-only
     236             : 
     237           0 : }
     238             : 
     239           0 : void SolveDataBuffer::enforceSolveWeights(const Bool phandonly)
     240             : {
     241             :   // If requested set cross-hand weights to zero (also---or only---flags?)
     242           0 :   if(phandonly && this->nCorrelations()>2)
     243           0 :       this->weightSpectrum()(Slice(1, 2, 1), Slice(), Slice()).set(0.0);
     244             : 
     245             :   // Set flagged weights to zero, ensuring they don't get used in accumulations
     246           0 :   this->weightSpectrum()(this->flagCube())=0.0f;
     247             : 
     248             :   // Set flagged data to zero (some solve types don't look at flags)
     249           0 :   Cube<Complex> vCC(this->visCubeCorrected());
     250           0 :   vCC(this->flagCube())=Complex(0.0f);
     251             : 
     252           0 : }
     253             : 
     254             : 
     255             : 
     256           0 : void SolveDataBuffer::setFocusChan(const Int focusChan) 
     257             : {
     258             : 
     259             :   // Nominally focus on the whole data array
     260           0 :   IPosition focusblc(3,0,0,0);
     261           0 :   IPosition focustrc(vb_->getShape());
     262           0 :   focustrc-=1;
     263             :   
     264             :   // if focusChan non-negative, select the single channel
     265           0 :   if (focusChan>-1) 
     266           0 :     focusblc(1)=focustrc(1)=focusChan;
     267             :   
     268           0 :   infocusFlagCube_p.reference(flagCube()(focusblc,focustrc));
     269           0 :   infocusWtSpec_p.reference(weightSpectrum()(focusblc,focustrc));
     270           0 :   infocusVisCube_p.reference(visCubeCorrected()(focusblc,focustrc));
     271           0 :   infocusModelVisCube_p.reference(visCubeModel()(focusblc,focustrc));
     272             : 
     273             :   // Remember current in-focus channel
     274           0 :   focusChan_p=focusChan;
     275             : 
     276           0 : }
     277             : 
     278           0 : void SolveDataBuffer::sizeResiduals(const Int& nPar,
     279             :                                     const Int& nDiff)
     280             : {
     281             : 
     282           0 :   IPosition ip1(vb_->getShape());
     283           0 :   if (focusChan_p>-1)
     284           0 :     ip1(1)=1;
     285           0 :   residuals_p.resize(ip1);
     286           0 :   residuals_p.set(0.0);
     287           0 :   residFlagCube_p.resize(ip1);
     288           0 :   residFlagCube_p.set(false);
     289             : 
     290           0 :   if (nPar>0 && nDiff>0) {
     291           0 :     IPosition ip2(5,ip1(0),nPar,ip1(1),ip1(2),nDiff);
     292           0 :     diffResiduals_p.resize(ip2);
     293           0 :     diffResiduals_p.set(0.0);
     294             :   }
     295             : 
     296           0 : }
     297             : 
     298           0 : void SolveDataBuffer::initResidWithModel() 
     299             : {
     300             : 
     301             :   // Copy (literally) the in-focus model to the residual workspace
     302             :   // TBD:  weights?
     303           0 :   residuals_p = infocusModelVisCube_p;
     304           0 :   residFlagCube_p = infocusFlagCube_p;
     305             :     
     306             :   // Ensure contiguity, because CalSolver will depend on this
     307           0 :   AlwaysAssert(residFlagCube_p.contiguousStorage(),AipsError);
     308           0 :   AlwaysAssert(residuals_p.contiguousStorage(),AipsError);
     309             : 
     310             : 
     311           0 : }
     312             : 
     313           0 : void SolveDataBuffer::finalizeResiduals() 
     314             : {
     315             : 
     316             :   // Subtract in-focus obs data from residuals workspace
     317           0 :   residuals_p -= infocusVisCube_p;
     318             : 
     319             :   // TBD: zero flagged samples here?
     320             : 
     321           0 : }
     322             : 
     323             : // Manage working weights
     324           0 : void SolveDataBuffer::updateWorkingFlags()
     325             : {
     326             : 
     327           0 :   workingFlagCube_p|=residFlagCube_p;
     328             : 
     329           0 : }
     330             : 
     331             : 
     332             : // Manage working weights
     333           0 : void SolveDataBuffer::updateWorkingWeights(Bool doL1, Float L1clamp)
     334             : {
     335             : 
     336           0 :   workingWtSpec_p.resize(0,0,0);  // nominally forces implicit use of infocusWtSpec
     337           0 :   if (doL1) {
     338             : 
     339             :     //cout << "****Using L1 weights!!! (" << L1clamp << ") ******" << endl;
     340             : 
     341           0 :     workingWtSpec_p.assign(infocusWtSpec_p);  // init from nominal weights
     342           0 :     const Cube<Bool>& wFC(this->const_workingFlagCube());   // adaptive access to 
     343             : 
     344           0 :     Cube<Float> Ramp(amplitude(this->residuals()));
     345             : 
     346           0 :     IPosition shRamp(Ramp.shape());
     347           0 :     Int nCorr=shRamp(0);
     348           0 :     Int nChan=shRamp(1);
     349           0 :     Int nRow=shRamp(2);
     350             : 
     351             :     // TBD: assert common shapes!
     352             : 
     353           0 :     for (Int irow=0;irow<nRow;++irow) {
     354           0 :       if (!flagRow()(irow)) {
     355           0 :         for (Int ich=0;ich<nChan;++ich) {
     356           0 :           for (Int icorr=0;icorr<nCorr;++icorr) {
     357           0 :             Float& nomWt=workingWtSpec_p(icorr,ich,irow);
     358           0 :             Float& Ra=Ramp(icorr,ich,irow);
     359           0 :             if (!wFC(icorr,ich,irow) &&  
     360           0 :                 nomWt>0.0 &&
     361           0 :                 Ra>0.0 ) {
     362           0 :               nomWt/=sqrt(Ra*Ra+L1clamp);
     363             :             }
     364             :             else {
     365           0 :               nomWt=0.0;
     366             :             }
     367             :           }
     368             :         }
     369             :       }
     370             :     }
     371             : 
     372             :   }
     373             :   //  else {
     374             :   //    cout << "****Using nominal weights!!!******" << endl;
     375             :     //infocusWorkingWtSpec_p.reference(infocusWtSpec_p);
     376             :   //}
     377             : 
     378           0 : }
     379             : 
     380           0 : void SolveDataBuffer::reportData()
     381             : {
     382             : 
     383           0 :   Slice corrs(0,2,3), sl;  // p-hands only 
     384             : 
     385           0 :   Vector<Int> a1(this->antenna1()), a2(this->antenna2());
     386           0 :   Cube<Complex> vCC(this->visCubeCorrected()(corrs,sl,sl));
     387           0 :   Cube<Complex> vCM(this->visCubeModel()(corrs,sl,sl));
     388           0 :   Cube<Float> wtS(this->weightSpectrum()(corrs,sl,sl));
     389           0 :   Cube<Bool> flg(this->flagCube()(corrs,sl,sl));
     390             : 
     391             :   /*
     392             :   cout << "******Making weights globally uniform!!!!!!!!!!!!!!!!" << endl;
     393             :     // this makes VI2 match VI1
     394             :   wtS.set(1.0f);
     395             :   //*/
     396             : 
     397             :   /*
     398             :   cout << "*******Zeroing zero-wt data (for K solutions)!!!!!!!!!!!!!" << endl;
     399             :     // this makes VI2 match VI1 solint='int' when some channels flagged
     400             :   vCC(wtS==0.0f)=Complex(0.0);
     401             :   //*/
     402             : 
     403             : 
     404             :   /*
     405             :   cout << "*******making weights uniform (for K solution testing)!!!!!!!!!!!!!" << endl;
     406             :   wtS.set(max(wtS));
     407             :   //*/
     408             : 
     409             :   /*
     410             :   cout << "*******zero off-wt data (for K solution testing)!!!!!!!!!!!!!" << endl;
     411             :   vCC(wtS!=max(wtS))=0.0f;
     412             :   wtS(wtS!=max(wtS))=0.0f;
     413             :   //*/
     414             : 
     415             :   /*
     416             :     // this makes VI2 match VI1 for  solint='inf' (and > 'int')
     417             :     cout << "*******renormalizing off-wt data (for K solution testing)!!!!!!!!!!!!!" << endl;
     418             :   vCC*=wtS;
     419             :   vCC/=max(wtS);
     420             :   //*/
     421             : 
     422             : 
     423           0 :   cout << "Time=" << MVTime(time()(0)/C::day).string(MVTime::YMD,7) << endl;
     424           0 :   cout.precision(8);
     425           0 :   for (Int irow=0;irow<nRows();++irow) {
     426           0 :     for (Int ich=0;ich<nChannels();++ich) {
     427           0 :       cout << std::setw(2) << a1(irow) << "-" << std::setw(2) << a2(irow) << " ";
     428           0 :       if (nChannels()>1) cout << "ich=" << ich << " ";
     429           0 :       cout << "fl=" << flg(Slice(),Slice(ich),Slice(irow)).nonDegenerate() << " ";
     430           0 :       cout << "wt=" << wtS(Slice(),Slice(ich),Slice(irow)).nonDegenerate() << " ";
     431           0 :       cout << "cM=" << vCM(Slice(),Slice(ich),Slice(irow)).nonDegenerate() << " ";
     432           0 :       cout << "cC=" << vCC(Slice(),Slice(ich),Slice(irow)).nonDegenerate() << " ";
     433           0 :       cout << endl;
     434             :     }
     435             :   }
     436           0 :   cout << "*****************************************************************************" << endl;
     437           0 : }
     438             : 
     439           0 : void SolveDataBuffer::initFromVB(const vi::VisBuffer2& vb) 
     440             : {
     441             : 
     442             :   // The required VB2 components
     443             :   vi::VisBufferComponents2 comps =
     444             :     vi::VisBufferComponents2::these({VisBufferComponent2::ObservationId,
     445             :                                     VisBufferComponent2::ArrayId,
     446             :                                     VisBufferComponent2::Scan,
     447             :                                     VisBufferComponent2::FieldId,
     448             :                                     VisBufferComponent2::DataDescriptionIds,
     449             :                                     VisBufferComponent2::SpectralWindows,
     450             :                                     VisBufferComponent2::Antenna1,
     451             :                                     VisBufferComponent2::Antenna2,
     452             :                                     VisBufferComponent2::Time,
     453             :                                     VisBufferComponent2::TimeCentroid,
     454             :                                     VisBufferComponent2::NCorrelations,
     455             :                                     VisBufferComponent2::NChannels,
     456             :                                     VisBufferComponent2::NRows,
     457             :                                     VisBufferComponent2::FlagRow,
     458             :                                     VisBufferComponent2::FlagCube,
     459             :           VisBufferComponent2::WeightSpectrum,
     460             :           VisBufferComponent2::VisibilityCubeCorrected,   
     461           0 :           VisBufferComponent2::VisibilityCubeModel});
     462             : 
     463             :   // Copy required components from the supplied VB2:
     464           0 :   vb_->copyComponents(vb,comps,True,True);   // will fetch things, if needed
     465             : 
     466             :   // Set weights for flagged data to zero
     467           0 :   Cube<Float> wtsp(vb_->weightSpectrum());
     468           0 :   wtsp(vb_->flagCube())=0.0;
     469             : 
     470             :   // Store the frequeny info
     471             :   //  TBD: also need bandwidth info....
     472           0 :   if (vb.isAttached()) {
     473           0 :     freqs_.assign(vb.getFrequencies(0));
     474           0 :     corrs_.assign(vb.correlationTypes());
     475           0 :     nAnt_=vb.nAntennas();
     476             :   }
     477             :   else {
     478             :     // Probably only needed in testing....  (gmoellen, 2016Aug04, 2019Jan07)
     479           0 :     cout << "The supplied VisBuffer2 is not attached to a ViImplementation2," << endl
     480           0 :          << " which is necessary to generate accurate frequency info." << endl
     481           0 :          << " This is probably just a test with a naked VisBuffer2." << endl
     482           0 :          << " Spoofing freq axis with 1 MHz channels at 100+10*ispw GHz." << endl
     483           0 :          << " Spoofing corr axis with [5,6,7,8] (circulars)" << endl;
     484             : 
     485           0 :     freqs_.resize(vb.nChannels());
     486           0 :     indgen(freqs_);
     487           0 :     freqs_*=1e6;
     488           0 :     freqs_+=100.0005e9; // _edge_ of first channel at 100 GHz.
     489           0 :     freqs_+=(10.0e9*vb.spectralWindows()(0));  // 10 GHz spacing of spws
     490             : 
     491           0 :     Int nC=vb.nCorrelations();
     492           0 :     corrs_.resize(nC);
     493           0 :     corrs_[0]=5;
     494           0 :     if (nC>1) corrs_[nC-1]=8;
     495           0 :     if (nC==4) {
     496           0 :       corrs_[1]=6;
     497           0 :       corrs_[2]=7;
     498             :     }
     499             : 
     500             :     // nAnt is last a2 index +1
     501             :     // Assumes simple sorting of these (which is how test data works)
     502           0 :     Int nR=vb.nRows();
     503           0 :     nAnt_=vb.antenna2()(nR-1)+1;
     504             :   }
     505             : 
     506             :   // Store the centroid freq (use mean, for now)
     507           0 :   centroidFreq_ = mean(freqs_);
     508             : 
     509             :   // Store the feedPa info
     510           0 :   if (vb.isAttached())
     511             :     // Assumes vb.time() is constant!
     512           0 :     feedPa_.assign(vb.feedPa(vb.time()(0)));
     513             : 
     514           0 : }
     515           0 : void SolveDataBuffer::cleanUp() 
     516             : {
     517             : 
     518             :   // Zero-size all workspaces
     519           0 :   infocusFlagCube_p.resize();
     520           0 :   infocusWtSpec_p.resize();
     521           0 :   infocusVisCube_p.resize();
     522           0 :   infocusModelVisCube_p.resize();
     523             : 
     524           0 :   residuals_p.resize();
     525           0 :   residFlagCube_p.resize();
     526           0 :   diffResiduals_p.resize();
     527             : 
     528           0 : }
     529             : 
     530           0 : String SolveDataBuffer::polBasis() const
     531             : {
     532             : 
     533             :   // UNKNOWN, nominally
     534           0 :   String polBas("UNKNOWN");
     535             : 
     536           0 :   Int nC(corrs_.nelements());
     537           0 :   if (nC<1)
     538             :     // Can't tell, so return UNKNOWN
     539           0 :     return polBas;
     540             : 
     541           0 :   if (corrs_(0)==5)
     542           0 :     polBas=String("CIRC");
     543           0 :   if (corrs_(0)==9)
     544           0 :     polBas=String("LIN");
     545             : 
     546           0 :   return polBas;
     547             : 
     548             : }
     549             : 
     550             : 
     551           0 : SDBList::SDBList() :
     552             :   nSDB_(0),
     553             :   SDB_(),
     554             :   freqs_(),
     555             :   aggCentroidFreq_(0),
     556           0 :   aggCentroidFreqOK_(false)
     557           0 : {}
     558             : 
     559           0 : SDBList::~SDBList() 
     560             : {
     561             :   // Delete the SDBs
     562           0 :   for (Int i=0;i<nSDB_;++i)
     563           0 :     delete SDB_[i];
     564           0 :   SDB_.resize(0);
     565           0 :   nSDB_=0;
     566           0 : }
     567             : 
     568           0 : void SDBList::add(const vi::VisBuffer2& vb)
     569             : {
     570             : 
     571             :   // Enlarge the list, copying existing SDB pointers
     572           0 :   SDB_.resize(nSDB_+1,true);
     573             : 
     574             :   // Generate the new SolveDataBuffer
     575           0 :   SDB_[nSDB_] = new SolveDataBuffer(vb);
     576             : 
     577             :   // increment the count
     578           0 :   nSDB_++;
     579             : 
     580             :   // Clear the freqs_ info (forces recalculation)
     581           0 :   freqs_.resize(0);
     582           0 :   aggCentroidFreq_=0.0;
     583           0 :   aggCentroidFreqOK_=false;
     584             : 
     585           0 : }
     586             : 
     587           0 : SolveDataBuffer& SDBList::operator()(Int i) 
     588             : {
     589           0 :   if (i<nSDB_)
     590           0 :     return *SDB_[i];
     591             :   else
     592           0 :     throw(AipsError("SDBList::operator(): requests non-existent SolveDataBuffer."));
     593             : 
     594             : }
     595             : 
     596           0 : Int SDBList::aggregateObsId() const {
     597           0 :   if (nSDB_>0)
     598             :     // Obs Id from first SDB
     599           0 :     return SDB_[0]->observationId()(0);
     600           0 :   throw(AipsError("SDBList::aggregateObsId(): No SDBs in this SDBList yet."));
     601             : }
     602             : 
     603           0 : Int SDBList::aggregateScan() const {
     604           0 :   if (nSDB_>0)
     605             :     // Scan number from first SDB
     606           0 :     return SDB_[0]->scan()(0);
     607           0 :   throw(AipsError("SDBList::aggregateScan(): No SDBs in this SDBList yet."));
     608             : }
     609             : 
     610           0 : Int SDBList::aggregateSpw() const {
     611           0 :   if (nSDB_>0)
     612             :     // from first SDB
     613           0 :     return SDB_[0]->spectralWindow()(0);
     614           0 :   throw(AipsError("SDBList::aggregateSpw(): No SDBs in this SDBList yet."));
     615             : }
     616             : 
     617           0 : Int SDBList::aggregateFld() const {
     618           0 :   if (nSDB_>0)
     619             :     // from first SDB
     620           0 :     return SDB_[0]->fieldId()(0);
     621           0 :   throw(AipsError("SDBList::aggregateFld(): No SDBs in this SDBList yet."));
     622             : }
     623             : 
     624           0 : Double SDBList::aggregateTime() const {
     625             : 
     626             :   // Simple average of the mean times in each SDB
     627             :   //  (TBD: Improve with attention to flags/weights?)
     628           0 :   if (nSDB_>0) {
     629           0 :     Double aTime(0.0);
     630           0 :     for (Int isdb=0;isdb<nSDB_;++isdb)
     631           0 :       aTime+=mean(SDB_[isdb]->time());
     632           0 :     aTime/=nSDB_;
     633           0 :     return aTime;
     634             :   }
     635             :   else
     636           0 :     throw(AipsError("SDBList::aggregateTime(): No SDBs in this SDBList yet."));
     637             : }
     638             : 
     639           0 : Double SDBList::aggregateTimeCentroid() const {
     640             : 
     641             :   // Weighted average of SDBs' timeCentroids
     642           0 :   if (nSDB_>0) {
     643           0 :     Double aTime(0.0);
     644           0 :     Double aWt(0.0);
     645           0 :     Vector<Double> wtvD;
     646           0 :     for (Int isdb=0;isdb<nSDB_;++isdb) {
     647           0 :       SolveDataBuffer& sdb(*SDB_[isdb]);
     648           0 :       Vector<Float> wtv(partialSums(sdb.weightSpectrum(),IPosition(2,0,1)));
     649           0 :       wtvD.resize(wtv.nelements());
     650           0 :       convertArray(wtvD,wtv);
     651           0 :       aTime+=sum(wtvD*sdb.timeCentroid());
     652           0 :       aWt+=sum(wtvD);
     653             :     }
     654           0 :     if (aWt>0.0)
     655           0 :       aTime/=aWt;
     656             :     else
     657             :       // Use aggregateTime if no unflagged data
     658           0 :       aTime=aggregateTime();
     659             : 
     660           0 :     return aTime;
     661             :   }
     662             :   else
     663           0 :     throw(AipsError("SDBList::aggregateFld(): No SDBs in this SDBList yet."));
     664             : }
     665             : 
     666             : 
     667             : // How many data chans?
     668             : //   Currently, this insists on uniformity over all SDBs
     669             : //   In future, we may _sum_ the SDBs nChans, and
     670             : //    enable forming aggregate spectra (e.g., for common normalization)
     671             : //    This will require focusChan loop over SDBs...
     672           0 : Int SDBList::nChannels() const {
     673             : 
     674           0 :   Int nChan=SDB_[0]->nChannels();  // from first
     675             : 
     676             :   // Trap non-uniformity, for now
     677           0 :   for (Int isdb=1;isdb<nSDB_;++isdb)
     678           0 :     AlwaysAssert((SDB_[isdb]->nChannels()==nChan),AipsError);
     679             : 
     680             :   // Reach here, then ok
     681           0 :   return nChan;
     682             : 
     683             : }
     684             : 
     685           0 : const Vector<Double>& SDBList::freqs() const {
     686             : 
     687           0 :   if (nSDB_==0)
     688           0 :     throw(AipsError("SDBList::freqs(): No SDBs in this SDBList yet."));
     689             :   
     690             : 
     691           0 :   if (nSDB_==1) {
     692             :     // Only one SDB, just return that one's freqs
     693           0 :     const Vector<Double>& f(SDB_[0]->freqs());  // from first SDB
     694           0 :     return f;
     695             :   }
     696             : 
     697             :   // Reach here, more than one SDB, need to gather info
     698           0 :   if (freqs_.nelements()==0) {
     699             :     // Haven't accumumlated yet
     700             :     
     701             :     // How many channels in aggregate?
     702             :     //  (This will insist on uniformity over SDBs)
     703           0 :     Int nchan(this->nChannels());   
     704             :     
     705             :     // Will accumulate mean freqs here
     706           0 :     freqs_.resize(nchan);
     707           0 :     freqs_.set(0.0);
     708             :     
     709             :     // Average over SDBs, counting each spw exactly _once_
     710             :     // Map to keep track of unique spws
     711           0 :     std::set<Int> spws;
     712           0 :     Int nSpw(0); 
     713           0 :     for (Int isdb=0;isdb<nSDB_;++isdb) {
     714           0 :       Int ispw=SDB_[isdb]->spectralWindow()(0);
     715           0 :       if (spws.count(ispw)<1) {
     716           0 :         freqs_+=SDB_[isdb]->freqs();
     717           0 :         spws.insert(ispw);  // Record that we got this spw
     718           0 :         ++nSpw;
     719             :       }
     720             :     }
     721             :     // Divide by nSpw
     722           0 :     freqs_/=Double(nSpw);
     723             :     
     724             :   }
     725             :   // else:  freqs_ already filled previously...
     726             : 
     727           0 :   return freqs_;
     728             :   
     729             : }
     730             : 
     731             : 
     732             : // ~Centroid frequency over all SDBs
     733           0 : casacore::Double SDBList::centroidFreq() const {
     734             : 
     735             :   // Calculate a simple mean frequency, for now
     736           0 :   Double fsum(0.0f);
     737           0 :   Int nf(0);
     738           0 :   for (Int isdb=0;isdb<nSDB_;++isdb) {
     739           0 :     const Vector<Double> f(SDB_[isdb]->freqs());
     740           0 :     for (uInt ich=0;ich<f.nelements();++ich) {
     741           0 :       fsum+=f(ich);
     742           0 :       ++nf;
     743             :     }
     744             :   }
     745           0 :   return fsum/Double(nf);
     746             : }
     747             : 
     748             : // ~Centroid frequency over all SDBs
     749           0 : casacore::Double SDBList::aggregateCentroidFreq() const {
     750             : 
     751             :   // Trap no data case
     752           0 :   if (nSDB_==0)
     753           0 :     throw(AipsError("SDBList::aggregateCentroidFreq(): No SDBs in this SDBList yet."));
     754             : 
     755             :   // Need to calculate?
     756           0 :   if (!aggCentroidFreqOK_) {
     757             :   
     758           0 :     if (nSDB_==1) {
     759             :       // from first and only SDB
     760           0 :       aggCentroidFreq_=SDB_[0]->centroidFreq();  
     761             :     }
     762             :     else {
     763             :       // More than one SDB, need to gather simple mean
     764             :       // TBD:  weight this by per-SDB bandwidth
     765           0 :       aggCentroidFreq_=0.0;
     766           0 :       for (Int isdb=0;isdb<nSDB_;++isdb)
     767           0 :         aggCentroidFreq_+=SDB_[isdb]->centroidFreq();
     768           0 :       aggCentroidFreq_/=Double(nSDB_);
     769             :     }
     770             :     // We've calculated it
     771           0 :     aggCentroidFreqOK_=true;
     772             :   }
     773             :  
     774             :   // Reach here, one way or another we have a good value, so return it
     775           0 :   return aggCentroidFreq_;
     776             : 
     777             : }
     778             : 
     779           0 : String SDBList::polBasis() const
     780             : {
     781           0 :   String polBas(SDB_[0]->polBasis());
     782             : 
     783             :   // Trap non-uniformity, for now
     784           0 :   for (Int isdb=1;isdb<nSDB_;++isdb)
     785           0 :     AlwaysAssert((SDB_[isdb]->polBasis()==polBas),AipsError);
     786             :  
     787           0 :   return polBas;
     788             : }
     789             : 
     790             : 
     791             : // How many antennas?
     792             : //   Currently, this insists on uniformity over all SDBs
     793           0 : Int SDBList::nAntennas() const {
     794             : 
     795           0 :   Int nAnt=SDB_[0]->nAntennas();
     796             : 
     797             :   // Trap non-uniformity, for now
     798           0 :   for (Int isdb=1;isdb<nSDB_;++isdb)
     799           0 :     AlwaysAssert((SDB_[isdb]->nAntennas()==nAnt),AipsError);
     800             : 
     801             :   // Reach here, then ok
     802           0 :   return nAnt;
     803             : 
     804             : }
     805             : 
     806             : // How many correlations?
     807             : //   Currently, this insists on uniformity over all SDBs
     808           0 : Int SDBList::nCorrelations() const {
     809             : 
     810           0 :   Int nCorr=SDB_[0]->nCorrelations();
     811             : 
     812             :   // Trap non-uniformity, for now
     813           0 :   for (Int isdb=1;isdb<nSDB_;++isdb)
     814           0 :     AlwaysAssert((SDB_[isdb]->nCorrelations()==nCorr),AipsError);
     815             : 
     816             :   // Reach here, then ok
     817           0 :   return nCorr;
     818             : 
     819             : }
     820             : 
     821             : 
     822             : 
     823             : 
     824             : 
     825           0 : Bool SDBList::Ok() {
     826             : 
     827           0 :   for (Int i=0;i<nSDB_;++i)
     828           0 :     if (SDB_[i]->Ok()) return True;
     829             : 
     830             :   // If we get here, either no SDBs, or none have non-zero weight.
     831           0 :   return False;
     832             : 
     833             : }
     834             : 
     835             : /*
     836             : void SDBList::divideCorrByModel()
     837             : {
     838             :   for (Int i=0;i<nSDB_;++i)
     839             :     SDB_[i]->divideCorrByModel();
     840             : }
     841             : */
     842             : 
     843           0 : void SDBList::enforceAPonData(const String& apmode)
     844             : {
     845           0 :   for (Int i=0;i<nSDB_;++i)
     846           0 :     SDB_[i]->enforceAPonData(apmode);
     847           0 : }
     848           0 : void SDBList::enforceSolveWeights(const Bool pHandOnly) 
     849             : {
     850           0 :   for (Int i=0;i<nSDB_;++i)
     851           0 :     SDB_[i]->enforceSolveWeights(pHandOnly);
     852           0 : }
     853             : 
     854           0 : void SDBList::sizeResiduals(const Int& nPar, const Int& nDiff)
     855             : {
     856           0 :   for (Int i=0;i<nSDB_;++i)
     857           0 :     SDB_[i]->sizeResiduals(nPar,nDiff);
     858           0 : }
     859           0 : void SDBList::initResidWithModel()
     860             : {
     861           0 :   for (Int i=0;i<nSDB_;++i)
     862           0 :     SDB_[i]->initResidWithModel();
     863           0 : }
     864           0 : void SDBList::finalizeResiduals()
     865             : {
     866           0 :   for (Int i=0;i<nSDB_;++i)
     867           0 :     SDB_[i]->finalizeResiduals();
     868           0 : }
     869             : 
     870             : // Manage working flags
     871           0 : void SDBList::updateWorkingFlags()
     872             : {
     873           0 :   for (Int i=0;i<nSDB_;++i)
     874           0 :     SDB_[i]->updateWorkingFlags();
     875           0 : }
     876             : 
     877             : // Manage working weights
     878           0 : void SDBList::updateWorkingWeights(casacore::Bool doL1,casacore::Float clamp)
     879             : {
     880           0 :   for (Int i=0;i<nSDB_;++i)
     881           0 :     SDB_[i]->updateWorkingWeights(doL1,clamp);
     882           0 : }
     883             : 
     884             : 
     885           0 : void SDBList::reportData()
     886             : {
     887           0 :   cout << "nSDB=" << nSDB_ << endl;
     888           0 :   for (Int i=0;i<nSDB_;++i) {
     889           0 :     cout << "isdb=" << i << endl;
     890           0 :     SDB_[i]->reportData();
     891             :   }
     892           0 : }
     893             : 
     894             : 
     895           0 : Int SDBList::extendCrossHandBaselineFlags(String& message) 
     896             : {
     897             : 
     898             : 
     899             :   // This enforces uniform nAnt in all SDBs
     900           0 :   Int nAnt(this->nAntennas());
     901           0 :   Int nBln=nAnt*(nAnt-1)/2;
     902             : 
     903             :   // channelized flags per baseline, cross-corr pair
     904           0 :   Cube<Bool> aggFlag(nChannels(),nAnt,nAnt,true);
     905             : 
     906             : 
     907             :   // Initialize aggregate flags 
     908             :   //  If an antenna pair is not avail here, it won't be used (default flagged)
     909             :   //  Subsequent SDBs might flag more baselines
     910             : 
     911           0 :   Int isdb0(0);
     912             :   {
     913             : 
     914             :     // Step forward to first SDB that has some unflagged data
     915             :     //  TBD: ...for now; in future, may wish to use least-flagged one, if we can also apply a 
     916             :     //       non-zero threshold in accumulation below...
     917           0 :     while (isdb0<nSDB_ && nfalse(SDB_[isdb0]->flagCube())<1)
     918           0 :       ++isdb0;
     919             : 
     920             :     // Trap all bad data case
     921           0 :     if (isdb0==nSDB_)
     922           0 :       throw(AipsError("Accumulated data entirely flagged."));
     923             :     
     924           0 :     Cube<Bool>& flc(SDB_[isdb0]->flagCube());
     925             : 
     926           0 :     const Vector<Int>& a1(SDB_[isdb0]->antenna1());
     927           0 :     const Vector<Int>& a2(SDB_[isdb0]->antenna2());
     928             :       
     929           0 :     Int nRows(SDB_[isdb0]->nRows());
     930           0 :     Int nChan(SDB_[isdb0]->nChannels());
     931             : 
     932           0 :     for (Int irow=0;irow<nRows;++irow) {
     933           0 :       for (Int ichan=0;ichan<nChan;++ichan) {
     934           0 :         aggFlag(ichan,a1(irow),a2(irow))=(flc(1,ichan,irow)||flc(2,ichan,irow));  // Either cross-hand flagged
     935             :       }      
     936             :     }
     937             :   }
     938             : 
     939             : 
     940             :   // Accumulate from other SDBs
     941           0 :   Int nBadSDB(0);
     942           0 :   for (Int isdb=0;isdb<nSDB_;++isdb) {
     943             : 
     944             :     // Skip the one we initialized with
     945           0 :     if (isdb==isdb0)
     946           0 :       continue;
     947             : 
     948           0 :     Cube<Bool>& flc(SDB_[isdb]->flagCube());
     949           0 :     const Vector<Int>& a1(SDB_[isdb]->antenna1());
     950           0 :     const Vector<Int>& a2(SDB_[isdb]->antenna2());
     951             : 
     952           0 :     Int ngood=nfalse(flc);
     953           0 :     if (ngood==0) {
     954           0 :       nBadSDB+=1;
     955           0 :       continue;
     956             :     }
     957             : 
     958           0 :     Int nRows(SDB_[isdb]->nRows());
     959           0 :     Int nChan(SDB_[isdb]->nChannels());
     960             : 
     961           0 :     for (Int irow=0;irow<nRows;++irow) {
     962           0 :       for (Int ichan=0;ichan<nChan;++ichan) {
     963           0 :         aggFlag(ichan,a1(irow),a2(irow))|=(flc(1,ichan,irow)||flc(2,ichan,irow));  // Either cross-hand flagged
     964             :       }      
     965             :     }
     966             :   }
     967             : 
     968             :   //  cout << "aggFlag: " << ntrue(aggFlag) << "/" << nfalse(aggFlag) << " sh=" << aggFlag.shape() << endl;
     969             : 
     970             :   // Count good baselines, by channel
     971           0 :   Vector<size_t> goodBL(partialNFalse(aggFlag,IPosition(2,1,2)));
     972             : 
     973             :   // Median number of good baselines, over channel
     974           0 :   size_t medGoodBL=median(goodBL);
     975             : 
     976             :   // Count good channels (those with at least median number of good baselines)
     977           0 :   Int goodChan=ntrue(goodBL>=medGoodBL);
     978             : 
     979             :   // Apply aggregate flags to each SDB
     980             :   //cout << "Flag sum = ";
     981           0 :   Int nGoodSDB(0);
     982           0 :   for (Int isdb=0;isdb<nSDB_;++isdb) {
     983           0 :     Cube<Bool>& flc(SDB_[isdb]->flagCube());
     984           0 :     const Vector<Int>& a1(SDB_[isdb]->antenna1());
     985           0 :     const Vector<Int>& a2(SDB_[isdb]->antenna2());
     986             : 
     987           0 :     Int nRows(SDB_[isdb]->nRows());
     988           0 :     Int nChan(SDB_[isdb]->nChannels());
     989             :       
     990           0 :     for (Int irow=0;irow<nRows;++irow) {
     991           0 :       for (Int ichan=0;ichan<nChan;++ichan) {
     992           0 :         if (aggFlag(ichan,a1(irow),a2(irow))) {
     993           0 :           flc(Slice(1,2,1),Slice(ichan),Slice(irow))=true;
     994             :         }
     995             :       }      
     996             :     }
     997           0 :     if (nfalse(flc)>0) ++nGoodSDB;
     998             : 
     999             :     //cout << ntrue(flc) << " ";
    1000             :   }
    1001             :   //cout << endl;
    1002             : 
    1003             :   // Assemble message
    1004           0 :   ostringstream ostr;
    1005           0 :   ostr << "There is usable (unflagged) data in " << nGoodSDB << " (of " << nSDB_ << " total) data segments, with " 
    1006           0 :        << goodChan << " good (of " << nChannels() << " total) channels (" << floor(10000.0*Double(goodChan)/Double(nChannels()))/100.0 << "%) having at least " 
    1007           0 :        << medGoodBL << " good (of " << nBln << " total) baselines (" << floor(10000.0*Double(medGoodBL)/Double(nBln))/100.0 <<"%).";
    1008             :   //  cout << ostr << endl;
    1009           0 :   message=ostr;
    1010             : 
    1011             : 
    1012             :   // Return number of surviving SDBs...
    1013           0 :   return nGoodSDB;
    1014             : 
    1015             : }
    1016             : 
    1017             : } //# NAMESPACE CASA - END
    1018             : 

Generated by: LCOV version 1.16