LCOV - code coverage report
Current view: top level - flagging/Flagging - FlagAgentTimeFreqCrop.cc (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 0 330 0.0 %
Date: 2024-10-28 15:53:10 Functions: 0 13 0.0 %

          Line data    Source code
       1             : //# FlagAgentTimeFreqCrop.cc: This file contains the implementation of the FlagAgentTimeFreqCrop class.
       2             : //#
       3             : //#  CASA - Common Astronomy Software Applications (http://casa.nrao.edu/)
       4             : //#  Copyright (C) Associated Universities, Inc. Washington DC, USA 2011, All rights reserved.
       5             : //#  Copyright (C) European Southern Observatory, 2011, All rights reserved.
       6             : //#
       7             : //#  This library is free software; you can redistribute it and/or
       8             : //#  modify it under the terms of the GNU Lesser General Public
       9             : //#  License as published by the Free software Foundation; either
      10             : //#  version 2.1 of the License, or (at your option) any later version.
      11             : //#
      12             : //#  This library is distributed in the hope that it will be useful,
      13             : //#  but WITHOUT ANY WARRANTY, without even the implied warranty of
      14             : //#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             : //#  Lesser General Public License for more details.
      16             : //#
      17             : //#  You should have received a copy of the GNU Lesser General Public
      18             : //#  License along with this library; if not, write to the Free Software
      19             : //#  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
      20             : //#  MA 02111-1307  USA
      21             : //# $Id: $
      22             : 
      23             : #include <flagging/Flagging/FlagAgentTimeFreqCrop.h>
      24             : 
      25             : // Polynomial-fitting classes
      26             : #include <casacore/scimath/Functionals/Polynomial.h>
      27             : #include <casacore/scimath/Fitting.h>
      28             : #include <casacore/scimath/Fitting/LinearFit.h>
      29             : #include <casacore/scimath/Fitting/GenericL2Fit.h>
      30             : 
      31             : using namespace casacore;
      32             : namespace casa { //# NAMESPACE CASA - BEGIN
      33             : 
      34             : // TODO : Get rid of this macro ?
      35             : #define MIN(a,b) ((a)<=(b) ? (a) : (b))
      36             : 
      37           0 : FlagAgentTimeFreqCrop::FlagAgentTimeFreqCrop(FlagDataHandler *dh, Record config, Bool writePrivateFlagCube, Bool flag):
      38           0 :                 FlagAgentBase(dh,config,ANTENNA_PAIRS,writePrivateFlagCube,flag)
      39             : {
      40           0 :         setAgentParameters(config);
      41             : 
      42             :         // Request loading polarization map to FlagDataHandler
      43           0 :         flagDataHandler_p->setMapPolarizations(true);
      44           0 : }
      45             : 
      46           0 : FlagAgentTimeFreqCrop::~FlagAgentTimeFreqCrop()
      47             : {
      48             :         // Compiler automagically calls FlagAgentBase::~FlagAgentBase()
      49           0 : }
      50             : 
      51           0 : void FlagAgentTimeFreqCrop::setAgentParameters(Record config)
      52             : {
      53           0 :         logger_p->origin(LogOrigin(agentName_p,__FUNCTION__,WHERE));
      54             :         int exists;
      55             : 
      56           0 :         exists = config.fieldNumber ("timecutoff");
      57           0 :         if (exists >= 0)
      58             :         {
      59           0 :                 if( config.type(exists) != TpDouble && config.type(exists) != TpFloat  && config.type(exists) != TpInt )
      60             :                 {
      61           0 :                          throw( AipsError ( "Parameter 'timecutoff' must be of type 'double'" ) );
      62             :                 }
      63             :                 
      64           0 :                 time_cutoff_p = config.asDouble("timecutoff");
      65             :         }
      66             :         else
      67             :         {
      68           0 :                 time_cutoff_p = 4.0;
      69             :         }
      70             : 
      71           0 :         *logger_p << logLevel_p << " timecutoff is " << time_cutoff_p << LogIO::POST;
      72             : 
      73           0 :         exists = config.fieldNumber ("freqcutoff");
      74           0 :         if (exists >= 0)
      75             :         {
      76           0 :                 if( config.type(exists) !=  TpDouble && config.type(exists) != TpFloat   && config.type(exists) != TpInt )
      77             :                 {
      78           0 :                          throw( AipsError ( "Parameter 'freqcutoff' must be of type 'double'" ) );
      79             :                 }
      80             :                 
      81           0 :                 freq_cutoff_p = config.asDouble("freqcutoff");
      82             :         }
      83             :         else
      84             :         {
      85           0 :                 freq_cutoff_p = 3.0;
      86             :         }
      87             : 
      88           0 :         *logger_p << logLevel_p << " freqcutoff is " << freq_cutoff_p << LogIO::POST;
      89             : 
      90           0 :         exists = config.fieldNumber ("maxnpieces");
      91           0 :         if (exists >= 0)
      92             :         {
      93           0 :                 if( config.type(exists) != TpInt )
      94             :                 {
      95           0 :                          throw( AipsError ( "Parameter 'maxnpieces' must be of type 'int'" ) );
      96             :                 }
      97             :                 
      98           0 :                 maxNPieces_p = config.asInt("maxnpieces");
      99             : 
     100           0 :                 if ((maxNPieces_p<1) or (maxNPieces_p>9))
     101             :                 {
     102           0 :                   throw ( AipsError (" Unsupported maxnpieces : " + String::toString(maxNPieces_p) + ". Supported values: 1-9") );
     103             :                 }
     104             :         }
     105             :         else
     106             :         {
     107           0 :                 maxNPieces_p = 7;
     108             :         }
     109             : 
     110           0 :         *logger_p << logLevel_p << " maxnpieces is " << maxNPieces_p << LogIO::POST;
     111             : 
     112           0 :         exists = config.fieldNumber ("timefit");
     113           0 :         if (exists >= 0)
     114             :         {
     115           0 :                 if( config.type(exists) != TpString )
     116             :                 {
     117           0 :                          throw( AipsError ( "Parameter 'timefit' must be of type 'string'" ) );
     118             :                 }
     119             :                 
     120           0 :                 timeFitType_p = config.asString("timefit");
     121           0 :                 if ((timeFitType_p.compare("line") != 0) and (timeFitType_p.compare("poly") != 0))
     122             :                 {
     123           0 :                          throw ( AipsError ("Unsupported timefit: " + timeFitType_p +". Supported modes: line,poly" ) );
     124             :                 }
     125             : 
     126             :         }
     127             :         else
     128             :         {
     129           0 :                 timeFitType_p = "line";
     130             :         }
     131             : 
     132           0 :         *logger_p << logLevel_p << " timefit is " << timeFitType_p << LogIO::POST;
     133             : 
     134           0 :         exists = config.fieldNumber ("freqfit");
     135           0 :         if (exists >= 0)
     136             :         {
     137           0 :                 if( config.type(exists) != TpString )
     138             :                 {
     139           0 :                          throw( AipsError ( "Parameter 'timefit' must be of type 'string'" ) );
     140             :                 }
     141             :                 
     142           0 :                 freqFitType_p = config.asString("freqfit");
     143             : 
     144           0 :                 if ((freqFitType_p.compare("line") != 0) and (freqFitType_p.compare("poly") != 0))
     145             :                 {
     146           0 :                          throw ( AipsError ("Unsupported freqfit: " + freqFitType_p +". Supported modes: line,poly" ) );
     147             :                 }
     148             :         }
     149             :         else
     150             :         {
     151           0 :                 freqFitType_p = "poly";
     152             :         }
     153             : 
     154           0 :         *logger_p << logLevel_p << " freqfit is " << freqFitType_p << LogIO::POST;
     155             : 
     156           0 :         exists = config.fieldNumber ("flagdimension");
     157           0 :         if (exists >= 0)
     158             :         {
     159           0 :                 if( config.type(exists) != TpString )
     160             :                 {
     161           0 :                          throw( AipsError ( "Parameter 'flagdimension' must be of type 'string'" ) );
     162             :                 }
     163             :                 
     164           0 :                 flagDimension_p = config.asString("flagdimension");
     165             : 
     166           0 :                 if ((flagDimension_p.compare("time") != 0) and (flagDimension_p.compare("freq") != 0)
     167           0 :                                 and (flagDimension_p.compare("timefreq") != 0) and (flagDimension_p.compare("freqtime") != 0))
     168             :                 {
     169           0 :                          throw ( AipsError ("Unsupported flagdimension: " + flagDimension_p +". Supported modes: time,freq,timefreq,freqtime" ) );
     170             :                 }
     171             :         }
     172             :         else
     173             :         {
     174           0 :                 flagDimension_p = "freqtime";
     175             :         }
     176             : 
     177           0 :         *logger_p << logLevel_p << " flagdimension is " << flagDimension_p << LogIO::POST;
     178             : 
     179           0 :         exists = config.fieldNumber ("halfwin");
     180           0 :         if (exists >= 0)
     181             :         {
     182           0 :                 if( config.type(exists) != TpInt )
     183             :                 {
     184           0 :                          throw( AipsError ( "Parameter 'halfwin' must be of type 'int'" ) );
     185             :                 }
     186             :                 
     187           0 :                 halfWin_p = config.asInt("halfwin");
     188             : 
     189           0 :                 if ((halfWin_p < 1) or (halfWin_p > 3))
     190             :                 {
     191           0 :                          throw ( AipsError ("Unsupported halfwin: " + String::toString(halfWin_p) +". Supported values : 1,2,3" ) );
     192             :                 }
     193             :         }
     194             :         else
     195             :         {
     196           0 :                 halfWin_p = 1;
     197             :         }
     198             : 
     199           0 :         *logger_p << logLevel_p << " halfwin is " << halfWin_p << LogIO::POST;
     200             : 
     201           0 :         exists = config.fieldNumber ("usewindowstats");
     202           0 :         if (exists >= 0)
     203             :         {
     204           0 :                 if( config.type(exists) != TpString )
     205             :                 {
     206           0 :                          throw( AipsError ( "Parameter 'usewindowstats' must be of type 'string'" ) );
     207             :                 }
     208             :                 
     209           0 :                 winStats_p = config.asString("usewindowstats");
     210             : 
     211           0 :                 if ((winStats_p.compare("none") != 0) and (winStats_p.compare("sum") != 0)
     212           0 :                                 and (winStats_p.compare("std") != 0) and (winStats_p.compare("both") != 0))
     213             :                 {
     214           0 :                          throw ( AipsError ("Unsupported usewindowstats: " + winStats_p +". Supported modes : none,sum,std,both") );
     215             :                 }
     216             :         }
     217             :         else
     218             :         {
     219           0 :                 winStats_p = "none";
     220             :         }
     221             : 
     222           0 :         *logger_p << logLevel_p << " usewindowstats is " << winStats_p << LogIO::POST;
     223             : 
     224             : 
     225           0 :         return;
     226             : }
     227             : 
     228             : bool
     229           0 : FlagAgentTimeFreqCrop::computeAntennaPairFlags(const vi::VisBuffer2 & /*visBuffer*/,
     230             :                                                VisMapper &visibilities,
     231             :                                                FlagMapper &flags,
     232             :                                                Int /*antenna1*/,
     233             :                                                Int /*antenna2*/,
     234             :                                                vector<uInt> & /*rows*/)
     235             : {
     236             :         // Call 'fltBaseAndFlag' as specified by the user.
     237           0 :         if(flagDimension_p == String("time"))
     238             :           {
     239           0 :             fitBaseAndFlag(timeFitType_p,String("time"),visibilities,flags);
     240             :           }
     241           0 :         else if( flagDimension_p == String("freq") )
     242             :           {
     243           0 :             fitBaseAndFlag(freqFitType_p,String("freq"),visibilities,flags);
     244             :           }
     245           0 :         else if( flagDimension_p == String("timefreq") )
     246             :           {
     247           0 :             fitBaseAndFlag(timeFitType_p,String("time"),visibilities,flags);
     248           0 :             fitBaseAndFlag(freqFitType_p,String("freq"),visibilities,flags);
     249             :           }
     250             :         else // freqtime (default)
     251             :           {
     252           0 :             fitBaseAndFlag(freqFitType_p,String("freq"),visibilities,flags);
     253           0 :             fitBaseAndFlag(timeFitType_p,String("time"),visibilities,flags);
     254             :           }
     255             : 
     256           0 :         return false;
     257             : }
     258             : 
     259             : //----------------------------------------------------------------------------------------------------------
     260             : 
     261             : // fitBaseAndFlag
     262             : // Average the data along the axis not-specified by 'direction' to generate a vector along 'direction'.
     263             : // Fit a piece-wise polynomial of type 'fittype' along the axis specified by 'direction'
     264             : // Divide the unaveraged data by this fit, and iteratively flag outliers - use flags.applyFlag()
     265           0 : void FlagAgentTimeFreqCrop :: fitBaseAndFlag(String fittype, String direction, VisMapper &visibilities,FlagMapper &flags)
     266             : {    
     267             :   // Get shapes
     268           0 :   IPosition flagCubeShape = visibilities.shape();
     269           0 :   uInt nChannels = flagCubeShape(0);
     270           0 :   uInt nTimes = flagCubeShape(1);
     271             : 
     272             :   // Work variables
     273           0 :   Vector<Float> avgDat,avgFit;
     274           0 :   Vector<Bool> avgFlag;
     275           0 :   Vector<Int> mind(2);
     276           0 :   Float tol=4.0,mn=1.0,sd=0,tpsd=0.0,tpsum=0.0, mval=0.0;
     277           0 :   Int mcnt=0;
     278             :   
     279             :   // Decide which direction to fit the base polynomial
     280           0 :   if(direction==String("freq"))
     281             :     { 
     282           0 :       mind[0]=nChannels;  mind[1]=nTimes;
     283           0 :       tol=freq_cutoff_p;
     284             :     }
     285           0 :   else if(direction==String("time") )
     286             :     { 
     287           0 :       mind[0]=nTimes;  mind[1]=nChannels;
     288           0 :       tol=time_cutoff_p;
     289             :     }
     290             :   else
     291             :     {
     292           0 :       throw AipsError("Internal Error. Unrecognized axis direction for tfcrop : " + direction);
     293             :     }
     294             :   
     295             :   // ALLOC : Resize temp arrays to either nChannel or nTime
     296           0 :   avgDat.resize(mind[0]);   avgDat=0.0;   
     297           0 :   avgFit.resize(mind[0]);    avgFit=0.0;                
     298           0 :   avgFlag.resize(mind[0]);  avgFlag=false;
     299             : 
     300             :   // A way to tell if anything is non-zero in this piece.
     301           0 :   Bool allzeros=true; 
     302             :   
     303             :   // STEP 1 : 
     304             :   // For each element in the dominant direction (axis0)
     305             :   // calculate the mean across the other direction (axis1).
     306             :   // The output average data and flags will later be sent for poly fitting...
     307           0 :   for(int i0=0;i0<mind[0];i0++)      
     308             :     {
     309             :       // Calc the mean across axes1 (with flags)
     310           0 :       mval=0.0;mcnt=0;
     311           0 :       for(uInt i1=0;i1<(uInt) mind[1];i1++)
     312             :         {
     313           0 :           if(mind[0]==(Int) nChannels)// if i0 is channel, and i1 is time
     314             :             {
     315           0 :               if( ! ( flags.getModifiedFlags(i0,i1) ) ) //C// && usePreFlags_p ) )
     316             :                 {
     317           0 :                   mval += visibilities(i0,i1);
     318           0 :                   mcnt++;
     319             :                 }
     320             :             }
     321             :           else // if i1 is channel, and i0 is time
     322             :             {
     323           0 :               if( ! ( flags.getModifiedFlags(i1,i0) ) ) //C// && usePreFlags_p ) )
     324             :                 {
     325           0 :                   mval += visibilities(i1,i0);
     326           0 :                   mcnt++;
     327             :                 }
     328             :             }
     329             :         }//for i1
     330             : 
     331             :       // Fill in the mean value across axis1 for i0
     332           0 :       avgDat[i0] = mcnt ? mval/mcnt : 0.0;
     333             :       // Fill in whether all visibilities are zero or not
     334           0 :       avgFlag[i0] = mcnt ? false : true;
     335           0 :       if(! avgFlag[i0] ) allzeros=false;
     336             : 
     337             :     }// for i0
     338             : 
     339             : 
     340             :   // STEP 2 : 
     341             :   // If there are any non-zero unflagged values in the average, 
     342             :   //     fit polynomials and flag. Otherwise, return.  
     343           0 :   if(allzeros==false)
     344             :     {
     345             :       // Fit a piece-wise polynomial across axis0 (or do a line)
     346             :       // This fit is done to the average computed in the previous step.
     347           0 :       if(fittype == String("poly"))     // Piecewise Poly Fit
     348             :         {
     349           0 :           fitPiecewisePoly(avgDat,avgFlag,avgFit,maxNPieces_p,4);       
     350             :         }
     351             :       else  // Line Fit 
     352             :         {
     353           0 :           fitPiecewisePoly(avgDat,avgFlag,avgFit,1,1);  
     354             :         }
     355             :       
     356             :       // STEP 3 : 
     357             :       // Now, iterate through the data again and flag.
     358             :       // This time, iterate in reverse order : for each i1, get all i0
     359             :       // This is because 'avgFit' is of size mind[0], 
     360             :       //     and window stats are to be computed along i0
     361           0 :       for(uInt i1=0;i1<(uInt) mind[1];i1++)
     362             :         {
     363             :           // STEP 3A : Divide out the clean bandpass 
     364           0 :           avgDat=0,avgFlag=false; 
     365           0 :           for(int i0=0;i0<mind[0];i0++)
     366             :             {
     367           0 :               if(mind[0]==(Int) nChannels)// if i0 is channel, and i1 is time
     368             :                 {
     369           0 :                   avgFlag[i0] = flags.getModifiedFlags(i0,i1); //C// && usePreFlags_p;
     370           0 :                   if(avgFlag[i0]==false) avgDat[i0] = visibilities(i0,i1)/avgFit(i0);
     371             :                 }
     372             :               else // if i1 is channel, i0 is time
     373             :                 {
     374           0 :                   avgFlag[i0] = flags.getModifiedFlags(i1,i0); //C// && usePreFlags_p;
     375           0 :                   if(avgFlag[i0]==false) avgDat[i0] = visibilities(i1,i0)/avgFit(i0);
     376             :                 }
     377             :             }//for i0
     378             : 
     379             :           // STEP 3B
     380             :           // Flag outliers based on absolute deviation from the model
     381             :           // Do this as a robust fit
     382           0 :           Float temp=0;
     383           0 :           for(Int loop=0;loop<5;loop++)
     384             :             {
     385             :               // Calculate the standard-deviation of the normalized data w.r.to the mean
     386           0 :               sd = calcStd(avgDat,avgFlag,mn);
     387             :               
     388             :               // Flag if the data differs from mn=1 by N sd
     389           0 :               for(Int i0=0;i0<mind[0];i0++)
     390             :                 {
     391           0 :                   if(avgFlag[i0]==false && fabs(avgDat[i0]-mn) > tol*sd) avgFlag[i0]=true ;
     392             :                 }
     393             :               
     394             :               // Stop iterating if the deviation of the normalized data from the mean is less than 10%
     395           0 :               if(fabs(temp-sd) < (Double)0.1)break;
     396             :               // else go on for 5 iterations
     397           0 :               temp=sd;
     398             :             }//for loop
     399             :           
     400             :           // STEP 3C :
     401             :           // Additional flagging based on sliding-window statistics
     402             :           // Note : this step looks only at vis values, not existing flags.
     403           0 :           if(halfWin_p>0 && (winStats_p != "none") )
     404             :             {
     405             :               // Start and end the sliding windows halfWin from the ends.
     406           0 :               for(Int i0=halfWin_p;i0<mind[0]-halfWin_p;i0++)
     407             :                 {
     408           0 :                   tpsum=0.0;tpsd=0.0;
     409             :                   
     410             :                   // Flag point i0  if average of N points around i0 crosses N sd
     411           0 :                   if(winStats_p=="sum" || winStats_p=="both")
     412             :                     {
     413           0 :                       for(Int i=i0-halfWin_p; i<i0+halfWin_p+1; i++) tpsum += fabs(avgDat[i]-mn);
     414           0 :                       if(tpsum/(2*halfWin_p+1.0) > tol*sd ) avgFlag[i0]=true;
     415             :                     }
     416             :                   
     417             :                   // Flag point i0 if the N point std around i0 is larger then N sd
     418           0 :                   if(winStats_p=="std" || winStats_p=="both")
     419             :                     {
     420           0 :                       for(Int i=i0-halfWin_p; i<i0+halfWin_p+1; i++) tpsd += (avgDat[i]-mn) * (avgDat[i]-mn) ;
     421           0 :                       if(sqrt( tpsd / (2*halfWin_p+1.0) ) > tol*sd)  avgFlag[i0]=true ;
     422             :                     }
     423             :                   
     424             :                 }//for i0
     425             :             }// if winStats != none
     426             : 
     427             : 
     428             :           // STEP 3D :
     429             :           // Fill the flags into the FlagMapper 
     430             :           // Note : To minimize copies, we can call flags.applyFlag() directly from STEPS 3B and 3C,
     431             :           //           in addition to filling in avgFlag for STEP 3B.  
     432             :           //       However, the following ensures minimal calls to flags.applyFlag().
     433           0 :           for(Int i0=0;i0<mind[0];i0++)
     434             :             {
     435           0 :               if(mind[0]==(Int) nChannels) // if i0 is channel, and i1 is time
     436             :                 {
     437           0 :                   if(avgFlag[i0])
     438             :                   {
     439           0 :                           flags.applyFlag(i0,i1);
     440           0 :                           visBufferFlags_p += 1;
     441             :                   }
     442             :                 }
     443             :               else //if i1 is channel, and i0 is time
     444             :                 {
     445           0 :                   if(avgFlag[i0])
     446             :                   {
     447           0 :                           flags.applyFlag(i1,i0);
     448           0 :                           visBufferFlags_p += 1;
     449             :                   }
     450             :                 }
     451             :             }// for i0
     452             :           
     453             :         }//for i1
     454             :       
     455             :     }// if allzeros==false
     456             : 
     457             : 
     458           0 :   return;
     459             :   
     460           0 : }// end fitBaseAndFlag
     461             : 
     462             : 
     463             : 
     464             : /* Calculate the MEAN of 'vect' ignoring values flagged in 'flag' */
     465           0 : Float FlagAgentTimeFreqCrop :: calcMean(Vector<Float> &vect, Vector<Bool> &flag)
     466             : {
     467           0 :   Float mean=0;
     468           0 :   Int cnt=0;
     469           0 :   for(uInt i=0;i<vect.nelements();i++)
     470           0 :     if(flag[i]==false)
     471             :       {
     472           0 :         mean += vect[i];
     473           0 :         cnt++;
     474             :       }
     475           0 :   if(cnt==0) cnt=1;
     476           0 :   return mean/cnt;
     477             : }
     478             : 
     479             : 
     480             : /* Calculate the variance of 'vect' w.r.to a given 'fit' 
     481             :  * ignoring values flagged in 'flag' 
     482             :  * Use  median ( data - median(data) )   as the estimator of variance
     483             :  */
     484           0 : Float FlagAgentTimeFreqCrop :: calcVar(Vector<Float> &vect, Vector<Bool> &flag, Vector<Float> &fit)
     485             : {
     486             :   //// Float var=0;
     487           0 :   uInt n=0,cnt=0;
     488           0 :   n = vect.nelements() < fit.nelements() ? vect.nelements() : fit.nelements();
     489           0 :   for(uInt i=0;i<n;i++)
     490             :     {
     491           0 :       if(flag[i]==false)cnt++;
     492             :     }
     493             :   
     494           0 :   Vector<Float> validvals(cnt);
     495           0 :   cnt=0;
     496           0 :   for(uInt i=0;i<n;i++)
     497             :     {
     498           0 :       if(flag[i]==false)
     499             :         {
     500           0 :           validvals[cnt] = fit[i] < (Double)1e-6 ? (Double)0.0 : fabs( (vect[i] - fit[i])/fit[i] );
     501           0 :           cnt++;
     502             :         }
     503             :     }
     504             :   
     505           0 :   Float med=0.0;
     506             :   
     507           0 :   if(validvals.nelements())
     508             :     {
     509           0 :       med = median(validvals,false);
     510             :       
     511             :       //cout << "validvals : " << validvals << endl;
     512             :       //cout << "median : " << med << endl;
     513             :       
     514           0 :       for(uInt i=0;i<validvals.nelements();i++)
     515           0 :         validvals[i] = fabs( validvals[i]-med );
     516             :       
     517           0 :       med = median(validvals,false);
     518             :       //cout << "median(data-median(data)) : " << med << endl;
     519             :     }
     520             :   
     521           0 :   return med;
     522           0 : }
     523             : 
     524             : 
     525             : 
     526             : /* Calculate the STANDARD DEVN. of 'vect' w.r.to a given 'fit' 
     527             :  * ignoring values flagged in 'flag' */
     528           0 : Float FlagAgentTimeFreqCrop :: calcStd(Vector<Float> &vect, Vector<Bool> &flag, Vector<Float> &fit)
     529             : {
     530           0 :   Float std=0;
     531           0 :   uInt n=0,cnt=0;
     532           0 :   n = vect.nelements() < fit.nelements() ? vect.nelements() : fit.nelements();
     533           0 :   for(uInt i=0;i<n;i++)
     534           0 :     if(flag[i]==false)
     535             :       {
     536           0 :         cnt++;
     537           0 :         std += (vect[i]-fit[i])*(vect[i]-fit[i]);
     538             :       }
     539           0 :   if(cnt==0) cnt=1;
     540           0 :   return sqrt(std/cnt);
     541             : }
     542             : 
     543             : 
     544             : /* Calculate the STANDARD DEVN. of 'vect' w.r.to a given mean 
     545             :  * ignoring values flagged in 'flag' */
     546           0 : Float FlagAgentTimeFreqCrop :: calcStd(Vector<Float> &vect, Vector<Bool> &flag, Float mean)
     547             : {
     548           0 :   Float std=0;
     549           0 :   uInt cnt=0;
     550           0 :   for(uInt i=0;i<vect.nelements();i++)
     551           0 :     if(flag[i]==false)
     552             :       {
     553           0 :         cnt++;
     554           0 :         std += (vect[i]-mean)*(vect[i]-mean);
     555             :       }
     556           0 :   return sqrt(std/cnt);
     557             : }
     558             : 
     559             : /* Fit Piecewise polynomials to 'data' and get the 'fit' */
     560           0 : void FlagAgentTimeFreqCrop :: fitPiecewisePoly(Vector<Float> &data, Vector<Bool> &flag, Vector<Float> &fit, uInt maxnpieces, uInt maxdeg)
     561             : {
     562           0 :   Int deg=0;//,start=0;
     563           0 :   Int left=0,right=0;
     564           0 :   Float sd,TOL=3;
     565           0 :   Vector<Float> tdata;
     566             :   
     567             :   // ALLOC : Another temp array to hold modified data
     568           0 :   tdata.resize(data.nelements());
     569           0 :   tdata = data;
     570             :   
     571           0 :   AlwaysAssert(data.nelements()==flag.nelements(), AipsError);    
     572             :   
     573             :   /* replace empty data values by adjacent values */
     574           0 :   for(uInt i=0;i<tdata.nelements();i++)
     575             :     {
     576           0 :       if(tdata[i]==0)
     577             :         {
     578           0 :           if(i==0)// find first non-zero value and set to that.
     579             :             {
     580           0 :               Int ind=0;
     581           0 :               for(uInt j=1;j<tdata.nelements();j++)
     582           0 :                 if(tdata[j]!=0){ind=j;break;}
     583           0 :               if(ind==0) tdata[i]=0;
     584           0 :               else tdata[i]=tdata[ind];
     585             :             }
     586             :           else// find next non-zero value and interpolate.
     587             :             {
     588           0 :               Int indr=0;
     589           0 :               for(uInt j=i+1;j<tdata.nelements();j++)
     590           0 :                 if(tdata[j]!=0){indr=j;break;}
     591           0 :               Int indl=-1;
     592           0 :               for(int j = i ; j >= 0 ; j--)
     593           0 :                 if(tdata[j]!=0){indl=j;break;}
     594             :               
     595           0 :               if(indl==-1 && indr==0) tdata[i]=0;
     596           0 :               if(indl>-1 && indr==0) tdata[i]=tdata[indl];
     597           0 :               if(indl==-1 && indr>0) tdata[i]=tdata[indr];
     598           0 :               if(indl>-1 && indr>0) tdata[i]=(tdata[indl]+tdata[indr])/2.0;
     599             :             }
     600             :         }
     601             :     }
     602             :   
     603             :   
     604             :   /* If there still are empty points (entire spectrum is flagged) flag it. */
     605           0 :   for(uInt i=0;i<tdata.nelements();i++)
     606           0 :     if(tdata[i]==0) 
     607             :       {
     608           0 :         flag[i]=true;
     609             :       }
     610             :   
     611           0 :   fit = tdata;
     612             :   
     613           0 :   Int psize=1;
     614           0 :   Int leftover=1,leftover_front=0,npieces=1;
     615             :   
     616           0 :   deg=1;
     617           0 :   npieces=1;
     618             :   
     619           0 :   for(uInt j=0;j<5;j++)
     620             :     {
     621           0 :       npieces = MIN(2*j+1, maxnpieces);
     622           0 :       if(j>1) {deg=2;}
     623           0 :       if(j>2) {deg=3;}
     624           0 :       deg = MIN(deg,(Int) maxdeg);
     625             :       
     626           0 :       psize = (int)(tdata.nelements()/npieces);
     627             :       //     cout << "Iter : " << j << " with Deg : " << deg << " and Piece-size : " << psize << endl;
     628             :       
     629           0 :       leftover = (int)(tdata.nelements() % npieces);
     630             :       
     631           0 :       leftover_front = (int)(leftover/2.0);
     632             :       
     633           0 :       left=0; right=tdata.nelements()-1;
     634           0 :       for(Int p=0;p<npieces;p++)
     635             :         {
     636           0 :           if(npieces>1)
     637             :             {
     638           0 :               left = leftover_front + p*psize;
     639           0 :               right = left + psize; 
     640             :               
     641           0 :               if(p==0) {left = 0; right = leftover_front + psize;}
     642           0 :               if(p==npieces-1) {right = tdata.nelements()-1;} 
     643             :             }
     644           0 :           if(deg==1) 
     645           0 :             lineFit(tdata,flag,fit,left,right);
     646             :           else 
     647             :             //lineFit(tdata,flag,fit,left,right);
     648           0 :             polyFit(tdata,flag,fit,left,right,deg);
     649             :         }
     650             :       
     651             :       /* Now, smooth the fit - make this nicer later */
     652             :       
     653           0 :       int winstart=0,winend=0;
     654           0 :       float winsum=0.0;
     655           0 :       int offset=2;
     656           0 :       for(uInt i=offset;i<tdata.nelements()-offset;i++)
     657             :         {
     658           0 :           winstart = i-offset;
     659           0 :           winend = i+offset;
     660           0 :           if(winstart<0)winstart=0;
     661           0 :           if(winend>=(int) tdata.nelements())winend=tdata.nelements()-1;
     662           0 :           if(winend <= winstart) break;
     663           0 :           winsum=0.0;
     664           0 :           for(uInt wi=winstart;wi<=(uInt) winend;++wi)
     665           0 :             winsum += fit[wi];
     666           0 :           fit[i] = winsum/(winend-winstart+1);
     667             :         }
     668             :       
     669             :       
     670             :       /* Calculate the STD of the fit */
     671           0 :       sd = calcStd(tdata,flag,fit);
     672           0 :       if(j>=2)  TOL=2;
     673           0 :       else TOL=3;
     674             :       
     675             :       
     676             :       /* Detect outliers */
     677           0 :       for(uInt i=0;i<tdata.nelements();i++)
     678             :         {
     679           0 :           if(tdata[i]-fit[i] > TOL*sd) 
     680           0 :             flag[i]=true;
     681             :         }
     682             :       
     683             :     } // for j
     684             :   
     685           0 : } // end of fitPiecewisePoly
     686             : 
     687             : 
     688             : 
     689             :   /* Fit a polynomial to 'data' from lim1 to lim2, of given degree 'deg', 
     690             :    * taking care of flags in 'flag', and returning the fitted values in 'fit' */
     691           0 : void FlagAgentTimeFreqCrop :: polyFit(Vector<Float> &data,Vector<Bool> &flag, Vector<Float> &fit, uInt lim1, uInt lim2,uInt deg)
     692             : {
     693           0 :   Vector<Double> x;
     694           0 :   Vector<Double> y;
     695           0 :   Vector<Double> sig;
     696           0 :   Vector<Double> solution;
     697             :   
     698           0 :   uInt cnt=0;
     699           0 :   for(uInt i=lim1;i<=lim2;i++)
     700           0 :     if(flag[i]==false) cnt++;
     701             :   
     702           0 :   if(cnt <= deg)
     703             :     {
     704           0 :       lineFit(data,flag,fit,lim1,lim2);
     705           0 :       return;
     706             :     }
     707             :   
     708             :   
     709           0 :   LinearFit<Double> fitter;
     710           0 :   Polynomial<Double> combination(deg);
     711             :   
     712           0 :   combination.setCoefficient(0,0.0);
     713           0 :   if (deg >= 1) combination.setCoefficient(1, 0.0);
     714           0 :   if (deg >= 2) combination.setCoefficient(2, 0.0);
     715           0 :   if (deg >= 3) combination.setCoefficient(3, 0.0);
     716           0 :   if (deg >= 4) combination.setCoefficient(4, 0.0);
     717             :   
     718             :   // ALLOC : Resize to the length of each 'piece' in the piecewise fit.
     719           0 :   x.resize(lim2-lim1+1);
     720           0 :   y.resize(lim2-lim1+1);
     721           0 :   sig.resize(lim2-lim1+1);
     722           0 :   solution.resize(deg+1);
     723             :   
     724           0 :   for(uInt i=lim1;i<=lim2;i++)
     725             :     {
     726           0 :       x[i-lim1] = i+1;
     727           0 :       y[i-lim1] = data[i];
     728           0 :       sig[i-lim1] = (flag[i]==true)?0:1;
     729             :     }
     730             :   
     731           0 :   fitter.asWeight(true);
     732           0 :   fitter.setFunction(combination);
     733           0 :   solution = fitter.fit(x,y,sig);
     734             :   
     735           0 :   for(uInt i=lim1;i<=lim2;i++)
     736             :     {
     737           0 :       fit[i]=0;
     738           0 :       for(uInt j=0;j<deg+1;j++)
     739           0 :         fit[i] += solution[j]*pow((double)(x[i-lim1]),(double)j);
     740             :     }
     741             :   
     742           0 : }
     743             : 
     744             : 
     745             : 
     746             : /* Fit a LINE to 'data' from lim1 to lim2, taking care of flags in 
     747             :  * 'flag', and returning the fitted values in 'fit' */
     748           0 : void FlagAgentTimeFreqCrop :: lineFit(Vector<Float> &data, Vector<Bool> &flag, Vector<Float> &fit, uInt lim1, uInt lim2)
     749             : {
     750           0 :   float Sx = 0, Sy = 0, Sxx = 0, Sxy = 0, S = 0, a, b, sd, mn;
     751             :   
     752           0 :   mn = calcMean(data, flag);
     753           0 :   sd = calcStd (data, flag, mn);
     754             :   
     755           0 :   for (uInt i = lim1; i <= lim2; i++)
     756             :     {
     757           0 :       if (flag[i] == false) // if unflagged
     758             :         {
     759           0 :           S += 1 / (sd * sd);
     760           0 :           Sx += i / (sd * sd);
     761           0 :           Sy += data[i] / (sd * sd);
     762           0 :           Sxx += (i * i) / (sd * sd);
     763           0 :           Sxy += (i * data[i]) / (sd * sd);
     764             :         }
     765             :     }
     766           0 :   a = (Sxx * Sy - Sx * Sxy) / (S * Sxx - Sx * Sx);
     767           0 :   b = (S * Sxy - Sx * Sy) / (S * Sxx - Sx * Sx);
     768             :   
     769           0 :   for (uInt i = lim1; i <= lim2; i++)
     770           0 :     fit[i] = a + b * i;
     771             :   
     772           0 : }
     773             : 
     774             : 
     775             : 
     776             : } //# NAMESPACE CASA - END
     777             : 
     778             : 

Generated by: LCOV version 1.16