class LeptonCheck(InteractionDeterminationFunctorInterface): lepton_flavour_labels = [ StateQuantumNumberNames.ElectronLN, StateQuantumNumberNames.MuonLN, StateQuantumNumberNames.TauLN ] name_label = get_xml_label(XMLLabelConstants.Name) qns_label = get_xml_label(XMLLabelConstants.QuantumNumber) def check(self, in_edge_props, out_edge_props, node_props): node_interaction_type = InteractionTypes.Undefined for edge_props in in_edge_props + out_edge_props: if sum([ get_particle_property(edge_props, x) for x in self.lepton_flavour_labels if get_particle_property(edge_props, x) is not None ]): if [ x for x in ['ve', 'vebar', 'vmu', 'vmubar', 'vtau', 'vtaubar'] if x == edge_props[self.name_label] ]: node_interaction_type = InteractionTypes.Weak break if edge_props[self.qns_label] != 0: node_interaction_type = InteractionTypes.EM return node_interaction_type
def get_helicity_from_edge_props(edge_props): qns_label = get_xml_label(XMLLabelConstants.QuantumNumber) type_label = get_xml_label(XMLLabelConstants.Type) spin_label = StateQuantumNumberNames.Spin proj_label = get_xml_label(XMLLabelConstants.Projection) for qn in edge_props[qns_label]: if qn[type_label] == spin_label.name: return qn[proj_label] logging.error(edge_props[qns_label]) raise ValueError("Could not find spin projection quantum number!")
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 remove_spin_projection(edge_props): qns_label = get_xml_label(XMLLabelConstants.QuantumNumber) type_label = get_xml_label(XMLLabelConstants.Type) spin_label = StateQuantumNumberNames.Spin proj_label = get_xml_label(XMLLabelConstants.Projection) new_edge_props = deepcopy(edge_props) for qn_entry in new_edge_props[qns_label]: if (StateQuantumNumberNames[qn_entry[type_label]] is spin_label): del qn_entry[proj_label] break return new_edge_props
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 test_filter_graphs_for_interaction_qns(self, input_values, filter_parameters, result): graphs = [] name_label = get_xml_label(XMLLabelConstants.Name) value_label = get_xml_label(XMLLabelConstants.Value) for x in input_values: tempgraph = make_ls_test_graph(x[1][0], x[1][1]) tempgraph.add_edges([0]) tempgraph.attach_edges_to_node_ingoing([0], 0) tempgraph.edge_props[0] = {name_label: {value_label: x[0]}} graphs.append(tempgraph) my_filter = require_interaction_property(*filter_parameters) filtered_graphs = filter_graphs(graphs, [my_filter]) assert len(filtered_graphs) == result
def generate(self, graphs): if len(graphs) <= 0: raise ValueError( "Number of solution graphs is not larger than zero!") decay_info = {get_xml_label(XMLLabelConstants.Type): 'nonResonant'} decay_info_label = get_xml_label(XMLLabelConstants.DecayInfo) for g in graphs: if self.top_node_no_dynamics: init_edges = get_initial_state_edges(g) if len(init_edges) > 1: raise ValueError( "Only a single initial state particle allowed") eprops = g.edge_props[init_edges[0]] eprops[decay_info_label] = decay_info self.particle_list = generate_particle_list(graphs) self.kinematics = generate_kinematics(graphs) # if use_parity_conservation flag is set to None, use automatic # settings. check if the parity prefactor is defined, if so use # parity conservation if (self.use_parity_conservation is None and isinstance( self.name_generator, HelicityPartialDecayNameGenerator)): prefactors = [x for x in graphs if get_prefactor(x) is not None] self.use_parity_conservation = False if prefactors: self.use_parity_conservation = True self.name_generator = HelicityPartialDecayNameGenerator( self.use_parity_conservation) logging.debug("Using parity conservation to connect fit " "parameters together with prefactors.") graph_groups = group_graphs_same_initial_and_final(graphs) logging.debug("There are " + str(len(graph_groups)) + " graph groups") # At first we need to define the fit parameters parameter_mapping = self.generate_fit_parameters( graph_groups, self.name_generator) self.fix_parameters_unambiguously(parameter_mapping) fit_params = set() for x in parameter_mapping.values(): for y in x.values(): if not y['Magnitude'][1]: fit_params.add('Magnitude_' + y['ParameterNameSuffix']) if not y['Phase'][1]: fit_params.add('Phase_' + y['ParameterNameSuffix']) logging.info("Number of parameters:" + str(len(fit_params))) self.fit_parameters = fit_params self.generate_amplitude_info(graph_groups, parameter_mapping)
def test_filter_graphs_for_interaction_qns(self, input_values, filter_parameters, result): graphs = [] name_label = get_xml_label(XMLLabelConstants.Name) value_label = get_xml_label(XMLLabelConstants.Value) for x in input_values: tempgraph = make_ls_test_graph(x[1][0], x[1][1]) tempgraph.add_edges([0]) tempgraph.attach_edges_to_node_ingoing([0], 0) tempgraph.edge_props[0] = {name_label: {value_label: x[0]}} graphs.append(tempgraph) myfilter = require_interaction_property( *filter_parameters) filtered_graphs = filter_graphs(graphs, [myfilter]) assert len(filtered_graphs) == result
def generate_amplitude_info(self, graph_groups, parameter_mapping): class_label = get_xml_label(XMLLabelConstants.Class) name_label = get_xml_label(XMLLabelConstants.Name) type_label = get_xml_label(XMLLabelConstants.Type) parameter_label = get_xml_label(XMLLabelConstants.Parameter) # for each graph group we create a coherent amplitude coherent_amplitudes = [] for graph_group in graph_groups: seq_partial_decays = [] ggi = graph_groups.index(graph_group) for graph in graph_group: gi = graph_group.index(graph) seq_partial_decays.append( self.generate_sequential_decay(graph, parameter_mapping[ggi][gi])) # in each coherent amplitude we create a product of partial decays coherent_amp_name = "coherent_" + \ str(graph_groups.index(graph_group)) coherent_amplitudes.append({ class_label: 'CoherentIntensity', name_label: coherent_amp_name, 'Amplitude': seq_partial_decays }) # now wrap it with an incoherent intensity incoherent_amp_name = "incoherent" self.helicity_amplitudes = { 'Intensity': { class_label: "StrengthIntensity", name_label: incoherent_amp_name + "_with_strength", parameter_label: { class_label: "Double", type_label: "Strength", name_label: "strength_" + incoherent_amp_name, 'Value': 1, 'Fix': True }, 'Intensity': { class_label: "IncoherentIntensity", name_label: incoherent_amp_name, 'Intensity': coherent_amplitudes } } }
def generate_model_xml(): from pycompwa.expertsystem.amplitude.helicitydecay import ( HelicityDecayAmplitudeGeneratorXML, ) from pycompwa.expertsystem.state.particle import ( XMLLabelConstants, get_xml_label, ) from pycompwa.expertsystem.ui.system_control import ( InteractionTypes, StateTransitionManager, ) # initialize the graph edges (initial and final state) initial_state = [("D1(2420)0", [-1, 1])] final_state = [("D0", [0]), ("pi-", [0]), ("pi+", [0])] tbd_manager = StateTransitionManager(initial_state, final_state, ["D*"]) tbd_manager.number_of_threads = 1 tbd_manager.set_allowed_interaction_types([InteractionTypes.Strong]) graph_interaction_settings_groups = tbd_manager.prepare_graphs() (solutions, violated_rules) = tbd_manager.find_solutions( graph_interaction_settings_groups ) print("found " + str(len(solutions)) + " solutions!") print("intermediate states:") decinfo_label = get_xml_label(XMLLabelConstants.DecayInfo) for g in solutions: print(g.edge_props[1]["@Name"]) for edge_props in g.edge_props.values(): if decinfo_label in edge_props: del edge_props[decinfo_label] edge_props[decinfo_label] = { get_xml_label(XMLLabelConstants.Type): "nonResonant" } xml_generator = HelicityDecayAmplitudeGeneratorXML() xml_generator.generate(solutions) xml_generator.write_to_file("model.xml")
def create_node_variables(self, node_id, qn_list): """ Creates variables for the quantum numbers of the specified node. """ variables = {} type_label = get_xml_label(XMLLabelConstants.Type) if node_id in self.graph.node_props: qns_label = get_xml_label(XMLLabelConstants.QuantumNumber) for qn_name in qn_list: converter = QNClassConverterMapping[ QNNameClassMapping[qn_name]] found_prop = None for node_qn in self.graph.node_props[node_id][qns_label]: if (node_qn[type_label] == qn_name.name): found_prop = node_qn break if found_prop is not None: value = converter.parse_from_dict(found_prop) variables[qn_name] = value return variables
class GammaCheck(InteractionDeterminationFunctorInterface): name_label = get_xml_label(XMLLabelConstants.Name) def check(self, in_edge_props, out_edge_props, node_props): int_type = InteractionTypes.Undefined for edge_props in in_edge_props + out_edge_props: if ('gamma' in edge_props[self.name_label]): int_type = InteractionTypes.EM break return int_type
def generate_particle_list(graphs): # create particle entries temp_particle_names = [] particles = [] for g in graphs: for edge_props in g.edge_props.values(): new_edge_props = remove_spin_projection(edge_props) par_name = new_edge_props[get_xml_label(XMLLabelConstants.Name)] if par_name not in temp_particle_names: particles.append(new_edge_props) temp_particle_names.append(par_name) return {'ParticleList': {'Particle': particles}}
def remove_qns_from_graph(graph, qn_list): qns_label = get_xml_label(XMLLabelConstants.QuantumNumber) type_label = get_xml_label(XMLLabelConstants.Type) int_qns = [ x for x in qn_list if isinstance(x, InteractionQuantumNumberNames) ] state_qns = [x for x in qn_list if isinstance(x, StateQuantumNumberNames)] part_props = [x for x in qn_list if isinstance(x, ParticlePropertyNames)] graph_copy = deepcopy(graph) for int_qn in int_qns: for props in graph_copy.node_props.values(): if qns_label in props: for qn_entry in props[qns_label]: if (InteractionQuantumNumberNames[qn_entry[type_label]] is int_qn): del props[qns_label][props[qns_label].index(qn_entry)] break for state_qn in state_qns: for props in graph_copy.edge_props.values(): if qns_label in props: for qn_entry in props[qns_label]: if (StateQuantumNumberNames[qn_entry[type_label]] is state_qn): del props[qns_label][props[qns_label].index(qn_entry)] break for part_prop in part_props: for props in graph_copy.edge_props.values(): if qns_label in props: for qn_entry in graph_copy.edge_props[qns_label]: if (ParticlePropertyNames[qn_entry[type_label]] is part_prop): del props[qns_label][props[qns_label].index(qn_entry)] break return graph_copy
def generate_model_xml(): from pycompwa.expertsystem.ui.system_control import ( StateTransitionManager, InteractionTypes) from pycompwa.expertsystem.amplitude.helicitydecay import ( HelicityDecayAmplitudeGeneratorXML) from pycompwa.expertsystem.state.particle import ( get_xml_label, XMLLabelConstants) # initialize the graph edges (initial and final state) initial_state = [("D1(2420)0", [-1, 1])] final_state = [("D0", [0]), ("pi-", [0]), ("pi+", [0])] tbd_manager = StateTransitionManager(initial_state, final_state, ['D*']) tbd_manager.number_of_threads = 1 tbd_manager.set_allowed_interaction_types( [InteractionTypes.Strong]) graph_interaction_settings_groups = tbd_manager.prepare_graphs() (solutions, violated_rules) = tbd_manager.find_solutions( graph_interaction_settings_groups) print("found " + str(len(solutions)) + " solutions!") print("intermediate states:") decinfo_label = get_xml_label(XMLLabelConstants.DecayInfo) for g in solutions: print(g.edge_props[1]['@Name']) for edge_props in g.edge_props.values(): if decinfo_label in edge_props: del edge_props[decinfo_label] edge_props[decinfo_label] = { get_xml_label(XMLLabelConstants.Type): "nonResonant"} xml_generator = HelicityDecayAmplitudeGeneratorXML() xml_generator.generate(solutions) xml_generator.write_to_file('model.xml')
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 add_qn_to_graph_element(graph, var_info, value): if value is None: return qns_label = get_xml_label(XMLLabelConstants.QuantumNumber) element_id = var_info.element_id qn_name = var_info.qn_name graph_prop_dict = graph.edge_props if var_info.graph_element_type is graph_element_types.node: graph_prop_dict = graph.node_props converter = QNClassConverterMapping[QNNameClassMapping[qn_name]] if element_id not in graph_prop_dict: graph_prop_dict[element_id] = {qns_label: []} graph_prop_dict[element_id][qns_label].append( converter.convert_to_dict(qn_name, value))
def generate_magnitude_and_phase(self, parameter_mapping): par_label = get_xml_label(XMLLabelConstants.Parameter) par_suffix = parameter_mapping['ParameterNameSuffix'] mag = parameter_mapping['Magnitude'] phase = parameter_mapping['Phase'] return { par_label: [{ '@Class': "Double", '@Type': "Magnitude", '@Name': "Magnitude_" + par_suffix, 'Value': mag[0], 'Fix': mag[1] }, { '@Class': "Double", '@Type': "Phase", '@Name': "Phase_" + par_suffix, 'Value': phase[0], 'Fix': phase[1] }] }
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)
def create_edge_id_particle_mapping(graph, external_edge_getter_function): name_label = get_xml_label(XMLLabelConstants.Name) return { i: graph.edge_props[i][name_label] for i in external_edge_getter_function(graph) }