def printTable(table, first_index=0, stable_decays=True): """Print MC truth from 'table' starting from particle at 'first_index'. Prints MC truth for the specified particle and its descendents in tabular format.""" print " row ID parent children" print "-----------------------------------------------" # First collect the indices of rows that need to be included. These # rows include that given by 'first_index', and its direct and # indirect descendents. Build the result here. indices = [first_index] # 'indices' doubles as our worklist, and 'position' is the start of # the worklist. position = 0 # Loop until we've considered all the rows we need to. while position < len(indices): i = indices[position] # Get the row. row = table[i] child_begin = i + row["child_offset"] child_end = child_begin + row["num_children"] # Append all children of this row. if stable_decays or not pdt.findId(row["id"]).is_stable: for j in range(child_begin, child_end): indices.append(j) # Done with this row. position += 1 # Put the rows into numerical order. indices.sort() # Print the rows. for i in indices: row = table[i] if row["parent_offset"] == 0: parent = " " else: parent = "%5d" % (i + row["parent_offset"]) child_begin = i + row["child_offset"] child_end = child_begin + row["num_children"] print "%5d %-20s %5s %5d-%5d" \ % (i, pdt.findId(row["id"]).name, parent, child_begin, child_end) print
def printStdhep(table, first_index): """Print an MC truth table for a particle decay tree. 'table' -- A STDHEP table. 'first_index' -- The index of the parent particle whose tree to print. Prints MC truth for the specified particle and its descendents in tabular format.""" print " row species parents children" print "------------------------------------------------------" # First collect the indices of rows that need to be included. These # rows include that given by 'first_index', and its direct and # indirect descendents. Build the result here. indices = [first_index] # 'indices' doubles as our worklist, and 'position' is the start of # the worklist. position = 0 # Loop until we've considered all the rows we need to. while position < len(indices): i = indices[position] # Get the row. row = table[i] child_begin = i + row["child_begin_offset"] child_end = i + row["child_end_offset"] # Append all children of this row. for j in range(child_begin, child_end): indices.append(j) # Done with this row. position += 1 # Put the rows into numerical order. indices.sort() # Print the rows. for i in indices: row = table[i] if row["parent_offset"] == 0: parent = " " else: parent = "%5d" % (i + row["parent_offset"]) if row["parent2_offset"] == 0: parent2 = " " else: parent2 = "%5d" % (i + row["parent2_offset"]) child_begin = i + row["child_begin_offset"] child_end = i + row["child_end_offset"] if child_begin == child_end: children = " - " else: children = "%5d -%5d" % (child_begin, child_end) print "%5d %-20s %5s %5s %s" \ % (i, pdt.findId(row["id"]).name, parent, parent2, children) print
def _printTree(table, index, indent, stable_decays, labels): row = table[index] pdt_info = pdt.findId(row["id"]) name = (indent * " ") + pdt_info.name child_begin = row["child_offset"] + index child_end = child_begin + row["num_children"] print "%5d %-20s %7.3f %7.3f %7.3f %7.3f %s" \ % (index, name, row["en"], row["px"], row["py"], row["pz"], str(labels.get(index, ""))) # Recursively print children too. if stable_decays or not pdt_info.is_stable: for child_index in range(child_begin, child_end): _printTree(table, child_index, indent + 1, stable_decays, labels)
def buildTable(decay, table, labels): """Construct an MC truth table from a 'Decay'. 'decay' -- A 'Decay' instance. 'table' -- A list to append to. This will contain the constructed table. 'labels' -- A dictionary in which to store label information. For each decay and subdecay, an entry is added whose key is the decay's label and whose value is the decay's index.""" # Keep a work list of subdecays to process, along with the parent # index for each. work_list = [(decay, -1, )] while len(work_list) > 0: # Get the next decay to work on. decay, parent = work_list.pop(0) # Construct the entry. index = len(table) entry = {} entry["id"] = decay.id entry["cc_id"] = pdt.findId(decay.id).charge_conjugate.id if parent == -1: entry["parent_offset"] = 0 else: entry["parent_offset"] = parent - index entry["child_begin_offset"] = len(work_list) + 1 entry["child_end_offset"] = len(work_list) + 1 + len(decay.products) # Add it to the result. table.append(entry) # Update labels. labels[decay.label] = index # Add child decays to the work list. for product in decay.products: work_list.append((product, index))
def __get_species(self): species = pdt.findId(self.id).name self.__dict__["species"] = species return species
def _matchTree(pattern, decay, cc_mode, matches): """Recursively match 'pattern' to 'decay', filling in 'matches'. returns -- 'is_match, match_cc_mode', where 'is_match' is true if the match succeeds, and if so, 'match_cc_mode' contains the actual CC mode of the match (which may be different from 'cc_mode', if 'cc_mode' is zero).""" # Get the ID of the pattern particle and its CC. pattern_id = pattern.id pattern_cc_id = pdt.findId(pattern_id).charge_conjugate.id # Get the ID of the decay particle. decay_id = decay.id if False: print "_matchTree(%s, %s, %d)" \ % (pdt.findId(pattern_id).name, pdt.findId(decay_id).name, cc_mode) if cc_mode == 1: # The MC truth must match the decay's ID. if decay_id != pattern_id: return False, None elif cc_mode == -1: # The MC truth must match the decay's CC ID. if decay_id != pattern_cc_id: return False, None elif cc_mode == 0: # We may match either the ID or its CC. if decay_id == pattern_id and decay_id == pattern_cc_id: pass elif decay_id == pattern_id: # Matched the ID. Disallow CC matches for the parent. cc_mode = 1 elif decay_id == pattern_cc_id: # Matched the CC ID. Disallow non-CC matches for the # parent. cc_mode = -1 else: return False, None try: label = pattern.label except AttributeError: pass else: matches[label] = decay pattern_products = pattern.decay_products # If the pattern is missing decay information, assume the match is # OK. if pattern_products is None: return True, cc_mode num_products = len(pattern_products) decay_products = decay.decay_products # It must have the same number of children as in the decay pattern. if len(decay_products) != num_products: return False, None # Loop over all permutations of match-ups between children in the # decay pattern and children in MC truth. for permutations in hep.fn.permute(tuple(range(num_products))): success = True # In each permutation, match each of the children. for i in xrange(num_products): # FIXME: If cc_mode is zero, don't we need to require that # all children match in the same cc_mode (or zero), i.e. # that there aren't both children that match for cc_mode = 1 # and children that match for cc_mode = -1 ? is_match, match_cc_mode = \ _matchTree(pattern_products[permutations[i]], decay_products[i], cc_mode, matches) if not is_match: # Match failed. Bail on this permutation. success = False break elif cc_mode == -match_cc_mode: # It matched, but with the wrong CC mode. success = False break # If we went all the way through all the children and matched # each without a failure, we're golden. if success: return True, match_cc_mode # None of the permutations worked out. The match fails. return False, None
def parse(input): """Parse a decay in indented textual notation. returns -- A MC truth table containing the decay.""" if isinstance(input, str): input = input.splitlines() # Keep a stack of parent decays and their indentation. stack = [] for line in input: # Strip comments from the line. if "#" in line: line = line[:line.index("#")] # Ignore blank lines. if line.strip() == "": continue # Count indentation for this line. indentation = 0 while line[indentation] == " ": indentation += 1 # If we are indented more than the previous line, we'll be # adding to the decay at the top of the stack. if len(stack) == 0 or indentation > stack[-1][0]: pass # If we are indentated the same as the previous line, this decay # will be a sibling of the decay at the top of the stack, so pop # it off so that we add to its parent. elif indentation == stack[-1][0]: stack.pop() # If this line is unindented, pop decays off the stack until we # reach the right indentation level. Then pop one more so that # the parent is at the top of the stack. else: while indentation < stack[-1][0]: stack.pop() if indentation != stack[-1][0]: raise ValueError, "invalid indentation" stack.pop() # Grab the ID name, and the label if provided. if "=" in line: name, label = line.split("=") label = label.strip() else: name = line label = None # Look up the ID. id = pdt[name.strip()].id # Make up a label if none was given. if label is None: label = pdt.findId(id).symbol_name # Build the decay object. decay = Particle(label, id) # Add it as a decay product of the particle at the top of the # stack. if len(stack) > 0: stack[-1][1].decay_products.append(decay) # Push it on to the stack. stack.append((indentation, decay)) return stack[0][1]