diff --git a/src/THcHelicityScaler.cxx b/src/THcHelicityScaler.cxx
index 058aa0714ee509efeccc9ecfa5130d95881e77fb..b18bf1c48fb6cb3000ff9828d8e415871d7258f0 100644
--- a/src/THcHelicityScaler.cxx
+++ b/src/THcHelicityScaler.cxx
@@ -5,17 +5,21 @@
 
 ~~~
 ~~~
-     THcHelcityScaler *hhelscaler = new THcHelicityScaler("H","HC helicity scalers");
-     // hscaler->SetDebugFile("HHelScaler.txt");
-     hhelscaler->SetROC(8);   // 5 for HMS defaults to 8 for SHMS
-     hhelscaler->SetBankID(0x9801); // Will default to this
-     gHaEvtHandlers->Add (hhelscaler);
+     THcHelcityScaler *phelscaler = new THcHelicityScaler("P","HC helicity scalers");
+     phelscaler->SetDebugFile("PHelScaler.txt");
+     phelscaler->SetROC(8);   // 5 for HMS defaults to 8 for SHMS
+     phelscaler->SetBankID(9801); // Will default to this
+     gHaEvtHandlers->Add (phelscaler);
 ~~~
-\author  
+\authors:  S. A. Wood (saw@jlab.org)
+           C. Yero (cyero@jlab.org)
+
 */
 
 //#include "THaEvtTypeHandler.h"
 #include "THcHelicityScaler.h"
+#include "GenScaler.h"
+#include "Scaler3801.h"
 #include "THaCodaData.h"
 #include "THaEvData.h"
 #include "THcGlobals.h"
@@ -43,20 +47,31 @@ using namespace Decoder;
 
 static const UInt_t ICOUNT    = 1;
 static const UInt_t IRATE     = 2;
-static const UInt_t ICURRENT = 3;
+static const UInt_t ICURRENT  = 3;
 static const UInt_t ICHARGE   = 4;
-static const UInt_t ITIME   = 5;
-static const UInt_t ICUT = 6;
+static const UInt_t ITIME     = 5;
+static const UInt_t ICUT      = 6;
 static const UInt_t MAXCHAN   = 32;
 static const UInt_t defaultDT = 4;
 
+
 THcHelicityScaler::THcHelicityScaler(const char *name, const char* description)
   : THaEvtTypeHandler(name,description),
     fBankID(9801),
