Skip to content
Snippets Groups Projects
THcHelicity.cxx 18.1 KiB
Newer Older
//*-- Author :    Julie Roche, November 2010
// this is a modified version of THaGOHelicity.C
////////////////////////////////////////////////////////////////////////
//
// THcHelicity
//
// Helicity of the beam from QWEAK electronics in delayed mode
//    +1 = plus,  -1 = minus,  0 = unknown
//
// Also supports in-time mode with delay = 0
// 
////////////////////////////////////////////////////////////////////////

#include "THcHelicity.h"

#include "THaApparatus.h"
#include "THaEvData.h"
#include "THcGlobals.h"
#include "THcParmList.h"
#include "TH1F.h"
#include "TMath.h"
#include <iostream>

using namespace std;

//_____________________________________________________________________________
THcHelicity::THcHelicity( const char* name, const char* description,
				    THaApparatus* app ):
  hcana::ConfigLogging<THaHelicityDet>( name, description, app ), 
  fnQrt(-1), fHelDelay(8), fMAXBIT(30)
{
  //  for( Int_t i = 0; i < NHIST; ++i )
  //    fHisto[i] = 0;
  //  memset(fHbits, 0, sizeof(fHbits));

}

//_____________________________________________________________________________
THcHelicity::THcHelicity()
  : hcana::ConfigLogging<THaHelicityDet>(),fnQrt(-1), fHelDelay(8), fMAXBIT(30)
{
  // Default constructor for ROOT I/O

  //  for( Int_t i = 0; i < NHIST; ++i )
  //    fHisto[i] = 0;
}

//_____________________________________________________________________________
THcHelicity::~THcHelicity() 
{
  DefineVariables( kDelete );

  // for( Int_t i = 0; i < NHIST; ++i ) {
  //   delete fHisto[i];
  // }
}

//_____________________________________________________________________________
THaAnalysisObject::EStatus THcHelicity::Init(const TDatime& date) {
  // Call `Setup` before everything else.
  Setup(GetName(), GetTitle());

  fFirstEvProcessed = kFALSE;
  fActualHelicity = kUnknown;
  fPredictedHelicity = kUnknown;

  // Call initializer for base class.
  // This also calls `ReadDatabase` and `DefineVariables`.
  EStatus status = THaDetector::Init(date);
  if (status) {
    fStatus = status;
    return fStatus;
  }

  fStatus = kOK;
  return fStatus;
}

//_____________________________________________________________________________
void THcHelicity::Setup(const char* name, const char* description) {
  // Prefix for parameters in `param` file.
  string kwPrefix = string(GetApparatus()->GetName()) + "_" + name;
  std::transform(kwPrefix.begin(), kwPrefix.end(), kwPrefix.begin(), ::tolower);
  fKwPrefix = kwPrefix;
}

//_____________________________________________________________________________
Int_t THcHelicity::ReadDatabase( const TDatime& date )
{

  _logger->info("In THcHelicity::ReadDatabase");
  //cout << "In THcHelicity::ReadDatabase" << endl;
  // Read general HelicityDet database values (e.g. fSign)
  //  Int_t st = THaHelicityDet::ReadDatabase( date );
  //  if( st != kOK )
  //    return st;

  // Read readout parameters (ROC addresses etc.)
  Int_t st = THcHelicityReader::ReadDatabase( GetDBFileName(), GetPrefix(),
					date, fQWEAKDebug );
  if( st != kOK )
      return st;

  fSign = 1;			// Default helicity sign
  fRingSeed_reported_initial = 0; // Initial see that should predict reported
                                // helicity of first quartet.
  fFirstCycle = -1; // First Cycle that starts a quad (0 to 3)
  fFreq = 29.5596;
  fHelDelay=8;

  DBRequest list[]= {
    //	  {"_hsign", &fSign, kInt, 0, 1},
    {"helicity_delay", &fHelDelay, kInt, 0, 1},
    {"helicity_freq", &fFreq, kDouble, 0, 1},
    //    {"helicity_seed", &fRingSeed_reported_initial, kInt, 0, 1},
    //    {"helicity_cycle", &fFirstCycle, kInt, 0, 1},
    {0}
  };

  gHcParms->LoadParmValues(list, "");

  fMAXBIT=30;

  fTIPeriod = 250000000.0/fFreq;

  // maximum of event in the pattern, for now we are working with quartets
  //  Int_t localpattern[4]={1,-1,-1,1}; 
  // careful, the first value here should always +1
  //  for(int i=0;i<fQWEAKNPattern;i++)
  //    {
  //      fPatternSequence.push_back(localpattern[i]);
  //    }
  HWPIN=kTRUE;

  fQuartet[0]=fQuartet[1]=fQuartet[2]=fQuartet[3]=0;

  if (fFirstCycle>=0 && fRingSeed_reported_initial!=0) {
    // Set the seed for predicted reported and predicted actual
  } else {
    // Initialize mode to find quartets and then seed
  }

  return kOK;
}

