def determine_node_settings(self, graphs): graph_node_setting_pairs = [] for graph in graphs: final_state_edges = get_final_state_edges(graph) initial_state_edges = get_initial_state_edges(graph) node_settings = {} for node_id in graph.nodes: node_int_types = [] out_edge_ids = get_edges_outgoing_to_node(graph, node_id) in_edge_ids = get_edges_outgoing_to_node(graph, node_id) in_edge_props = [ graph.edge_props[edge_id] for edge_id in [x for x in in_edge_ids if x in initial_state_edges] ] out_edge_props = [ graph.edge_props[edge_id] for edge_id in [x for x in out_edge_ids if x in final_state_edges] ] node_props = {} if node_id in graph.node_props: node_props = graph.node_props[node_id] for int_det in self.interaction_determinators: node_int_types.append( int_det.check(in_edge_props, out_edge_props, node_props)) node_int_types = filter_interaction_types( node_int_types, self.allowed_interaction_types) logging.debug("using " + str(node_int_types) + " interaction order for node: " + str(node_id)) node_settings[node_id] = [ deepcopy(self.interaction_type_settings[x]) for x in node_int_types ] graph_node_setting_pairs.append((graph, node_settings)) return graph_node_setting_pairs
def determine_attached_final_state(graph, edge_id): ''' Determines all final state particles of a graph, which are attached downward (forward in time) for a given edge (resembling the root) Args: graph (:class:`.StateTransitionGraph`) edge_id (int): id of the edge, which is taken as the root Returns: list of final state edge ids ([int]) ''' final_state_edge_ids = [] all_final_state_edges = get_final_state_edges(graph) current_edges = [edge_id] while current_edges: temp_current_edges = current_edges current_edges = [] for curr_edge in temp_current_edges: if curr_edge in all_final_state_edges: final_state_edge_ids.append(curr_edge) else: node_id = graph.edges[curr_edge].ending_node_id current_edges.extend(get_edges_outgoing_to_node( graph, node_id)) return final_state_edge_ids
def initialize_contraints(self): """ Initializes all of the constraints for this graph. For each interaction node a set of independent constraints/conservation laws are created. For each conservation law a new CSP wrapper is created. This wrapper needs all of the qn numbers/variables which enter or exit the node and play a role for this conservation law. Hence variables are also created within this method. """ for node_id, interaction_settings in self.node_settings.items(): new_cons_laws = interaction_settings.conservation_laws for cons_law in new_cons_laws: variable_mapping = {} # from cons law and graph determine needed var lists qn_names = cons_law.get_required_qn_names() # create needed variables for edges state qns part_qn_dict = self.prepare_qns( qn_names, interaction_settings.qn_domains, (StateQuantumNumberNames, ParticlePropertyNames)) in_edges = get_edges_ingoing_to_node(self.graph, node_id) in_edge_vars = self.create_edge_variables( in_edges, part_qn_dict) variable_mapping["ingoing"] = in_edge_vars[0] variable_mapping["ingoing-fixed"] = in_edge_vars[1] var_list = [key for key in variable_mapping["ingoing"]] out_edges = get_edges_outgoing_to_node(self.graph, node_id) out_edge_vars = self.create_edge_variables( out_edges, part_qn_dict) variable_mapping["outgoing"] = out_edge_vars[0] variable_mapping["outgoing-fixed"] = out_edge_vars[1] var_list.extend([key for key in variable_mapping["outgoing"]]) # now create variables for node/interaction qns int_qn_dict = self.prepare_qns(qn_names, interaction_settings.qn_domains, InteractionQuantumNumberNames) int_node_vars = self.create_node_variables( node_id, int_qn_dict) variable_mapping["interaction"] = int_node_vars[0] variable_mapping["interaction-fixed"] = int_node_vars[1] var_list.extend( [key for key in variable_mapping["interaction"]]) constraint = ConservationLawConstraintWrapper( cons_law, variable_mapping, self.particle_variable_delimiter) constraint.register_graph_node(node_id) self.constraints.append(constraint) if var_list: self.problem.addConstraint(constraint, var_list) else: self.constraints[-1].conditions_never_met = True
def generate_sequential_decay(self, graph, parameter_props): class_label = get_xml_label(XMLLabelConstants.Class) name_label = get_xml_label(XMLLabelConstants.Name) spin_label = StateQuantumNumberNames.Spin decay_info_label = get_xml_label(XMLLabelConstants.DecayInfo) type_label = get_xml_label(XMLLabelConstants.Type) partial_decays = [] for node_id in graph.nodes: # in case a scalar without dynamics decays into daughters with no # net helicity, the partial amplitude can be dropped # (it is just a constant) in_edges = get_edges_ingoing_to_node(graph, node_id) out_edges = get_edges_outgoing_to_node(graph, node_id) # check mother particle is spin 0 in_spin = get_particle_property(graph.edge_props[in_edges[0]], spin_label) out_spins = [ get_particle_property(graph.edge_props[x], spin_label) for x in out_edges ] if (in_spin is not None and None not in out_spins and in_spin.magnitude() == 0): if abs(out_spins[0].projection() - out_spins[1].projection()) == 0.0: # check if dynamics is non resonsant (constant) if ('NonResonant' == graph.edge_props[in_edges[0]] [decay_info_label][type_label]): continue partial_decays.append( self.generate_partial_decay(graph, node_id, parameter_props)) amp_name = parameter_props['AmplitudeName'] seq_decay_dict = { class_label: "CoefficientAmplitude", name_label: amp_name, 'Amplitude': { class_label: "SequentialAmplitude", name_label: amp_name, 'Amplitude': partial_decays } } seq_decay_dict.update( self.generate_magnitude_and_phase(parameter_props)) prefactor = get_prefactor(graph) if prefactor != 1.0 and prefactor is not None: prefactor_label = get_xml_label(XMLLabelConstants.PreFactor) seq_decay_dict[prefactor_label] = { '@Magnitude': prefactor, '@Phase': 0.0 } return seq_decay_dict
def wrapper(self, graph, node_id, parameter_props): spinqn = StateQuantumNumberNames.Spin partial_decay_dict = decay_generate_function( self, graph, node_id, parameter_props) node_props = graph.node_props[node_id] L = get_interaction_property(node_props, InteractionQuantumNumberNames.L) S = get_interaction_property(node_props, InteractionQuantumNumberNames.S) in_edge_ids = get_edges_ingoing_to_node(graph, node_id) parent_spin = get_particle_property( graph.edge_props[in_edge_ids[0]], spinqn) daughter_spins = [] for out_edge_id in get_edges_outgoing_to_node(graph, node_id): daughter_spins.append( get_particle_property(graph.edge_props[out_edge_id], spinqn)) decay_particle_lambda = (daughter_spins[0].projection() - daughter_spins[1].projection()) cg_ls = OrderedDict() cg_ls['@Type'] = "LS" cg_ls['@j1'] = L.magnitude() if L.projection() != 0.0: raise ValueError("Projection of L is non-zero!: " + str(L.projection())) cg_ls['@m1'] = L.projection() cg_ls['@j2'] = S.magnitude() cg_ls['@m2'] = decay_particle_lambda cg_ls['@J'] = parent_spin.magnitude() cg_ls['@M'] = decay_particle_lambda cg_ss = OrderedDict() cg_ss['@Type'] = "s2s3" cg_ss['@j1'] = daughter_spins[0].magnitude() cg_ss['@m1'] = daughter_spins[0].projection() cg_ss['@j2'] = daughter_spins[1].magnitude() cg_ss['@m2'] = -daughter_spins[1].projection() cg_ss['@J'] = S.magnitude() cg_ss['@M'] = decay_particle_lambda cg_dict = { 'CanonicalSum': { '@L': L.magnitude(), '@S': S.magnitude(), 'ClebschGordan': [cg_ls, cg_ss] } } partial_decay_dict.update(cg_dict) return partial_decay_dict
def generate_partial_decay(self, graph, node_id, parameter_props): class_label = get_xml_label(XMLLabelConstants.Class) name_label = get_xml_label(XMLLabelConstants.Name) decay_products = [] for out_edge_id in get_edges_outgoing_to_node(graph, node_id): decay_products.append({ name_label: graph.edge_props[out_edge_id][name_label], '@FinalState': determine_attached_final_state_string(graph, out_edge_id), '@Helicity': get_helicity_from_edge_props(graph.edge_props[out_edge_id]) }) in_edge_ids = get_edges_ingoing_to_node(graph, node_id) if len(in_edge_ids) != 1: raise ValueError("This node does not represent a two body decay!") dec_part = graph.edge_props[in_edge_ids[0]] recoil_edge_id = get_recoil_edge(graph, in_edge_ids[0]) parent_recoil_edge_id = get_parent_recoil_edge(graph, in_edge_ids[0]) recoil_system_dict = {} if recoil_edge_id is not None: tempdict = { '@RecoilFinalState': determine_attached_final_state_string(graph, recoil_edge_id) } if parent_recoil_edge_id is not None: tempdict.update({ '@ParentRecoilFinalState': determine_attached_final_state_string( graph, parent_recoil_edge_id) }) recoil_system_dict['RecoilSystem'] = tempdict amp_name = parameter_props[node_id]['Name'] partial_decay_dict = { name_label: amp_name, class_label: "HelicityDecay", 'DecayParticle': { name_label: dec_part[name_label], '@Helicity': get_helicity_from_edge_props(dec_part) }, 'DecayProducts': { 'Particle': decay_products } } # partial_decay_dict.update(self.generate_magnitude_and_phase(amp_name)) partial_decay_dict.update(recoil_system_dict) return partial_decay_dict
def create_variable_containers(self, node_id, cons_law): in_edges = get_edges_ingoing_to_node(self.graph, node_id) out_edges = get_edges_outgoing_to_node(self.graph, node_id) qn_names = cons_law.get_required_qn_names() qn_list = self.prepare_qns( qn_names, (StateQuantumNumberNames, ParticlePropertyNames)) in_edges_vars = self.create_edge_variables(in_edges, qn_list) out_edges_vars = self.create_edge_variables(out_edges, qn_list) node_vars = self.create_node_variables( node_id, self.prepare_qns(qn_names, InteractionQuantumNumberNames)) return (in_edges_vars, out_edges_vars, node_vars)
def generate(self, graph, node_id): ''' Generates partial amplitude name and fit parameter suffix. The fit parameters with the same name are connected and treated as one. For these fit parameter suffixes, a name sorted scheme is used. On the other hand amplitude names are purely cosmetic! ''' # get ending node of the edge # then make name for in_edges = get_edges_ingoing_to_node(graph, node_id) out_edges = get_edges_outgoing_to_node(graph, node_id) name_label = get_xml_label(XMLLabelConstants.Name) in_names_hel_dict = {} out_names_hel_dict = {} for i in in_edges: temphel = float(get_helicity_from_edge_props(graph.edge_props[i])) # remove .0 if temphel % 1 == 0: temphel = int(temphel) in_names_hel_dict[graph.edge_props[i][name_label]] = temphel for i in out_edges: temphel = float(get_helicity_from_edge_props(graph.edge_props[i])) # remove .0 if temphel % 1 == 0: temphel = int(temphel) out_names_hel_dict[graph.edge_props[i][name_label]] = temphel par_name_suffix = '_to_' + \ generate_particles_string(out_names_hel_dict) name = generate_particles_string(in_names_hel_dict) + par_name_suffix par_name_suffix = generate_particles_string(in_names_hel_dict, False) + par_name_suffix if par_name_suffix not in self.generated_parameter_names: append_name = True if self.use_parity_conservation: # first check if parity partner exists pp_par_name_suffix = generate_particles_string( in_names_hel_dict, False) + '_to_' + \ generate_particles_string(out_names_hel_dict, make_parity_partner=True) if pp_par_name_suffix in self.generated_parameter_names: par_name_suffix = pp_par_name_suffix append_name = False if append_name: self.generated_parameter_names.append(par_name_suffix) return (name, par_name_suffix)
def get_recoil_edge(graph, edge_id): ''' Determines the id of the recoil edge for the specified edge of a graph. Args: graph (:class:`.StateTransitionGraph`) edge_id (int): id of the edge, for which the recoil partner is determined Returns: recoil edge id (int) ''' node_id = graph.edges[edge_id].originating_node_id if node_id is None: return None outgoing_edges = get_edges_outgoing_to_node(graph, node_id) outgoing_edges.remove(edge_id) if len(outgoing_edges) != 1: raise ValueError("The node with id " + str(node_id) + " has more than 2 outgoing edges \n" + str(graph)) return outgoing_edges[0]
def generate(self, graph, node_id): ''' Method which adds two clebsch gordan coefficients based on the translation of helicity amplitudes to canonical ones. ''' # get ending node of the edge # then make name for in_edges = get_edges_ingoing_to_node(graph, node_id) out_edges = get_edges_outgoing_to_node(graph, node_id) name_label = get_xml_label(XMLLabelConstants.Name) in_names_hel_dict = {} out_names_hel_dict = {} for i in in_edges: temphel = float(get_helicity_from_edge_props(graph.edge_props[i])) # remove .0 if temphel % 1 == 0: temphel = int(temphel) in_names_hel_dict[graph.edge_props[i][name_label]] = temphel for i in out_edges: temphel = float(get_helicity_from_edge_props(graph.edge_props[i])) # remove .0 if temphel % 1 == 0: temphel = int(temphel) out_names_hel_dict[graph.edge_props[i][name_label]] = temphel name = generate_particles_string(in_names_hel_dict) + \ '_to_' + generate_particles_string(out_names_hel_dict) par_name_suffix = generate_particles_string( in_names_hel_dict, False) + '_to_' +\ generate_particles_string(out_names_hel_dict, False) node_props = graph.node_props[node_id] L = get_interaction_property(node_props, InteractionQuantumNumberNames.L) S = get_interaction_property(node_props, InteractionQuantumNumberNames.S) addition_string = '_L_' + str(L.magnitude()) + \ '_S_' + str(S.magnitude()) return (name + addition_string, par_name_suffix + addition_string)