-    fUseFirstEvent(kTRUE),
-    fDelayedType(-1),
-    fBCM_Gain(0), fBCM_Offset(0)
+    fUseFirstEvent(kTRUE), fDelayedType(-1),
+    fBCM_Gain(0), fBCM_Offset(0), fBCM_SatOffset(0), fBCM_SatQuadratic(0), fBCM_delta_charge(0),
+    evcount(0), evcountR(0.0), ifound(0),
+    fNormIdx(-1), fNormSlot(-1),
+    dvars(0), dvarsFirst(0),
+    fScalerTree(0), fOnlyBanks(kFALSE),
+    fClockChan(-1), fLastClock(0)
 {
+
+  fRocSet.clear();
+  fModuleSet.clear();
+ 
+  //---------------------------------------------------------------------------
+  
   fROC=-1;
   fNScalerChannels = 32;
 
@@ -66,12 +81,24 @@ THcHelicityScaler::THcHelicityScaler(const char *name, const char* description)
   AddEvtType(5);
   AddEvtType(6);
   AddEvtType(7);
+  AddEvtType(129);
   SetDelayedType(129);
   
 }
 
 THcHelicityScaler::~THcHelicityScaler()
 {
+
+  if (!TROOT::Initialized()) {
+    delete fScalerTree;
+  }
+  Podd::DeleteContainer(scalers);
+  Podd::DeleteContainer(scalerloc);
+  delete [] dvars;
+  delete [] dvarsFirst;
+  delete [] fBCM_SatOffset;
+  delete [] fBCM_SatQuadratic;
+  delete [] fBCM_delta_charge;  
   delete [] fBCM_Gain;
   delete [] fBCM_Offset;
 
@@ -83,117 +110,205 @@ THcHelicityScaler::~THcHelicityScaler()
 
 Int_t THcHelicityScaler::End( THaRunBase* )
 {
-  // Process any delayed events in order received
 
-  cout << "THcHelicityScaler::End Analyzing " << fDelayedEvents.size() << " delayed helicity scaler events" << endl;
-    for(std::vector<UInt_t*>::iterator it = fDelayedEvents.begin();
+  // Process any delayed events in order received
+      
+  for(std::vector<UInt_t*>::iterator it = fDelayedEvents.begin();
       it != fDelayedEvents.end(); ++it) {
     UInt_t* rdata = *it;
-    AnalyzeBuffer(rdata);
+    AnalyzeBuffer(rdata);  
   }
-
+  evNumberR = -1;
+  
   for( vector<UInt_t*>::iterator it = fDelayedEvents.begin();
        it != fDelayedEvents.end(); ++it )
     delete [] *it;
   fDelayedEvents.clear();
+  
+  //Write the helicity variables to scaler tree
+  if (fScalerTree) { fScalerTree->Write(); }
 
-  //  cout << " -- Helicity Scalers -- " << endl;
+  
+  //Compute Scaler Asymmetries
+  /*
   for(Int_t i=0;i<fNScalerChannels;i++) {
     if(fScalerSums[i]>0.5) {
-      fAsymmetry[i] = (fHScalers[0][i]-fHScalers[1][i])/fScalerSums[i];
-      fAsymmetryError[i] = 2*TMath::Sqrt(fHScalers[0][i]*fHScalers[1][i]
-					*fScalerSums[i])
+      fScalAsymmetry[i] = (fHScalers[0][i]-fHScalers[1][i])/fScalerSums[i];
+      fScalAsymmetryError[i] = 2*TMath::Sqrt(fHScalers[0][i]*fHScalers[1][i]
+					 *fScalerSums[i])
 	/(fScalerSums[i]*fScalerSums[i]);
     } else {
-      fAsymmetry[i] = 0.0;
-      fAsymmetryError[i] = 0.0;
+      fScalAsymmetry[i] = 0.0;
+      fScalAsymmetryError[i] = 0.0;
+    }
+    
+  }
+  */
+
+    //------Compute Time Asymmetries-------
+
+  //C.Y. 12/15/2020  Time Asymmetry / Error Calculations (with scaler_current cut)
+      
+    if(fQuartetCount <= 1) {
+      fTimeAsymmetry       = -1000.;
+      fTimeAsymmetryError  = 0.0;
+    } else {
+      fTimeAsymmetry = fTimeAsymSum/fQuartetCount;  //normalize asymmetry to total number of quartets
+      if(fTimeAsymSum2 >= fQuartetCount*TMath::Power(fTimeAsymmetry,2)) {
+	fTimeAsymmetryError = TMath::Sqrt((fTimeAsymSum2 -
+						fQuartetCount*TMath::Power(fTimeAsymmetry,2)) /
+					       (fQuartetCount*(fQuartetCount-1)));
+      } else {
+	fTimeAsymmetryError = 0.0;
+      }
+    }
+
+  
+  
+  //------Compute Scaler Asymmetries-------
+
+  //C.Y. 12/15/2020  Scaler Asymmetry / Error Calculations (with scaler_current cut)
+  
+  for(Int_t i=0; i<fNScalerChannels; i++) {
+    
+    if(fQuartetCount <= 1) {
+      fScalAsymmetry[i]       = -1000.;
+      fScalAsymmetryError[i]  = 0.0;
+    } else {
+      fScalAsymmetry[i] = fScalAsymSum[i]/fQuartetCount;  //normalize asymmetry to total number of quartets
+      if(fScalAsymSum2[i] >= fQuartetCount*TMath::Power(fScalAsymmetry[i],2)) {
+	fScalAsymmetryError[i] = TMath::Sqrt((fScalAsymSum2[i] -
+						fQuartetCount*TMath::Power(fScalAsymmetry[i],2)) /
+					       (fQuartetCount*(fQuartetCount-1)));
+      } else {
+	fScalAsymmetryError[i] = 0.0;
+      }
     }
-    //    printf("%2d %12.0f %12.0f %12.0f %12.8f\n",i,fScalerSums[i],
-    //	   fHScalers[0][i],fHScalers[1][i],
-    //	   fAsymmetry[i]);
+
   }
-  //  cout << " ---------------------- " << endl;
 
-  // Compute Charge Asymmetries
+  
+  //------Compute Charge Asymmetries-------
+
+  //C.Y. 12/14/2020  Charge Asymmetry / Error Calculations (with scaler_current cut)
+  
+  //Set the helicity scaler module channels for each BCM
   std::map<std::string, Int_t> bcmindex;
-  bcmindex["BCM1"] = 0;
-  bcmindex["BCM2"] = 2;
-  //  bcmindex["Unser"] = 6;
-  bcmindex["BCM4A"] = 10;
-  bcmindex["BCM4B"] = 4;
-  bcmindex["BCM4C"] = 12;
-  //  bcmindex["1MHz"] = 8;
-  Int_t clockindex=8;
-  Double_t clockfreq=1000000.0;
-  Double_t pclock = fHScalers[0][clockindex];
-  Double_t mclock = fHScalers[1][clockindex];
-  cout << " -- Beam Charge Asymmetries -- " << endl;
+  bcmindex["BCM1_Hel.scal"] = 0;
+  bcmindex["BCM2_Hel.scal"] = 2;
+  bcmindex["Unser_Hel.scal"] = 6;
+  bcmindex["BCM4A_Hel.scal"] = 10;
+  bcmindex["BCM4B_Hel.scal"] = 4;
+  bcmindex["BCM4C_Hel.scal"] = 12;
+  //bcmindex["1MHz_Hel.scal"] = 8;
+  
+
+  //cout << endl << "---------------------- Beam Charge Asymmetries ---------------------- " << endl;
+  //cout << "  BCM        Total     Charge        Beam ON     Beam ON      Asymmetry" << endl;
+  //cout << " Name       Charge    Asymmetry       Charge    Asymmetry        Error"    << endl;
+  
   for(Int_t i=0;i<fNumBCMs;i++) {
-    if(bcmindex.find(fBCM_Name[i]) != bcmindex.end()) {
-      Int_t index=bcmindex[fBCM_Name[i]];
-      Double_t pcounts = fHScalers[0][index];
-      Double_t mcounts = fHScalers[1][index];
-      //      cout << index << " " << fBCM_Name[i] << " " << pcounts << " " << mcounts
-      //	   << " " << fBCM_Gain[i]
-      //      	   << " " << fBCM_Offset[i] << endl;
-      Double_t pcharge = (pcounts - (pclock/clockfreq)*fBCM_Offset[i])
-	/fBCM_Gain[i];
-      Double_t mcharge = (mcounts - (mclock/clockfreq)*fBCM_Offset[i])
-	/fBCM_Gain[i];
-      fCharge[i] = pcharge+mcharge;
-      if(fCharge[i]>0.0) {
-	fChargeAsymmetry[i] = (pcharge-mcharge)/fCharge[i];
+    
+    if(fQuartetCount <= 1) {
+      fChargeAsymmetry[i]       = -1000.;
+      fChargeAsymmetryError[i]  = 0.0;
+    } else {
+      fChargeAsymmetry[i] = fChargeAsymSum[i]/fQuartetCount;  //normalize charge asymmetry to total number of quartets (as the sum is for every quartet)
+
+      if(fChargeAsymSum2[i] >= fQuartetCount*TMath::Power(fChargeAsymmetry[i],2)) {
+	fChargeAsymmetryError[i] = TMath::Sqrt((fChargeAsymSum2[i] -
+						fQuartetCount*TMath::Power(fChargeAsymmetry[i],2)) /
+					       (fQuartetCount*(fQuartetCount-1)));
       } else {
-	fChargeAsymmetry[i] = 0.0;
+	fChargeAsymmetryError[i] = 0.0;
       }
-      printf("%6s %12.2f %12.8f\n",fBCM_Name[i].c_str(),fCharge[i],fChargeAsymmetry[i]);
     }
+
+    //printf("%6s %12.2f %12.8f %12.2f %12.8f %12.8f\n",fBCM_Name[i].c_str(),fCharge[i],
+    //	   fChargeAsymmetry[i],fChargeSum[i],asy,asyerr);
   }
-  fTime = (pclock+mclock)/clockfreq;
-  if(pclock+mclock>0) {
-    fTimeAsymmetry = (pclock-mclock)/(pclock+mclock);
-  } else {
-    fTimeAsymmetry = 0.0;
-  }
-  printf("TIME(s)%12.2f %12.8f\n",fTime,fTimeAsymmetry);
+
+
+  //Compute +/- helicity Times  (no BCM cut)
+  Double_t pclock = fHScalers[0][fClockChan];
+  Double_t mclock = fHScalers[1][fClockChan];
+
+  fTimePlus = pclock/fClockFreq;
+  fTimeMinus = mclock/fClockFreq;
+  //fTime = (pclock+mclock)/fClockFreq;
+  //if(pclock+mclock>0) {
+    //fTimeAsymmetry = (pclock-mclock)/(pclock+mclock);
+    //} else {
+    //  fTimeAsymmetry = 0.0;
+    //}
+  //printf("TIME(s)%12.2f %12.8f %12.2f\n",fTime, fTimeAsymmetry, fTimeSum);
+  
+
+  //Compute Helicity Trigger Asymmetries (no BCM cut)
   if(fNTriggersPlus+fNTriggersMinus > 0) {
     fTriggerAsymmetry = ((Double_t) (fNTriggersPlus-fNTriggersMinus))/(fNTriggersPlus+fNTriggersMinus);
   } else {
     fTriggerAsymmetry = 0.0;
   }
-  cout << " ----------------------------- " << endl;
+  
   return 0;
 }
 
 
 Int_t THcHelicityScaler::ReadDatabase(const TDatime& date )
 {
+    
   char prefix[2];
-  prefix[0]='g'; prefix[1]='\0';
-
+  prefix[0]='g';
+  prefix[1]='\0';
   fNumBCMs = 0;
-  string bcm_namelist;
   DBRequest list[]={
-		    {"NumBCMs",&fNumBCMs, kInt, 0, 1},
-		    {"BCM_Names",     &bcm_namelist,       kString},
-		    {0}
+    {"NumBCMs",&fNumBCMs, kInt, 0, 1},
+    {0}
   };
   gHcParms->LoadParmValues((DBRequest*)&list, prefix);
+  
   if(fNumBCMs > 0) {
     fBCM_Gain = new Double_t[fNumBCMs];
     fBCM_Offset = new Double_t[fNumBCMs];
+    fBCM_SatOffset = new Double_t[fNumBCMs];
+    fBCM_SatQuadratic = new Double_t[fNumBCMs];
+    fBCM_delta_charge= new Double_t[fNumBCMs];
+    
+    string bcm_namelist;
     DBRequest list2[]={
       {"BCM_Gain",      fBCM_Gain,         kDouble, (UInt_t) fNumBCMs},
       {"BCM_Offset",     fBCM_Offset,       kDouble,(UInt_t) fNumBCMs},
+      {"BCM_SatQuadratic",     fBCM_SatQuadratic,       kDouble,(UInt_t) fNumBCMs,1},
+      {"BCM_SatOffset",     fBCM_SatOffset,       kDouble,(UInt_t) fNumBCMs,1},
+      {"BCM_Names",     &bcm_namelist,       kString},
+      {"BCM_Current_threshold",     &fbcm_Current_Threshold,       kDouble,0, 1},
+      {"BCM_Current_threshold_index",     &fbcm_Current_Threshold_Index,       kInt,0,1},
       {0}
     };
+    
+    fbcm_Current_Threshold = 0.0;
+    fbcm_Current_Threshold_Index = 0;
+    for(Int_t i=0;i<fNumBCMs;i++) {
+      fBCM_SatOffset[i]=0.;
+      fBCM_SatQuadratic[i]=0.;
+    }
     gHcParms->LoadParmValues((DBRequest*)&list2, prefix);
-    fBCM_Name = vsplit(bcm_namelist);
+    vector<string> bcm_names = vsplit(bcm_namelist);
+    for(Int_t i=0;i<fNumBCMs;i++) {
+      fBCM_Name.push_back(bcm_names[i]+"_Hel.scal");
+      fBCM_delta_charge[i]=0.;
+    }
   }
-  
+  fTotalTime=0.;
+  fPrevTotalTime=0.;
+  fDeltaTime=-1.;
+   
   return kOK;
 }
+
 void THcHelicityScaler::SetDelayedType(int evtype) {
+
   /**
    * \brief Delay analysis of this event type to end.
    *
@@ -207,7 +322,11 @@ void THcHelicityScaler::SetDelayedType(int evtype) {
   
 Int_t THcHelicityScaler::Analyze(THaEvData *evdata)
 {
-
+  
+  //C.Y. | THcScalerEvtHandler::Analyze() uses this flag (which is forced to be 1),
+  //but as to why, it is beyond me. For consistency, I have also used it here.
+  Int_t lfirst=1;  
+   
   if ( !IsMyEvent(evdata->GetEvType()) ) return -1;
 
   if (fDebugFile) {
@@ -215,43 +334,99 @@ Int_t THcHelicityScaler::Analyze(THaEvData *evdata)
     *fDebugFile << "\nEnter THcHelicityScaler  for fName = "<<fName<<endl;
     EvDump(evdata);
   }
+  
+  
+  if (lfirst && !fScalerTree) {
+
+    lfirst = 0; 
+
+    //Assign a name to the helicity scaler tree
+    TString sname1 = "TSHel";
+    TString sname2 = sname1 + fName;
+    TString sname3 = fName + "  Scaler Data";
+
+    if (fDebugFile) {
+      *fDebugFile << "\nAnalyze 1st time for fName = "<<fName<<endl;
+      *fDebugFile << sname2 << "      " <<sname3<<endl;
+    }
+
+    //Create Scaler Tree
+    fScalerTree = new TTree(sname2.Data(),sname3.Data());
+    fScalerTree->SetAutoSave(200000000);
+
+    TString name, tinfo;
+
+    name = "evcount";
+    tinfo = name + "/D";
+    fScalerTree->Branch(name.Data(), &evcountR, tinfo.Data(), 4000);
+ 
+    name = "evNumber";
+    tinfo = name + "/D";
+    fScalerTree->Branch(name.Data(), &evNumberR, tinfo.Data(), 4000);
 
+    //C.Y. 12/02/2020 Added actual helicity to be stored in scaler tree
+    name = "actualHelicity";                                                                                                                      
+    tinfo = name + "/D";                                                                                                  
+    fScalerTree->Branch(name.Data(), &actualHelicityR, tinfo.Data(), 4000); 
+
+    //C.Y. 12/09/2020 Added quartetphase to be stored in scaler tree
+    name = "quartetPhase";
+    tinfo = name + "/D";                                                                                                  
+    fScalerTree->Branch(name.Data(), &quartetphaseR, tinfo.Data(), 4000);
+    
+    for (size_t i = 0; i < scalerloc.size(); i++) {
+      name = scalerloc[i]->name;
+      tinfo = name + "/D";
+      fScalerTree->Branch(name.Data(), &dvars[i], tinfo.Data(), 4000);
+    }
+    
+  }
+  
   UInt_t *rdata = (UInt_t*) evdata->GetRawDataBuffer();
   
   if(evdata->GetEvType() == fDelayedType) { // Save this event for processing later
     Int_t evlen = evdata->GetEvLength();
+    
     UInt_t *datacopy = new UInt_t[evlen];
     fDelayedEvents.push_back(datacopy);
     memcpy(datacopy,rdata,evlen*sizeof(UInt_t));
     return 1;
-  } else { 			// A normal event
+  }
+  
+  else { 			// A normal event
     if (fDebugFile) *fDebugFile<<"\n\nTHcHelicityScaler :: Debugging event type "<<dec<<evdata->GetEvType()<< " event num = " << evdata->GetEvNum() << endl<<endl;
     evNumber=evdata->GetEvNum();
+    evNumberR = evNumber;
+    
     Int_t ret;
-    if((ret=AnalyzeBuffer(rdata))) {
-      //
-    }
+    if((ret=AnalyzeBuffer(rdata))) 
+      {	
+	if (fDebugFile) *fDebugFile << "scaler tree ptr 1 "<<fScalerTree<<endl;
+	if (fDebugFile) *fDebugFile << "ret = "<< ret <<endl; 
+      }
+    
     return ret;
-  }
-
+  }  
+  
 }
 Int_t THcHelicityScaler::AnalyzeBuffer(UInt_t* rdata)
 {
-  fNTrigsInBuf = 0;
 
+  fNTrigsInBuf = 0;
+  
   // Parse the data, load local data arrays.
   UInt_t *p = (UInt_t*) rdata;
 
   UInt_t *plast = p+*p;		// Index to last word in the bank
   Int_t roc = -1;
   Int_t evlen = *p+1;
-
+  
   Int_t ifound=0;
   
   while(p<plast) {
     Int_t banklen = *p;
     p++;			  // point to header
-
+    
     if (fDebugFile) {
       *fDebugFile << "Bank: " << hex << *p << dec << " len: " << *(p-1) << endl;
     }
@@ -259,7 +434,7 @@ Int_t THcHelicityScaler::AnalyzeBuffer(UInt_t* rdata)
       if(evlen-*(p-1) > 1) { // Don't use overall event header
         roc = (*p>>16) & 0xf;
 	if(fDebugFile) *fDebugFile << "ROC: " << roc << " " << evlen << " " << *(p-1) << hex << " " << *p << dec << endl;
-//		cout << "ROC: " << roc << " " << evlen << " " << *(p-1) << hex << " " << *p << dec << endl;
+	// cout << "ROC: " << roc << " " << evlen << " " << *(p-1) << hex << " " << *p << dec << endl;
 	if(roc != fROC) { // Not a ROC with helicity scaler
 	  p+=*(p-1)-1;		// Skip to next ROC
 	}
@@ -274,7 +449,7 @@ Int_t THcHelicityScaler::AnalyzeBuffer(UInt_t* rdata)
       // At any point in the bank where the word is not a matching
       // header, we stop.
       UInt_t tag = (*p>>16) & 0xffff; // Bank ID (ROC #)
-  //          UInt_t num = (*p) & 0xff;
+      // UInt_t num = (*p) & 0xff;
       UInt_t *pnext = p+banklen;	// Next bank
       p++;			// First data word
       // If the bank is not a helicity scaler bank
@@ -284,7 +459,7 @@ Int_t THcHelicityScaler::AnalyzeBuffer(UInt_t* rdata)
 
       if (tag != fBankID) {
 	p = pnext;		// Fall through to end of the above else if
-	//	cout << "  Skipping to next bank" << endl;
+	// cout << "  Skipping to next bank" << endl;
 
       } else {
 	// This is a helicity scaler bank
@@ -296,20 +471,23 @@ Int_t THcHelicityScaler::AnalyzeBuffer(UInt_t* rdata)
 	  }
 	  
 	  fNTrigsInBuf = 0;
+
 	  // Save helcitiy and quad info for THcHelicity
 	  for (Int_t iev = 0; iev < nevents; iev++) {  // find number of helicity events in each bank
 	    Int_t index = fNScalerChannels*iev+1;
-	    AnalyzeHelicityScaler(p+index);
-	    //	    cout << "H: " << evNumber << endl;
+
+	    //C.Y. 11/26/2020 This methods extracts the raw helicity information
+	    AnalyzeHelicityScaler(p+index); 
 	  }
 	}
       }
-
+    
       while(p < pnext) {
 	Int_t nskip = 0;
 	if(fDebugFile) {
 	  *fDebugFile << "Scaler Header: " << hex << *p << dec;
 	}
+
 	if(nskip == 0) {
 	  if(fDebugFile) {
 	    *fDebugFile << endl;
@@ -333,12 +511,12 @@ Int_t THcHelicityScaler::AnalyzeBuffer(UInt_t* rdata)
   if (!ifound) return 0;
 
   return 1;
-
- 	
 }
 
 Int_t THcHelicityScaler::AnalyzeHelicityScaler(UInt_t *p)
 {
+
+
   Int_t hbits = (p[0]>>30) & 0x3; // quartet and helcity bits in scaler word
   Bool_t isquartet = (hbits&2) != 0;
   Int_t ispos = hbits&1;
@@ -348,6 +526,8 @@ Int_t THcHelicityScaler::AnalyzeHelicityScaler(UInt_t *p)
   fNTriggers++;
 
   Int_t quartetphase = (fNTriggers-fFirstCycle)%4;
+
+  
   if(fFirstCycle >= -10) {
     if(quartetphase == 0) {
       Int_t predicted = RanBit30(fRingSeed_reported);
@@ -377,7 +557,7 @@ Int_t THcHelicityScaler::AnalyzeHelicityScaler(UInt_t *p)
     if(isquartet) { // Helicity and quartet signal for next set of scalers
       fFirstCycle = fNTriggers - 3;
       quartetphase = (fNTriggers-fFirstCycle)%4;
-      //// Helicity at start of quartet is same as last of quartet, so we can start filling the seed
+      // Helicity at start of quartet is same as last of quartet, so we can start filling the seed
       fRingSeed_reported = ((fRingSeed_reported<<1) | ispos) & 0x3FFFFFFF;
       fNBits++;
       if(fNBits==30) {
@@ -386,11 +566,11 @@ Int_t THcHelicityScaler::AnalyzeHelicityScaler(UInt_t *p)
       }
     }
   }
-
+  
   if(fNBits>=30) {
     fRingSeed_actual = RanBit30(fRingSeed_reported);
     fRingSeed_actual = RanBit30(fRingSeed_actual);
-
+    
 #define DELAY9
 #ifdef DELAY9
     if(quartetphase == 3) {
@@ -402,6 +582,7 @@ Int_t THcHelicityScaler::AnalyzeHelicityScaler(UInt_t *p)
 	actualhelicity = -actualhelicity;
       }
     }
+    quartetphase = (quartetphase+1)%4;
 #else
     actualhelicity = (fRingSeed_actual&1)?+1:-1;
     if(quartetphase == 1 || quartetphase == 2) {
@@ -412,21 +593,426 @@ Int_t THcHelicityScaler::AnalyzeHelicityScaler(UInt_t *p)
     fRingSeed_actual = 0;
   }
 
+  //C.Y. 12/09/2020 : Pass quartet phase to scaler tree varable
+  quartetphaseR = quartetphase;
+  
+  //C.Y. 11/26/2020  The block of code below is used to extract the helicity information from each
+  //channel of the helicity scaler onto a variable to be stored in the scaler tree. For each channel,
+  //each helicity state (+, -, or undefined) is stored in a single varibale. Each helicity state
+  //is tagged to the corresponding scaler read via 'actualHelicityR' which is stored below..
+  
+  //C.Y. Assign actual helicity value to a variable to be written to tree (the value may be (0, +hel (+1), or -hel(-1))
+  //Where actualhelicity=0  is NOT the MPS.  It is zero when the actual helicity has not been determined.
+  actualHelicityR = actualhelicity;
+  
+  //C.Y. 11/26/2020  Loop over all 32 scaler channels for a specific helicity scaler module (SIS 3801)
+  for(Int_t i=0;i<fNScalerChannels;i++) {
+    
+    //C.Y. 11/26/2020 the count expression below gets the scaler raw helicity information (+, -, or MPS helicity states) for the ith channel
+    Int_t count = p[i]&0xFFFFFF; // Bottom 24 bits  equivalent of scalers->Decode()
+    fScalerChan[i] = count;        //pass the helicity raw information to each helicity scaler channel array element
+  }
+
+  
+  
+  //C.Y. 11/26/2020  The block of code below is used to get a cumulative sum of +/- helicity used
+  //for calculation of the cumulative beam charge asymmetry and other quantities in the ::End() method
   if(actualhelicity!=0) {
-    Int_t hindex = (actualhelicity>0)?0:1;
+
+    //index=0 (+ helicity), index=1 (- helicity)
+    Int_t hindex = (actualhelicity>0)?0:1;  
+    
+    //C.Y. 11/24/2020  increment the counter for either '+' or '-' helicity states
     (actualhelicity>0)?(fNTriggersPlus++):(fNTriggersMinus++);
+    
+    //C.Y. 11/24/2020  Loop over all 32 scaler channels for a specific helicity scaler module (SIS 3801)
     for(Int_t i=0;i<fNScalerChannels;i++) {
-      Int_t count = p[i]&0xFFFFFF; // Bottom 24 bits
+      
+      Int_t count = p[i]&0xFFFFFF; // Bottom 24 bits  equivalent of scalers->Decode()
+      
+      //Increment either the '+' (hindex=0) or '-' (hindex=1) helicity counts for each [i] scaler channel channel of a given module
       fHScalers[hindex][i] += count;
       fScalerSums[i] += count;
     }
   }
+
+  
+  
+  //Set the helicity scaler clock to define the time
+  fDeltaTime = fScalerChan[fClockChan]/fClockFreq;    //total clock counts / clock_frequency (1MHz) for a specific scaler read interval
+  fTotalTime = fPrevTotalTime + fDeltaTime;           //cumulative scaler time  
+  
+  if (fDeltaTime==0) {
+    cout << " *******************   Severe Warning ****************************" << endl;
+    cout << "       In THcHelicityScaler have found fDeltaTime is zero !!      " << endl;
+    cout << " ******************* Alert DAQ experts ***************************" << endl;
+    if (fDebugFile) *fDebugFile << " In THcHelicityScaler have found fDeltaTime is zero !!   " << endl;   
+  }
+  
+  fPrevTotalTime=fTotalTime; //set the current total time to the previous time for the upcoming read
+ 
+  //C.Y. Nov 27, 2020 : (below) code to write the helicity raw data to a variable
+  //and map the variable to the scaler location
+
+  Double_t scal_current=0;
+  //Loop over each scaler variable from the map
+  for (size_t i = 0; i < scalerloc.size(); i++)  {
+    size_t ivar = scalerloc[i]->ivar;
+    size_t idx = scalerloc[i]->index;  
+    size_t ichan = scalerloc[i]->ichan;
+
+    //ANALYZE 1ST SCALER READ SEPARATE (There is no previous read before this one)
+    if (evcount==0) {
+
+      //Loop over the scaler variable (ivar), helicity slot (idx), and slot channel (ichan) --> idx=0 (only one helicity module per spectrometer arm)
+      if ((ivar < scalerloc.size()) &&
+	  (idx < scalers.size()) &&
+	  (ichan < MAXCHAN)) {
+	
+	//If fUseFirstEvent=kTRUE (do not skip 1st read)
+	if(fUseFirstEvent){
+
+	  //Write scaler counts 
+	  if (scalerloc[ivar]->ikind == ICOUNT){
+	    dvars[ivar] = fScalerChan[ichan];
+	    dvarsFirst[ivar] = 0.0;          
+	  }
+
+	  //Write scaler time
+	  if (scalerloc[ivar]->ikind == ITIME){
+	    dvars[ivar] = fDeltaTime; 
+	    dvarsFirst[ivar] = 0.0;
+	  }
+
+	  //Write scaler rate
+	  if (scalerloc[ivar]->ikind == IRATE) {
+	    dvars[ivar] = (fScalerChan[ichan])/fDeltaTime;
+	    dvarsFirst[ivar] = 0.0;  
+	  }
+
+	  //Write either scaler current or scaler charge
+	  if(scalerloc[ivar]->ikind == ICURRENT || scalerloc[ivar]->ikind == ICHARGE){
+
+	    //Get BCM index
+	    Int_t bcm_ind=-1;
+	    for(Int_t itemp =0; itemp<fNumBCMs;itemp++)
+	      {		
+		size_t match = string(scalerloc[ivar]->name.Data()).find(string(fBCM_Name[itemp]));
+		if (match!=string::npos)
+		  {
+		    bcm_ind=itemp;
+		  }
+	      }
+
+	    //Calculate and write scaler current
+	    if (scalerloc[ivar]->ikind == ICURRENT) {
+
+	      //set default to zero
+	      dvars[ivar]=0.;
+	      //Check bcm index and calculate current in a temporary placeholder, "cur_temp"
+	      if (bcm_ind != -1) {
+		Double_t cur_temp=((fScalerChan[ichan])/fDeltaTime-fBCM_Offset[bcm_ind])/fBCM_Gain[bcm_ind];
+		cur_temp = cur_temp + fBCM_SatQuadratic[bcm_ind]*TMath::Max(cur_temp-fBCM_SatOffset[i],0.0);
+		//Assign the calculated scaler current to dvars
+		dvars[ivar]=cur_temp;		
+	      }
+	      //Check which bcm index to place a bcm current threshold cut later on. Assign the the beam current read to "scal_current" for later use.
+	      if (bcm_ind == fbcm_Current_Threshold_Index) {scal_current= dvars[ivar];}
+	    }
+
+	    //Calculate andd write scaler charge
+	    if (scalerloc[ivar]->ikind == ICHARGE) {
+	      //Check bcm index and calculate current in a temporary placeholder, "cur_temp", to determine the charge later on.
+	      if (bcm_ind != -1) {
+		Double_t cur_temp=((fScalerChan[ichan])/fDeltaTime-fBCM_Offset[bcm_ind])/fBCM_Gain[bcm_ind];
+		cur_temp=cur_temp+fBCM_SatQuadratic[bcm_ind]*TMath::Power(TMath::Max(cur_temp-fBCM_SatOffset[bcm_ind],0.0),2.0);
+		//Calculate the charge for this scaler read
+		fBCM_delta_charge[bcm_ind]=fDeltaTime*cur_temp;
+		//Assign the charge to dvars
+		dvars[ivar] = fBCM_delta_charge[bcm_ind];  
+	      }
+	    }
+	  } 
+	}
+	
+	//If user has set fUseFirstEvent=kFALSE (then use dvarsFirst to store the information for the 1st event, and leave dvars at 0.0)
+	//(The same calculations as above, but assign dvars=0.0, so that it does not count when written to the scaler tree)
+	else { //ifnotusefirstevent
+	  
+	  if (scalerloc[ivar]->ikind == ICOUNT) {	    
+	    dvarsFirst[ivar] = fScalerChan[ichan];  
+	    dvars[ivar] = 0.0;
+	  }
+	  
+	  if (scalerloc[ivar]->ikind == ITIME){
+	    dvarsFirst[ivar] = fDeltaTime; 
+	    dvars[ivar] = 0.0;
+	  }
+	  
+	  if (scalerloc[ivar]->ikind == IRATE)  {
+	    dvarsFirst[ivar] = (fScalerChan[ichan])/fDeltaTime;
+	    dvars[ivar] = 0.0;
+	  }
+	  
+	  if(scalerloc[ivar]->ikind == ICURRENT || scalerloc[ivar]->ikind == ICHARGE)
+	    {
+	      Int_t bcm_ind=-1;
+	      for(Int_t itemp =0; itemp<fNumBCMs;itemp++)
+		{		
+		  size_t match = string(scalerloc[ivar]->name.Data()).find(string(fBCM_Name[itemp]));
+		  if (match!=string::npos)
+		    {
+		      bcm_ind=itemp;
+		    }
+		}
+	      
+	      if (scalerloc[ivar]->ikind == ICURRENT) {
+
+		dvarsFirst[ivar] = 0.0;
+		dvars[ivar] = 0.0;
+		
+                if (bcm_ind != -1) {
+		  Double_t cur_temp=((fScalerChan[ichan])/fDeltaTime-fBCM_Offset[bcm_ind])/fBCM_Gain[bcm_ind];
+		  cur_temp=cur_temp+fBCM_SatQuadratic[bcm_ind]*TMath::Power(TMath::Max(cur_temp-fBCM_SatOffset[i],0.0),2.0);
+		  dvarsFirst[ivar] = cur_temp;
+		}
+		
+         	if (bcm_ind == fbcm_Current_Threshold_Index) scal_current= dvarsFirst[ivar];
+	      }
+	      
+	      if (scalerloc[ivar]->ikind == ICHARGE) {
+		
+		if (bcm_ind != -1) {
+		  Double_t cur_temp=((fScalerChan[ichan])/fDeltaTime-fBCM_Offset[bcm_ind])/fBCM_Gain[bcm_ind];
+		  cur_temp=cur_temp+fBCM_SatQuadratic[bcm_ind]*TMath::Power(TMath::Max(cur_temp-fBCM_SatOffset[bcm_ind],0.0),2.0);
+		  fBCM_delta_charge[bcm_ind]=fDeltaTime*cur_temp;
+		  dvarsFirst[ivar] = fBCM_delta_charge[bcm_ind];
+		}
+	      }
+	    }
+	}
+      }      
+      else {
+	cout << "THcHelicityScaler:: ERROR:: incorrect index "<<ivar<<"  "<<idx<<"  "<<ichan<<endl;
+      }
+    }
+
+    //Calculate Scaler Quantities for ALL OTHER SCALER READS (OTHER THAN THE FIRST READ)
+    else{ // evcount != 0
+    
+      if ((ivar < scalerloc.size()) &&
+	  (idx < scalers.size()) &&
+	  (ichan < MAXCHAN)) {
+	
+	if (scalerloc[ivar]->ikind == ICOUNT) {	  
+	  dvars[ivar] = fScalerChan[ichan];
+	  }
+	
+	if (scalerloc[ivar]->ikind == ITIME) {
+	  dvars[ivar] = fDeltaTime; 
+	}
+	
+	if (scalerloc[ivar]->ikind == IRATE) {
+	  dvars[ivar] =  fScalerChan[ichan]/fDeltaTime; 
+	}
+	
+	if(scalerloc[ivar]->ikind == ICURRENT || scalerloc[ivar]->ikind == ICHARGE)
+	  {
+	    Int_t bcm_ind=-1;
+	    for(Int_t itemp =0; itemp<fNumBCMs;itemp++)
+	      {		
+		size_t match = string(scalerloc[ivar]->name.Data()).find(string(fBCM_Name[itemp]));
+		if (match!=string::npos)
+		  {
+		    bcm_ind=itemp;
+		  }
+	      }
+	    if (scalerloc[ivar]->ikind == ICURRENT) {
+	      dvars[ivar]=0.;
+
+	      if (bcm_ind != -1) {
+
+		if (fDeltaTime>0) {
+		  Double_t cur_temp=(fScalerChan[ichan]/fDeltaTime-fBCM_Offset[bcm_ind])/fBCM_Gain[bcm_ind];  
+		  cur_temp=cur_temp+fBCM_SatQuadratic[bcm_ind]*TMath::Power(TMath::Max(cur_temp-fBCM_SatOffset[bcm_ind],0.0),2.0);		  
+		  dvars[ivar]=cur_temp;
+		}
+	      }
+	      if (bcm_ind == fbcm_Current_Threshold_Index) scal_current= dvars[ivar];
+	    }
+	    
+	    if (scalerloc[ivar]->ikind == ICHARGE) {
+	      
+	      if (bcm_ind != -1) {
+		dvars[ivar] = 0.0;
+
+		if (fDeltaTime>0)  {  
+		  Double_t cur_temp=(fScalerChan[ichan]/fDeltaTime-fBCM_Offset[bcm_ind])/fBCM_Gain[bcm_ind];  
+		  cur_temp=cur_temp+fBCM_SatQuadratic[bcm_ind]*TMath::Power(TMath::Max(cur_temp-fBCM_SatOffset[bcm_ind],0.0),2.0);
+		  fBCM_delta_charge[bcm_ind]=fDeltaTime*cur_temp;
+		}
+		dvars[ivar] = fBCM_delta_charge[bcm_ind];   
+	      }
+	    }
+	  }
+	
+      } else {
+	cout << "THcHelicityScaler:: ERROR:: incorrect index "<<ivar<<"  "<<idx<<"  "<<ichan<<endl;
+      }
+    } 
+  }
+  
+  //Analyze Scaler Reads ONLY FOR SCAL_CURRENTS > BCM_CURRENT THRESHOLD
+  //(These variables have the name structure: varibaleName_Cut)
+
+  for (size_t i = 0; i < scalerloc.size(); i++)  {
+    size_t ivar = scalerloc[i]->ivar;
+    size_t ichan = scalerloc[i]->ichan;
+
+    if (scalerloc[ivar]->ikind == ICUT+ICOUNT){
+      if ( scal_current > fbcm_Current_Threshold) {
+	dvars[ivar] = fScalerChan[ichan];
+      }
+    }
+    
+    if (scalerloc[ivar]->ikind == ICUT+ICHARGE){
+      Int_t bcm_ind=-1;
+      for(Int_t itemp =0; itemp<fNumBCMs;itemp++)
+	{		
+	  size_t match = string(scalerloc[ivar]->name.Data()).find(string(fBCM_Name[itemp]));
+	  if (match!=string::npos)
+	    {
+	      bcm_ind=itemp;
+	    }
+	}
+      if ( scal_current > fbcm_Current_Threshold && bcm_ind != -1) {
+	dvars[ivar] = fBCM_delta_charge[bcm_ind];  
+      } 
+    }
+    
+    if (scalerloc[ivar]->ikind == ICUT+ITIME){
+      if ( scal_current > fbcm_Current_Threshold) {
+	dvars[ivar] = fDeltaTime; 
+      }
+    }
+    
+  }
+
+  //--------------------------------------
+
+  //C.Y. 12/13/2020 : Calculate the asymmetries / errors at the end of each quartet  (S.A. Wood approach)
+
+  if(actualhelicity!=0) {
+    
+    //Reset fHaveCycle to kFALSE at the start of each quartet (e.g.  - + + -,  + - - +
+    if(quartetphase==0) {
+      fHaveCycle[0] = fHaveCycle[1] = fHaveCycle[2] = fHaveCycle[3] = kFALSE;
+    }
+        
+    //Check if BCM scaler current is above set threshold  
+    if(scal_current > fbcm_Current_Threshold && (quartetphase==0 || fHaveCycle[max(quartetphase-1,0)])) {
+      fHaveCycle[quartetphase] = kTRUE;
+
+      //Loop over each BCM to get the charge for each cycle of a quartet
+      for(Int_t i=0; i<fNumBCMs; i++) {	 
+	fChargeCycle[quartetphase][i] = fBCM_delta_charge[i];
+      }
+
+      //Loop over each Scaler Channel to the the counts for each cycle of a quartet 
+      for(Int_t i=0; i<fNScalerChannels; i++) {	 
+	fScalCycle[quartetphase][i] = fScalerChan[i];
+      }
+
+      //Set the time for each cycle of the quartet
+      fTimeCycle[quartetphase] = fDeltaTime;
+
+    }
+    
+    // Compute asymmetries at the end of each quartet
+    if(quartetphase == 3 && fHaveCycle[3]) {	
+
+      //Loop over BCMs
+      for(Int_t i=0;i<fNumBCMs;i++) {
+
+	//compute charge asymmetry for each quartet at the end of said quartet
+	Double_t asy = actualhelicity*(fChargeCycle[0][i]+fChargeCycle[3][i]
+				       - fChargeCycle[1][i]-fChargeCycle[2][i]) /
+	  (fChargeCycle[0][i]+fChargeCycle[3][i]+fChargeCycle[1][i]+fChargeCycle[2][i]);
+	
+	fChargeSum[i] += fChargeCycle[0][i]+fChargeCycle[1][i]
+	  +fChargeCycle[2][i]+fChargeCycle[3][i];
+	
+	//keep track of sums for proper error calculation
+	fChargeAsymSum[i] += asy;
+	fChargeAsymSum2[i] += asy*asy;
+      }
+      
+      //-------
+      
+      //Loop over Scaler Channels
+      for(Int_t i=0; i<fNScalerChannels; i++) {
+
+	//compute scaler asymmetry for each quartet at the end of said quartet
+	Double_t asy = actualhelicity*(fScalCycle[0][i]+fScalCycle[3][i]
+				       - fScalCycle[1][i]-fScalCycle[2][i]) /
+	  (fScalCycle[0][i]+fScalCycle[3][i]+fScalCycle[1][i]+fScalCycle[2][i]);
+	
+	fScalSum[i] += fScalCycle[0][i]+fScalCycle[1][i]
+	  +fScalCycle[2][i]+fScalCycle[3][i];
+	
+	//keep track of sums for proper error calculation
+	fScalAsymSum[i] += asy;
+	fScalAsymSum2[i] += asy*asy;
+      }
+
+      //-------
+
+      //compute time asymmetry for each quartet at the end of said quartet
+      Double_t asy = actualhelicity*(fTimeCycle[0]+fTimeCycle[3]
+				     - fTimeCycle[1]-fTimeCycle[2]) /
+	(fTimeCycle[0]+fTimeCycle[3]+fTimeCycle[1]+fTimeCycle[2]);
+
+      //keep track of total time
+      fTimeSum += fTimeCycle[0]+fTimeCycle[1]
+	+fTimeCycle[2]+fTimeCycle[3];
+      
+      //keep track of sums for proper error calculation
+      fTimeAsymSum += asy;
+      fTimeAsymSum2 += asy*asy;
+      
+      //------
+
+      //keep track of the total number of quartets
+      fQuartetCount++;   
+
+
+    }
+
+
+  }
+  
+  
+  //--------------------------------------
+  
+  //increment scaler reads
+  evcount = evcount + 1;
+  evcountR = evcount;
+  
+  //clear Genscaler scalers
+  for (size_t j=0; j<scalers.size(); j++) scalers[j]->Clear("");
+  
+  
+  //C.Y. 12/02/2020  Fill Scaler Tree Here
+  if (fScalerTree) {
+    fScalerTree->Fill(); 
+  }
+  
   return(0);
 }
+
 //_____________________________________________________________________________
 Int_t  THcHelicityScaler::RanBit30(Int_t ranseed)
 {
-  
   UInt_t bit7    = (ranseed & 0x00000040) != 0;
   UInt_t bit28   = (ranseed & 0x08000000) != 0;
   UInt_t bit29   = (ranseed & 0x10000000) != 0;
@@ -444,25 +1030,173 @@ THaAnalysisObject::EStatus THcHelicityScaler::Init(const TDatime& date)
 {
   
   ReadDatabase(date);
-
+  const int LEN = 200;
+  char cbuf[LEN];
+  
   fStatus = kOK;
-
+  fNormIdx = -1;
+ 
   for( vector<UInt_t*>::iterator it = fDelayedEvents.begin();
        it != fDelayedEvents.end(); ++it )
     delete [] *it;
   fDelayedEvents.clear();
 
   cout << "Howdy !  We are initializing THcHelicityScaler !!   name =   "
-        << fName << endl;
+       << fName << endl;
 
   if(eventtypes.size()==0) {
     eventtypes.push_back(0);  // Default Event Type
   }
-
+  
   if(fROC < 0) {
     fROC = 8;			// Default to SHMS crate
   }
 
+  
+  //C.Y. 11/26/2020 : Read In and Parse the variables in the helicity scaler map file 
+  TString dfile;
+  dfile = fName + "scaler.txt";
+
+  TString sname0 = "Scalevt";
+  TString sname;
+  sname = "hel"+fName+sname0;   //This should be: 'helPScalevt' or 'helHScalevt'
+
+  //Open helicity scaler .dat map file 
+  FILE *fi = OpenFile(sname.Data(), date);
+  if ( !fi ) {
+    cout << "Cannot find db file for "<<fName<<" scaler event handler"<<endl;
+    return kFileError;
+  }
+  
+  size_t minus1 = -1;
+  size_t pos1;
+  string scomment = "#";
+  string svariable = "variable";
+  string smap = "map";
+  vector<string> dbline;
+  
+  while( fgets(cbuf, LEN, fi) != NULL) {
+    std::string sin(cbuf);
+    std::string sinput(sin.substr(0,sin.find_first_of("#")));
+    if (fDebugFile) *fDebugFile << "string input "<<sinput<<endl;
+    dbline = vsplit(sinput);
+    if (dbline.size() > 0) {
+      pos1 = FindNoCase(dbline[0],scomment);
+      if (pos1 != minus1) continue;
+      pos1 = FindNoCase(dbline[0],svariable);
+      
+      if (pos1 != minus1 && dbline.size()>4) {
+	string sdesc = "";
+	for (size_t j=5; j<dbline.size(); j++) sdesc = sdesc+" "+dbline[j];
+	UInt_t islot = atoi(dbline[1].c_str());
+	UInt_t ichan = atoi(dbline[2].c_str());
+	UInt_t ikind = atoi(dbline[3].c_str());
+	if (fDebugFile)
+	  *fDebugFile << "add var "<<dbline[1]<<"   desc = "<<sdesc<<"    islot= "<<islot<<"  "<<ichan<<"  "<<ikind<<endl;
+	TString tsname(dbline[4].c_str());
+	TString tsdesc(sdesc.c_str());
+	AddVars(tsname,tsdesc,islot,ichan,ikind);
+	// add extra scaler which is cut on the current
+	if (ikind == ICOUNT ||ikind == ITIME ||ikind == ICHARGE  ) {
+	  tsname=tsname+"Cut";
+	  AddVars(tsname,tsdesc,islot,ichan,ICUT+ikind);
+	  }
+      }
+      
+      pos1 = FindNoCase(dbline[0],smap);
+      if (fDebugFile) *fDebugFile << "map ? "<<dbline[0]<<"  "<<smap<<"   "<<pos1<<"   "<<dbline.size()<<endl;
+      if (pos1 != minus1 && dbline.size()>6) {
+	Int_t imodel, icrate, islot, inorm;
+	UInt_t header, mask;
+	char cdum[20];
+	sscanf(sinput.c_str(),"%s %d %d %d %x %x %d \n",cdum,&imodel,&icrate,&islot, &header, &mask, &inorm);
+	if ((fNormSlot >= 0) && (fNormSlot != inorm)) cout << "THcHelicityScaler::WARN:  contradictory norm slot  "<<fNormSlot<<"   "<<inorm<<endl;
+	fNormSlot = inorm;  // slot number used for normalization.  This variable is not used but is checked.
+	Int_t clkchan = -1;
+	Double_t clkfreq = 1;
+	if (dbline.size()>8) {
+	  clkchan = atoi(dbline[7].c_str());
+	  clkfreq = 1.0*atoi(dbline[8].c_str());
+	  fClockChan=clkchan;
+	  fClockFreq=clkfreq;
+	}
+	if (fDebugFile) {
+	  *fDebugFile << "map line "<<dec<<imodel<<"  "<<icrate<<"  "<<islot<<endl;
+	  *fDebugFile <<"   header  0x"<<hex<<header<<"  0x"<<mask<<dec<<"  "<<inorm<<"  "<<clkchan<<"  "<<clkfreq<<endl;
+	}
+	
+	switch (imodel) {
+	case 3801:   //Hall C Helicity Scalers (SIS 3801)
+	  scalers.push_back(new Scaler3801(icrate, islot));
+	  if(!fOnlyBanks) fRocSet.insert(icrate);
+	  fModuleSet.insert(imodel);
+	  break;
+	}
+
+	if (scalers.size() > 0) {
+	  UInt_t idx = scalers.size()-1;
+	  // Headers must be unique over whole event, not
+	  // just within a ROC
+	  scalers[idx]->SetHeader(header, mask);
+	  // The normalization slot has the clock in it, so we automatically recognize it.
+	  // fNormIdx is the index in scaler[] and 
+	  // fNormSlot is the slot#, checked for consistency
+	  if (clkchan >= 0) {
+	    scalers[idx]->SetClock(defaultDT, clkchan, clkfreq);
+	    cout << "Setting scaler clock ... channel = "<<clkchan<<" ... freq = "<<clkfreq<<endl;
+	    if (fDebugFile) *fDebugFile <<"Setting scaler clock ... channel = "<<clkchan<<" ... freq = "<<clkfreq<<endl;
+	    fNormIdx = idx;
+	    if (islot != fNormSlot) cout << "THcHelicityScaler:: WARN: contradictory norm slot ! "<<islot<<endl;  
+	    
+	  }
+	}	
+	
+      }
+    }
+    
+  } //end while loop
+  
+  // can't compare UInt_t to Int_t (compiler warning), so do this
+  nscalers=0;
+  for (size_t i=0; i<scalers.size(); i++) nscalers++;
+  // need to do LoadNormScaler after scalers created and if fNormIdx found
+  if (fDebugFile) *fDebugFile <<"fNormIdx = "<<fNormIdx<<endl;
+  if ((fNormIdx >= 0) && fNormIdx < nscalers) {
+    for (Int_t i = 0; i < nscalers; i++) {
+      if (i==fNormIdx) continue;
+      scalers[i]->LoadNormScaler(scalers[fNormIdx]);
+    }
+  }
+  
+  //Called after AddVars() has been called
+  DefVars();
+  
+  // Verify that the slots are not defined twice
+  for (UInt_t i1=0; i1 < scalers.size()-1; i1++) {
+    for (UInt_t i2=i1+1; i2 < scalers.size(); i2++) {
+      if (scalers[i1]->GetSlot()==scalers[i2]->GetSlot())
+	cout << "THcHelicityScaler:: WARN:  same slot defined twice"<<endl;
+    }
+  }
+  // Identify indices of scalers[] vector to variables.
+  for (UInt_t i=0; i < scalers.size(); i++) {
+    for (UInt_t j = 0; j < scalerloc.size(); j++) {
+      if (scalerloc[j]->islot==static_cast<UInt_t>(scalers[i]->GetSlot()))
+	scalerloc[j]->index = i;
+    }
+  }
+  
+  if(fDebugFile) *fDebugFile << "THcHelicityScaler:: Name of scaler bank "<<fName<<endl;
+  for (size_t i=0; i<scalers.size(); i++) {
+    if(fDebugFile) {
+      *fDebugFile << "Scaler  #  "<<i<<endl;
+      scalers[i]->SetDebugFile(fDebugFile);
+      scalers[i]->DebugPrint(fDebugFile);
+    }
+  }
+
+  
+  //------Initialize Helicity Variables / Arrays-----
   fNTriggers = 0;
   fNTrigsInBuf = 0;
   fFirstCycle = -100;
@@ -470,61 +1204,219 @@ THaAnalysisObject::EStatus THcHelicityScaler::Init(const TDatime& date)
   fRingSeed_actual = 0;
   fNBits = 0;
   fNTriggersPlus = fNTriggersMinus = 0;
-  fHScalers[0] = new Double_t[fNScalerChannels];
-  fHScalers[1] = new Double_t[fNScalerChannels];
-  fScalerSums = new Double_t[fNScalerChannels];
-  fAsymmetry = new Double_t[fNScalerChannels];
-  fAsymmetryError = new Double_t[fNScalerChannels];
+  fHScalers[0] = new Double_t[fNScalerChannels];  //+ helicity scaler counts  
+  fHScalers[1] = new Double_t[fNScalerChannels];  //- helicity scaler counts
+  fScalerSums = new Double_t[fNScalerChannels];   //total helicity scaler counts (hel=0, excluded)
+  fScalerChan = new Double_t[fNScalerChannels]; //C.Y. 11/26/2020 : added array to store helicity information per channel 
+
   for(Int_t i=0;i<fNScalerChannels;i++) {
     fHScalers[0][i] = 0.0;
     fHScalers[1][i] = 0.0;
-    fScalerSums[0] = 0.0;
-    fAsymmetry[0] = 0.0;
-    fAsymmetryError[0] = 0.0;
+    fScalerSums[i] = 0.0;
+    fScalerChan[i] = 0.0;
   }
 
-  fCharge = new Double_t[fNumBCMs];
-  fChargeAsymmetry = new Double_t[fNumBCMs];
 
-  fTime = fTimeAsymmetry = 0;
+  fTimePlus = fTimeMinus = 0.0;
   fTriggerAsymmetry = 0.0;
 
-  MakeParms();
 
+
+  //------C.Y.: 12/13/2020  Initialize Variables for quartet-by-quartet asymmetries (include BCM current threshold cut)---------
+  //(and error calculation)
+
+  for(Int_t i=0; i<4; i++) {
+    
+    fChargeCycle[i] = new Double_t[fNumBCMs];
+    fScalCycle[i]   = new Double_t[fNScalerChannels];
+
+    fHaveCycle[i] = kFALSE;
+    
+    for(Int_t j=0; j<fNumBCMs; j++) {
+      fChargeCycle[i][j] = 0.0;
+    }
+    
+    for(Int_t j=0; j<fNScalerChannels; j++) {
+      fScalCycle[i][j] = 0.0;
+    }    
+    
+    fTimeCycle[i] = 0.0;
+
+  }
+
+  //Initialize quartet counter
+  fQuartetCount      = 0.0;
+ 
+  //Initialize variables for time asymmetry calculation
+  fTimeSum            = 0.0;
+  fTimeAsymmetry      = 0.0;
+  fTimeAsymmetryError = 0.0;
+  fTimeAsymSum        = 0.0;
+  fTimeAsymSum2       = 0.0;
+ 
+
+  //Initialize variables for charge asymmetry calculation
+  fChargeSum            = new Double_t[fNumBCMs];
+  fChargeAsymmetry      = new Double_t[fNumBCMs];
+  fChargeAsymmetryError = new Double_t[fNumBCMs];
+  fChargeAsymSum        = new Double_t[fNumBCMs];
+  fChargeAsymSum2       = new Double_t[fNumBCMs];
+
+  for(Int_t i=0;i<fNumBCMs;i++) {
+    fChargeSum[i]       = 0.0;
+    fChargeAsymmetry[i] = 0.0;
+    fChargeAsymSum[i]   = 0.0;
+    fChargeAsymSum2[i]  = 0.0;
+  }
+
+  //Initialize variables for scaler asymmetry calculation
+  fScalSum            = new Double_t[fNScalerChannels];
+  fScalAsymmetry      = new Double_t[fNScalerChannels];
+  fScalAsymmetryError = new Double_t[fNScalerChannels];
+  fScalAsymSum        = new Double_t[fNScalerChannels];
+  fScalAsymSum2       = new Double_t[fNScalerChannels];
+
+  for(Int_t i=0;i<fNScalerChannels;i++) {
+    fScalSum[i]       = 0.0;
+    fScalAsymmetry[i] = 0.0;
+    fScalAsymSum[i]   = 0.0;
+    fScalAsymSum2[i]  = 0.0;
+  }
+  
+  
+  //------------------------------------------------------------------------------------------
+
+  
+  //Call MakeParms() to define variables to be used in report file 
+  MakeParms();
+  
   return kOK;
 }
 
 void THcHelicityScaler::MakeParms()
 {
-  /**
-     Put Various helicity scaler results in gHcParms so they can be included in results.
-  */
+  
+  //Put Various helicity scaler results in gHcParms so they can be included in results.
+
+  //no bcm cut required
   gHcParms->Define(Form("g%s_hscaler_plus[%d]",fName.Data(),fNScalerChannels),
 		   "Plus Helcity Scalers",*(fHScalers[0]));
+
   gHcParms->Define(Form("g%s_hscaler_minus[%d]",fName.Data(),fNScalerChannels),
 		   "Minus Helcity Scalers",*(fHScalers[1]));
-  gHcParms->Define(Form("g%s_hscaler_sum[%d]",fName.Data(),fNScalerChannels),
-		   "Helcity Scalers Sum",*fScalerSums);
-  gHcParms->Define(Form("g%s_hscaler_asy[%d]",fName.Data(),fNScalerChannels),
-		   "Helicity Scaler Asymmetry[%d]",*fAsymmetry);
-  gHcParms->Define(Form("g%s_hscaler_asyerr[%d]",fName.Data(),fNScalerChannels),
-		   "Helicity Scaler Asymmetry Error[%d]",*fAsymmetryError);
+
+  //gHcParms->Define(Form("g%s_hscaler_sum[%d]",fName.Data(),fNScalerChannels),
+  //		   "Helcity Scalers Sum",*fScalerSums);
+
   gHcParms->Define(Form("g%s_hscaler_triggers",fName.Data()),
 		   "Total Helicity Scaler Triggers",fNTriggers);
+
   gHcParms->Define(Form("g%s_hscaler_triggers_plus",fName.Data()),
 		   "Positive Helicity Scaler Triggers",fNTriggersPlus);
+
   gHcParms->Define(Form("g%s_hscaler_triggers_minus",fName.Data()),
 		   "Negative Helicity Scaler Triggers",fNTriggersMinus);
+
+  gHcParms->Define(Form("g%s_hscaler_trigger_asy",fName.Data()),  
+                   "Helicity Trigger Asymmetry",fTriggerAsymmetry);
+
+  //gHcParms->Define(Form("g%s_hscaler_time_plus",fName.Data()),
+  //		   "Positive Helicity Time",fTimePlus);
+
+  //gHcParms->Define(Form("g%s_hscaler_time_minus",fName.Data()),
+  //		   "Negative Helicity Time",fTimeMinus);
+  
+  //bcm cut
+  gHcParms->Define(Form("g%s_hscaler_sum[%d]",fName.Data(),fNScalerChannels),
+		   "Helcity Scalers Sum",*fScalSum);
+
+  gHcParms->Define(Form("g%s_hscaler_asy[%d]",fName.Data(),fNScalerChannels),
+		   "Helicity Scaler Asymmetry[%d]",*fScalAsymmetry);
+
+  gHcParms->Define(Form("g%s_hscaler_asyerr[%d]",fName.Data(),fNScalerChannels),
+		   "Helicity Scaler Asymmetry Error[%d]",*fScalAsymmetryError);
+
   gHcParms->Define(Form("g%s_hscaler_charge[%d]",fName.Data(),fNumBCMs),
-		   "Helicity Gated Charge",*fCharge);
+		   "Helicity Gated Charge",*fChargeSum);
+
   gHcParms->Define(Form("g%s_hscaler_charge_asy[%d]",fName.Data(),fNumBCMs),
 		   "Helicity Gated Charge Asymmetry",*fChargeAsymmetry);
+
+  gHcParms->Define(Form("g%s_hscaler_charge_asyerr[%d]",fName.Data(),fNumBCMs),
+		   "Helicity Gated Charge Asymmetry Error",*fChargeAsymmetryError);
+    
   gHcParms->Define(Form("g%s_hscaler_time",fName.Data()),
-		   "Helicity Gated Time (sec)",fTime);
+		   "Helicity Gated Time (sec)",fTimeSum);
+
   gHcParms->Define(Form("g%s_hscaler_time_asy",fName.Data()),
 		   "Helicity Gated Time Asymmetry",fTimeAsymmetry);
-  gHcParms->Define(Form("g%s_hscaler_trigger_asy",fName.Data()),
-		   "Helicity Trigger Asymmetry",fTriggerAsymmetry);
+
+  gHcParms->Define(Form("g%s_hscaler_time_asyerr",fName.Data()),  
+                   "Helicity Gated Time Asymmetry Error",fTimeAsymmetryError);
+
+
+  
 }
 
+
+
+//--------------------C.Y. Sep 20, 2020 : Added Utility Functions--------------------
+
+void THcHelicityScaler::AddVars(TString name, TString desc, UInt_t islot,
+				  UInt_t ichan, UInt_t ikind)
+{
+  if (fDebugFile) *fDebugFile << "C.Y. | Calling THcHelicityScaler::AddVars() "<<endl; 
+  // need to add fName here to make it a unique variable.  (Left vs Right HRS, for example)
+  TString name1 = fName + name;
+  TString desc1 = fName + desc;
+  // We don't yet know the correspondence between index of scalers[] and slots.
+  // Will put that in later.
+  scalerloc.push_back( new HCScalerLoc(name1, desc1, 0, islot, ichan, ikind,
+				       scalerloc.size()) );
+}
+
+void THcHelicityScaler::DefVars()
+{
+  if (fDebugFile) *fDebugFile << "C.Y. | Calling THcHelicityScaler::DefVars() "<<endl; 
+  // called after AddVars has finished being called.
+  Nvars = scalerloc.size();
+  if (Nvars == 0) return;
+  dvars = new Double_t[Nvars];  // dvars is a member of this class
+  dvarsFirst = new Double_t[Nvars];  // dvarsFirst is a member of this class
+  memset(dvars, 0, Nvars*sizeof(Double_t));
+  memset(dvarsFirst, 0, Nvars*sizeof(Double_t));
+  if (gHaVars) {
+    if(fDebugFile) *fDebugFile << "THcScalerEVtHandler:: Have gHaVars "<<gHaVars<<endl;
+  } else {
+    cout << "No gHaVars ?!  Well, that's a problem !!"<<endl;
+    return;
+  }
+  if(fDebugFile) *fDebugFile << "THcHelicityScaler:: scalerloc size "<<scalerloc.size()<<endl;
+  const Int_t* count = 0;
+  for (size_t i = 0; i < scalerloc.size(); i++) {
+    gHaVars->DefineByType(scalerloc[i]->name.Data(), scalerloc[i]->description.Data(),
+			  &dvars[i], kDouble, count);
+  }
+}
+
+size_t THcHelicityScaler::FindNoCase(const string& sdata, const string& skey)
+{
+  // Find iterator of word "sdata" where "skey" starts.  Case insensitive.
+  string sdatalc, skeylc;
+  sdatalc = "";  skeylc = "";
+  for (string::const_iterator p =
+	 sdata.begin(); p != sdata.end(); ++p) {
+    sdatalc += tolower(*p);
+  }
+  for (string::const_iterator p =
+	 skey.begin(); p != skey.end(); ++p) {
+    skeylc += tolower(*p);
+  }
+  if (sdatalc.find(skeylc,0) == string::npos) return -1;
+  return sdatalc.find(skeylc,0);
+};
+
+//---------------------------------------------------------------------------------
+
+
 ClassImp(THcHelicityScaler)
diff --git a/src/THcHelicityScaler.h b/src/THcHelicityScaler.h
index 8ca54718b77d7f01d9a6dc0d5b1f1932dafbe87e..8e797865ece1b06eeacaa46b7c41480ad6f71495 100644
--- a/src/THcHelicityScaler.h
+++ b/src/THcHelicityScaler.h
@@ -9,6 +9,7 @@
 /////////////////////////////////////////////////////////////////////
 
 #include "THaEvtTypeHandler.h"
+#include "THcScalerEvtHandler.h"
 #include "Decoder.h"
 #include <string>
 #include <vector>
@@ -18,7 +19,9 @@
 #include "TString.h"
 #include <cstring>
 
+
 class THcHelicity;
+class HCScalerLoc;
 
 class THcHelicityScaler : public THaEvtTypeHandler {
 
@@ -50,6 +53,15 @@ public:
 
 private:
 
+  //------------C.Y. Sep 20, 2020 :: Added Utility Function Prototypes----------------
+  void AddVars(TString name, TString desc, UInt_t iscal, UInt_t ichan, UInt_t ikind);
+  void DefVars();
+  static size_t FindNoCase(const std::string& sdata, const std::string& skey);
+  
+  std::vector<Decoder::GenScaler*> scalers;
+  std::vector<HCScalerLoc*> scalerloc;
+  //----------------------------------------------------------------------------------
+  
   Int_t RanBit30(Int_t ranseed);
   void MakeParms();
 
@@ -74,12 +86,53 @@ private:
   Double_t *fScalerSums;
   Double_t *fAsymmetry;
   Double_t *fAsymmetryError;
-  Double_t *fCharge;
-  Double_t *fChargeAsymmetry;
-  Double_t fTime;
-  Double_t fTimeAsymmetry;
+  //Double_t *fCharge;
+
+  Double_t fTimePlus;     
+  Double_t fTimeMinus;       
+  //Double_t fTime;
+  //Double_t fTimeAsymmetry;
   Double_t fTriggerAsymmetry;
 
+  //---- C.Y.: 12/14/2020  Variables for quartet-by-quartet asymmetry/error calculations ----
+  Bool_t   fHaveCycle[4];
+
+  Int_t fQuartetCount;      //keep track of number of quartets
+
+  //quartet-by-quartet time asymmetry variables
+  Double_t fTimeCycle[4];
+  Double_t fTimeSum;
+  Double_t fTimeAsymmetry;
+  Double_t fTimeAsymmetryError;
+  Double_t fTimeAsymSum;
+  Double_t fTimeAsymSum2;
+  
+  //quartet-by-quartet scaler counts asymmetry variables
+  Double_t *fScalCycle[4];  
+  Double_t *fScalSum;     //reminder: need to initialize
+  Double_t *fScalAsymmetry;
+  Double_t *fScalAsymmetryError;
+  Double_t *fScalAsymSum;
+  Double_t *fScalAsymSum2;
+  
+  //quartet-by-quartet charge asymmetry variables
+  Double_t *fChargeCycle[4];
+  Double_t *fChargeSum;
+  Double_t *fChargeAsymmetry;
+  Double_t *fChargeAsymmetryError;
+  Double_t *fChargeAsymSum;
+  Double_t *fChargeAsymSum2;
+
+
+
+  
+  //----------------------
+
+  
+  
+  //----C.Y. Nov 26, 2020----
+  Double_t *fScalerChan;
+
   std::vector<UInt_t*> fDelayedEvents;
   Int_t fROC;
   Int_t fNScalerChannels;	// Number of scaler channels/event
@@ -87,12 +140,41 @@ private:
   Int_t fNumBCMs;
   Double_t *fBCM_Gain;
   Double_t *fBCM_Offset;
+  //---C.Y. Sep 2020 : Added additional BCM-related variables--
+  Double_t *fBCM_SatOffset;
+  Double_t *fBCM_SatQuadratic;
+  Double_t *fBCM_delta_charge;
+  Double_t fTotalTime;
+  Double_t fDeltaTime;
+  Double_t fPrevTotalTime;
+  Double_t fbcm_Current_Threshold;
+  Double_t fClockFreq;
+  Int_t fbcm_Current_Threshold_Index;
   std::vector <std::string> fBCM_Name;
 
+  //----C.Y. Sep 20, 2020 : Added additional variables-----
+  // (required by utility functions and scaler tree output)
+  UInt_t evcount;
+  Double_t evcountR;
+  UInt_t evNumber;
+  Double_t evNumberR;
+  Double_t actualHelicityR;
+  Double_t quartetphaseR;
+  Int_t Nvars, ifound, fNormIdx, fNormSlot, nscalers;
+  Double_t *dvars;
+  Double_t *dvarsFirst;
+  TTree *fScalerTree;
+  Bool_t fOnlySyncEvents;
+  Bool_t fOnlyBanks;
+  Int_t fClockChan;
+  UInt_t fLastClock;
+  std::set<UInt_t> fRocSet;
+  std::set<UInt_t> fModuleSet;
+  //--------------------------------------------------------
+  
   THcHelicityScaler(const THcHelicityScaler& fh);
   THcHelicityScaler& operator=(const THcHelicityScaler& fh);
 
-  UInt_t evNumber;
 
   ClassDef(THcHelicityScaler,0)  // Scaler Event handler