//_____________________________________________________________________________

void THcHelicity::MakePrefix()
{
 THaDetector::MakePrefix();
}
//_____________________________________________________________________________
Int_t THcHelicity::DefineVariables( EMode mode )
{
  // Initialize global variables

  _logger->info("Called THcHelicity::DefineVariables with mode == {}", mode);
  //cout << "Called THcHelicity::DefineVariables with mode == "
  //     << mode << endl;

  if( mode == kDefine && fIsSetup ) return kOK;
  fIsSetup = ( mode == kDefine );

  // Define standard variables from base class
  THaHelicityDet::DefineVariables( mode );

  const RVarDef var[] = {
    { "nqrt",     "position of cycle in quartet",          "fnQrt" },
    { "hel",      "actual helicity for event",             "fActualHelicity" },
    { "helrep",   "reported helicity for event",           "fReportedHelicity" },
    { "helpred",  "predicted reported helicity for event", "fPredictedHelicity" },
    { "mps", "In MPS blanking period", "fMPS"},
    { 0 }
  };
  //cout << "Calling THcHelicity DefineVarsFromList" << endl;
  _logger->info("Calling THcHelicity DefineVarsFromList");
  return DefineVarsFromList( var, mode );
}
//_____________________________________________________________________________

void THcHelicity::PrintEvent(Int_t evtnum)
{

  cout<<" ++++++ THcHelicity::Print ++++++\n";

  cout<<" +++++++++++++++++++++++++++++++++++++\n";

  return;
}

//_____________________________________________________________________________
Int_t THcHelicity::Begin( THaRunBase* )
{
  THcHelicityReader::Begin();

  //  fHisto[0] = new TH1F("hel.seed","hel.seed",32,-1.5,30.5);
  //  fHisto[1] = new TH1F("hel.error.code","hel.error.code",35,-1.5,33.5);
 
  return 0;
}

//_____________________________________________________________________________
//void THcHelicity::FillHisto()
//{
//  fHisto[0]->Fill(fRing_NSeed);
//  fHisto[1]->Fill(fErrorCode);
//  return;
//}
//_____________________________________________________________________________
void THcHelicity::SetErrorCode(Int_t error)
{
 // used as a control for the helciity computation
  // 2^0: if the reported number of events in a  pattern is larger than fQWEAKNPattern
  // 2^1: if the offset between the ring reported value and TIR value is not fOffsetTIRvsRing
  // 2^2: if the reported time in the ring is 0
  // 2^3: if the predicted reported helicity doesn't match the reported helicity in the ring
  // 2^4: if the helicity cannot be computed using the SetHelicity routine
  // 2^5: if seed is being gathered

  if(fErrorCode==0)
    fErrorCode=(1<<error);
  // only one reported error at the time

  return;
}

//_____________________________________________________________________________
void THcHelicity::Clear( Option_t* opt ) 
{
  // Clear event-by-event data

  THaHelicityDet::Clear(opt);
  THcHelicityReader::Clear(opt);
  fEvtype = 0;

  fQrt=0;
  fErrorCode=0;

  return;
}

