//# CalInterp.cc: Implementation of Calibration Interpolation //# Copyright (C) 1996,1997,1998,1999,2000,2001,2002,2003 //# Associated Universities, Inc. Washington DC, USA. //# //# This library is free software; you can redistribute it and/or modify it //# under the terms of the GNU Library General Public License as published by //# the Free Software Foundation; either version 2 of the License, or (at your //# option) any later version. //# //# This library is distributed in the hope that it will be useful, but WITHOUT //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public //# License for more details. //# //# You should have received a copy of the GNU Library General Public License //# along with this library; if not, write to the Free Software Foundation, //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. //# //# Correspondence concerning AIPS++ should be addressed as follows: //# Internet email: aips2-request@nrao.edu. //# Postal address: AIPS++ Project Office //# National Radio Astronomy Observatory //# 520 Edgemont Road //# Charlottesville, VA 22903-2475 USA //# #include #include #include #include #include #include #include #include #include #include using namespace casacore; namespace casa { //# NAMESPACE CASA - BEGIN CalInterp::CalInterp(CalSet& cs, const String& timetype, const String& freqtype) : cs_(&cs), timeType_(timetype), freqType_(freqtype), spwMap_(cs.nSpw(),-1), spwOK_(cs.nSpw(),false), lastTime_(cs.nSpw(),-1.0e99), finit_(cs.nSpw(),false), nFreq_(cs.nSpw(),1), solFreq_(cs.nSpw(),NULL), datFreq_(cs.nSpw(),NULL), currSpw_(-1), currSlot_(cs.nSpw(),-1), exactTime_(false), ip4d_(cs.nSpw(),NULL), ip3d_(cs.nSpw(),NULL), ip2d_(cs.nSpw(),NULL), t0_(cs.nSpw(),0.0), tS_(cs.nSpw(),0.0), lastlo_(cs.nSpw(),-1), tAC_(cs.nSpw(),NULL), tPC_(cs.nSpw(),NULL), tCC_(cs.nSpw(),NULL), tOk_(cs.nSpw(),NULL), ch0_(cs.nSpw(),NULL), ef_(cs.nSpw(),NULL), df_(cs.nSpw(),NULL), fdf_(cs.nSpw(),NULL), fAC_(cs.nSpw(),NULL), fPC_(cs.nSpw(),NULL), fCC_(cs.nSpw(),NULL), fOk_(cs.nSpw(),NULL), verbose_(false) { if (verbose_) cout << "CalInterp::constructor" << endl; if (verbose_) cout << " timeType_ = " << timeType_ << endl; if (verbose_) cout << " freqType_ = " << freqType_ << endl; // Nominally, spwOK_ follows CalSet spwOK_ = cs_->spwOK(); // Allocate (zero-size) working arrays and shapes // (will resize non-trivially as needed) for (currSpw_=0;currSpw_(); tOk_[currSpw()] = new Cube(); tPC_[currSpw()] = new Array(); tCC_[currSpw()] = new Array(); fAC_[currSpw()] = new Array(); fOk_[currSpw()] = new Cube(); fPC_[currSpw()] = new Array(); fCC_[currSpw()] = new Array(); df_[currSpw()] = new Vector(); fdf_[currSpw()] = new Vector(); ch0_[currSpw()] = new Vector(); ef_[currSpw()] = new Vector(); } currSpw_=-1; }; CalInterp::~CalInterp() { if (verbose_) cout << "CalInterp::destructor" << endl; deflTimeC(); deflFreqC(); deflFreqA(); } Bool CalInterp::interpolate(const Double& time, const Int& spw, const Vector& /*freq*/) { if (verbose_) cout << endl << "CalInterp::interpolate()" << endl; // TODO: // - catch case where requested spw has no solutions // Assume no change, for starters Bool newInterp(false); // If spw has changed, re-map spw currSpw()=spw; newInterp = interpTime(time); // Interpolate in Freq // if (newInterp) interpFreq(freq); // Finalize interpolation finalize(); return newInterp; } Bool CalInterp::interpTime(const Double& time) { // Interpolate in Time if (verbose_) cout << "CalInterp::interpTime()" << endl; Bool newTime=false; // assume no new calculations needed Bool newSlot(false); if (time != lastTime() ) { lastTime()=time; // if not "nearest", must recalcuate time interp if ( !nearestT() ) newTime=true; // Find relevant time slot newSlot = findSlot(time); if (newSlot) newTime = true; if (!exactTime() && !nearestT()) updTimeCoeff(); } if (verbose_) cout << " " << boolalpha << "newTime = " << newTime << " " << "newSlot = " << newSlot << " " << "currSlot() = " << currSlot() << " " << "fieldId = " << cs_->fieldId(currSpwMap())(currSlot()) << " " << "exactTime() = " << exactTime() << " " << "nearestT() = " << nearestT() << " " << endl; // newTime=true here if we need to re-calc time interp (*any* mode) if (newTime) { if ( nearestT() || exactTime() ) { exactTime_=true; // Behave as exact if (verbose_) cout << " " << "FOUND EXACT TIME!" << endl; // Just reference CalSet parameter IPosition blc(4,0,0,0,currSlot()); IPosition trc(4,nPar()-1,nChan()-1,nElem()-1,currSlot()); Cube t; t.reference(csPar()(blc,trc).reform(IPosition(3,nPar(),nChan(),nElem()))); r_.reference(t); tOk().reference(csParOK()(blc,trc).reform(IPosition(3,nPar(),nChan(),nElem()))); } else { if (verbose_) cout << " " << "NON-EXACT TIME." << endl; // Do non-trivial interpolation // r_.resize(0,0,0); interpTimeCalc(time); } if (verbose_) cout << " CalInterp addr: " << r_.data() << endl; } return newTime; // signals whether new interp calc required } void CalInterp::interpFreq(const Vector& freq) { if (verbose_) cout << "CalInterp::interpFreq()" << endl; // Only if more than one cal channel is freq interp (potentially) necessary if (nChan() > 1) { // setup freq interp info (~no-op if already done) initFreqInterp(freq); // if all exact freqs, just reference time interp result: if ( allEQ(ef(),true) ) { // un-reference r r.resize(); } else { // do non-trivial freq interpolation // ensure correct info available from time interpolation calcAPC(); // update coeffs updFreqCoeff(); // do freq interp calc interpFreqCalc(); } } } Bool CalInterp::findSlot(const Double& time) { if (verbose_) cout << "CalInterp::findSlot()" << endl; Int slot(-1); Bool newSlot(false); // Assume no change // If only one slot, we've found it if (nTime()==1) { slot=0; exactTime_=true; // More than one slot, find the right one: } else { Vector timelist(csTimes()); if (exactTime_) newSlot=true; // Behave as nearest outside absolute range of available calibration // to avoid wild extrapolation, else search for the correct soln slot if (timetimelist(nTime()-1)) { // After last timestamp, use last slot as nearest one slot=nTime()-1; exactTime_=true; } else // Find index in timelist where time would be: slot=binarySearch(exactTime_,timelist,time,nTime(),0); // cout << "time = " << time << " slot = " << slot << " nTime() = " << nTime() << endl; // If not already an exact match... if ( !exactTime_ ) { // identify this time via index just prior if (slot>0) slot--; // If nearest, fine-tune slot to actual nearest: if ( timeType()=="nearest" ) { exactTime_=true; // Nearest behaves like exact match if (slot!=nTime()-1 && (timelist(slot+1)-time) < (time-timelist(slot)) ) slot++; } else { // linear modes require one later slot if (slot==nTime()-1) slot--; } } } newSlot = (slot!=currSlot()); if (newSlot) { currSlot_(currSpw_)=slot; } return newSlot; } void CalInterp::updTimeCoeff() { if (verbose_) cout << "CalInterp::updTimeCoeff()" << endl; if ( currSlot() != lastlo() ) { lastlo()=currSlot(); // Resize Coefficient arrays IPosition ip4s(4,2,nPar(),nChan(),nElem()); IPosition ip3s(3,nPar(),nChan(),nElem()); tAC().resize(ip4s); tOk().resize(); // ensure not referencing csParOK! tOk().resize(ip3s); if ( timeType()=="linear") tPC().resize(ip4s); else if (timeType()=="aipslin") tCC().resize(ip4s); // Time ref/step for this interval t0()=csTimes()(currSlot()); tS()=csTimes()(currSlot()+1)-t0(); // For indexing parameter cache IPosition lo(4,0,0,0,currSlot()), hi(4,0,0,0,currSlot()+1); IPosition ref(4,0,0,0,0), slope(4,1,0,0,0); for (Int ielem=0;ielem C::pi) pslope-=(2*C::pi); else if (pslope < -C::pi) pslope+=(2*C::pi); tPC()(slope) = pslope; } else if (timeType()=="aipslin") { tCC()(ref) = csPar()(lo); tCC()(slope) = csPar()(hi)-tCC()(ref); } } else { tAC()(ref)=1.0; tAC()(slope)=0.0; if (timeType()=="linear") { tPC()(ref)=0.0; tPC()(slope)=0.0; } else if (timeType()=="aipslin") { tCC()(ref)=Complex(1.0,0.0); tCC()(slope)=Complex(0.0,0.0); } } } } } } } void CalInterp::interpTimeCalc(const Double& time) { if (verbose_) cout << "CalInterp::interpTimeCalc()" << endl; // TODO: // a. Use matrix math instead of loops? (tOk() usage?) // Fractional time interval for this timestamp Float dt( Float( (time-t0())/tS() ) ); // Ensure intermediate results cache is properly sized and ref'd if (tA_.nelements()==0) { tA_.resize(nPar(),nChan(),nElem()); a.reference(tA_); ok.reference(tOk()); if (timeType()=="linear") { tP_.resize(nPar(),nChan(),nElem()); p.reference(tP_); c.resize(); } else if (timeType()=="aipslin") { tC_.resize(nPar(),nChan(),nElem()); c.reference(tC_); p.resize(); } } IPosition ref(4,0,0,0,0),slope(4,1,0,0,0); for (Int ielem=ref(3)=slope(3)=0; ielem0.0) tC_(ipar,ichan,ielem) = tCtmp/abs(tCtmp); else tC_(ipar,ichan,ielem) = Complex(1.0); } } else { tA_(ipar,ichan,ielem) = 1.0; if (timeType()=="linear") { tP_(ipar,ichan,ielem) = 0.0; } else if (timeType()=="aipslin") { tC_(ipar,ichan,ielem) = Complex(1.0,0.0); } } // tOk() } // ipar } // ichan } // ielem if (verbose_) { cout << "tA_ = " << tA_.nonDegenerate() << endl; if (timeType()=="linear") cout << "tP_ = " << tP_.nonDegenerate() << endl; else if (timeType()=="aipslin") cout << "tC_ = " << tC_.nonDegenerate() << endl; } } void CalInterp::initFreqInterp(const Vector freq) { if (verbose_) cout << "CalInterp::initFreqInterp()" << endl; // Initialize freq interpolation if // a. not yet initialized (first time thru), or, // b. # of requested frequencies not equal to previous, or, // (c. # of requested freqs same, but freqs different --- NYI) if (nFreq() != Int(freq.nelements()) || !allEQ(freq,datFreq()) ) finit()=false; if (!finit()) { // Remember number of requested frequencies nFreq() = freq.nelements(); // Remember the frequencies: datFreq() = freq; ch0().resize(nFreq()); ch0()=-1; ef().resize(nFreq()); ef()=false; if (nChan()==1) { // one-to-many case (e.g., G) // need not support non-trivial freq interpolation ch0()=0; ef()=true; } else { // many-to-many case (e.g., B) // support non-trivial freq interpolation if some non-exact freqs // Fill ref ch indices for each input freq: Int ichan(0); for (Int i=0;i0 && abs(freq(i)-csFreq()(ichan-1))0) ichan--; if (ichan==nChan()-1) ichan--; } } ch0()(i)=ichan; } // Fill in frac freq info if some non-exact freqs if ( !allEQ(ef(),true) ) { df().resize(nFreq()); df()=0.0; fdf().resize(nFreq()); fdf()=0.0; // Fill in frac freq info for (Int i=0;i rp,ip; rPart(tC_,rp); iPart(tC_,ip); // NEED TO CHECK for tA_=0 here! rp/=tA_; ip/=tA_; r.resize(); // drop reference to nearest cached solution } else if (timeType()=="linear") { // a ok, need c tC_.resize(nPar(),nChan(),nElem()); Array rp,ip; rPart(tC_,rp); iPart(tC_,ip); rp = cos(tP_); ip = sin(tP_); } } } void CalInterp::updFreqCoeff() { if (verbose_) cout << "CalInterp::updFreqCoeff()" << endl; // Resize Coefficient arrays (no-op if already correct size) ip4d()(2)=ip2d()(0)=nFreq(); fAC().resize(ip4d()); fOk().resize(ip3d()); if ( timeType()=="linear") fPC().resize(ip4d()); else if (timeType()=="aipslin") fCC().resize(ip4d()); // For indexing parameter cache IPosition lo(3,0,0,0), hi(3,0,0,0); IPosition ref(4,0,0,0,0), slope(4,1,0,0,0); for (Int ielem=0;ielem C::pi) pslope-=(2*C::pi); else if (pslope < -C::pi) pslope+=(2*C::pi); fPC()(slope) = pslope; } else if (freqType()=="aipslin") { fCC()(ref) = tC_(lo); fCC()(slope) = tC_(hi)-tC_(lo); } } else { fAC()(ref)=1.0; fAC()(slope)=0.0; if (timeType()=="linear") { fPC()(ref)=0.0; fPC()(slope)=0.0; } else if (timeType()=="aipslin") { fCC()(ref)=Complex(1.0,0.0); fCC()(slope)=Complex(0.0,0.0); } } // fOk() } // ipar } // !ef()(ichan) } // ichan } // ielem } void CalInterp::interpFreqCalc() { if (verbose_) cout << "CalInterp::interpFreqCalc()" << endl; // TODO: // a. Use matrix math instead of loops? (fOk(), ef() usage?) fA_.resize(nPar(),nFreq(),nElem()); a.reference(fA_); ok.reference(fOk()); if (freqType()=="linear") { fP_.resize(nPar(),nFreq(),nElem()); p.reference(fP_); c.resize(); } else if (freqType()=="aipslin") { fC_.resize(nPar(),nFreq(),nElem()); c.reference(fC_); p.resize(); } IPosition ref(4,0,0,0,0),slope(4,1,0,0,0); for (Int ielem=ref(3)=slope(3)=0; ielem 0 ) { // if we did phase interp, shape and set r/i parts of r_ // cout << "CalInterp::finalize(): pppppp" << endl; c.resize(p.shape()); Array rp,ip; rPart(c,rp); iPart(c,ip); rp = a*cos(p); ip = a*sin(p); } else if (c.nelements() > 0) { // just reference c Array rp,ip; rPart(c,rp); iPart(c,ip); rp*=a; ip*=a; } r_.reference(c); } // make public by reference r.reference(r_); ok.reference(tOk()); } // Deflate in-focus time interpolation coeff cache void CalInterp::deflTimeC() { for (Int ispw=0; ispw& in, Array& out) { IPosition ip1(in.shape()); IPosition ip2(1,2); ip2.append(ip1); out.takeStorage(ip2,(Float*)(in.data()),SHARE); } void CalInterp::part(const Array& c, const Int& which, Array& f) { IPosition ip1(c.shape()); Array asfl; asFloatArr(c,asfl); IPosition ip2(asfl.shape()); IPosition blc(ip2), trc(ip2); blc=0; trc-=1; blc(0)=trc(0)=which; f.reference(asfl(blc,trc).reform(ip1)); } void CalInterp::setSpwOK() { for (Int i=0;i-1) spwOK_(i) = cs_->spwOK()(spwMap(i)); else spwOK_(i) = cs_->spwOK()(i); // cout << "CalInterp::spwOK() (spwmap) = " << boolalpha << spwOK() << endl; } } //# NAMESPACE CASA - END