LCOV - code coverage report
Current view: top level - synthesis/Utilities - PointingDirectionCalculator.cc (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 0 611 0.0 %
Date: 2024-10-12 00:35:29 Functions: 0 51 0.0 %

          Line data    Source code
       1             : //# PointingDirectionCalculator.cc: Implementation of PointingDirectionCalculator.h
       2             : //# All helper functions of imager moved here for readability
       3             : //# Copyright (C) 1997,1998,1999,2000,2001,2002,2003
       4             : //# Associated Universities, Inc. Washington DC, USA.
       5             : //#
       6             : //# This library is free software; you can redistribute it and/or modify it
       7             : //# under the terms of the GNU Library General Public License as published by
       8             : //# the Free Software Foundation; either version 2 of the License, or (at your
       9             : //# option) any later version.
      10             : //#
      11             : //# This library is distributed in the hope that it will be useful, but WITHOUT
      12             : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13             : //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
      14             : //# License for more details.
      15             : //#
      16             : //# You should have received a copy of the GNU Library General Public License
      17             : //# along with this library; if not, write to the Free Software Foundation,
      18             : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
      19             : //#
      20             : //# Correspondence concerning AIPS++ should be addressed as follows:
      21             : //#        Internet email: casa-feedback@nrao.edu.
      22             : //#        Postal address: AIPS++ Project Office
      23             : //#                        National Radio Astronomy Observatory
      24             : //#                        520 Edgemont Road
      25             : //#                        Charlottesville, VA 22903-2475 USA
      26             : //#
      27             : //# $Id$
      28             : #include <cassert>
      29             : #include <sstream>
      30             : #include <iostream>
      31             : #include <iomanip>
      32             : 
      33             : #include <synthesis/Utilities/PointingDirectionCalculator.h>
      34             : #include <memory>  // for unique_ptr<>
      35             : #include <utility> // for std::pair
      36             : 
      37             : #include <casacore/casa/aipstype.h>
      38             : #include <casacore/casa/Exceptions/Error.h>
      39             : #include <casacore/casa/IO/ArrayIO.h>
      40             : #include <casacore/casa/Arrays/ArrayMath.h>
      41             : #include <casacore/casa/BasicSL/String.h>
      42             : #include <casacore/casa/Quanta/Quantum.h>
      43             : #include <casacore/casa/Containers/Block.h>
      44             : #include <casacore/casa/Utilities/BinarySearch.h>
      45             : #include <casacore/casa/Logging/LogIO.h>
      46             : #include <casacore/tables/TaQL/ExprNode.h>
      47             : #include <casacore/ms/MSSel/MSSelection.h>
      48             : #include <casacore/measures/Measures/MPosition.h>
      49             : #include <casacore/measures/Measures/MEpoch.h>
      50             : #include <casacore/measures/Measures/MDirection.h>
      51             : // CAS-8418 NEW //
      52             : #include <synthesis/Utilities/SDPosInterpolator.h>
      53             : 
      54             : using namespace casacore;
      55             : using namespace casacore;
      56             : using namespace std;
      57             : 
      58             : // Debug Message Handling
      59             : // if DIRECTIONCALC_DEBUG is defined, the macro debuglog and
      60             : // debugpost point standard output stream (std::cout and
      61             : // std::endl so that debug messages are sent to standard
      62             : // output. Otherwise, these macros basically does nothing.
      63             : // "Do nothing" behavior is implemented in NullLogger
      64             : // and its associating << operator below.
      65             : //
      66             : // Usage:
      67             : // Similar to standard output stream.
      68             : //
      69             : //   debuglog << "Any message" << any_value << debugpost;
      70             : //
      71             : 
      72             : //   #define DIRECTIONCALC_DEBUG
      73             : 
      74             : namespace {
      75             : struct NullLogger {
      76             : };
      77             : 
      78             : template<class T>
      79           0 : inline NullLogger &operator<<(NullLogger &logger, T /*value*/) {
      80           0 :     return logger;
      81             : }
      82             : 
      83             : #ifndef DIRECTIONCALC_DEBUG
      84             : NullLogger nulllogger;
      85             : #endif
      86             : }
      87             : 
      88             : #ifdef DIRECTIONCALC_DEBUG
      89             : #define debuglog cout << "PointingDirectionCalculator::DEBUG "
      90             : #define debugpost endl
      91             : #else
      92             : #define debuglog nulllogger
      93             : #define debugpost 0
      94             : #endif
      95             : 
      96             : namespace {
      97             : #define ARRAY_DIRECTION(ColumnName) \
      98             : inline MDirection ColumnName ## Accessor(MSPointingColumns &pointingColumns, uInt rownr) { \
      99             :     return pointingColumns.ColumnName ## Meas(rownr); \
     100             : }
     101             : 
     102             : #define SCALAR_DIRECTION(ColumnName) \
     103             : inline MDirection ColumnName ## Accessor(MSPointingColumns &pointingColumns, uInt rownr) { \
     104             :     return pointingColumns.ColumnName ## Meas()(rownr); \
     105             : }
     106             : 
     107           0 : ARRAY_DIRECTION(direction)
     108           0 : ARRAY_DIRECTION(target)
     109           0 : ARRAY_DIRECTION(pointingOffset)
     110           0 : ARRAY_DIRECTION(sourceOffset)
     111           0 : SCALAR_DIRECTION(encoder)
     112             : 
     113             : // working function for moving source correction
     114             : // convertToAzel must be configured with moving source direction and
     115             : // proper reference frame. Also, convertToCelestial must refer proper
     116             : // reference frame.
     117           0 : inline void performMovingSourceCorrection(
     118             :         CountedPtr<MDirection::Convert> &convertToAzel,
     119             :         CountedPtr<MDirection::Convert> &convertToCelestial,
     120             :         Vector<Double> &direction) {
     121             :     // moving source handling
     122             :     // If moving source is specified, output direction list is always
     123             :     // offset from reference position of moving source
     124             : 
     125           0 :         debuglog << "MovingSourceCorrection <Working>." << debugpost;
     126             : 
     127             :     // DEBUG (CAS-11818) //
     128           0 :     assert( convertToCelestial != nullptr );
     129           0 :     assert( convertToAzel != nullptr );
     130             : 
     131           0 :     MDirection srcAzel = (*convertToAzel)();
     132           0 :     MDirection srcDirection = (*convertToCelestial)(srcAzel);
     133           0 :     Vector<Double> srcDirectionVal = srcDirection.getAngle("rad").getValue();
     134           0 :     direction -= srcDirectionVal;
     135           0 : }
     136             : 
     137           0 : inline void skipMovingSourceCorrection(
     138             :         CountedPtr<MDirection::Convert> &/*convertToAzel*/,
     139             :         CountedPtr<MDirection::Convert> &/*convertToCelestial*/,
     140             :         Vector<Double> &/*direction*/) {
     141             : 
     142           0 :         debuglog << "MovingSourceCorrection <NO ACTION>" << debugpost;
     143             : 
     144             :     // do nothing
     145           0 : }
     146             : } // anonymous namespace
     147             : 
     148             : using namespace casacore;
     149             : namespace casa {
     150             : 
     151             : //+
     152             : // Original Constructor
     153             : //-
     154           0 : PointingDirectionCalculator::PointingDirectionCalculator(
     155           0 :         MeasurementSet const &ms) :
     156           0 :         originalMS_(new MeasurementSet(ms)), selectedMS_(), pointingTable_(),
     157           0 :         pointingColumns_(), timeColumn_(), intervalColumn_(), antennaColumn_(),
     158           0 :         directionColumnName_(), accessor_(NULL), antennaPosition_(), referenceEpoch_(),
     159           0 :         referenceFrame_(referenceEpoch_, antennaPosition_),
     160           0 :         directionConvert_(NULL), directionType_(MDirection::J2000), movingSource_(NULL),
     161           0 :         movingSourceConvert_(NULL), movingSourceCorrection_(NULL),
     162           0 :         antennaBoundary_(), numAntennaBoundary_(0), pointingTimeUTC_(), lastTimeStamp_(-1.0),
     163           0 :         lastAntennaIndex_(-1), pointingTableIndexCache_(0),
     164           0 :         shape_(PointingDirectionCalculator::COLUMN_MAJOR),
     165             : 
     166           0 :   /*CAS-8418*/ useSplineInterpolation_(true),   ////!!  Set, when Spline is used.  ////
     167           0 :   /*CAS-8418*/ currSpline_(nullptr),
     168           0 :   /*CAS-8418*/ splineObj_(PointingDirectionCalculator::PtColID::nItems),
     169           0 :   /*CAS-8418*/ initializeReady_(PointingDirectionCalculator::PtColID::nItems,false),// Spline initialization Ready
     170           0 :   /*CAS-8418*/ coefficientReady_(PointingDirectionCalculator::PtColID::nItems,false), // Spline Coefficient Ready
     171           0 :   /*CAS-8418*/ accessorId_(DIRECTION)               // specify default accessor ID
     172             : {
     173             : // -- original code -- //
     174           0 :     accessor_ = directionAccessor;
     175             : 
     176           0 :     Block<String> sortColumns(2);
     177           0 :     sortColumns[0] = "ANTENNA1";
     178           0 :     sortColumns[1] = "TIME";
     179             : 
     180           0 :     selectedMS_ = new MeasurementSet(originalMS_->sort(sortColumns));
     181           0 :     debuglog << "Calling init()" << debugpost;
     182           0 :     init();
     183             : 
     184             :     // set default output direction reference frame
     185           0 :     debuglog << "Calling setFrame(J2000)" << debugpost;
     186           0 :     setFrame("J2000");
     187             : 
     188             :     // set default direction column name
     189           0 :     setDirectionColumn("DIRECTION");
     190           0 : }
     191             : 
     192             : 
     193           0 : PointingDirectionCalculator::~PointingDirectionCalculator()
     194             : {
     195             :   // Nothing at the moment. //
     196           0 : }
     197             : 
     198           0 : void PointingDirectionCalculator::init() {
     199             :     // attach column
     200           0 :     timeColumn_.attach(*selectedMS_, "TIME");
     201           0 :     intervalColumn_.attach(*selectedMS_, "INTERVAL");
     202           0 :     antennaColumn_.attach(*selectedMS_, "ANTENNA1");
     203             : 
     204             :     // initial setup
     205           0 :     debuglog << "inspectAntenna" << debugpost;
     206           0 :     inspectAntenna();
     207           0 :     debuglog << "done" << debugpost;
     208             : 
     209           0 :     resetAntennaPosition(antennaColumn_(0));
     210           0 : }
     211             : 
     212           0 : void PointingDirectionCalculator::selectData(String const &antenna,
     213             :         String const &spw, String const &field, String const &time,
     214             :         String const &scan, String const &feed, String const &intent,
     215             :         String const &observation, String const &uvrange,
     216             :         String const &msselect) {
     217             :     // table selection
     218           0 :     MSSelection thisSelection;
     219           0 :     thisSelection.setAntennaExpr(antenna);
     220           0 :     thisSelection.setSpwExpr(spw);
     221           0 :     thisSelection.setFieldExpr(field);
     222           0 :     thisSelection.setTimeExpr(time);
     223           0 :     thisSelection.setScanExpr(scan);
     224           0 :     thisSelection.setStateExpr(intent);
     225           0 :     thisSelection.setObservationExpr(observation);
     226           0 :     thisSelection.setUvDistExpr(uvrange);
     227           0 :     thisSelection.setTaQLExpr(msselect);
     228             : 
     229           0 :     TableExprNode exprNode = thisSelection.getTEN(&(*originalMS_));
     230             : 
     231             :     // sort by ANTENNA1 and TIME for performance reason
     232           0 :     Block<String> sortColumns(2);
     233           0 :     sortColumns[0] = "ANTENNA1";
     234           0 :     sortColumns[1] = "TIME";
     235           0 :     if (exprNode.isNull()) {
     236           0 :         debuglog << "NULL selection" << debugpost;
     237           0 :         selectedMS_ = new MeasurementSet(originalMS_->sort(sortColumns));
     238             :     } else {
     239           0 :         debuglog << "Sort of selection" << debugpost;
     240           0 :         MeasurementSet tmp = (*originalMS_)(exprNode);
     241           0 :         selectedMS_ = new MeasurementSet(tmp.sort(sortColumns));
     242           0 :     }
     243           0 :     debuglog << "selectedMS_->nrow() = " << selectedMS_->nrow() << debugpost;
     244           0 :     if (selectedMS_->nrow() == 0) {
     245           0 :         stringstream ss;
     246           0 :         ss << "Selected MS is empty for given selection: " << endl;
     247           0 :         if (!antenna.empty()) {
     248           0 :             ss << "\tantenna \"" << antenna << "\"" << endl;
     249             :         }
     250           0 :         if (!spw.empty()) {
     251           0 :             ss << "\tspw \"" << spw << "\"" << endl;
     252             :         }
     253           0 :         if (!field.empty()) {
     254           0 :             ss << "\tfield \"" << field << "\"" << endl;
     255             :         }
     256           0 :         if (!time.empty()) {
     257           0 :             ss << "\ttime \"" << time << "\"" << endl;
     258             :         }
     259           0 :         if (!scan.empty()) {
     260           0 :             ss << "\tscan \"" << scan << "\"" << endl;
     261             :         }
     262           0 :         if (!feed.empty()) {
     263           0 :             ss << "\tfeed \"" << feed << "\"" << endl;
     264             :         }
     265           0 :         if (!intent.empty()) {
     266           0 :             ss << "\tintent \"" << intent << "\"" << endl;
     267             :         }
     268           0 :         if (!observation.empty()) {
     269           0 :             ss << "\tobservation \"" << observation << "\"" << endl;
     270             :         }
     271           0 :         if (!uvrange.empty()) {
     272           0 :             ss << "\tuvrange \"" << uvrange << "\"" << endl;
     273             :         }
     274           0 :         if (!msselect.empty()) {
     275           0 :             ss << "\tmsselect \"" << msselect << "\"" << endl;
     276             :         }
     277             : 
     278           0 :         throw AipsError(ss.str());
     279           0 :     }
     280             : 
     281           0 :     init();
     282             : 
     283           0 :     debuglog << "done selectdata" << debugpost;
     284           0 : }
     285             : 
     286           0 : void PointingDirectionCalculator::configureMovingSourceCorrection() {
     287             : #if 0   // Causes Crash //
     288             :     if (!movingSource_.null() || directionColumnName_.contains("OFFSET")) {
     289             : #else   // FIXED //
     290           0 :     if ( !movingSource_.null() && !directionColumnName_.contains("OFFSET") )
     291             :     {
     292             : #endif
     293           0 :         debuglog << "configureMovingSourceCorrection::Perfrom." << debugpost;
     294           0 :         movingSourceCorrection_ = performMovingSourceCorrection;
     295             :     } else {
     296           0 :         debuglog << "configureMovingSourceCorrection::Skip." << debugpost;
     297           0 :         movingSourceCorrection_ = skipMovingSourceCorrection;
     298             :     }
     299           0 : }
     300             : 
     301             : 
     302           0 : void PointingDirectionCalculator::setDirectionColumn(String const &columnName) {
     303           0 :     String columnNameUpcase = columnName;
     304           0 :     columnNameUpcase.upcase();
     305           0 :     if (!(originalMS_->pointing().tableDesc().isColumn(columnNameUpcase))) {
     306           0 :         stringstream ss;
     307           0 :         ss << "Column \"" << columnNameUpcase
     308           0 :                 << "\" doesn't exist in POINTING table.";
     309           0 :         throw AipsError(ss.str());
     310           0 :     }
     311             : 
     312           0 :     directionColumnName_ = columnNameUpcase;
     313             : 
     314             : //+
     315             : // New code reuired by CAS-8418
     316             : //   - When setDirectionColumn is called ,
     317             : //   - new spline coeffcient table corresoinding to specified Direction column is generated.
     318             : //      Once generated and from next time, lately created Obj. is pointed and used.
     319             : //   - from init(), this function is called.
     320             : //   - See indetal in;
     321             : //         initializeSplinefromPointingColumn(*originalMS_, accessorId_ );
     322             : //-
     323             : 
     324           0 :     if (directionColumnName_ == "DIRECTION") {
     325           0 :         accessor_ = directionAccessor;
     326           0 :         accessorId_ =  DIRECTION;
     327           0 :         initializeSplinefromPointingColumn(*originalMS_, accessorId_ );
     328             : 
     329           0 :     } else if (directionColumnName_ == "TARGET") {
     330           0 :         accessor_ = targetAccessor;
     331           0 :         accessorId_ = TARGET;
     332           0 :         initializeSplinefromPointingColumn(*originalMS_, accessorId_ );
     333             : 
     334           0 :     } else if (directionColumnName_ == "POINTING_OFFSET") {
     335           0 :         accessor_ = pointingOffsetAccessor;
     336           0 :         accessorId_ = POINTING_OFFSET;
     337           0 :         initializeSplinefromPointingColumn(*originalMS_, accessorId_ );
     338             : 
     339           0 :     } else if (directionColumnName_ == "SOURCE_OFFSET") {
     340           0 :         accessor_ = sourceOffsetAccessor;
     341           0 :         accessorId_ = SOURCE_OFFSET;
     342           0 :         initializeSplinefromPointingColumn(*originalMS_, accessorId_ );
     343             : 
     344           0 :     } else if (directionColumnName_ == "ENCODER") {
     345           0 :         accessor_ = encoderAccessor;
     346           0 :         accessorId_ = ENCODER;
     347           0 :         initializeSplinefromPointingColumn(*originalMS_, accessorId_ );
     348             : 
     349             :     } else {
     350           0 :         stringstream ss;
     351           0 :         ss << "Column \"" << columnNameUpcase << "\" is not supported.";
     352           0 :         throw AipsError(ss.str());
     353           0 :     }
     354             : 
     355             :     //+
     356             :     // CAS:8418::Limmited service,
     357             :     // when indeicated by flag,force to use traditional Linear Interpolation.
     358             :     //-
     359             : 
     360           0 :      if (getCurrentSplineObj()->isCoefficientReady() == false )
     361             :      {
     362           0 :          useSplineInterpolation_ = false;
     363             :      }
     364             : 
     365           0 :      debuglog << "initializeSplinefromPointingColumn, Normal End." << debugpost;
     366             : 
     367             :      // ---org code ---
     368           0 :      configureMovingSourceCorrection();
     369           0 : }
     370             : 
     371           0 : void PointingDirectionCalculator::setFrame(String const frameType) {
     372           0 :     Bool status = MDirection::getType(directionType_, frameType);
     373           0 :     if (!status) {
     374           0 :         LogIO os(LogOrigin("PointingDirectionCalculator", "setFrame", WHERE));
     375             :         os << LogIO::WARN << "Conversion of frame string \"" << frameType
     376             :                 << "\" into direction type enum failed. Use J2000."
     377           0 :                 << LogIO::POST;
     378           0 :         directionType_ = MDirection::J2000;
     379           0 :     }
     380             : 
     381             :     // create conversion engine
     382             : 
     383             :     // Accessor
     384           0 :     MDirection nominalInputMeasure = accessor_(*pointingColumns_, 0);
     385             : 
     386             :     // RefFrame
     387           0 :     MDirection::Ref outReference(directionType_, referenceFrame_);
     388             : 
     389             :     // Conversion
     390             :     directionConvert_ = new MDirection::Convert(nominalInputMeasure,
     391           0 :             outReference);
     392             :     // Epoch
     393           0 :     const MEpoch *e = dynamic_cast<const MEpoch *>(referenceFrame_.epoch());
     394             :     const MPosition *p =
     395           0 :             dynamic_cast<const MPosition *>(referenceFrame_.position());
     396             :     debuglog << "Conversion Setup: Epoch "
     397           0 :             << e->get("s").getValue() << " " << e->getRefString() << " Position "
     398           0 :             << p->get("m").getValue() << " " << p->getRefString()
     399           0 :             << debugpost;
     400           0 : }
     401             : 
     402           0 : void PointingDirectionCalculator::setDirectionListMatrixShape(
     403             :         PointingDirectionCalculator::MatrixShape const shape) {
     404           0 :     shape_ = shape;
     405           0 : }
     406             : 
     407           0 : void PointingDirectionCalculator::setMovingSource(String const sourceName) {
     408           0 :     MDirection sourceDirection(Quantity(0.0, "deg"), Quantity(90.0, "deg"));
     409           0 :     sourceDirection.setRefString(sourceName);
     410           0 :     setMovingSource(sourceDirection);
     411           0 : }
     412             : 
     413           0 : void PointingDirectionCalculator::setMovingSource(
     414             :         MDirection const &sourceDirection) {
     415           0 :     movingSource_ = dynamic_cast<MDirection *>(sourceDirection.clone());
     416             : 
     417             :     // create conversion engine for moving source
     418           0 :     MDirection::Ref refAzel(MDirection::AZEL, referenceFrame_);
     419           0 :     movingSourceConvert_ = new MDirection::Convert(*movingSource_, refAzel);
     420             : 
     421           0 :     configureMovingSourceCorrection();
     422           0 : }
     423             : 
     424           0 : void PointingDirectionCalculator::unsetMovingSource() {
     425           0 :   if (!movingSource_.null()) {
     426           0 :     movingSource_ = nullptr;
     427             :   }
     428           0 : }
     429             : 
     430             : 
     431           0 : Matrix<Double> PointingDirectionCalculator::getDirection() {
     432           0 :     assert(!selectedMS_.null());
     433           0 :     uInt const nrow = selectedMS_->nrow();
     434           0 :     debuglog << "selectedMS_->nrow() = " << nrow << debugpost;
     435           0 :     Vector<Double> outDirectionFlattened(2 * nrow);
     436             :     // column major data offset and increment for outDirectionFlattened,
     437             :     // and output matrix shape
     438           0 :     uInt offset = nrow;
     439           0 :     uInt increment = 1;
     440             :     // matrix shape: number of rows is nrow and number of columns is 2
     441           0 :     IPosition outShape(2, nrow, 2);
     442           0 :     if (shape_ == PointingDirectionCalculator::ROW_MAJOR) {
     443             :         // column major specific offset, increment and output shape
     444           0 :         offset = 1;
     445           0 :         increment = 2;
     446             :         // matrix shape: number of rows is 2 and number of columns is nrow
     447           0 :         outShape = IPosition(2, 2, nrow);
     448             :     }
     449             : 
     450           0 :     for (uInt i = 0; i < numAntennaBoundary_ - 1; ++i) {
     451           0 :         uInt start = antennaBoundary_[i];
     452           0 :         uInt end = antennaBoundary_[i + 1];
     453           0 :         uInt currentAntenna = antennaColumn_(start);
     454             : 
     455           0 :         resetAntennaPosition(currentAntenna);
     456             : 
     457             :         debuglog << "antenna " << currentAntenna << " start " << start
     458           0 :                 << " end " << end << debugpost;
     459           0 :         uInt const nrowPointing = pointingTimeUTC_.nelements();
     460           0 :         debuglog << "nrowPointing = " << nrowPointing << debugpost;
     461             :         debuglog << "pointingTimeUTC = " << min(pointingTimeUTC_) << "~"
     462           0 :         << max(pointingTimeUTC_) << debugpost;
     463             : 
     464           0 :         for (uInt j = start; j < end; ++j) {
     465           0 :             debuglog << "start index " << j << debugpost;
     466             : 
     467             :             // doGetDirection call //
     468             : 
     469           0 :             Vector<Double> direction = doGetDirection(j,currentAntenna); // CAS-8418 args werre changed.
     470             : 
     471             :             debuglog << "index for lat: " << (j * increment)
     472             :                     << " (cf. outDirectionFlattened.nelements()="
     473           0 :                     << outDirectionFlattened.nelements() << ")" << debugpost;
     474           0 :             debuglog << "index for lon: " << (offset + j * increment)
     475           0 :                     << debugpost;
     476           0 :             outDirectionFlattened[j * increment] = direction[0];
     477           0 :             outDirectionFlattened[offset + j * increment] = direction[1];
     478           0 :         }
     479           0 :         debuglog << "done antenna " << currentAntenna << debugpost;
     480             :     }
     481           0 :     debuglog << "done getDirection" << debugpost;
     482           0 :     return Matrix < Double > (outShape, outDirectionFlattened.data());
     483           0 : }
     484             : 
     485             : //**************************************************
     486             : // CAS-8418
     487             : // doGetDirection(irow)
     488             : // - Spline Interpolation is executed, except
     489             : //   number of data is insufficient
     490             : // - Interpolation path in the module was separated.
     491             : //***************************************************
     492           0 : Vector<Double> PointingDirectionCalculator::doGetDirection(uInt irow, uInt antID) {
     493           0 :      debuglog << "doGetDirection(" << irow << "," << antID << ")" << debugpost;
     494             : 
     495             : // sec:1 Linear , Spline common//
     496           0 :     Double currentTime =  timeColumn_.convert(irow, MEpoch::UTC).get("s").getValue();
     497           0 :     resetTime(currentTime);
     498             : 
     499             :     // search and interpolate if necessary
     500             :     Bool exactMatch;
     501           0 :     uInt const nrowPointing = pointingTimeUTC_.nelements();
     502             :     // pointingTableIndexCache_ is not so effective in terms of performance
     503             :     // simple binary search may be enough,
     504           0 :     Int index = binarySearch(exactMatch, pointingTimeUTC_, currentTime,
     505             :             nrowPointing, 0);
     506           0 :     debuglog << "binarySearch result " << index << debugpost;
     507             :     debuglog << "Time " << setprecision(16) << currentTime << " idx=" << index
     508           0 :             << debugpost;
     509             :     //+
     510             :     // Check section on series of pointing data
     511             :     // by 'Binary match' wth Pointing Table
     512             :     // -
     513           0 :     MDirection direction;
     514           0 :     assert(accessor_ != NULL);
     515           0 :     if (exactMatch) {
     516           0 :         debuglog << "exact match" << debugpost;
     517           0 :         direction = accessor_(*pointingColumns_, index);
     518           0 :     } else if (index <= 0) {
     519           0 :         debuglog << "take 0th row" << debugpost;
     520           0 :         direction = accessor_(*pointingColumns_, 0);
     521           0 :     } else if (index > (Int) (nrowPointing - 1)) {
     522           0 :         debuglog << "take final row" << debugpost;
     523           0 :         direction = accessor_(*pointingColumns_, nrowPointing - 1);
     524             :     } else {
     525           0 :         debuglog << "linear interpolation " << debugpost;
     526             : 
     527             :         // commonly used result buffer .. //
     528           0 :         Vector<Double> interpolated(2);
     529             : 
     530             :         //*
     531             :         // CAS-8418 Time Gap
     532             :         //*
     533           0 :         bool fgsw = getCurrentSplineObj()->isTimeGap(antID, index);
     534           0 :         if((fgsw==false) &&                // Not specially Marled. (CAS-8418)
     535           0 :            (useSplineInterpolation_) )     // SPLINE //
     536             :         {
     537             :             //+
     538             :             // CAS-8418::  Spline Interpolation section.
     539             :             //-
     540             : 
     541           0 :             Double t0 = pointingTimeUTC_[index - 1];
     542           0 :             Double dtime =  (currentTime - t0) ;
     543             : 
     544             :             // determin section on 'uIndex'
     545             :             uInt uIndex;
     546           0 :             if( index >=1 ){
     547           0 :                 uIndex = index-1;
     548           0 :             } else if (index > (Int)(nrowPointing-1) ) {
     549           0 :                  uIndex = nrowPointing-1;
     550             :             } else  {
     551           0 :                  stringstream ss; ss  << "BUGCHECK, never come here. "  << endl;
     552           0 :                  throw AipsError( ss.str() );
     553           0 :             }
     554             : 
     555             :             //+
     556             :             // Execute Interpolation
     557             :             //-
     558             : 
     559           0 :               if(getCurrentSplineObj() == nullptr){
     560           0 :                   stringstream  ss; ss << "FAITAL ERROR: Invalid Current Spline Object pointer.";
     561           0 :                   throw AipsError(ss.str());
     562           0 :               }
     563           0 :               interpolated = getCurrentSplineObj()-> calculate(uIndex, dtime, antID );
     564             : 
     565             :             // obtain refType1 (original copied)//
     566             : 
     567           0 :               MDirection         dir1 = accessor_(*pointingColumns_, index - 1);
     568           0 :               String             dirRef1 = dir1.getRefString();
     569             :               MDirection::Types  refType1;
     570           0 :               MDirection::getType(refType1, dirRef1);
     571             : 
     572             :             // LINEAR/SPLINE common
     573             :             // Convert the interpolated diretion from MDirection to Vector //
     574           0 :               direction = MDirection(Quantum<Vector<Double> >(interpolated, "rad"),refType1);
     575           0 :         }
     576             :         else // LINEAR (basically same as original code)//
     577             :         {
     578           0 :             Double t0 = pointingTimeUTC_[index - 1];
     579           0 :             Double t1 = pointingTimeUTC_[index];
     580           0 :             Double dt = t1 - t0;
     581             : 
     582             :             debuglog << "Interpolate between " << setprecision(16) << index - 1
     583             :                   << " (" << t0 << ") and " << index << " (" << t1 << ")"
     584           0 :                   << debugpost;
     585             : 
     586           0 :             MDirection dir1 = accessor_(*pointingColumns_, index - 1);
     587           0 :             MDirection dir2 = accessor_(*pointingColumns_, index);
     588             : 
     589             :             // obtain Ref type //
     590           0 :             String dirRef1 = dir1.getRefString();
     591           0 :             String dirRef2 = dir2.getRefString();
     592             : 
     593             :             MDirection::Types refType1, refType2;
     594           0 :             MDirection::getType(refType1, dirRef1);
     595           0 :             MDirection::getType(refType2, dirRef2);
     596             : 
     597             :             debuglog << "dirRef1 = " << dirRef1 << " ("
     598           0 :                     << MDirection::showType(refType1) << ")" << debugpost;
     599             : 
     600           0 :             if (dirRef1 != dirRef2) {
     601           0 :                 MeasFrame referenceFrameLocal((pointingColumns_->timeMeas())(index),
     602           0 :                          *(referenceFrame_.position()));
     603           0 :                 dir2 = MDirection::Convert(dir2,
     604           0 :                          MDirection::Ref(refType1, referenceFrameLocal))();
     605           0 :             }
     606             : 
     607           0 :             Vector<Double> dirVal1 = dir1.getAngle("rad").getValue();
     608           0 :             Vector<Double> dirVal2 = dir2.getAngle("rad").getValue();
     609           0 :             Vector<Double> scanRate = dirVal2 - dirVal1;
     610             : 
     611           0 :             interpolated = dirVal1 + scanRate * (currentTime - t0) / dt;
     612             : 
     613             :             // LINEAR/SPLINE common
     614             :             // Convert the interpolated diretion from MDirection to Vector //
     615           0 :               direction = MDirection(Quantum<Vector<Double> >(interpolated, "rad"),refType1);
     616             : 
     617           0 :         }
     618           0 :     }
     619             : 
     620             :     // CAS-8418:: Ending Section,following section is same as original //
     621             :     debuglog << "direction = "
     622           0 :             << direction.getAngle("rad").getValue() << " (unit rad reference frame "
     623           0 :             << direction.getRefString()
     624           0 :             << ")" << debugpost;
     625           0 :     Vector<Double> outVal(2);
     626           0 :     if (direction.getRefString() == MDirection::showType(directionType_)) {
     627           0 :         outVal = direction.getAngle("rad").getValue();
     628             :     } else {
     629           0 :         MDirection converted = (*directionConvert_)(direction);
     630           0 :         outVal = converted.getAngle("rad").getValue();
     631             :         debuglog << "converted = " << outVal << "(unit rad reference frame "
     632           0 :                 << converted.getRefString() << ")" << debugpost;
     633           0 :     }
     634             : 
     635             :     // moving source correction
     636           0 :     assert(movingSourceCorrection_ != NULL);
     637           0 :     movingSourceCorrection_(movingSourceConvert_, directionConvert_, outVal);
     638             : 
     639           0 :     return outVal;
     640           0 : }
     641             : 
     642           0 : Vector<Double> PointingDirectionCalculator::getDirection(uInt i) {
     643           0 :     if (i >= selectedMS_->nrow()) {
     644           0 :         stringstream ss;
     645           0 :         ss << "Out of range row index: " << i << " (nrow for selected MS "
     646           0 :                 << getNrowForSelectedMS() << ")" << endl;
     647           0 :         throw AipsError(ss.str());
     648           0 :     }
     649           0 :     debuglog << "start row " << i << debugpost;
     650           0 :     Int currentAntennaIndex = antennaColumn_(i);
     651             :     debuglog << "currentAntennaIndex = " << currentAntennaIndex
     652           0 :             << " lastAntennaIndex_ = " << lastAntennaIndex_ << debugpost;
     653             :     Double currentTime =
     654           0 :             timeColumn_.convert(i, MEpoch::UTC).get("s").getValue();
     655           0 :     resetAntennaPosition(currentAntennaIndex);
     656             :     debuglog << "currentTime = " << currentTime << " lastTimeStamp_ = "
     657           0 :             << lastTimeStamp_ << debugpost;
     658           0 :     if (currentTime != lastTimeStamp_) {
     659           0 :         resetTime(i);
     660             :     }
     661           0 :     debuglog << "doGetDirection" << debugpost;
     662             : 
     663           0 :     Vector<Double> direction = doGetDirection(i,currentAntennaIndex);  // CAS-8418 args were changed
     664             : 
     665           0 :     return direction;
     666             : }
     667             : 
     668           0 : Vector<rownr_t> PointingDirectionCalculator::getRowId() {
     669           0 :     return selectedMS_->rowNumbers();
     670             : }
     671             : 
     672           0 : Vector<rownr_t> PointingDirectionCalculator::getRowIdForOriginalMS() {
     673           0 :     return selectedMS_->rowNumbers(*originalMS_, True);
     674             : }
     675             : 
     676           0 : rownr_t PointingDirectionCalculator::getRowId(uInt i) {
     677           0 :     return selectedMS_->rowNumbers()[i];
     678             : }
     679             : 
     680             : 
     681           0 : void PointingDirectionCalculator::inspectAntenna() {
     682             :     // selectedMS_ must be sorted by ["ANTENNA1", "TIME"]
     683           0 :     antennaBoundary_.resize(selectedMS_->antenna().nrow() + 1);
     684           0 :     antennaBoundary_ = -1;
     685           0 :     uInt count = 0;           // CAS-8418 :: Int ->iUnt //
     686           0 :     antennaBoundary_[count] = 0;
     687             : 
     688           0 :     ++count;
     689             : 
     690           0 :     Vector<Int> antennaList = antennaColumn_.getColumn();
     691           0 :     uInt nrow = antennaList.nelements();
     692           0 :     Int lastAnt = antennaList[0];
     693             : 
     694           0 :     for (uInt i = 0; i < nrow; ++i) {
     695           0 :         if (antennaList[i] != lastAnt) {
     696           0 :             antennaBoundary_[count] = i;
     697           0 :             ++count;
     698           0 :             lastAnt = antennaList[i];
     699             :         }
     700             :     }
     701             :     //+
     702             :     // CAS-8418 access violation check
     703             :     //-
     704           0 :       assert( count <= selectedMS_->antenna().nrow() );
     705             :     // end add
     706             : 
     707           0 :     antennaBoundary_[count] = nrow;
     708           0 :     ++count;
     709           0 :     numAntennaBoundary_ = count;
     710           0 :     debuglog << "antennaBoundary_=" << antennaBoundary_ << debugpost;
     711           0 : }
     712             : 
     713           0 : void PointingDirectionCalculator::initPointingTable(Int const antennaId) {
     714           0 :     if (!pointingTable_.null() && !pointingColumns_.null()
     715           0 :             && pointingTable_->nrow() > 0
     716           0 :             && pointingColumns_->antennaId()(0) == antennaId) {
     717             :         // no need to update
     718           0 :         return;
     719             :     }
     720           0 :     debuglog << "update pointing table for antenna " << antennaId << debugpost;
     721           0 :     MSPointing original = selectedMS_->pointing();
     722           0 :     MSPointing selected = original(original.col("ANTENNA_ID") == antennaId);
     723           0 :     if (selected.nrow() == 0) {
     724             :         debuglog << "no rows for antenna " << antennaId << " try -1"
     725           0 :                 << debugpost;
     726             :         // try ANTENNA_ID == -1
     727           0 :         selected = original(original.col("ANTENNA_ID") == -1);
     728             : 
     729             : #if 0   // follwing assert() invalidate throw AipsError() //
     730             :         assert(selected.nrow() > 0);
     731             : #endif
     732           0 :         if (selected.nrow() == 0) {
     733           0 :             stringstream ss;
     734           0 :             ss << "Internal Error: POINTING table has no entry for antenna "
     735           0 :                     << antennaId << "." << endl;
     736           0 :             throw AipsError(ss.str());
     737           0 :         }
     738             :     }
     739           0 :     debuglog << "selected pointing rows " << selected.nrow() << debugpost;
     740           0 :     pointingTable_ = new MSPointing(selected.sort("TIME"));
     741             : 
     742             :     // attach columns
     743           0 :     pointingColumns_ = new MSPointingColumns(*pointingTable_);
     744             : 
     745             :     // initialize pointingTimeUTC_
     746           0 :     uInt const nrowPointing = pointingTable_->nrow();
     747           0 :     pointingTimeUTC_.resize(nrowPointing);
     748             :     ScalarMeasColumn<MEpoch> pointingTimeColumn =
     749           0 :             pointingColumns_->timeMeas();
     750           0 :     for (uInt i = 0; i < nrowPointing; ++i) {
     751           0 :         MEpoch e = pointingTimeColumn(i);
     752           0 :         if (e.getRefString() == MEpoch::showType(MEpoch::UTC)) {
     753           0 :             pointingTimeUTC_[i] = e.get("s").getValue();
     754             :         } else {
     755           0 :             pointingTimeUTC_[i] =
     756           0 :                     MEpoch::Convert(e, MEpoch::UTC)().get("s").getValue();
     757             :         }
     758           0 :     }
     759             : 
     760             :     // reset index cache for pointing table
     761           0 :     pointingTableIndexCache_ = 0;
     762             : 
     763           0 :     debuglog << "done initPointingTable" << debugpost;
     764           0 : }
     765             : 
     766           0 : void PointingDirectionCalculator::resetAntennaPosition(Int const antennaId) {
     767           0 :     MSAntenna antennaTable = selectedMS_->antenna();
     768           0 :     uInt nrow = antennaTable.nrow();
     769           0 :     if (antennaId < 0 || (Int) nrow <= antennaId) {
     770           0 :         stringstream ss;
     771           0 :         ss << "Internal Error: Invalid ANTENNA_ID is specified (" << antennaId
     772           0 :                 << ")." << endl;
     773           0 :         throw AipsError(ss.str());
     774           0 :     } else if (antennaId != lastAntennaIndex_ || lastAntennaIndex_ == -1) {
     775             :         ScalarMeasColumn < MPosition
     776           0 :                 > antennaPositionColumn(antennaTable, "POSITION");
     777           0 :         antennaPosition_ = antennaPositionColumn(antennaId);
     778             :         debuglog << "antenna position: "
     779           0 :                 << antennaPosition_.getRefString() << " "
     780           0 :                 << setprecision(16) << antennaPosition_.get("m").getValue() << debugpost;
     781           0 :         referenceFrame_.resetPosition(antennaPosition_);
     782             : 
     783           0 :         initPointingTable(antennaId);
     784             : 
     785           0 :         lastAntennaIndex_ = antennaId;
     786           0 :     }
     787           0 : }
     788             : 
     789           0 : void PointingDirectionCalculator::resetTime(Double const timestamp) {
     790           0 :     debuglog << "resetTime(Double " << timestamp << ")" << debugpost;
     791             :     debuglog << "lastTimeStamp_ = " << lastTimeStamp_ << " timestamp = "
     792           0 :             << timestamp << debugpost;
     793           0 :     if (timestamp != lastTimeStamp_ || lastTimeStamp_ < 0.0) {
     794           0 :         referenceEpoch_ = MEpoch(Quantity(timestamp, "s"), MEpoch::UTC);
     795           0 :         referenceFrame_.resetEpoch(referenceEpoch_);
     796             : 
     797           0 :         lastTimeStamp_ = timestamp;
     798             :     }
     799           0 : }
     800             : 
     801             : //*********************************************************
     802             : //  CAS-8418::
     803             : //  Extended dunctions in PointingDirectionCalculator
     804             : //   for initializing Spline Interpolation
     805             : //*********************************************************
     806             : 
     807             : //+
     808             : // Direction Columns and
     809             : // AccessorId and accessor_ (function pointer)
     810             : //-
     811             : 
     812             : std::vector<string>   dirColList
     813             : = { "DIRECTION","TARGET","POINTING_OFFSET","SOURCE_OFFSET","ENCODER" };
     814             : 
     815             : std::vector<PointingDirectionCalculator::ACCESSOR> accList
     816             : = {  directionAccessor, targetAccessor,pointingOffsetAccessor,
     817             :    sourceOffsetAccessor, encoderAccessor };
     818             : 
     819             : // Column checck in Pointing Table //
     820           0 : bool PointingDirectionCalculator::checkColumn(MeasurementSet const &ms,String const &columnName )
     821             : {
     822           0 :     String columnNameUpcase = columnName;
     823           0 :     columnNameUpcase.upcase();
     824           0 :     if (true == (ms.pointing().tableDesc().isColumn(columnNameUpcase))) return true;
     825           0 :     else return false;
     826           0 : }
     827             : //+
     828             : // Activate Spline Interpolation
     829             : // - check specified Column if exist
     830             : // - create Spline object from specified Direction column
     831             : // - prepare Coeffient table for calulation.
     832             : //-
     833           0 : bool PointingDirectionCalculator::initializeSplinefromPointingColumn(MeasurementSet const &ms,
     834             :                                      PointingDirectionCalculator::PtColID  DirColNo )
     835             : {
     836           0 :     debuglog << "initializeSplinefromPointingColumn, columNo=" << DirColNo << debugpost;
     837             : 
     838           0 :     String colName = dirColList[DirColNo] ;
     839           0 :     PointingDirectionCalculator::ACCESSOR acc   = accList[DirColNo] ;
     840             : 
     841             :     //+
     842             :     // Column Range check
     843             :     //-
     844           0 :     if( DirColNo >PointingDirectionCalculator::PtColID::nItems )
     845             :     {
     846           0 :         stringstream ss;
     847           0 :         ss << "Bugcheck. No column on Pointing Table." << endl;
     848           0 :         throw AipsError(ss.str());
     849             :         return false;  // Bad Param //
     850           0 :     }
     851             : 
     852             :     //+
     853             :     // CASE 1: Spline Object is already available.
     854             :     //-
     855           0 :     if( initializeReady_[DirColNo] == true )
     856             :     {
     857           0 :         debuglog << "initializeSplinefromPointingColumn, Normal,already active."  << debugpost;
     858             : 
     859             :         // SWITCH Master pointer  //
     860           0 :         currSpline_ = splineObj_[DirColNo].get();
     861           0 :         assert(currSpline_ !=nullptr);
     862             : 
     863           0 :         return true;   // Servece already OK //
     864             :     }
     865             :     //+
     866             :     // CASE 2: New Direction Colomn, initialize Spline Obj.
     867             :     //-
     868           0 :     if(checkColumn(ms, colName))
     869             :     {
     870           0 :         debuglog << "Spline Obj:: attempt to construct by " << colName.c_str() << debugpost;
     871             : 
     872             :         // Temporary Obj. //
     873           0 :           unique_ptr<SplineInterpolation> spTemp( new SplineInterpolation(ms,acc));
     874             : 
     875             :         // Spline Available (N>4)
     876           0 :           coefficientReady_ [DirColNo] = spTemp-> isCoefficientReady();
     877             : 
     878             :         // move to Spline obj. //
     879           0 :           assert(splineObj_[DirColNo] == nullptr);
     880           0 :           splineObj_[DirColNo] = std::move(spTemp);
     881             : 
     882             :         // copy to Master pointer, if this is desired.  //
     883           0 :           currSpline_ = splineObj_[DirColNo].get();
     884             : 
     885             :         // Obj. available //
     886           0 :            initializeReady_[DirColNo] = true;
     887             : 
     888           0 :         return true;
     889           0 :     }
     890             : 
     891             :     //+
     892             :     // Initialize Faiure.
     893             :     //-
     894             : 
     895           0 :     stringstream ss;
     896           0 :     ss << "FAILED:: No spline obj, atempted to make. No column on Pointing Table." << endl;
     897           0 :     throw AipsError(ss.str());
     898             : 
     899           0 : }
     900             : 
     901             : //+
     902             : // CAS-8418::
     903             : // Exporting Internal Status/Object Service
     904             : //-
     905             : 
     906             : // Export  COEFF:  returns Coefficitent Table of the current Spline-Object
     907           0 : PointingDirectionCalculator::COEFF  PointingDirectionCalculator::exportCoeff()
     908             : {
     909           0 :     SplineInterpolation *sp =  this->getCurrentSplineObj();
     910           0 :     return (sp->getCoeff());
     911             : }
     912             : 
     913             : // Export status of COEFF: returns true if COEFF is available.
     914           0 : bool PointingDirectionCalculator::isCoefficientReady()
     915             : {
     916           0 :     SplineInterpolation *sp =  this->getCurrentSplineObj();
     917           0 :     return (sp->isCoefficientReady() );
     918             : }
     919             : 
     920             : //***************************************************
     921             : //  CAS-8418:
     922             : //  Antenna Boundary (for Pointing Table ) methods
     923             : //  - create antenna information on Pointing Table.
     924             : //***************************************************
     925             : 
     926             : //+
     927             : // Antenna Boundary Class
     928             : //-
     929             : class AntennaBoundary {
     930             : public:
     931             :          AntennaBoundary(casacore::MeasurementSet const &ms) ;
     932           0 :         ~AntennaBoundary() { };
     933             : 
     934             :         std::pair<casacore::uInt, casacore::uInt>  getAntennaBoundary( casacore::uInt n );
     935             : 
     936           0 :         casacore::uInt  getNumOfAntenna() {return numAntennaBoundary_ - 1;}
     937             : 
     938           0 :         casacore::MSPointing  getPointingHandle() { return hPointing_; };
     939             : 
     940             : private:
     941             :        //  AntennaBoundary on Pointing Tablle
     942             :          casacore::Vector<casacore::uInt>            antennaBoundary_;
     943             :          casacore::uInt                              numAntennaBoundary_;
     944             : 
     945             :        // Pointing Table handle
     946             :          casacore::MSPointing hPointing_;
     947             : 
     948             : };
     949             : 
     950             : // Constructor //
     951           0 : AntennaBoundary::AntennaBoundary(MeasurementSet const &ms)
     952             : {
     953             :         // Antenna Boundary body //
     954           0 :         antennaBoundary_.resize(ms.antenna().nrow() + 1);
     955           0 :         antennaBoundary_ = -1;
     956             : 
     957           0 :         Int count = 0;
     958           0 :         antennaBoundary_[count] = 0;
     959           0 :         ++count;
     960             : 
     961             :         // Pointing Table Handle and the Columns Handle//
     962             :         //   with sorting by AntennaID and Time
     963             : 
     964           0 :         MSPointing hPointing_org  = ms.pointing();
     965             : 
     966             :         // Sort keys //
     967           0 :         Block<String> sortColumns(2);
     968           0 :         sortColumns[0]="ANTENNA_ID";
     969           0 :         sortColumns[1]="TIME";
     970             : 
     971             :         // Pointing Table handle //
     972           0 :         MSPointing hPointingTmp(hPointing_org.sort(sortColumns));
     973           0 :         hPointing_ = hPointingTmp;
     974             : 
     975             :         // Column Handle //
     976             :         std::unique_ptr<casacore::MSPointingColumns>
     977           0 :                 columnPointing( new casacore::MSPointingColumns( hPointing_ ));
     978             : 
     979             :         // Antenna List //
     980             : 
     981           0 :         ScalarColumn<casacore::Int>  antennaColumn = columnPointing->antennaId();
     982           0 :         Vector<Int> antennaList =  antennaColumn.getColumn();
     983             : 
     984           0 :         uInt nrow = antennaList.nelements();
     985           0 :         Int lastAnt = antennaList[0];
     986             : 
     987           0 :         for (uInt i = 0; i < nrow; ++i)
     988             :         {
     989           0 :             if (antennaList[i] > lastAnt)
     990             :             {
     991           0 :                 antennaBoundary_[count] = i;
     992           0 :                 count++;
     993           0 :                 lastAnt = antennaList[i];
     994             :             }
     995           0 :             else if (antennaList[i] < lastAnt )
     996             :             {
     997           0 :                  stringstream ss;
     998           0 :                  ss << "Bugcheck. Bad sort in creating antenna list." << endl;
     999           0 :                  throw AipsError(ss.str());
    1000           0 :             }
    1001             :         }
    1002             : 
    1003           0 :         antennaBoundary_[count] = nrow;
    1004           0 :         ++count;
    1005           0 :         numAntennaBoundary_ = count;
    1006             : 
    1007             : 
    1008           0 : }
    1009             : // getAntenaBoundary(start, end) //
    1010           0 : std::pair<casacore::uInt, casacore::uInt> AntennaBoundary::getAntennaBoundary( casacore::uInt n )
    1011             : {
    1012           0 :     std::pair<casacore::uInt, casacore::uInt> pos(antennaBoundary_[n],antennaBoundary_[n+1]);
    1013           0 :     return pos;
    1014             : }
    1015             : 
    1016             : //***************************************************
    1017             : //  CAS-8418:
    1018             : //  Spline Inerpolation  methods
    1019             : //***************************************************
    1020             : 
    1021             : // constructor (for each accessor) //
    1022           0 : SplineInterpolation::SplineInterpolation(MeasurementSet const &ms,
    1023           0 :                                          PointingDirectionCalculator::ACCESSOR accessor )
    1024             : {
    1025           0 :     stsCofficientReady  = false;
    1026           0 :     init(ms, accessor);
    1027           0 : }
    1028             : 
    1029             : // initialize //
    1030           0 : void SplineInterpolation::init(MeasurementSet const &ms,
    1031             :                                PointingDirectionCalculator::ACCESSOR const my_accessor)
    1032             : {
    1033             :     // Antenna Bounday //
    1034             : 
    1035           0 :         AntennaBoundary  antb(ms);
    1036           0 :         uInt numAnt = antb.getNumOfAntenna();
    1037             : 
    1038             :     // prepere MS handle from selectedMS_
    1039           0 :         MSPointing hPoint = antb.getPointingHandle();
    1040             :         std::unique_ptr<casacore::MSPointingColumns>
    1041           0 :                 columnPointing( new casacore::MSPointingColumns( hPoint ));
    1042             : 
    1043             :     // Resize (top level) //
    1044           0 :       tmp_time.        resize(numAnt);
    1045           0 :       tmp_dir.         resize(numAnt);
    1046             : 
    1047             :     // CAS-8418 Time Gap //
    1048           0 :       tmp_dtime.         resize(numAnt);
    1049           0 :       tmp_timegap.       resize(numAnt);
    1050             : 
    1051             :     // Column handle (only time,direction are needed, others are reserved) //
    1052             : 
    1053           0 :       ScalarColumn<Double> pointingTime           = columnPointing ->time();
    1054           0 :       ScalarColumn<Double> pointingInterval       = columnPointing ->interval();
    1055             : 
    1056             :     // Following columns are accessed by 'accessor_'   //
    1057             : 
    1058           0 :       ArrayColumn<Double>  pointingDirection      = columnPointing ->direction();
    1059           0 :       ArrayColumn<Double>  pointingTarget         = columnPointing ->target();
    1060           0 :       ArrayColumn<Double>  pointingPointingOffset = columnPointing ->pointingOffset();
    1061           0 :       ArrayColumn<Double>  pointingSourceOffset   = columnPointing ->sourceOffset();
    1062           0 :       ArrayColumn<Double>  pointingencoder        = columnPointing ->encoder();
    1063             : 
    1064           0 :     for(uInt ant=0; ant <numAnt; ant++)
    1065             :     {
    1066             :         // Antenna Bounday Pos(start,end) //
    1067           0 :           std::pair<uInt,uInt> pos = antb.getAntennaBoundary(ant);
    1068           0 :           uInt startPos = pos.first;
    1069           0 :           uInt endPos   = pos.second;
    1070             : 
    1071             :         // define size of each antenna
    1072           0 :           uInt size = endPos - startPos;
    1073           0 :           tmp_dir [ant]. resize(size);
    1074           0 :           tmp_time[ant]. resize(size);
    1075             : 
    1076             :          // CAS-8418 Time Gap //
    1077           0 :           tmp_dtime[ant]. resize(size);
    1078           0 :           tmp_timegap[ant]. resize(size);
    1079             : 
    1080             :         // set up //
    1081           0 :           std::fill(tmp_timegap[ant].begin(), tmp_timegap[ant].end(), false); // DEFAULT = false //
    1082           0 :           Double prv_time =  pointingTime.get(startPos); // For making diff time
    1083             :         // for each row //
    1084           0 :         for (uInt row = startPos; row < endPos; row++)
    1085             :         {
    1086           0 :             uInt index = row - startPos;
    1087             : 
    1088             :             // resizei (for Dir) //
    1089           0 :             tmp_dir[ant][index].resize(2);
    1090             : 
    1091           0 :             Double        time    = pointingTime.get(row);
    1092           0 :             MDirection     dir    = my_accessor(*columnPointing, row);
    1093           0 :             Vector<Double> dirVal = dir.getAngle("rad").getValue();
    1094             : 
    1095             :             // set on Vector //
    1096           0 :             tmp_time[ant][index] = time;
    1097           0 :             tmp_dir [ant][index] = dirVal;
    1098             : 
    1099             :             // CAS-8418 Time Gap //
    1100             : 
    1101             :               /* Pointing Interval */
    1102           0 :               Double p_interval =  pointingInterval.  get(row);
    1103           0 :               p_interval  = round(10000.0 * p_interval)/10000.0;  // Round at 0.0001 order
    1104             : 
    1105             :               /* Measured Interval */
    1106           0 :               Double dd = time - prv_time;
    1107           0 :               dd  = round(10000.0 * dd)/10000.0;  // Round at 0.0001 order
    1108             : 
    1109           0 :               tmp_dtime[ant][index] = dd; // record backward diff //
    1110           0 :               prv_time  = time;
    1111             : 
    1112             :               /* Mark the position (force to exec LINEAR) */
    1113           0 :              if(size>=7)
    1114             :              {
    1115           0 :                if(dd >  p_interval){
    1116           0 :                    if((index < size-3 )&&(index >=3)) {
    1117           0 :                       tmp_timegap [ant][index+3] =true; // forward
    1118           0 :                       tmp_timegap [ant][index+2] =true;
    1119           0 :                       tmp_timegap [ant][index+1] =true;
    1120             : 
    1121           0 :                       tmp_timegap [ant][index  ] =true; // center (detected point)
    1122             : 
    1123           0 :                       tmp_timegap [ant][index-1] =true;
    1124           0 :                       tmp_timegap [ant][index-2] =true;
    1125           0 :                       tmp_timegap [ant][index-3] =true; // backward
    1126             : 
    1127             :                    }
    1128             :                    //*
    1129             :                    // In case, marking on edges;
    1130             :                    // (note: time diff(=dd) is backward difference)
    1131             :                    //*
    1132           0 :                    else if (index == 1) {
    1133           0 :                       tmp_timegap [ant][index+3] =true; // forward
    1134           0 :                       tmp_timegap [ant][index+2] =true;
    1135           0 :                       tmp_timegap [ant][index+1] =true;
    1136           0 :                       tmp_timegap [ant][index  ] =true; // center (detected point)
    1137           0 :                       tmp_timegap [ant][index-1] =true;
    1138             :                    }
    1139           0 :                    else if (index == 2) {
    1140           0 :                       tmp_timegap [ant][index+3] =true; // forward
    1141           0 :                       tmp_timegap [ant][index+2] =true;
    1142           0 :                       tmp_timegap [ant][index+1] =true;
    1143           0 :                       tmp_timegap [ant][index  ] =true; // center (detected point)
    1144           0 :                       tmp_timegap [ant][index-1] =true;
    1145           0 :                       tmp_timegap [ant][index-2] =true;
    1146             :                    }
    1147           0 :                    else if (index == size-3) {
    1148           0 :                       tmp_timegap [ant][index+2] =true;
    1149           0 :                       tmp_timegap [ant][index+1] =true;
    1150           0 :                       tmp_timegap [ant][index  ] =true; // center (detected point)
    1151           0 :                       tmp_timegap [ant][index-1] =true;
    1152           0 :                       tmp_timegap [ant][index-2] =true;
    1153           0 :                       tmp_timegap [ant][index-3] =true; // backward
    1154             :                    }
    1155           0 :                    else if (index == size-2) {
    1156           0 :                       tmp_timegap [ant][index+1] =true;
    1157           0 :                       tmp_timegap [ant][index  ] =true; // center (detected point)
    1158           0 :                       tmp_timegap [ant][index-1] =true;
    1159           0 :                       tmp_timegap [ant][index-2] =true;
    1160           0 :                       tmp_timegap [ant][index-3] =true; // backward
    1161             :                    }
    1162           0 :                    else if (index == size-1) {
    1163           0 :                       tmp_timegap [ant][index  ] =true; // center (detected point)
    1164           0 :                       tmp_timegap [ant][index-1] =true;
    1165           0 :                       tmp_timegap [ant][index-2] =true;
    1166           0 :                       tmp_timegap [ant][index-3] =true; // backward
    1167             :                    }
    1168             :                }
    1169             :              }
    1170           0 :         }
    1171             :     }
    1172             : 
    1173             :     //+
    1174             :     // Minimum Condition Inspection
    1175             :     // (N >=4)
    1176             :     //-
    1177             : 
    1178           0 :     for(uInt ant=0; ant <numAnt; ant++)
    1179             :     {
    1180           0 :         uInt s_time =tmp_time[ant].size();
    1181           0 :         uInt s_dir  =tmp_dir [ant].size();
    1182           0 :         if ((s_time < 4)||(s_dir < 4))
    1183             :         {
    1184             :           // Warning .. //
    1185           0 :             LogIO os(LogOrigin("SplineInterpolation", "init()", WHERE));
    1186             :             os << LogIO::WARN << "INSUFFICIENT NUMBER OF POINTING DATA, must be ge. 4 "
    1187           0 :                << "Alternatively, Linear Interpolation will be used. " << LogIO::POST;
    1188             : 
    1189           0 :            stsCofficientReady = false; // initially in-usable ..
    1190           0 :            return;
    1191           0 :         }
    1192             :     }
    1193             : 
    1194             :     //+
    1195             :     // SDPosInterpolator Objct
    1196             :     //   - create Coefficient Table -
    1197             :     //-
    1198           0 :       SDPosInterpolator  sdp (tmp_time, tmp_dir);
    1199             : 
    1200             :     // Obtain Coeff (copy object) //
    1201           0 :       coeff_ = sdp.getSplineCoeff();
    1202             : 
    1203             :     // Table Active ..
    1204           0 :       stsCofficientReady = true;
    1205             : 
    1206             :     // In case COEFF inspection needed, locate dump here. //
    1207             : 
    1208           0 : }
    1209             : 
    1210             : //+
    1211             : // Interpolation Calculation
    1212             : //-
    1213           0 : casacore::Vector<casacore::Double> SplineInterpolation::calculate(uInt index,
    1214             :                                                                   Double dt,
    1215             :                                                                   uInt antID )
    1216             : {
    1217           0 :     debuglog << "SplineInterpolation::calculate()" << debugpost;
    1218             : 
    1219             :     // Error check //
    1220           0 :     uInt arraySize = coeff_[antID].size();
    1221           0 :     if(  index >= arraySize)
    1222             :     {
    1223             :         // Exception handling is to be here... //
    1224           0 :         stringstream ss;
    1225           0 :         ss << "Bugcheck. Requested Index is too large." << endl;
    1226           0 :         throw AipsError(ss.str());
    1227           0 :     }
    1228             :     // Coefficient //
    1229             : 
    1230           0 :     auto pCoeff_1 =coeff_[antID][index][0];
    1231           0 :     auto pCoeff_2 =coeff_[antID][index][1];
    1232             : 
    1233           0 :     Double a0 = pCoeff_1[0];
    1234           0 :     Double a1 = pCoeff_1[1];
    1235           0 :     Double a2 = pCoeff_1[2];
    1236           0 :     Double a3 = pCoeff_1[3];
    1237             : 
    1238           0 :     Double b0 = pCoeff_2[0];
    1239           0 :     Double b1 = pCoeff_2[1];
    1240           0 :     Double b2 = pCoeff_2[2];
    1241           0 :     Double b3 = pCoeff_2[3];
    1242             : 
    1243             :    // Spline Calc //
    1244             : 
    1245           0 :     Double Xs =  (((0* dt + a3)*dt + a2)*dt + a1)*dt + a0;
    1246           0 :     Double Ys =  (((0* dt + b3)*dt + b2)*dt + b1)*dt + b0;
    1247             : 
    1248             :     // Return //
    1249             : 
    1250           0 :     Vector<Double> outval(2);
    1251           0 :     outval[0] = Xs;
    1252           0 :     outval[1] = Ys;
    1253             : 
    1254           0 :     debuglog << "SplineInterpolation::calculate() Normal return." << debugpost;
    1255             : 
    1256           0 :     return outval;
    1257             : 
    1258           0 : }
    1259             : 
    1260             : 
    1261             : }  //# NAMESPACE CASA - END

Generated by: LCOV version 1.16