//_____________________________________________________________________________
Int_t THcHelicity::Decode( const THaEvData& evdata )
{

  // Decode Helicity data.
  // Return 1 if helicity was assigned, 0 if not, <0 if error.

  Int_t err = ReadData( evdata ); // from THcHelicityReader class
  if( err ) {
    Error( Here("THcHelicity::Decode"), "Error decoding helicity data." );
    return err;
  }

  fReportedHelicity = (fIsHelp?(fIsHelm?kUnknown:kPlus):(fIsHelm?kMinus:kUnknown));
  fMPS = fIsMPS?1:0;
  if(fHelDelay == 0) {		// If no delay actual=reported (but zero if in MPS)
    fActualHelicity = fIsMPS?kUnknown:fReportedHelicity;
    return 0;
  }
  if(fFirstEvProcessed) {	// Normal processing
    Int_t missed = 0;
    //    Double_t elapsed_time = (fTITime - fFirstEvTime)/250000000.0;
    if(fIsMPS) {
      fFoundMPS = kTRUE;
      Int_t missed = TMath::Nint(floor((fTITime-fLastMPSTime)/fTIPeriod));
      //      cout << fTITime/250000000.0 << " " << fNCycle << " MPS " << fReportedHelicity <<endl;
      if(missed <= 1) {
	fLastMPSTime = fTITime;
	fIsNewCycle = kTRUE;
	fActualHelicity = kUnknown;
	fPredictedHelicity = kUnknown;
      } // If there is a skip, pass it off to next non MPS event
      // Need to also check here for missed MPS's
      //      cout << "Found MPS" << endl;
      // check for Nint((time-last)/period) > 1
    } else if (fFoundMPS) {	//
      if(fTITime - fLastMPSTime > fTIPeriod) { // We missed MPS periods
	Int_t missed = TMath::Nint(floor((fTITime-fLastMPSTime)/fTIPeriod));
	if(missed > 1) {
	  //	  cout << "Missed " << missed << " MPSes" << endl;
	  Int_t newNCycle = fNCycle + missed -1; // How many cycles really missed
	  Int_t quartets_missed = (newNCycle-fFirstCycle)/4 - (fNCycle-fFirstCycle)/4;
	  for(Int_t i=0;i<quartets_missed;i++) { // Advance the seeds.
	    fRingSeed_reported = RanBit30(fRingSeed_reported);
	    fRingSeed_actual = RanBit30(fRingSeed_actual);
	  }
	  //	  cout << "Cycles " << fNCycle << " " << newNCycle << " " << fFirstCycle 
	  //	       << " skipped " << quartets_missed << " quartets" << endl;
	  fNCycle = newNCycle;
	  // Need to reset fQuartet to reflect where we are based on the current
	  // reported helicity.  So we don't fail quartet testing.
	  // But only do this if we are calibrated.
	  if(fNBits >= fMAXBIT) {
	    if (((fNCycle - fFirstCycle)%2)==1) {
	      //	    fQuartet[2] = fQuartet[3] = -fQuartet[0];
	      //	    fQuartet[1] = fQuartet[0];
	      fQuartet[0] = fReportedHelicity;
	      fQuartet[1] = fQuartet[2] = -fQuartet[0];
	    } else {
	      //	    fQuartet[1] = fQuartet[2] = -fQuartet[0];
	      //	    fQuartet[3] = fQuartet[0];
	      fQuartet[0] = fQuartet[1] = -fReportedHelicity;
	      fQuartet[2] = -fQuartet[1];
	    }
	  } else {
	    fQuartet[0] = fReportedHelicity;
	    fQuartet[1] = 0;
	  }
	}
	fLastMPSTime += missed*fTIPeriod;
	fIsNewCycle = kTRUE;
	fLastReportedHelicity = fReportedHelicity;
      }
      if(fIsNewCycle) {
	fQuartet[3]=fQuartet[2]; fQuartet[2]=fQuartet[1]; fQuartet[1]=fQuartet[0];
	fQuartet[0]=fReportedHelicity;
	fNCycle++;
	if((fNCycle-fFirstCycle)%4 == 3) {// Test if last in a quartet
	  if((abs(fQuartet[0]+fQuartet[3]-fQuartet[1]-fQuartet[2])==4)) {
	    if(!fFoundQuartet) {
	      //	      fFirstCycle = fNCycle - 3;
              _logger->info("Quartet potentially found, starting at cycle {} - event {}", fFirstCycle, evdata.GetEvNum());
              //cout << "Quartet potentially found, starting at cycle " << fFirstCycle << " - event "
              //     << evdata.GetEvNum() << endl;
              fFoundQuartet = kTRUE;
	    }
	  } else {
	    if(fNCycle - fFirstCycle > 4) { // Not at start of run.  Reset
              _logger->warn("Lost quartet sync at cycle {} - event {}", fNCycle,evdata.GetEvNum());
              _logger->warn("{} {} {} {}",fQuartet[0],fQuartet[1],fQuartet[2],fQuartet[3]);
              //cout << "Lost quartet sync at cycle " << fNCycle << " - event " << evdata.GetEvNum()
              //     << endl;
              //cout << fQuartet[0] << " " << fQuartet[1] << " " << fQuartet[2] << " " << fQuartet[3]
              //     << endl;

              fFirstCycle += 4*((fNCycle-fFirstCycle)/4); // Update, but don't change phase
	    }
	    fFoundQuartet = kFALSE;
            fNBits        = 0;
            _logger->info("Searching for first of a quartet at cycle {} - event {}", fFirstCycle, evdata.GetEvNum());
            //cout << "Searching for first of a quartet at cycle "
            //     << " " << fFirstCycle << " - event " << evdata.GetEvNum() << endl;
            //cout << fQuartet[0] << " " << fQuartet[1] << " " << fQuartet[2] << " " << fQuartet[3]
            //     << endl;
            _logger->info("{} {} {} {}", fQuartet[0], fQuartet[1], fQuartet[2], fQuartet[3]);
	    fFirstCycle++;
	  }
	}
	// Load the actual helicity.  Calibrate if not calibrated.
	fActualHelicity = kUnknown;
	LoadHelicity(fReportedHelicity, fNCycle, missed);
	fLastReportedHelicity = fReportedHelicity;
	fIsNewCycle = kFALSE;
	//	cout << fTITime/250000000.0 << " " << fNCycle << " " << fReportedHelicity << endl;
	//	cout << fNCycle << ": " << fReportedHelicity << " "
	//	     << fPredictedHelicity << " " << fActualHelicity << endl;
      }
      // Ignore until a MPS Is found
    }
  } else {
    //cout << "Initializing" << endl;
    _logger->info("Initializing Helicity");
    fLastReportedHelicity = fReportedHelicity;
    fActualHelicity = kUnknown;
    fPredictedHelicity = kUnknown;
    fFirstEvTime = fTITime;
    fLastEvTime = fTITime;
    fLastMPSTime = fTITime;  // Not necessarily during the MPS
    fNCycle = 0;
    fFirstEvProcessed = kTRUE;
    fFoundMPS = kFALSE;
    fFoundQuartet = kFALSE;
    fIsNewCycle = kFALSE;
    fNBits = 0;
  }

  return 0;
}

