13 Decay File Parser to check whether a decay file is correctly defined
20 from colours
import mesg, query, fail, done, warning
23 mesg(
'Starting the decfile check')
24 query(
'Opening decfile')
26 fail([
'Please pass the decfile as the first argument.'])
29 filename = sys.argv[1]
30 dkfilespath = os.path.dirname(os.path.abspath(sys.argv[0])) +
'/' \
31 + settings.dkfilespath
33 if not os.path.exists(filename):
34 fail([
'The file does not exist'])
36 elif not os.path.isfile(filename):
38 fail([
'The path does not point to a regular file.'])
43 fail([
'Unknown error opening file.'])
48 documentation_inprocess =
False
67 decay_inprocess =
False
80 def getfield(line, string):
82 if string +
':' in line:
83 query(
'Now parsing: ' + string)
84 tmp = line.partition(string +
':')[2]
86 if tmp.startswith(
' '):
90 warning(
'Field empty on line ' + str(linecount))
97 if line.strip() ==
'':
100 if line.startswith(
'#')
and not decay_started:
102 if documentation_inprocess:
103 if 'EndDocumentation' in line:
104 documentation_inprocess =
False
105 documentation =
' '.join(documentation)
107 documentation += [line.strip(
'#')]
110 tmp = getfield(line,
'Documentation')
112 file2 = open(filename)
114 if 'EndDocumentation' in line2:
115 documentation_inprocess =
True
118 documentation += [tmp]
120 tmp = getfield(line,
'EventType')
124 except BaseException:
125 fail([
'Failed parsing eventtype on line ' + str(linecount),
127 order += [
'EventType']
128 mesg(
'Eventtype found: ' + str(eventtype))
130 tmp = getfield(line,
'Descriptor')
133 order += [
'descriptor']
134 if '{,gamma}' in tmp:
136 'Please do not include radiative photons in the descriptor.')
138 tmp = getfield(line,
'NickName')
141 fail([
'NickName empty on line ' + str(linecount)])
142 elif not tmp == os.path.basename(filename).partition(
'.dec')[0]:
143 fail([
'NickName not the same as filename!'])
146 order += [
'nickname']
148 tmp = getfield(line,
'Cuts')
152 test_cuts = [
'None',
'DaughtersInBelleII']
153 if cuts
not in test_cuts:
161 tmp = getfield(line,
'FullEventCuts')
164 order += [
'fulleventcuts']
166 tmp = getfield(line,
'ExtraOptions')
169 order += [
'extraopts']
171 tmp = getfield(line,
'PhysicsWG')
174 order += [
'physicswg']
176 tmp = getfield(line,
'Tested')
179 warning(
'File not tested! Please test the file!')
180 elif not tmp ==
'Yes':
181 warning(
'Unkown Tested state. Please use Yes or No.')
186 tmp = getfield(line,
'Responsible')
189 order += [
'responsible']
191 tmp = getfield(line,
'Email')
194 warning(
'Please use a correct email format.')
199 tmp = getfield(line,
'ParticleValue')
204 part = part.strip(
'"')
206 tmp2[part[6]] = part[1]
209 tmp = getfield(line,
'Date')
213 if not date / 10000 == time.gmtime().tm_year:
214 warning(
'Date is not from this year. Please use YYYYMMDD for date field. YYYY parsed:' +
215 str(date / 10000) +
' vs. current year: ' + str(time.gmtime().tm_year))
216 if date - 10000 * (date / 10000) > 1231:
217 warning(
'Cannot parse date. Please use YYYYMMDD for date field. MMDD parsed:' +
218 str(date - 10000 * (date / 10000)))
219 if date - 100 * (date / 100) > 31:
220 warning(
'Cannot parse date. Please use YYYYMMDD for date field. DD parsed:' +
221 str(date - 100 * (date / 100)))
222 except BaseException:
223 warning(
'Cannot parse date. Please use YYYYMMDD for date field.'
225 elif not line ==
'' and not decay_started
and not Ended:
227 mesg(
'End of header.')
234 if not line.startswith(
'#'):
236 elements = line.partition(
'Alias')[2].strip().split()
237 alias[elements[0].strip()] = elements[1].strip()
238 if 'ChargeConj' in line:
239 elements = line.partition(
'ChargeConj')[2].strip().split()
240 chargeconj[elements[0].strip()] = elements[1].strip()
243 elements = line.partition(
'CDecay')[2].strip()
245 elif 'Decay' in line:
247 mother = line.partition(
'Decay ')[2].strip()
248 mesg(
'Found decay: ' + mother)
249 decay_inprocess =
True
252 if 'End' in line
and 'Enddecay' not in line:
254 decay_started =
False
257 if 'Enddecay' in line:
258 decay[mother] = current_decay
259 decay_inprocess =
False
264 line = line.strip().split()
269 except BaseException:
270 warning(
'Branching fraction not a number on line: ' +
271 str(linecount) +
'. Skipping.')
273 for daug
in line[1:-1]:
274 if daug.strip(
';')
in settings.terminators:
277 elif daug.endswith(
';'):
279 'A new terminator found: ' +
282 settings.terminators += [daug.strip(
';')]
287 elif daug
in chargeconj:
293 "You defined a charge conjugation without either particle being an alias. "
294 "Are you sure you know what you're doing on line " + str(linecount) +
'?')
299 'You defined an alias to particle ' +
305 ' you use the original particle. Is this what you want?')
307 if not line[-1].endswith(
';'):
311 ' does not end with a ;')
312 current_decay += [(bf, dec)]
314 mesg(
'File parsed successfully.')
318 warning(
"Cannot proceed without eventtype. Please fix the eventtype so it's recognisable."
324 query(
'Checking general flag')
325 general = parttype / 10000000
327 parttype -= general * 10000000
331 mother = daug.partition(
'sig')[0]
335 if nickname.startswith(
'uubar'):
337 elif nickname.startswith(
'ddbar'):
339 elif nickname.startswith(
'ssbar'):
341 elif nickname.startswith(
'mixed'):
343 elif nickname.startswith(
'charged'):
345 elif nickname.startswith(
'charm'):
348 fail([
'Cannot find the signal particle and cannot determine the inclusive mode.'])
352 if 'B' in mother
or 'b0' in mother
or 'Upsilon' in mother
or 'chi_b' in mother:
354 elif 'D' in mother
or 'psi' in mother
or 'chi_c' in mother
or 'c+' in mother:
356 elif 'K_S0' in mother
or 'Lambda' in mother
or 'Sigma' in mother
or 'tau' in mother:
359 warning(
"Didn't recognise the mother particle. Check general flag manually.")
361 if not flag == general:
362 fail([
'General flag not compliant. Should be ' + str(flag) +
'.Please check.'])
365 newevtype += str(flag)
367 query(
'Checking selection flag')
368 selection = parttype / 1000000
369 parttype -= selection * 1000000
373 elif mother ==
'D-' or mother ==
'B0' or mother ==
'D+' or mother ==
'anti-B0':
375 elif mother ==
'D0' or mother ==
'anti-D0' or mother ==
'B+' or mother ==
'B-':
377 elif mother ==
'B_s0' or mother ==
'D_s-' or mother ==
'D_s+':
379 elif mother ==
'J/psi':
381 elif mother ==
'Lambda_b0' or mother ==
'Lambda_c+':
383 elif (
'Sigma_b' in mother
or 'chi_b' in mother
or 'Omega_b' in mother)
and general == 1:
385 elif (
'Upsilon' in mother
or 'chi_b' in mother)
and general == 1:
387 elif (
'D' in mother
and '*' in mother
or 'D_s1' in mother)
and general == 2:
389 elif (
'psi(2S)' in mother
or 'X_1(3872)' in mother
or 'h_c' in mother
or
390 'chi_c' in mother
or mother ==
'eta_c')
and general == 2:
395 if mother ==
'tau+' or mother ==
'tau-':
397 elif 'Lambda' in mother:
399 elif 'Sigma' in mother:
401 elif mother ==
'K_S0':
405 'General flag is 3 but mother particle is not recogniced - assuming minbias.')
408 warning(
'Cannot determine selection flag. Please check manually.')
410 if not flag == selection:
412 'Selection flag is not compliant, should be ' +
417 newevtype += str(flag)
419 query(
'Unfolding decay.')
423 current_decay = (decay[mother +
'sig'])[:]
425 for (bf2, dec2)
in current_decay:
429 newdecay.remove(daug)
430 for (bf2, dau2)
in decay[daug]:
432 for (bf3, dau3)
in decay[daug]:
434 newbf = bf * bf2 / norm
435 newdecay2 = sorted(newdecay[:] + dau2[:])
436 current_decay += [(newbf, newdecay2)]
443 for (bf, dec2)
in dec:
452 main_decay = [getmax(decay[mother +
'sig'])]
455 while not clean
and mother:
457 olddec = (main_decay[-1])[:]
458 for daug
in main_decay[-1]:
461 if daug
not in decay:
465 elif chargeconj[k] == daug:
467 if daug
not in decay:
468 warning(
'Aliased particle but cannot find its decay!: ' + daug)
469 newdec = [alias[daug]]
471 newdec = getmax(decay[daug])
475 main_decay += [olddec]
478 query(
'Checking the decay flag')
480 decayflag = parttype / 100000
481 parttype -= decayflag * 100000
488 for (bf, dec)
in current_decay:
490 for (bf2, dec2)
in current_decay:
495 if test_dec2 == test_dec1:
524 if not decayflag == flag:
525 fail([
'Decay flag is not compliant. Should be ' + str(flag) +
'. Please check'])
528 newevtype += str(flag)
530 query(
'Checking charm and lepton flag')
537 charmflag = parttype / 10000
538 parttype -= charmflag * 10000
542 for field
in [extraopts, cuts, fulleventcuts]:
543 if 'Electron' in field
or 'electron' in field:
545 if 'mu' in field
or 'Mu' in field:
547 if 'D0' in field
or 'Dmu' in field
or 'Ds' in field
or 'DS' in field
or 'DMass' in field
or 'DMu' in field:
552 for dec
in main_decay:
559 if daug ==
'e-' or daug ==
'e+':
562 if daug ==
'mu-' or daug ==
'mu+':
565 if (
'D' in daug
or '_c' in daug)
and 'chi_c' not in daug:
573 if 'psi' in daug
or 'chi_c' in daug:
588 if not flag == charmflag:
589 fail([
'Charm flag is not compliant. Should be :' + str(flag) +
'. Please check'])
592 newevtype += str(flag)
594 query(
'Checking track flag.')
595 trackflag = parttype / 1000
596 parttype -= trackflag * 1000
601 warning(
'Inclusive decay: Problem with settings the track flag. Check manually.'
603 if 'DiLepton' in fulleventcuts
or 'DiLepton' in cuts
or 'DiLepton' in extraopts:
605 for dec
in main_decay:
612 if daug
in settings.longlived:
615 if tracks > maxtracks:
618 if not trackflag == maxtracks:
619 fail([
'Track flag not compliant. Should be: ' +
620 str(maxtracks) +
'. Please check.'])
623 newevtype += str(maxtracks)
625 query(
'Checking neutrals flag.')
626 neutrals = parttype / 100
627 parttype -= neutrals * 100
634 for dec
in main_decay:
638 if daug ==
'K_S0' or daug ==
'Lambda0' or mother ==
'K_S0' or mother ==
'Lambda0':
640 elif daug ==
'pi0' or daug ==
'eta':
646 for i
in range(len(main_decay)):
647 if 'gamma' in main_decay[i]:
650 for daug
in main_decay[i - 1]:
654 if daug2 ==
'pi0' or daug2 ==
'eta':
655 if daug
not in main_decay[i]:
672 if not flag == neutrals:
673 fail([
'Neutrals flag not compliant. Should be ' + str(flag) +
'. Please check.'])
676 newevtype += str(flag)
678 query(
'Checking the extra and user for duplicity .')
682 warning(
'Cannot parse decfiles webpage')
683 settings.use_url =
False
685 for (k, v)
in zippednos:
686 if filename.partition(
'=')[0] == v.partition(
687 '=')[0]
and not eventtype / 10 == k / 10:
693 ' should contain the same decay, therefore the first 7 '
694 'digits of the eventtype should match. Please check and use the same extra flag.')
697 warning(
'Error: ' + v +
' has this eventtype already.')
699 if k / 10 == eventtype / \
700 10
and not os.path.basename(filename).partition(
'=')[0] == v.partition(
'=')[0]:
706 ' uses this extra flag, but the decay seems different. '
707 'Please check and use a unique extra flag.')
713 warning(
'Cannot parse obsoletes trac file.')
714 settings.use_url =
False
716 if str(eventtype)
in obsnos:
717 warning(
'The eventtype is obsolete on the line ' +
718 str(obsnos.index(str(eventtype)) + 1) +
' in: ' +
722 if not settings.use_url:
723 filelist = os.listdir(dkfilespath)
726 for filen
in filelist:
727 if filen.endswith(
'.dec'):
728 file = open(dkfilespath +
'/' + filen)
730 if 'EventType: ' in line:
732 newtype = int(line.partition(
'EventType: ')[2].strip())
734 except BaseException:
736 if filen.partition(
'=')[0] == filename.partition(
'='):
737 if not newtype / 10 == eventtype / 10:
743 ' should contain the same decay, therefore the first 7 '
744 'digits of the eventtype should match. Please check and use the same extra flag.')
747 if newtype == eventtype:
748 warning(
'Error: ' + filen +
' has this eventtype already.')
751 if settings.obsoletepath:
752 obsfile = open(settings.obsoletepath +
'/table_obsolete.sql')
755 if int(line.partition(
'EVTTYPEID = ')[2].partition(
756 ', DESCRIPTION')[0]) == eventtype:
758 'The eventtype is obsolete on the following line in: ' +
759 settings.obsoletepath +
760 '/table_obsolete.sql')
764 extraflag = eventtype / 10
765 extraflag = eventtype - extraflag * 10
766 if 'DaughtersInBelleII' not in cuts
and extraflag
and cuts == 0:
768 'Your cuts are not empty, please set your userflag to greater or equal to 1.')
770 if cuts == [
'None']
and extraflag != 0:
771 warning(
"Your cuts are empty, your user flag should be 0 unless that's taken. Please check."
778 mesg(
'Eventtype constructed: ' + newevtype +
'XX')
780 query(
'Checking nickname.')
783 if not nickname == os.path.basename(filename).partition(
'.dec')[0]:
784 faillist += [
'Filename not the same as nickname! Fix.']
786 nick = nickname.partition(
'=')
787 if not nick[1] ==
'=' and not cuts == []:
789 [
'The = sign not found in the nickname while cuts are present. Check nickname conventions and fix.'
791 warning(
'The = sign not found in the nickname while cuts are present. Check nickname conventions and fix.'
794 if 'DaughtersInBelleII' in cuts
and 'DecProdCut' not in nick[2].split(
','):
796 [
'You have decay angular acceptance cut in Cuts but not in the nickname.'
805 if not len(nick[0].split(
',')) > 1
and mother:
806 warning(
'Found only one decay level in the nickname - highly unusual, you should probably use at least two.'
809 if len(nick[2].split(
',')) < len(cuts.split(
',')):
810 warning(
'You have more cuts than declared in the nickname. Please check.')
812 query(
'Checking the Physics WG.')
813 if physicswg
not in settings.groups:
814 fail([
'The group /' + physicswg +
815 '/ is not known. Please use one of the following:', settings.groups])
820 query(
'Building descriptor.')
823 for (bf, dec)
in decay[mother +
'sig']:
826 for (bf, dec)
in decay[mother +
'sig']:
829 descript = [mother] + [
'->'] + curdec
833 for daug
in descript:
838 for (bf, dec)
in decay[daug]:
841 for (bf, dec)
in decay[daug]:
844 ind = descript.index(daug)
845 descript.remove(daug)
846 if daug
not in alias:
847 warning(
'You decay a particle: [' + daug +
848 '] without aliasing it first. Step aborted.')
853 toadd = [
'(', daug,
'->'] + curdec + [
')']
856 descript.insert(ind, el)
863 descript =
'[' +
' '.join(descript) +
']'
864 descript = descript.replace(
'( ',
'(')
865 descript = descript.replace(
' )',
')')
873 query(
'Checking descriptor.')
875 decr_old = descriptor.partition(
'[')[2].partition(
']')[0].split()
876 decr_new = descript.partition(
'[')[2].partition(
']')[0].split()
884 fail([
'Descriptor not matched. Please check the old one:', descriptor,
885 '\nAnd the one built by the parser: ', descript])
886 for mes
in descriptcheck.mesgdict:
890 print(daug, decay[daug])
892 print(
'Main decay chain:')
893 for dec
in main_decay:
896 sys.exit(
'Decfile check complete.')
def convertToList(stringA)
def compareList(listA, listB)