cms-gem-daq-project / gem-plotting-tools

Repository for GEM commissioning plotting tools
GNU General Public License v3.0
1 stars 26 forks source link

Feature Request: Identifying Original maskReason & Date Range of Burned Input #88

Closed bdorney closed 6 years ago

bdorney commented 6 years ago

Brief summary of issue

We have 30720 channels in CMS presently. And we need some automated way for tracking when changes occur. Ideally this should be via the DB but this is not up and running (yet...). But we have an automated procedure to make time series plots from the entire calibration dataset, see #87.

So my proposal is to use these time series plots to identify:

Issue with Channel Mask

Right now when a channel is masked it's maskReason will be recorded in the output TTree of the analysis scan. However once a channel is masked the history will be somewhat "lost." This is because the channel will be masked at the time of acquisition so the s-curve analysis will see that a fit to it fails (because there is no data). The maskReason will then be assigned FitFailed. This is because the scan software does not know the history.

Types of issue

Expected Behavior

To accomplish this a secondary analysis tool should be made, macros/timeHistoryAnalyzer.py, which should should have a function like:

def analyzeTimeSeriesPlot(timeSeriesHisto, obsType, deadChanCutLow=4.14E-02, deadChanCutHigh=1.09E-01):
"""
timeSeriesHisto - TH2 object created by gemPlotter.py when making time series plots
obsType - The observable to be investigate from the set {noise, ..., maskReason, etc...} see for example the observables produced here https://github.com/cms-gem-daq-project/gem-plotting-tools/blob/0ce86672ddac3affee27b80517eb34e8cd50b029/macros/plotTimeSeries.py#L10-L26
deadChanCutLow - lower bound on s-curve width for identifying a dead channel, value in fC
deadChanCutHigh - higher bound on s-curve width for identifying a dead channel, value in fC
"""
# import numpy
# import nesteddict from gem sw

chanArray = nesteddict()
# Load info from the histo
for binY in timeSeriesHisto:
   lastGoodScanDate = 2017.01.01
   firstDateAfterBurn = None
   for bin X in timSeriesHisto:
      # get the point value and store it
      scanDate = timSeriesHisto.GetBinLabel(binX)
      chanStripOrPanPin = binY-1 #bins go from 1 to nbins but channel/strips/panpin go 0 to 127
      scanVal = timSeriesHisto.GetBinContent(binX,binY)

      # See if channel went from bad to good
      if obsType == "noise":
          if scanVal > deadChanCutHigh:
              lastGoodScanDate = scanDate
          if deadChanCutLow <= scanVal and scanVal <= deadChanCutHigh:
              if firstDateAfterBurn is not None:
                   firstDateAfterBurn = scanDate

         chanArray[chanStripOrPanPin] = (lastGoodScanDate, firstDateAfterBurn)

     # Try to determine original mask reason
     if obsType == "maskReason":
         # Similar to above example

   # Display to user
   print "| chan | lastGoodScanDate | firstDateAfterBurn |" # in markdown format
   print "| :---:  | :------------------: | :-----------------: |"
   for chan in range(0,len(chanArray)):
      print "| %i | %s | %s |"%(chan, chanArray[chan][0], chanArray[chan][1])

   # Similarly display a table which shows the number of channels in the VFAT that have the following maskReasons based on the "original" maskReason:
    #NotMasked   = 0x0
    #HotChannel  = 0x01
    #FitFailed   = 0x02
    #DeadChannel = 0x04
    #HighNoise   = 0x08
    #HighEffPed  = 0x10

Caveats is that this needs to be modified to not be sensitive to transient effects; e.g. in this example two scans failed to complete successfully so the data is missing and the channels and this may throw off the algorithm if this were "maskReason" case. Testing would be required

Current Behavior

Presently the last good scandate and first date after burned channel need to be determined by hand. Also the FitFailed maskReason slowly dominates the dataset.

Context (for feature requests)

We need to be able to accurately report our channel status and history to ourselves and CMS

bdorney commented 6 years ago

I have assigned this task to the PFA team this morning.

bdorney commented 6 years ago

To have a more sophisticated algorithm you could convert the scandate into a datetime object. The documentation for the datetime class can be found here.

And an example is given:

    import datetime
    startDay = datetime.date(datetime.MINYEAR,1,1)
    if startDate is not None:
        startDateInfo = [ int(info) for info in startDate.split(".") ]
        startDay = datetime.date(startDateInfo[0], startDateInfo[1], startDateInfo[2])
        pass

    endDay = datetime.date.today()
    if endDate is not None:
        endDateInfo = [ int(info) for info in endDate.split(".") ]
        endDat = datetime.date(endDateInfo[0], endDateInfo[1], endDateInfo[2])
        pass

And then you can have logical comparisons on datetime objects (e.g. the < and > symbols will evaluate whether dateime X was before or after Y):

        if (startDay < thisDay and thisDay <= endDay):
            listOfScanDatesFile.write('%s%s%s\n'%(chamberName,delim,scandate))
bdorney commented 6 years ago

Addressed by #112