//_____________________________________________________________________________
Int_t THcHelicity::End( THaRunBase* )
{
  // End of run processing. Write histograms.
  THcHelicityReader::End();

  //  for( Int_t i = 0; i < NHIST; ++i )
  //    fHisto[i]->Write();

  return 0;
}
//_____________________________________________________________________________
void THcHelicity::SetDebug( Int_t level )
{
  // Set debug level of this detector as well as the THcHelicityReader 
  // helper class.

  THaHelicityDet::SetDebug( level );
  fQWEAKDebug = level;
}
//_____________________________________________________________________________
void THcHelicity::LoadHelicity(Int_t reportedhelicity, Int_t cyclecount, Int_t missedcycles)
{
  //  static const char* const here = "THcHelicity::LoadHelicity";
  int quartetphase = (cyclecount-fFirstCycle)%4;
  fnQrt = quartetphase;
  if(missedcycles > 1) {	// If we missed windows
    if(fNBits< fMAXBIT) {	// and we haven't gotten the seed, start over
      fNBits = 0;
      return;
    }
  }
  if(!fFoundQuartet) {		// Wait until we have found quad phase before starting
    return;			// to calibrate
  }
  if(quartetphase == 0) { // Start of a quad
    if(fNBits < fMAXBIT) {
      if(fNBits == 0) {
	_logger->info("Start calibrating at cycle {}" ,cyclecount );
	//cout << "Start calibrating at cycle " << cyclecount << endl;
	fRingSeed_reported = 0;
      }
      if(fReportedHelicity == kPlus) {
	fRingSeed_reported = ((fRingSeed_reported<<1) | 1) & 0x3FFFFFFF;
      } else {
	fRingSeed_reported = (fRingSeed_reported<<1) & 0x3FFFFFFF;
      }
      fNBits++;
      if(fReportedHelicity == kUnknown) {
	fNBits = 0;
	fRingSeed_reported = 0;
      } else if (fNBits==fMAXBIT) {

	_logger->info("Seed Found {} at cycle {} with first cycle {}" , fRingSeed_reported , cyclecount , fFirstCycle );
	//cout << "Seed Found " << hex << fRingSeed_reported << dec << " at cycle " << cyclecount << " with first cycle " << fFirstCycle << endl;
	Int_t backseed = GetSeed30(fRingSeed_reported);
        _logger->info("Seed at cycle {} should be {}", fFirstCycle , backseed);
	//cout << "Seed at cycle " << fFirstCycle << " should be " << hex << backseed << dec << endl;
      }
      fActualHelicity = kUnknown;
    } else if (fNBits >= fMAXBIT) {
      fRingSeed_reported = RanBit30(fRingSeed_reported);
      if(fNBits==fMAXBIT) {
	fRingSeed_actual = fRingSeed_reported;
	for(Int_t i=0;i<fHelDelay/4; i++) {
	  fRingSeed_actual = RanBit30(fRingSeed_actual);
	}
	fNBits++;
      } else {
	fRingSeed_actual = RanBit30(fRingSeed_actual);
      }
      fActualHelicity = (fRingSeed_actual&1)?kPlus:kMinus;
      fPredictedHelicity = (fRingSeed_reported&1)?kPlus:kMinus;
      //      if(fTITime/250000000.0 > 380.0) cout << fTITime/250000000.0 << " " << fNCycle << " " << hex <<
      //					fRingSeed_reported << " " << fRingSeed_actual << dec << endl;
      if(fReportedHelicity != fPredictedHelicity) {
	_logger->warn("Helicity prediction failed {} {} {}", fReportedHelicity, fPredictedHelicity, fActualHelicity);
	//cout << "Helicity prediction failed " << fReportedHelicity << " "
	//     << fPredictedHelicity << " " << fActualHelicity << endl;
	fNBits = 0;		// Need to reaquire seed
	fActualHelicity = kUnknown;
	fPredictedHelicity = kUnknown;
      }
    }
    fQuartetStartHelicity = fActualHelicity;
    fQuartetStartPredictedHelicity = fPredictedHelicity;
  } else { 			// Not the beginning of a quad
    if(fNBits>=fMAXBIT) {
      fActualHelicity = (quartetphase==0||quartetphase==3)?
	fQuartetStartHelicity:-fQuartetStartHelicity;
      fPredictedHelicity = (quartetphase==0||quartetphase==3)?
	fQuartetStartPredictedHelicity:-fQuartetStartPredictedHelicity;
    }
  }
  return;
}
//_____________________________________________________________________________
Int_t  THcHelicity::RanBit30(Int_t ranseed)
{
  
  UInt_t bit7    = (ranseed & 0x00000040) != 0;
  UInt_t bit28   = (ranseed & 0x08000000) != 0;
  UInt_t bit29   = (ranseed & 0x10000000) != 0;
  UInt_t bit30   = (ranseed & 0x20000000) != 0;

  UInt_t newbit = (bit30 ^ bit29 ^ bit28 ^ bit7) & 0x1;

  
  if(ranseed<=0) {
    if(fQWEAKDebug>1)
      std::cerr<<"ranseed must be greater than zero!"<<"\n";

    newbit = 0;
  }
  ranseed =  ( (ranseed<<1) | newbit ) & 0x3FFFFFFF;
  //here ranseed is changed
  if(fQWEAKDebug>1)
    {
      cout<< "THcHelicity::RanBit30, newbit="<<newbit<<"\n";
    }

  return ranseed;

}
//_____________________________________________________________________________
Int_t  THcHelicity::GetSeed30(Int_t currentseed)
/* Back track the seed by 30 samples */
{
#if 1
  Int_t seed = currentseed;
  for(Int_t i=0;i<30;i++) {
    UInt_t bit1    = (seed & 0x00000001) != 0;
    UInt_t bit8    = (seed & 0x00000080) != 0;
    UInt_t bit29   = (seed & 0x10000000) != 0;
    UInt_t bit30   = (seed & 0x20000000) != 0;
    
    UInt_t newbit30 = (bit30 ^ bit29 ^ bit8 ^ bit1) & 0x1;
    seed = (seed >> 1) | (newbit30<<29);
  }
#else
  Int_t bits = currentseed;
  Int_t seed=0;
  for(Int_t i=0;i<30;i++) {
    Int_t val;
    // XOR at virtual position 0 and 29
    if(i==0) {
      val = ((bits & (1<<(i)))!=0) ^ ((bits & (1<<(i+29)))!=0);
    } else {
      val = ((bits & (1<<(i)))!=0) ^ ((seed & (1<<(i-1)))!=0);
    }
    if(i<=1) {
      val = ((bits & (1<<(1-i)))!=0) ^ val;
    } else {
      val = ((seed & (1<<(i-2)))!=0) ^ val;
    }
    if(i<=22) {
      val = ((bits & (1<<(i-22)))!=0) ^ val;
    } else {
      val = ((seed & (1<<(i-23)))!=0) ^ val;
    }
    seed |= (val<<i);
  }
#endif
  return seed;
}

ClassImp(THcHelicity)