Belle II Software  release-08-01-10
decparser.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 
11 
12 """
13 Decay File Parser to check whether a decay file is correctly defined
14 """
15 
16 import sys
17 import settings
18 import os
19 import time
20 from colours import mesg, query, fail, done, warning
21 import descriptcheck
22 
23 mesg('Starting the decfile check')
24 query('Opening decfile')
25 if len(sys.argv) < 2:
26  fail(['Please pass the decfile as the first argument.'])
27  sys.exit()
28 
29 filename = sys.argv[1]
30 dkfilespath = os.path.dirname(os.path.abspath(sys.argv[0])) + '/' \
31  + settings.dkfilespath
32 
33 if not os.path.exists(filename):
34  fail(['The file does not exist'])
35  sys.exit()
36 elif not os.path.isfile(filename):
37 
38  fail(['The path does not point to a regular file.'])
39  sys.exit()
40 
41 file = open(filename)
42 if not file:
43  fail(['Unknown error opening file.'])
44  sys.exit()
45 
46 done()
47 
48 documentation_inprocess = False
49 date = ''
50 responsible = ''
51 eventtype = 0
52 descriptor = ''
53 nickname = ''
54 cuts = ''
55 fulleventcuts = ''
56 documentation = []
57 physicswg = ''
58 tested = ''
59 email = ''
60 extraopts = ''
61 particledefs = []
62 decay = {}
63 current_decay = []
64 order = []
65 
66 decay_started = False
67 decay_inprocess = False
68 
69 alias = {}
70 chargeconj = {}
71 cdecay = []
72 mother = ''
73 
74 Ended = False
75 endcheck = False
76 
77 linecount = 0
78 
79 
80 def getfield(line, string):
81  tmp = ''
82  if string + ':' in line:
83  query('Now parsing: ' + string)
84  tmp = line.partition(string + ':')[2]
85  done()
86  if tmp.startswith(' '):
87  tmp = tmp.strip()
88 # warning("Please leave a single space after the : sign. on line:"+str(linecount))
89  if tmp == '':
90  warning('Field empty on line ' + str(linecount))
91  return tmp
92 
93 
94 for line in file:
95  linecount += 1
96 
97  if line.strip() == '':
98  continue
99 
100  if line.startswith('#') and not decay_started:
101 
102  if documentation_inprocess:
103  if 'EndDocumentation' in line:
104  documentation_inprocess = False
105  documentation = ' '.join(documentation)
106  continue
107  documentation += [line.strip('#')]
108  continue
109 
110  tmp = getfield(line, 'Documentation')
111  if tmp:
112  file2 = open(filename)
113  for line2 in file2:
114  if 'EndDocumentation' in line2:
115  documentation_inprocess = True
116  break
117  file2.close()
118  documentation += [tmp]
119 
120  tmp = getfield(line, 'EventType')
121  if tmp:
122  try:
123  eventtype = int(tmp)
124  except BaseException:
125  fail(['Failed parsing eventtype on line ' + str(linecount),
126  'Not a number.'])
127  order += ['EventType']
128  mesg('Eventtype found: ' + str(eventtype))
129 
130  tmp = getfield(line, 'Descriptor')
131  if tmp:
132  descriptor = tmp
133  order += ['descriptor']
134  if '{,gamma}' in tmp:
135  warning(
136  'Please do not include radiative photons in the descriptor.')
137 
138  tmp = getfield(line, 'NickName')
139  if tmp:
140  if tmp == '':
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!'])
144  else:
145  nickname = tmp
146  order += ['nickname']
147 
148  tmp = getfield(line, 'Cuts')
149  if tmp:
150  cuts = tmp
151  order += ['cuts']
152  test_cuts = ['None', 'DaughtersInBelleII']
153  if cuts not in test_cuts:
154  warning(
155  'Unknown cuts <' +
156  cuts +
157  '> on line ' +
158  str(linecount) +
159  '. Please check.')
160 
161  tmp = getfield(line, 'FullEventCuts')
162  if tmp:
163  fulleventcuts = tmp
164  order += ['fulleventcuts']
165 
166  tmp = getfield(line, 'ExtraOptions')
167  if tmp:
168  extraopts = tmp
169  order += ['extraopts']
170 
171  tmp = getfield(line, 'PhysicsWG')
172  if tmp:
173  physicswg = tmp
174  order += ['physicswg']
175 
176  tmp = getfield(line, 'Tested')
177  if tmp:
178  if tmp == 'No':
179  warning('File not tested! Please test the file!')
180  elif not tmp == 'Yes':
181  warning('Unkown Tested state. Please use Yes or No.')
182  else:
183  tested = tmp
184  order += ['tested']
185 
186  tmp = getfield(line, 'Responsible')
187  if tmp:
188  responsible = tmp
189  order += ['responsible']
190 
191  tmp = getfield(line, 'Email')
192  if tmp:
193  if '@' not in tmp:
194  warning('Please use a correct email format.')
195  else:
196  email = tmp
197  order += ['email']
198 
199  tmp = getfield(line, 'ParticleValue')
200  if tmp:
201  tmp = tmp.split(',')
202  tmp2 = {}
203  for part in tmp:
204  part = part.strip('"')
205  part = part.split()
206  tmp2[part[6]] = part[1]
207  particledefs = tmp2
208 
209  tmp = getfield(line, 'Date')
210  if tmp:
211  try:
212  date = int(tmp)
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.'
224  )
225  elif not line == '' and not decay_started and not Ended:
226 
227  mesg('End of header.')
228  decay_started = True
229 
230  if Ended:
231  endcheck = True
232 
233  if decay_started:
234  if not line.startswith('#'):
235  if 'Alias' in line:
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()
241 
242  if 'CDecay' in line:
243  elements = line.partition('CDecay')[2].strip()
244  cdecay += [elements]
245  elif 'Decay' in line:
246 
247  mother = line.partition('Decay ')[2].strip()
248  mesg('Found decay: ' + mother)
249  decay_inprocess = True
250  continue
251 
252  if 'End' in line and 'Enddecay' not in line:
253  Ended = True
254  decay_started = False
255 
256  if decay_inprocess:
257  if 'Enddecay' in line:
258  decay[mother] = current_decay
259  decay_inprocess = False
260  # mesg("Found decay end of: "+mother)
261  current_decay = []
262  else:
263 
264  line = line.strip().split()
265  bf = line[0]
266  dec = []
267  try:
268  bf = float(bf)
269  except BaseException:
270  warning('Branching fraction not a number on line: ' +
271  str(linecount) + '. Skipping.')
272  continue
273  for daug in line[1:-1]:
274  if daug.strip(';') in settings.terminators:
275  # mesg("Terminator found, ending decay line.")
276  break
277  elif daug.endswith(';'):
278  warning(
279  'A new terminator found: ' +
280  daug.strip(';') +
281  '. Adding to list')
282  settings.terminators += [daug.strip(';')]
283  break
284  if daug in alias:
285  # daug = alias[daug]
286  pass
287  elif daug in chargeconj:
288  # daug = chargeconj[daug]
289  if daug in alias:
290  daug = alias[daug]
291  else:
292  warning(
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) + '?')
295  else:
296  for k in alias:
297  if daug == alias[k]:
298  warning(
299  'You defined an alias to particle ' +
300  daug +
301  ' called ' +
302  k +
303  ' but on line ' +
304  str(linecount) +
305  ' you use the original particle. Is this what you want?')
306  dec += [daug]
307  if not line[-1].endswith(';'):
308  warning(
309  'Line ' +
310  str(linecount) +
311  ' does not end with a ;')
312  current_decay += [(bf, dec)]
313 
314 mesg('File parsed successfully.')
315 file.close()
316 
317 if not eventtype:
318  warning("Cannot proceed without eventtype. Please fix the eventtype so it's recognisable."
319  )
320  sys.exit()
321 
322 newevtype = ''
323 parttype = eventtype
324 query('Checking general flag')
325 general = int(str(parttype)[0])
326 flag = 0
327 mother = ''
328 for daug in decay:
329  if 'sig' in daug:
330  mother = daug.partition('sig')[0]
331  # mesg("Found mother: "+mother)
332  break
333 else:
334  if nickname.startswith('uubar'):
335  flag = 3
336  elif nickname.startswith('ddbar'):
337  flag = 3
338  elif nickname.startswith('ssbar'):
339  flag = 3
340  elif nickname.startswith('mixed'):
341  flag = 1
342  elif nickname.startswith('charged'):
343  flag = 1
344  elif nickname.startswith('charm'):
345  flag = 2
346  else:
347  fail(['Cannot find the signal particle and cannot determine the inclusive mode.'])
348  sys.exit()
349  done()
350 if mother:
351  if 'B' in mother or 'b0' in mother or 'Upsilon' in mother or 'chi_b' in mother:
352  flag = 1
353  elif 'D' in mother or 'psi' in mother or 'chi_c' in mother or 'c+' in mother:
354  flag = 2
355  elif 'K_S0' in mother or 'Lambda' in mother or 'Sigma' in mother or 'tau' in mother:
356  flag = 3
357  else:
358  warning("Didn't recognise the mother particle. Check general flag manually.")
359  flag = general
360  if not flag == general:
361  fail(['General flag not compliant. Should be ' + str(flag) + '. Please check.'])
362  else:
363  done()
364 newevtype += str(flag)
365 
366 query('Checking selection flag')
367 selection = int(str(parttype)[1])
368 flag = selection
369 if not mother:
370  flag = 0
371 elif mother == 'D-' or mother == 'B0' or mother == 'D+' or mother == 'anti-B0':
372  flag = 1
373 elif mother == 'D0' or mother == 'anti-D0' or mother == 'B+' or mother == 'B-':
374  flag = 2
375 elif mother == 'B_s0' or mother == 'D_s-' or mother == 'D_s+':
376  flag = 3
377 elif mother == 'J/psi':
378  flag = 4
379 elif mother == 'Lambda_b0' or mother == 'Lambda_c+':
380  flag = 5
381 elif ('Sigma_b' in mother or 'chi_b' in mother or 'Omega_b' in mother) and general == 1:
382  flag = 6
383 elif ('Upsilon' in mother or 'chi_b' in mother) and general == 1:
384  flag = 8
385 elif ('D' in mother and '*' in mother or 'D_s1' in mother) and general == 2:
386  flag = 7
387 elif ('psi(2S)' in mother or 'X_1(3872)' in mother or 'h_c' in mother or
388  'chi_c' in mother or mother == 'eta_c') and general == 2:
389 
390  flag = 8
391 elif general == 3:
392 
393  if mother == 'tau+' or mother == 'tau-':
394  flag = 1
395  elif 'Lambda' in mother:
396  flag = 3
397  elif 'Sigma' in mother:
398  flag = 2
399  elif mother == 'K_S0':
400  flag = 4
401  else:
402  warning(
403  'General flag is 3 but mother particle is not recogniced - assuming minbias.')
404  flag = 0
405 else:
406  warning('Cannot determine selection flag. Please check manually.')
407  flag = selection
408 if not flag == selection:
409  warning(
410  'Selection flag is not compliant, should be ' +
411  str(flag) +
412  '. Please check.')
413 else:
414  done()
415 newevtype += str(flag)
416 
417 query('Unfolding decay.')
418 
419 current_decay = []
420 if mother:
421  current_decay = (decay[mother + 'sig'])[:]
422 
423 for (bf2, dec2) in current_decay:
424  for daug in dec2:
425  if daug in decay:
426  newdecay = dec2[:]
427  newdecay.remove(daug)
428  for (bf2, dau2) in decay[daug]:
429  norm = 0.0
430  for (bf3, dau3) in decay[daug]:
431  norm += float(bf3)
432  newbf = bf * bf2 / norm
433  newdecay2 = sorted(newdecay[:] + dau2[:])
434  current_decay += [(newbf, newdecay2)]
435  break
436 
437 
438 def getmax(dec):
439  maximumbf = 0
440  toret = []
441  for (bf, dec2) in dec:
442  if bf > maximumbf:
443  maximumbf = bf
444  toret = dec2[:]
445  return toret
446 
447 
448 main_decay = []
449 if mother:
450  main_decay = [getmax(decay[mother + 'sig'])]
451 
452 clean = False
453 while not clean and mother:
454  clean = True
455  olddec = (main_decay[-1])[:]
456  for daug in main_decay[-1]:
457  if daug in alias:
458  olddec.remove(daug)
459  if daug not in decay:
460  for k in chargeconj:
461  if k == daug:
462  daug = chargeconj[k]
463  elif chargeconj[k] == daug:
464  daug = k
465  if daug not in decay:
466  warning('Aliased particle but cannot find its decay!: ' + daug)
467  newdec = [alias[daug]]
468  else:
469  newdec = getmax(decay[daug])
470  olddec += newdec
471  clean = False
472  if not clean:
473  main_decay += [olddec]
474 done()
475 
476 query('Checking the decay flag')
477 
478 decayflag = int(str(parttype)[2])
479 neutrinos = False
480 nFinal = 0
481 nCommon = 0
482 
483 final = []
484 
485 for (bf, dec) in current_decay:
486  common = 0
487  for (bf2, dec2) in current_decay:
488  test_dec1 = dec
489  test_dec2 = dec2
490  test_dec1.sort()
491  test_dec2.sort()
492  if test_dec2 == test_dec1:
493  common += 1
494  for daug in dec:
495  if 'nu_' in daug:
496  neutrinos = True
497  if common >= 2:
498  nCommon += 1
499  for daug in dec:
500  if daug in alias:
501  break
502  else:
503  if not final:
504  final = sorted(dec)
505  else:
506  dec.sort()
507  if final == dec:
508  continue
509  nFinal += 1
510 
511 flag = 0
512 if mother:
513  flag += 1
514 if nFinal > 1:
515  flag += 2
516 if nCommon > 0:
517  flag += 1
518 if neutrinos:
519  flag += 4
520 
521 if not decayflag == flag:
522  fail(['Decay flag is not compliant. Should be ' + str(flag) + '. Please check'])
523 else:
524  done()
525 newevtype += str(flag)
526 
527 query('Checking charm and lepton flag')
528 electron = False
529 muon = False
530 opencharm = False
531 closedcharm = False
532 doubleopen = False
533 
534 charmflag = int(str(parttype)[3])
535 
536 caughtopen = False
537 if not mother:
538  for field in [extraopts, cuts, fulleventcuts]:
539  if 'Electron' in field or 'electron' in field:
540  electron = True
541  if 'mu' in field or 'Mu' in field:
542  muon = True
543  if 'D0' in field or 'Dmu' in field or 'Ds' in field or 'DS' in field or 'DMass' in field or 'DMu' in field:
544  opencharm = True
545  if 'Jpsi' in field:
546  closedcharm = True
547 
548 for dec in main_decay:
549  caughtopen = False
550  for daug in dec:
551  if daug in alias:
552  daug = alias[daug]
553  # if "D" in mother or "Lambda_c" in mother:
554  # opencharm=True
555  if daug == 'e-' or daug == 'e+':
556  electron = True
557  continue
558  if daug == 'mu-' or daug == 'mu+':
559  muon = True
560  continue
561  if ('D' in daug or '_c' in daug) and 'chi_c' not in daug:
562  if caughtopen:
563  doubleopen = True
564  caughtopen = False
565  continue
566  caughtopen = True
567  opencharm = True
568  continue
569  if 'psi' in daug or 'chi_c' in daug:
570  closedcharm = True
571  continue
572 flag = 0
573 if opencharm:
574  flag += 6
575 elif closedcharm:
576  flag += 3
577 if electron:
578  flag += 2
579 elif muon:
580  flag += 1
581 if doubleopen:
582  flag = 9
583 
584 if not flag == charmflag:
585  fail(['Charm flag is not compliant. Should be ' + str(flag) + '. Please check'])
586 else:
587  done()
588 newevtype += str(flag)
589 
590 query('Checking track flag.')
591 trackflag = int(str(parttype)[4])
592 
593 maxbf = 0
594 maxtracks = 0
595 if not mother:
596  warning('Inclusive decay: Problem with settings the track flag. Check manually.'
597  )
598  if 'DiLepton' in fulleventcuts or 'DiLepton' in cuts or 'DiLepton' in extraopts:
599  maxtracks = 2
600 for dec in main_decay:
601  for daug in dec:
602  if daug in decay:
603  break
604  else:
605  tracks = 0
606  for daug in dec:
607  if daug in settings.longlived:
608  if tracks <= 9:
609  tracks += 1
610  if tracks > maxtracks:
611  maxtracks = tracks
612 
613 if not trackflag == maxtracks:
614  fail(['Track flag not compliant. Should be ' +
615  str(maxtracks) + '. Please check.'])
616 else:
617  done()
618 newevtype += str(maxtracks)
619 
620 query('Checking neutrals flag.')
621 neutrals = int(str(parttype)[5])
622 
623 pi0eta = False
624 gamma = False
625 Kslambda = False
626 klong = False
627 
628 for dec in main_decay:
629  for daug in dec:
630  if daug in alias:
631  daug = alias[daug]
632  if daug == 'K_S0' or daug == 'Lambda0' or mother == 'K_S0' or mother == 'Lambda0':
633  Kslambda = True
634  elif daug == 'pi0' or daug == 'eta':
635  pi0eta = True
636  elif daug == 'K_L0':
637  Klong = True
638 
639 previous_pi = False
640 for i in range(len(main_decay)):
641  if 'gamma' in main_decay[i]:
642  toBreak = False
643  if i != 0:
644  for daug in main_decay[i - 1]:
645  daug2 = daug
646  if daug in alias:
647  daug2 = alias[daug]
648  if daug2 == 'pi0' or daug2 == 'eta':
649  if daug not in main_decay[i]:
650  toBreak = True
651  if toBreak:
652  continue
653  gamma = True
654 
655 flag = 0
656 if Kslambda:
657  flag += 1
658 if klong:
659  flag += 8
660 else:
661  if gamma:
662  flag += 2
663  if pi0eta:
664  flag += 4
665 
666 if not flag == neutrals:
667  fail(['Neutrals flag not compliant. Should be ' + str(flag) + '. Please check.'])
668 else:
669  done()
670 newevtype += str(flag)
671 
672 query('Checking the extra and user for duplicity .')
673 
674 if not settings.use_url:
675  filelist = os.listdir(dkfilespath)
676  newtype = 0
677  failed = False
678  for filen in filelist:
679  if filen.endswith('.dec'):
680  file = open(dkfilespath + '/' + filen)
681  for line in file:
682  if 'EventType: ' in line:
683  try:
684  newtype = int(line.partition('EventType: ')[2].strip())
685  break
686  except BaseException:
687  break
688  if filen.partition('=')[0] == filename.partition('='):
689  if not newtype / 10 == eventtype / 10:
690  warning(
691  'The decfile: ' +
692  filen +
693  ':' +
694  str(newtype) +
695  ' should contain the same decay, therefore the first 7 '
696  'digits of the eventtype should match. Please check and use the same extra flag.')
697  failed = True
698 # if newtype == eventtype and not os.path.basename(filename) == v:
699  if newtype == eventtype:
700  warning('Error: ' + filen + ' has this eventtype already.')
701  failed = True
702 
703  if settings.obsoletepath:
704  obsfile = open(dkfilespath + '/' + settings.obsoletepath + '/table_obsolete.sql')
705  if obsfile:
706  for line in obsfile:
707  if int(line.partition('EVTTYPEID = ')[2].partition(
708  ', DESCRIPTION')[0]) == eventtype:
709  warning(
710  'The eventtype is obsolete on the following line in: ' +
711  settings.obsoletepath +
712  '/table_obsolete.sql')
713  mesg(line)
714  failed = True
715 
716 extraflag = eventtype / 10
717 extraflag = eventtype - extraflag * 10
718 if 'DaughtersInBelleII' not in cuts and extraflag and cuts == 0:
719  warning(
720  'Your cuts are not empty, please set your userflag to greater or equal to 1.')
721  failed = True
722 if cuts == ['None'] and extraflag != 0:
723  warning("Your cuts are empty, your user flag should be 0 unless that's taken. Please check."
724  )
725 
726 if failed:
727  fail([])
728 else:
729  done()
730 mesg('Eventtype constructed: ' + newevtype + 'XX')
731 
732 query('Checking nickname.')
733 faillist = []
734 failed = False
735 if not nickname == os.path.basename(filename).partition('.dec')[0]:
736  faillist += ['Filename not the same as nickname! Fix.']
737  failed = True
738 nick = nickname.partition('=')
739 if not nick[1] == '=' and not cuts == []:
740  faillist += \
741  ['The = sign not found in the nickname while cuts are present. Check nickname conventions and fix.'
742  ]
743  warning('The = sign not found in the nickname while cuts are present. Check nickname conventions and fix.'
744  )
745  # failed = True
746 if 'DaughtersInBelleII' in cuts and 'DecProdCut' not in nick[2].split(','):
747  faillist += \
748  ['You have decay angular acceptance cut in Cuts but not in the nickname.'
749  ]
750  failed = True
751 
752 if failed:
753  fail(faillist)
754 else:
755  done()
756 
757 if not len(nick[0].split(',')) > 1 and mother:
758  warning('Found only one decay level in the nickname - highly unusual, you should probably use at least two.'
759  )
760 
761 if len(nick[2].split(',')) < len(cuts.split(',')):
762  warning('You have more cuts than declared in the nickname. Please check.')
763 
764 query('Checking the Physics WG.')
765 if physicswg not in settings.groups:
766  fail(['The group /' + physicswg +
767  '/ is not known. Please use one of the following:', settings.groups])
768 else:
769  done()
770 
771 if mother:
772  query('Building descriptor.')
773  max_bf = 0
774  curdec = []
775  for (bf, dec) in decay[mother + 'sig']:
776  if bf > max_bf:
777  max_bf = bf
778  for (bf, dec) in decay[mother + 'sig']:
779  if bf == max_bf:
780  curdec = dec[:]
781  descript = [mother] + ['->'] + curdec
782 
783  notclean = True
784  while notclean:
785  for daug in descript:
786  notclean = False
787  if daug in decay:
788  notclean = True
789  max_bf = 0
790  for (bf, dec) in decay[daug]:
791  if bf > max_bf:
792  max_bf = bf
793  for (bf, dec) in decay[daug]:
794  if bf == max_bf:
795  curdec = dec[:]
796  ind = descript.index(daug)
797  descript.remove(daug)
798  if daug not in alias:
799  warning('You decay a particle: [' + daug +
800  '] without aliasing it first. Step aborted.')
801  notclean = False
802  break
803  else:
804  daug = alias[daug]
805  toadd = ['(', daug, '->'] + curdec + [')']
806  toadd.reverse()
807  for el in toadd:
808  descript.insert(ind, el)
809 
810 # Obsolete piece of code
811 # for i in range(len(descript)):
812 # if descript[i] in settings.descripslation:
813 # descript[i] = settings.descripslation[descript[i]]
814 
815  descript = '[' + ' '.join(descript) + ']'
816  descript = descript.replace('( ', '(')
817  descript = descript.replace(' )', ')')
818  for daug in cdecay:
819  if 'sig' in daug:
820  descript += 'cc'
821  break
822 
823  done()
824 
825  query('Checking descriptor.')
826 
827  decr_old = descriptor.partition('[')[2].partition(']')[0].split()
828  decr_new = descript.partition('[')[2].partition(']')[0].split()
829 
830  listA = descriptcheck.convertToList(descript)
831  listB = descriptcheck.convertToList(descriptor)
832 
833  if descriptcheck.compareList(listB, listA):
834  done()
835  else:
836  fail(['Descriptor not matched. Please check the old one:', descriptor,
837  '\nAnd the one built by the parser: ', descript])
838  for mes in descriptcheck.mesgdict:
839  warning(mes)
840 
841  for daug in decay:
842  print(daug, decay[daug])
843 
844  print('Main decay chain:')
845  for dec in main_decay:
846  print(dec)
847 
848 sys.exit('Decfile check complete.')
def convertToList(stringA)
def compareList(listA, listB)