Commit 5f290776 authored by Erik Asbjørn Mikkelsen Jensen's avatar Erik Asbjørn Mikkelsen Jensen
Browse files

Initial commit (too much work done outside VCS, bad bad bad)

parent 9286d672
SHELL := /bin/bash
CXX = $$(root-config --cxx)
CXXFLAGS = -Wall $$(root-config --cflags)
LDLIBS = $$(root-config --glibs)
DATATABLES = ame16/mass16.txt ame16/rct1-16.txt ame16/rct2-16.txt nubase16/nubase2016.txt
EXAMPLE_FIGURES = qec.pdf
EXAMPLE_DATAFILES = qec.dat qbn.dat
EXECUTABLES = dataprinter expand-nuchart-QEC expand-nuchart-QBxn-QBxp-QBa
.PHONEY: default all clean
default: nuchart.root
all: default $(EXAMPLE_FIGURES) qbn.dat
nuchart.root: treemaker.py expand-nuchart-QEC expand-nuchart-QBxn-QBxp-QBa
source $$(root-config --bindir)/thisroot.sh && python3 treemaker.py
./expand-nuchart-QEC
./expand-nuchart-QBxn-QBxp-QBa
qec.pdf: graph-example-qec.py
python3 $<
graph-example-qec.py: qec.dat
qec.dat: dataprinter Makefile
./$< nuchart.root a A Z QEC QEC_est "A <= 70" "QEC >= 0" > $@
qbn.dat: dataprinter Makefile
./$< nuchart.root a A Z QB QEC Sp QBp "A <= 70" > $@
dataprinter: dataprinter.cxx
$(CXX) $(CXXFLAGS) -o $@ $< $(LDLIBS)
expand-nuchart-QEC: expand-nuchart-QEC.cxx
$(CXX) $(CXXFLAGS) -o $@ $< $(LDLIBS)
expand-nuchart-QBxn-QBxp-QBa: expand-nuchart-QBxn-QBxp-QBa.cxx
$(CXX) $(CXXFLAGS) -o $@ $< $(LDLIBS)
treemaker.py: datagetter.py
datagetter.py: $(DATATABLES)
clean:
$(RM) -r __pycache__
$(RM) nuchart.root $(EXECUTABLES) $(EXAMPLE_FIGURES) $(EXAMPLE_DATAFILES)
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
# TODO: improve pattern7 to accomodate the limitation described in the comment on the first line of the function get_parity()
import re
# DEFINITION OF REGEX PATTERNS AND COMPILATION OF THEIR CORRESPONDING MATCH OBJECTS
pattern1 = "([0 ]) {0,2}(-?\d{1,3}) {0,4}(\d{1,5}) {0,4}(\d{1,5}) {0,4}(\d{1,5}) [ ]?([A-Z]?[a-z]?) [ ]{0,4}([-A-Za-z0-9+]{0,4}) {0,8}(-?\d{1,8})([.#]) {0,5}(\d{0,5}) {0,9}(\d{1,5})([.#]) {0,5}(\d{0,5}) {0,10}(-?\d{1,7})([.#]) {0,3}(\d{0,3}) {0,6}(\d{1,5})([.#]) {0,3}(\d{0,3}) {0,2} [-B]{2} {0,6}(-?\d{0,7}[*]?)([.# ]) {0,3}(\d{0,3}) {0,7}(\d{0,5})([.# ]) {0,3}(\d{0,3}) {0,2} [ ]{0,2}(\d{1,3}) (\d{6})([.#])(\d{0,5}) {0,8}(\d{1,5})([.#])(\d{0,5})" # description of whole line format in mass16.txt
pattern2 = "([0 ]) {0,2}(\d{1,3}) [ ]?([A-Z]?[a-z]?) [ ]{0,3}(\d{1,3}) [ ]{0,6}(-?\d{0,7}[*]?)([.# ]) {0,2}(\d{0,2}) {0,6}(\d{0,5})([.# ]) {0,2}(\d{0,2})[ ]{0,7}(-?\d{0,7}[*]?)([.# ]) {0,2}(\d{0,2}) {0,6}(\d{0,5})([.# ]) {0,2}(\d{0,2})[ ]{0,7}(-?\d{0,7}[*]?)([.# ]) {0,2}(\d{0,2}) {0,6}(\d{0,5})([.# ]) {0,2}(\d{0,2})[ ]{0,7}(-?\d{0,7}[*]?)([.# ]) {0,2}(\d{0,2}) {0,6}(\d{0,5})([.# ]) {0,2}(\d{0,2})[ ]{0,7}(-?\d{0,7}[*]?)([.# ]) {0,2}(\d{0,2}) {0,6}(\d{0,5})([.# ]) {0,2}(\d{0,2})[ ]{0,7}(-?\d{0,7}[*]?)([.# ]?) {0,2}(\d{0,2}) {0,6}(\d{0,5})([.# ]?) {0,2}(\d{0,2})" # description of whole line format in rct1-16.txt
pattern3 = "([0 ]) {0,2}(\d{1,3}) [ ]?([A-Z]?[a-z]?) [ ]{0,3}(\d{1,3}) [ ]{0,6}(-?\d{0,7}[*]?)([.# ]) {0,2}(\d{0,2}) {0,6}(\d{0,5})([.# ]) {0,2}(\d{0,2})[ ]{0,7}(-?\d{0,7}[*]?)([.# ]) {0,2}(\d{0,2}) {0,6}(\d{0,5})([.# ]) {0,2}(\d{0,2})[ ]{0,7}(-?\d{0,7}[*]?)([.# ]) {0,2}(\d{0,2}) {0,6}(\d{0,5})([.# ]) {0,2}(\d{0,2})[ ]{0,7}(-?\d{0,7}[*]?)([.# ]) {0,2}(\d{0,2}) {0,6}(\d{0,5})([.# ]) {0,2}(\d{0,2})[ ]{0,7}(-?\d{0,7}[*]?)([.# ]) {0,2}(\d{0,2}) {0,6}(\d{0,5})([.# ]) {0,2}(\d{0,2})[ ]{0,7}(-?\d{0,7}[*]?)([.# ]?) {0,2}(\d{0,2}) {0,6}(\d{0,5})([.# ]?) {0,2}(\d{0,2})" # description of whole line format in rct2-16.txt
pattern4 = "(\d{3})[ ](\d{3})(\d).{0,52} {0,3}([-><0-9a-zA-Z]{0,9})([.# ]?)(\d{0,4})[ ]{0,6}([A-Za-z]{0,2})" # description of line format in nubase2016.txt up to and including the time multipliers (e.g. 's', 'm', 'h', 'd', ...); only A, Z, ground state-flags and half-lives are described by this
pattern5 = ".{110}(.*)" # description of line format in nubase2016.txt; only the comments (e.g. 'B-=100') at the end of each line is described
pattern6 = ".{68}[ ]{0,2}([a-zA-Z]{0,2})[ ]([><0-9a-zA-Z]{0,6})([.]?)([0-9a-zA-Z]{0,6})" # description of line format in nubase2016.txt; used to get uncertainty on half-life -- "prefixed" half-life time multiplier also included
pattern7 = ".{79}([(]?)([><]?)(\d{0,2})([/2]*)([+-]?)([#]?)([)]?)([(]?)([+-]?)([#]?)([)]?)([^ -+()#*]?)" # description of line format in nubase2016.txt; used to get spin and parity
re1 = re.compile(pattern1)
re2 = re.compile(pattern2)
re3 = re.compile(pattern3)
re4 = re.compile(pattern4)
re5 = re.compile(pattern5)
re6 = re.compile(pattern6)
re7 = re.compile(pattern7)
# DEFINITION OF GENERAL DATA EXTRACTION FUNCTIONS
def get_number_from_match_object(match_object, index):
return int(match_object[0][index])
def combine_two_numbers(match_object, index_before_decimal, index_after_decimal):
result = int(match_object[0][index_before_decimal])
decimal = int(match_object[0][index_after_decimal])
decimal /= 10**(len(match_object[0][index_after_decimal]))
if result >= 0:
result += decimal
else:
result -= decimal
return result
def is_estimate(match_object, index_to_check):
check = match_object[0][index_to_check]
if "#" == check:
return True
else:
return False
def is_calculable(match_object, index_to_check):
check = match_object[0][index_to_check]
if "*" != check:
return True
else:
return False
def get_float_possibly_estimate(match_object, index_before_decimal):
is_est = is_estimate(match_object, index_before_decimal + 1)
if is_est:
return get_number_from_match_object(match_object, index_before_decimal), is_est
else:
return combine_two_numbers(match_object, index_before_decimal, index_before_decimal + 2), is_est
def get_float_possibly_estimate_possibly_incalculable(match_object, index_before_decimal):
is_calc = is_calculable(match_object, index_before_decimal)
if not is_calc:
return float('nan'), False, is_calc
is_est = is_estimate(match_object, index_before_decimal + 1)
if is_est:
return get_number_from_match_object(match_object, index_before_decimal), is_est, is_calc
else:
return combine_two_numbers(match_object, index_before_decimal, index_before_decimal + 2), is_est, is_calc
# REGEX PATTERN-SPECIFIC DATA EXTRACTION FUNCTIONS
# IT IS THE USER'S RESPONSIBILITY TO SUPPLY A match_object WHICH IS EXPECTED CF. THE COMMENTS NEXT TO EACH FUNCTION DEFINITION BELOW
def get_N(match_object): # match_object MUST be the result of a match to pattern1
return get_number_from_match_object(match_object, 2)
def get_Z(match_object): # match_object MUST be the result of a match to pattern1
return get_number_from_match_object(match_object, 3)
def get_A(match_object): # match_object MUST be the result of a match to pattern1
return get_number_from_match_object(match_object, 4)
def get_element(match_object): # match_object MUST be the result of a match to pattern1
A = match_object[0][4]
elem = match_object[0][5]
return A + elem # this is a string
def get_ME(match_object): # match_object MUST be the result of a match to pattern1
return get_float_possibly_estimate(match_object, 7)
def get_ME_err(match_object): # match_object MUST be the result of a match to pattern1
return get_float_possibly_estimate(match_object, 10)
def get_BE(match_object): # match_object MUST be the result of a match to pattern1
return get_float_possibly_estimate(match_object, 13)
def get_BE_err(match_object): # match_object MUST be the result of a match to pattern1
return get_float_possibly_estimate(match_object, 16)
def get_QB(match_object): # match_object MUST be the result of a match to pattern1
return get_float_possibly_estimate_possibly_incalculable(match_object, 19)
def get_QB_err(match_object): # match_object MUST be the result of a match to pattern1
if match_object[0][22].isdigit(): # if QB is incalculable, the data strings related to QB_err are empty
result, is_est = get_float_possibly_estimate(match_object, 22)
is_calc = True
return result, is_est, is_calc
else:
return float('nan'), False, False
def get_AMU(match_object): # match_object MUST be the result of a match to pattern1
result = int(match_object[0][25])
result *= 1e6
correction = int(match_object[0][26])
result += correction
is_est = is_estimate(match_object, 27)
if is_est:
return result, is_est
else:
decimal = int(match_object[0][28])
decimal /= 10**(len(match_object[0][28]))
result += decimal
return result, is_est
def get_AMU_err(match_object): # match_object MUST be the result of a match to pattern1
return get_float_possibly_estimate(match_object, 29)
def get_S2n(match_object): # match_object MUST be the result of a match to pattern2
return get_float_possibly_estimate_possibly_incalculable(match_object, 4)
def get_S2n_err(match_object): # match_object MUST be the result of a match to pattern2
if match_object[0][7].isdigit(): # if S2n is incalculable, the data strings related to S2n_err are empty
result, is_est = get_float_possibly_estimate(match_object, 7)
is_calc = True
return result, is_est, is_calc
else:
return float('nan'), False, False
def get_S2p(match_object): # match_object MUST be the result of a match to pattern2
return get_float_possibly_estimate_possibly_incalculable(match_object, 10)
def get_S2p_err(match_object): # match_object MUST be the result of a match to pattern2
if match_object[0][13].isdigit(): # if S2p is incalculable, the data strings related to S2p_err are empty
result, is_est = get_float_possibly_estimate(match_object, 13)
is_calc = True
return result, is_est, is_calc
else:
return float('nan'), False, False
def get_Qa(match_object): # match_object MUST be the result of a match to pattern2
return get_float_possibly_estimate_possibly_incalculable(match_object, 16)
def get_Qa_err(match_object): # match_object MUST be the result of a match to pattern2
if match_object[0][19].isdigit(): # if Qa is incalculable, the data strings related to Qa_err are empty
result, is_est = get_float_possibly_estimate(match_object, 19)
is_calc = True
return result, is_est, is_calc
else:
return float('nan'), False, False
def get_Q2B(match_object): # match_object MUST be the result of a match to pattern2
return get_float_possibly_estimate_possibly_incalculable(match_object, 22)
def get_Q2B_err(match_object): # match_object MUST be the result of a match to pattern2
if match_object[0][25].isdigit(): # if Q2B is incalculable, the data strings related to Q2B_err are empty
result, is_est = get_float_possibly_estimate(match_object, 25)
is_calc = True
return result, is_est, is_calc
else:
return float('nan'), False, False
def get_Qep(match_object): # match_object MUST be the result of a match to pattern2
return get_float_possibly_estimate_possibly_incalculable(match_object, 28)
def get_Qep_err(match_object): # match_object MUST be the result of a match to pattern2
if match_object[0][31].isdigit(): # if Qep is incalculable, the data strings related to Qep_err are empty
result, is_est = get_float_possibly_estimate(match_object, 31)
is_calc = True
return result, is_est, is_calc
else:
return float('nan'), False, False
def get_QBn(match_object): # match_object MUST be the result of a match to pattern2
return get_float_possibly_estimate_possibly_incalculable(match_object, 34)
def get_QBn_err(match_object): # match_object MUST be the result of a match to pattern2
if match_object[0][37].isdigit(): # if QBn is incalculable, the data strings related to QBn_err are empty
result, is_est = get_float_possibly_estimate(match_object, 37)
is_calc = True
return result, is_est, is_calc
else:
return float('nan'), False, False
def get_Sn(match_object): # match_object MUST be the result of a match to pattern3
return get_float_possibly_estimate_possibly_incalculable(match_object, 4)
def get_Sn_err(match_object): # match_object MUST be the result of a match to pattern3
if match_object[0][7].isdigit(): # if Sn is incalculable, the data strings related to Sn_err are empty
result, is_est = get_float_possibly_estimate(match_object, 7)
is_calc = True
return result, is_est, is_calc
else:
return float('nan'), False, False
def get_Sp(match_object): # match_object MUST be the result of a match to pattern3
return get_float_possibly_estimate_possibly_incalculable(match_object, 10)
def get_Sp_err(match_object): # match_object MUST be the result of a match to pattern3
if match_object[0][13].isdigit(): # if Sp is incalculable, the data strings related to Sp_err are empty
result, is_est = get_float_possibly_estimate(match_object, 13)
is_calc = True
return result, is_est, is_calc
else:
return float('nan'), False, False
def get_Q4B(match_object): # match_object MUST be the result of a match to pattern3
return get_float_possibly_estimate_possibly_incalculable(match_object, 16)
def get_Q4B_err(match_object): # match_object MUST be the result of a match to pattern3
if match_object[0][19].isdigit(): # if Q4B is incalculable, the data strings related to Q4B_err are empty
result, is_est = get_float_possibly_estimate(match_object, 19)
is_calc = True
return result, is_est, is_calc
else:
return float('nan'), False, False
def get_Qda(match_object): # match_object MUST be the result of a match to pattern3
return get_float_possibly_estimate_possibly_incalculable(match_object, 22)
def get_Qda_err(match_object): # match_object MUST be the result of a match to pattern3
if match_object[0][25].isdigit(): # if Qda is incalculable, the data strings related to Qda_err are empty
result, is_est = get_float_possibly_estimate(match_object, 25)
is_calc = True
return result, is_est, is_calc
else:
return float('nan'), False, False
def get_Qpa(match_object): # match_object MUST be the result of a match to pattern3
return get_float_possibly_estimate_possibly_incalculable(match_object, 28)
def get_Qpa_err(match_object): # match_object MUST be the result of a match to pattern3
if match_object[0][31].isdigit(): # if Qpa is incalculable, the data strings related to Qpa_err are empty
result, is_est = get_float_possibly_estimate(match_object, 31)
is_calc = True
return result, is_est, is_calc
else:
return float('nan'), False, False
def get_Qna(match_object): # match_object MUST be the result of a match to pattern3
return get_float_possibly_estimate_possibly_incalculable(match_object, 34)
def get_Qna_err(match_object): # match_object MUST be the result of a match to pattern3
if match_object[0][37].isdigit(): # if Qna is incalculable, the data strings related to Qna_err are empty
result, is_est = get_float_possibly_estimate(match_object, 37)
is_calc = True
return result, is_est, is_calc
else:
return float('nan'), False, False
def get_A4(match_object): # match_object MUST be the result of a match to pattern4; use get_A() instead
return get_number_from_match_object(match_object, 0)
def get_Z4(match_object): # match_object MUST be the result of a match to pattern4; use get_Z() instead
return get_number_from_match_object(match_object, 1)
def is_ground_state(match_object): # match_object MUST be the result of a match to pattern4
check = match_object[0][2]
if "0" == check:
return True
else:
return False
# definition of year_in_secs and timeunits to be used in get_half_life()
year_in_secs = 31556926
timeunits = {
"s": 1,
"ms": 1e-3,
"us": 1e-6,
"ns": 1e-9,
"ps": 1e-12,
"fs": 1e-15,
"as": 1e-18,
"zs": 1e-21,
"ys": 1e-24,
"y": year_in_secs,
"ky": 1e3*year_in_secs,
"My": 1e6*year_in_secs,
"Gy": 1e9*year_in_secs,
"Ty": 1e12*year_in_secs,
"Py": 1e15*year_in_secs,
"Ey": 1e18*year_in_secs,
"Zy": 1e21*year_in_secs,
"Yy": 1e24*year_in_secs,
"m": 60,
"h": 60*60,
"d": 60*60*24
}
def get_half_life(match_object): # match_object MUST be the result of a match to pattern4
string = match_object[0][3]
if not string:
return float('nan'), False, False, False
is_est = is_estimate(match_object, 4)
is_greater_or_smaller = False
if string[0] == "<" or string[0] == ">":
string = string[1:]
is_greater_or_smaller = True
is_est = True
is_stable = False
if not string.isdigit():
if string == "stbl":
is_stable = True
return float('nan'), False, False, is_stable
else:
return float('nan'), False, False, is_stable
result = int(string)
check_decimal = match_object[0][4]
if check_decimal != " " and check_decimal != "#":
decimal = int(match_object[0][5])
decimal /= 10**(len(match_object[0][5]))
result += decimal
result *= timeunits.get(match_object[0][6])
return result, is_est, is_greater_or_smaller, is_stable
def get_half_life_err(match_object): # match_object MUST be the result of a match to pattern6
string = match_object[0][1]
if not string:
return float('nan'), False, False
is_est = False # decimal point is not replaced by '#' if the result is an estimate in this case, so we cannot invoke is_estimate()
is_greater_or_smaller = False
if string[0] == "<" or string[0] == ">":
string = string[1:]
is_greater_or_smaller = True
is_est = True
whole_number_string = multiplier_string = ""
for i in range(0, len(string)):
if string[i].isdigit():
whole_number_string += string[i]
else:
multiplier_string = string[i:]
break
result = int(whole_number_string)
if not multiplier_string:
check_decimal = match_object[0][2]
string = match_object[0][3]
if check_decimal and string:
decimal_string = ""
for i in range(0, len(string)):
if string[i].isdigit():
decimal_string += string[i]
else:
multiplier_string = string[i:]
break
decimal = int(decimal_string)
decimal /= 10**(len(decimal_string))
result += decimal
if multiplier_string:
result *= timeunits.get(multiplier_string)
else:
result *= timeunits.get(match_object[0][0])
return result, is_est, is_greater_or_smaller
def get_spin(match_object): # match_object MUST be the result of a match to pattern7
# if entry 2 is empty, there is no spin value; if entries 1 or 11 contain anything, the spin is not uniquely determined
if not match_object[0][2] or match_object[0][1] or match_object[0][11]:
return float('nan'), False
result = int(match_object[0][2]) # spin value without a possible division by 2
if match_object[0][3] == "/2":
result /= 2
is_uncertain = False
if match_object[0][0] == "(":
is_uncertain = True
return result, is_uncertain
def parity_string_to_int(parity_string):
if parity_string == "+":
return 1
elif parity_string == "-":
return -1
else:
print("parity string conversion error, returning undefined parity value (integer zero)")
return 0
def get_parity(match_object): # match_object MUST be the result of a match to pattern7
# if both entries 4 and 8 are empty, there is no parity value; if entries 1 or 11 contain anything, the spin is not uniquely determined -- it is likely that the parity also is not uniquely determined (the regex in pattern7 is not able to handle the cases where the parity is uniquely determined despite the spin not being uniquely determined)
if (not match_object[0][4] and not match_object[0][8]) or match_object[0][1] or match_object[0][11]:
return 0, False, False
result = 0
is_est = is_uncertain = False
if match_object[0][4]:
result = parity_string_to_int(match_object[0][4])
if match_object[0][5] == "#":
is_est = True
if match_object[0][0] == "(":
is_uncertain = True
else:
result = parity_string_to_int(match_object[0][8])
if match_object[0][9] == "#":
is_est = True
if match_object[0][7] == "(":
is_uncertain = True
return result, is_est, is_uncertain
def get_comment(match_object): # match_object MUST be the result of a match to pattern5
if match_object:
return match_object[0]
else:
return ""
// TODO: give a general description of the program (block comment)
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <TFile.h>
#include <TTree.h>
using namespace std;
void modify_and_print(string filename) {
ifstream ifs(filename.c_str());
string line;
getline(ifs, line); // skip first line
getline(ifs, line);
line[0] = '#';
for (char& c : line) {
if (c == '*') c = ' ';
}
cout << line << endl;
getline(ifs, line); // skip third line
int flag = 0;
while (getline(ifs, line)) {
for (char& c : line) {
if (c == '*') c = ' ';
if (c == '=') flag = 1; // skip final line
}
if (flag == 0) cout << line << endl;
}
}
int main(int argc, char* argv[]) {
// Open the root-file, which is the first given argument, and access its tree with the name of the second given argument
TFile input(argv[1]);
TTree *t;
input.GetObject(argv[2], t);
// Separate out all other arguments as either parameters to be printed or criteria on the parameters (comparison statements)
vector<string> args(argv + 3, argv + argc);
vector<string> comps{"==", "!=", "<", ">", "<=", ">="};
string printvars = "";
string selection = "";
int flag; // flag = 0 means the string s in the loop below is a parameter to be printed, flag = 1 means it is a criterion
for (string s : args) {
flag = 0;
for (string q : comps) {
if (s.find(q) != string::npos) { // if string q is found in string s, s is a criterion -> flag = 1
flag = 1;
break;
}
}
if (flag == 0) {
if (!printvars.empty()) printvars += ":"; // printvars = "var1:var2:var3:...:varN" when we are done
printvars += s;
} else {
if (!selection.empty()) selection += " && "; // selection = "sel1 && sel2 && sel3 && ... && selM" when we are done
selection += s;
}
}
/*
* TTree::Scan, used below, prints the parameters with the criteria we ask for, but it contains
* symbols, mainly lots of "*"'s, and lines which we need to replace or remove.
* More precisely, TTree::Scan prints the output via printf statements, and the only way to
* properly catch the output, modify the output and then print the modified output, as far as I
* can tell, is to redirect stdout (different from cout) to a file, then read the file, then
* modify its contents, etc.
* The temporary file will be deleted again when we are done.
*/
FILE* saved = stdout;
string tmpf = "tmp.dat";
stdout = fopen(tmpf.c_str(), "w"); // stdout redirected to temporary file
t->SetScanField(0); // print all data in one go (any int > 0 would print only that amount)
t->Scan(printvars.c_str(), selection.c_str());
fclose(stdout);
stdout = saved; // stdout back to normal
// Print a comment line showing the command which created the output
cout << "#";
for (int i = 0; i < argc; i++) {
cout << argv[i] << " ";
}
cout << "[criteria must be surrounded by \"'s, e.g. A <= 20 -> \"A <= 20\"]" << endl;
// Print output in suitable format
modify_and_print(tmpf);
remove(tmpf.c_str());
input.Close();
return EXIT_SUCCESS;
}
root nuchart.root :
a->Print()
a->Show(0), a->Show(1), ..., a->Show(3435)
new TBrowser
# assumed clicked around in TBrowser and closed again
a->SetMarkerStyle(21)
a->Draw("Z:N:QB", "", "colz")
a->SetMarkerSize(4) # or similar, [1, 7]
a->Draw("Z:N:QB", "5 < A && A < 65 && QB_est == 0", "colz")
a->Draw("Z >> (100, 0, 99)", "")
a->Draw("Z >> (100, 0, 99)", "QB > 0")
.q
back at terminal :
root QECdatamaker.cxx --> qec.dat
.q
python3 qec.py --> qec.pdf
// TODO: Finish this script (remember to check whether the resulting values correct?),
// same as expand-nuchart-QEC.cxx
/*
* In this ROOT macro the ROOT Tree 'nuchart.root' generated by treemaker.py is expanded by
* adding Q-values for electron capture to the tree via the formula
* QEC = MEP - MED;
* QEC is the Q-value for electron capture,
* MEP is the mass excess of the Parent which is decaying,
* MED is the mass excess of the Daughter which the Parent decays into.
* If either or both of MEP or MED is an estimate (as given by the original ROOT Tree
* 'nuchart.root'), QEC is also considered an estimate.
* If MEP exists, but there is no available MED, the Q-value for the Parent is flagged as
* incalculable.
*/
#define ELMASS 510.99895 // electron mass in keV
#include <TFile.h>