Skip to content

Commit

Permalink
feat: deprecate OkForAsymmetry and Golden, and provide guidance f…
Browse files Browse the repository at this point in the history
…or their replacement (#50)
  • Loading branch information
c-dilks authored Sep 17, 2024
1 parent ac42218 commit 6668925
Show file tree
Hide file tree
Showing 23 changed files with 978 additions and 236 deletions.
273 changes: 126 additions & 147 deletions README.md

Large diffs are not rendered by default.

31 changes: 31 additions & 0 deletions bin/makeDefectMarkdown.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env ruby

# generates a Markdown table of the defect bits and their descriptions

require 'json'

unless ENV.has_key? 'QADB'
$stderr.puts 'you need to source environment variables'
exit 1
end

def puts_row(columns)
puts "| #{columns.join ' | '} |"
end

puts_row ['Bit', 'Name', 'Description', 'Additional Notes']
puts_row 4.times.map{|i|'---'}

File.open("#{ENV['QADB']}/qadb/defect_definitions.json") do |defect_file|
defect_defs = JSON.load defect_file
defect_defs.each do |defect_def|
defect_cols = ['bit_number', 'bit_name', 'description', 'documentation'].map do |k|
if k == 'bit_name'
"`#{defect_def[k]}`"
else
defect_def[k].to_s
end
end
puts_row defect_cols
end
end
122 changes: 122 additions & 0 deletions qadb/defect_definitions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
[
{
"bit_number": 0,
"bit_name": "TotalOutlier",
"description": "Outlier FD electron N/F, but not `TerminalOutlier` or `MarginalOutlier`",
"documentation": ""
},
{
"bit_number": 1,
"bit_name": "TerminalOutlier",
"description": "Outlier FD electron N/F of first or last QA bin of run",
"documentation": ""
},
{
"bit_number": 2,
"bit_name": "MarginalOutlier",
"description": "Marginal FD electron outlier N/F, within one standard deviation of cut line",
"documentation": ""
},
{
"bit_number": 3,
"bit_name": "SectorLoss",
"description": "FD electron N/F diminished for several consecutive QA bins",
"documentation": "For older datasets (RG-A,B,K,M pass 1), this bit _replaced_ the assignment of `TotalOutlier`, `TerminalOutlier`, and `MarginalOutlier`; newer datasets only add the `SectorLoss` bit and do not remove the outlier bits."
},
{
"bit_number": 4,
"bit_name": "LowLiveTime",
"description": "Live time < 0.9",
"documentation": "This assignment of this bit may be correlated with a low fraction of events with a defined (nonzero) helicity."
},
{
"bit_number": 5,
"bit_name": "Misc",
"description": "Miscellaneous defect, documented as comment",
"documentation": "This bit is often assigned to all QA bins within a run, but in some cases, may only be assigned to the relevant QA bins. The analyzer must decide whether data assigned with the `Misc` bit should be excluded from their analysis; the comment is provided for this purpose. Analyzers are also encouraged to check the Hall B log book for further details."
},
{
"bit_number": 6,
"bit_name": "TotalOutlierFT",
"description": "Outlier FT electron N/F, but not `TerminalOutlierFT` or `MarginalOutlierFT`",
"documentation": "_cf_. `TotalOutlier`."
},
{
"bit_number": 7,
"bit_name": "TerminalOutlierFT",
"description": "Outlier FT electron N/F of first or last QA bin of run",
"documentation": "_cf_. `TerminalOutlier`."
},
{
"bit_number": 8,
"bit_name": "MarginalOutlierFT",
"description": "Marginal FT electron outlier N/F, within one standard deviation of cut line",
"documentation": "_cf_. `MarginalOutlier`."
},
{
"bit_number": 9,
"bit_name": "LossFT",
"description": "FT electron N/F diminished for several consecutive QA bins",
"documentation": "_cf_. `SectorLoss`."
},
{
"bit_number": 10,
"bit_name": "BSAWrong",
"description": "Beam Spin Asymmetry is the wrong sign",
"documentation": "This bit is assigned per run. The asymmetry is significant, but the sign is opposite than expected; analyzers must therefore _flip_ the helicity sign."
},
{
"bit_number": 11,
"bit_name": "BSAUnknown",
"description": "Beam Spin Asymmetry is unknown, likely because of low statistics",
"documentation": "This bit is assigned per run. There are not enough data to determine if the helicity sign is correct for this run."
},
{
"bit_number": 12,
"bit_name": "TSAWrong",
"description": "Target Spin Asymmetry is the wrong sign",
"documentation": "__Not yet used.__"
},
{
"bit_number": 13,
"bit_name": "TSAUnknown",
"description": "Target Spin Asymmetry is unknown, likely because of low statistics",
"documentation": "__Not yet used.__"
},
{
"bit_number": 14,
"bit_name": "DSAWrong",
"description": "Double Spin Asymmetry is the wrong sign",
"documentation": "__Not yet used.__"
},
{
"bit_number": 15,
"bit_name": "DSAUnknown",
"description": "Double Spin Asymmetry is unknown, likely because of low statistics",
"documentation": "__Not yet used.__"
},
{
"bit_number": 16,
"bit_name": "ChargeHigh",
"description": "FC Charge is abnormally high",
"documentation": "NOTE: the assignment criteria of this bit are still under study."
},
{
"bit_number": 17,
"bit_name": "ChargeNegative",
"description": "FC Charge is negative",
"documentation": "The FC charge is calculated from the charge readout at QA bin boundaries. Normally the later charge readout is higher than the earlier; this bit is assigned when the opposite happens."
},
{
"bit_number": 18,
"bit_name": "ChargeUnknown",
"description": "FC Charge is unknown; the first and last time bins _always_ have this defect",
"documentation": "QA bin boundaries are at scaler charge readouts. The first QA bin, before any readout, has no initial charge; the last QA bin, after all scaler readouts, has no final charge. Therefore, the first and last QA bins have an unknown, but likely _very small_ charge accumulation."
},
{
"bit_number": 19,
"bit_name": "PossiblyNoBeam",
"description": "Both N and F are low, indicating the beam was possibly off",
"documentation": "NOTE: the assignment criteria of this bit are still under study."
}
]
3 changes: 1 addition & 2 deletions src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ This directory contains the Groovy source code to access the QA database
provided by `coatjava` (at `$COATJAVA/bin/run-groovy`)
- see example scripts in `examples/` directory
- a standard usage of QA cuts is demonstrated in
`examples/cutAsymmetry.groovy`, where the QA criteria for a spin asymmetry
analysis are applied
[`examples/cutCustom.groovy`](examples/cutCustom.groovy)
- usage notes:
- include the `QADB` class with `import clasqa.QADB`, then instantiate
- the `QADB` class provides several methods for accessing the QA info;
Expand Down
100 changes: 98 additions & 2 deletions src/clasqa/QADB.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package clasqa

import groovy.json.JsonSlurper
import groovy.json.JsonOutput
import groovy.json.JsonParserType
import clasqa.Tools

class QADB {
Expand Down Expand Up @@ -30,7 +31,7 @@ class QADB {
// concatenate trees
qaTree = [:]
chargeTree = [:]
slurper = new JsonSlurper()
slurper = new JsonSlurper().setType(JsonParserType.INDEX_OVERLAY)
def dbDir = new File(dbDirN)
def dbFilter = ~/.*Tree.json$/
def slurpAction = { tree,branch ->
Expand Down Expand Up @@ -106,6 +107,33 @@ class QADB {
chargeTotal = 0
chargeCounted = false
chargeCountedFiles = []
dep_warned_Golden = false
dep_warned_OkForAsymmetry = false
allowMiscBitList = []
}

//...............................
// deprecation warnings
//```````````````````````````````
private void deprecationGuidance() {
System.err.print('''| INSTEAD: use the general methods
| - use `QADB::checkForDefect` to choose which defects you want
| to filter out, then use `QADB::pass` on each event
| - for runs with the `Misc` defect bit (bit 5) assigned:
| - use `QADB::getComment` to check the QADB comment, which
| explains why this bit was assigned for the run
| - use `QADB::allowMiscBit` to ignore the `Misc` bit for certain
| runs that you want to allow in your analysis (`OkForAsymmetry`
| internally does this for a specific list of RG-A runs)
''')
}

private void warningBanner(boolean first) {
if(first) {
System.err.print("\nWARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING\n|\n")
} else {
System.err.print("|\nWARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING\n\n")
}
}


Expand All @@ -114,6 +142,20 @@ class QADB {
//```````````````````````````````
// returns false if the event is in a file with *any* defect
public boolean golden(int runnum_, int evnum_) {
if(!dep_warned_Golden) {
dep_warned_Golden = true
warningBanner(true)
System.err.print('''| WARNING: `QADB::golden` is DEPRECATED
| - you may still use this method, but since many more defect bits have been
| defined, and "Golden" means "no defect bits set", you may find that
| requiring your data to be "Golden" is too strict for your analysis
| - NOTE: QADBs for Run Groups A, B, K, and M for Pass1 data only use
| defect bits 0 to 9, whereas newer QADBs define many more bits
| - in some cases, none of the data are "Golden"
''')
deprecationGuidance()
warningBanner(false)
}
def foundHere = query(runnum_,evnum_)
return foundHere && defect==0
}
Expand All @@ -125,6 +167,23 @@ class QADB {
// if true, this event is good for a spin asymmetry analysis
public boolean OkForAsymmetry(int runnum_, int evnum_) {

if(!dep_warned_OkForAsymmetry) {
dep_warned_OkForAsymmetry = true
warningBanner(true)
System.err.print('''| WARNING: `QADB::OkForAsymmetry` is DEPRECATED
| - you may still use this method, but `OkForAsymmetry` does
| not include NEW defect bits that have been recently defined
''')
deprecationGuidance()
System.err.print('''| EXAMPLE:
| - see '$QADB/src/tests/testOkForAsymmetry.groovy' for a
| preferred, equivalent implementation; from there, you may
| customize your QA criteria and use the new defect bits
''')
warningBanner(false)
}


// perform lookup
def foundHere = query(runnum_,evnum_)
if(!foundHere) return false;
Expand Down Expand Up @@ -170,13 +229,30 @@ class QADB {
if(state) mask |= (0x1 << defectBit)
}
}
public void checkForDefect(String bitStr, boolean state=true) { // alias
setMaskBit(bitStr, state)
}
// access the custom mask, if you want to double-check it
public int getMask() { return mask }
// then call this method to check your custom QA cut for a given
// run number and event number
public boolean pass(int runnum_, int evnum_) {
def foundHere = query(runnum_,evnum_)
return foundHere && !(defect & mask)
if(!foundHere) {
return false
}
def use_mask = mask
if(hasDefectBit(5)) {
if(runnum_ in allowMiscBitList) {
use_mask &= ~(0x1 << 5) // set `use_mask`'s Misc bit to 0
}
}
return foundHere && !(defect & use_mask)
}

// ignore certain runs for the `Misc` bit assignment
public void allowMiscBit(int runnum_) {
allowMiscBitList.add(runnum_)
}


Expand All @@ -186,6 +262,7 @@ class QADB {
// --- access this file's info
public int getRunnum() { return found ? runnum.toInteger() : -1 }
public int getFilenum() { return found ? filenum.toInteger() : -1 }
public int getBinnum() { return getFilenum() }
public String getComment() { return found ? comment : "" }
public int getEvnumMin() { return found ? evnumMin : -1 }
public int getEvnumMax() { return found ? evnumMax : -1 }
Expand Down Expand Up @@ -319,6 +396,18 @@ class QADB {
// result of query
return found
}
// aliases
public boolean queryByBinnum(int runnum_, int binnum_) {
return queryByFilenum(runnum_, binnum_)
}

// check if this bin number exists
public boolean hasBinnum(int runnum_, int binnum_) {
if(qaTree["$runnum_"] != null) {
return qaTree["$runnum_"]["$binnum_"] != null
}
return false
}


// get maximum file number for a given run (useful for QADB validation)
Expand All @@ -330,6 +419,9 @@ class QADB {
}
return maxFilenum
}
public int getMaxBinnum(int runnum_) { // alias
return getMaxFilenum(runnum_)
}



Expand Down Expand Up @@ -387,4 +479,8 @@ class QADB {
private def mask
private def asymMask
private def allowForOkForAsymmetry
private def allowMiscBitList

private boolean dep_warned_Golden
private boolean dep_warned_OkForAsymmetry
}
4 changes: 2 additions & 2 deletions src/examples/chargeSum.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ while(reader.hasEvent()) {

// accumulate charge; note that although the call to
// QADB::accumulateCharge() charge happens for each
// event within a DST file that passed the QA cuts, that
// file's charge will only be accumulated once, so
// event within a QA bin that passed the QA cuts, that
// bin's charge will only be accumulated once, so
// overcounting is not possible
qa.accumulateCharge()

Expand Down
14 changes: 7 additions & 7 deletions src/examples/cutCustom.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ QADB qa = new QADB()

// custom QA cut definition
// - decide which defects you want to check for; an event will not pass
// the QA cut if the associated file has any of the specified defects
// the QA cut if the associated bin has any of the specified defects
// - set to true to check the bit
// - set to false to ignore the bit (by default, all bits are ignored)
qa.setMaskBit('TotalOutlier',false)
qa.setMaskBit('TerminalOutlier',false)
qa.setMaskBit('MarginalOutlier',false)
qa.setMaskBit('SectorLoss',true) // this is the only bit we check here
qa.setMaskBit('LowLiveTime',false)
qa.setMaskBit('Misc',false)
qa.checkForDefect('TotalOutlier',false)
qa.checkForDefect('TerminalOutlier',false)
qa.checkForDefect('MarginalOutlier',false)
qa.checkForDefect('SectorLoss',true) // this is the only bit we check here
qa.checkForDefect('LowLiveTime',false)
qa.checkForDefect('Misc',false)

// print the defect bit mask
println "\ndefect mask = " + qa.util.printBinary(qa.getMask(),16) + "\n"
Expand Down
Loading

0 comments on commit 6668925

Please sign in to comment.