# This file is part of MAUS: http://micewww.pp.rl.ac.uk/projects/maus # # MAUS is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # MAUS is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with MAUS. If not, see . """ GUI handler for setting up a beam """ import numpy import ROOT from xboa.hit import Hit import xboa.common as common import maus_cpp import maus_cpp.field from gui.window import Window from gui.window import GuiError SHARE_DIR = "" class TwissSetup: """GUI window to setup a beam according to 2D Twiss parameterisation""" def __init__(self, beam_setup, root_frame): """Initialise the window""" self.window = Window(ROOT.gClient.GetRoot(), # pylint: disable = E1101 root_frame, SHARE_DIR+"twiss_setup.json") self.beam_setup = beam_setup self.window.set_button_action("&Okay", self.okay_action) self.window.set_button_action("&Cancel", self.cancel_action) def okay_action(self): """Handle a click on the Okay button, building the beam matrix""" ref = self.beam_setup.get_reference() matrix = maus_cpp.covariance_matrix.create_from_twiss_parameters( mass = ref['mass'], momentum = ref['p'], emittance_x = self.window.get_text_entry("emittance_x", type(1.)), beta_x = self.window.get_text_entry("beta_x", type(1.)), emittance_y = self.window.get_text_entry("emittance_y", type(1.)), beta_y = self.window.get_text_entry("beta_y", type(1.)), emittance_l = self.window.get_text_entry("emittance_l", type(1.)), beta_l = self.window.get_text_entry("beta_l", type(1.)), alpha_x = self.window.get_text_entry("alpha_x", type(1.)), alpha_y = self.window.get_text_entry("alpha_y", type(1.)), alpha_l = self.window.get_text_entry("alpha_l", type(1.)), dispersion_x = self.window.get_text_entry("disp_x", type(1.)), dispersion_prime_x = self.window.get_text_entry("disp_prime_x", type(1.)), dispersion_y = self.window.get_text_entry("disp_y", type(1.)), dispersion_prime_y = self.window.get_text_entry("disp_prime_y", type(1.)) ) self.beam_setup.set_matrix(matrix) self.beam_setup.get_matrix() # check for consistency self.window.close_window() self.beam_setup.matrix_select = None def cancel_action(self): """Handle a click on the Cancel button""" self.window.close_window() self.beam_setup.matrix_select = None class PennSetup: """GUI window to setup a beam according to 4D Penn parameterisation""" def __init__(self, beam_setup, root_frame): """Initialise the window""" self.window = Window(ROOT.gClient.GetRoot(), # pylint: disable = E1101 root_frame, SHARE_DIR+"penn_setup.json") self.beam_setup = beam_setup self.window.set_button_action("&Okay", self.okay_action) self.window.set_button_action("&Cancel", self.cancel_action) self.window.set_button_action("Get &B0", self.get_b0_action) self.window.set_button_action("&Constant Beta", self.constant_beta_action) def okay_action(self): """Handle a click on the Okay button, building the beam matrix""" ref = self.beam_setup.get_reference() matrix = maus_cpp.covariance_matrix.create_from_penn_parameters( mass = ref['mass'], momentum = ref['p'], emittance_t = self.window.get_text_entry("emittance_trans", type(1.)), beta_t = self.window.get_text_entry("beta_trans", type(1.)), emittance_l = self.window.get_text_entry("emittance_l", type(1.)), beta_l = self.window.get_text_entry("beta_l", type(1.)), alpha_t = self.window.get_text_entry("alpha_trans", type(1.)), alpha_l = self.window.get_text_entry("alpha_l", type(1.)), charge = ref["charge"], # BUG - multiply by -1 to fix BUG in source code bz = -self.window.get_text_entry("B0", type(1.))*common.units['T'], ltwiddle = self.window.get_text_entry("Lc", type(1.)), dispersion_x = self.window.get_text_entry("disp_x", type(1.)), dispersion_prime_x = self.window.get_text_entry("disp_prime_x", type(1.)), dispersion_y = self.window.get_text_entry("disp_y", type(1.)), dispersion_prime_y = self.window.get_text_entry("disp_prime_y", type(1.)) ) self.beam_setup.set_matrix(matrix) self.beam_setup.get_matrix() # check for consistency self.window.close_window() self.beam_setup.matrix_select = None def cancel_action(self): """Handle a click on the Cancel button""" self.window.close_window() self.beam_setup.matrix_select = None def get_b0_action(self): """ Handle a click on the Get B0 button, getting B magnitude at the location of the reference particle """ ref = self.beam_setup.get_reference() b_vec = maus_cpp.field.get_field_value(ref['x'], ref['y'], ref['z'], ref['t']) _b0 = (b_vec[0]**2+b_vec[1]**2+b_vec[2]**2)**0.5 self.window.set_text_entry('B0', _b0*common.units['T']) def constant_beta_action(self): """ Handle a click on the Constant Beta button, getting beta function that would be required to get a constant beta function, given other settings (reference particle, B0, Lc) """ _b0 = abs(self.window.get_text_entry("B0", type(1.))*1e-3) # kT if abs(_b0) < 1e-9: raise ValueError( "Constant beta requires B0 is not 0. "+\ "Modify the B0 field and try again." ) _lc = self.window.get_text_entry("Lc", type(1.)) # kT mom = self.beam_setup.get_reference()['p'] # MeV/c charge = abs(self.beam_setup.get_reference()['charge']) # eplus beta = (1+_lc**2)**0.5 * 2.*charge*mom/common.constants['c_light']/_b0 self.window.set_text_entry('alpha_trans', 0.0) self.window.set_text_entry('beta_trans', beta) # beta in mm class BeamSetup: """GUI window to setup a reference particle and beam ellipse""" def __init__(self, main_window, parent): """Initialise the window""" self.window = Window(ROOT.gClient.GetRoot(), # pylint: disable = E1101 parent, SHARE_DIR+"beam_setup.json") self.main_window = main_window self.parent = parent self.matrix_select = None self.matrix = None self.window.set_button_action("&Penn", self.penn_action) self.window.set_button_action("&Twiss", self.twiss_action) self.window.set_button_action("&Okay", self.okay_action) self.window.set_button_action("&Cancel", self.cancel_action) def twiss_action(self): """Handle Twiss button - open a window to set up Twiss parameters""" if self.matrix_select == None: self.matrix_select = TwissSetup(self, self.parent) def penn_action(self): """Handle Penn button - open a window to set up Penn parameters""" if self.matrix_select == None: self.matrix_select = PennSetup(self, self.parent) def okay_action(self): """ Handle Okay button - set the beam in lattice and then close the window """ if self.matrix_select != None: print "Close the matrix_select window" return self.main_window.lattice.set_beam(self.get_reference(), self.get_matrix()) self.main_window.lattice.run_lattice() self.main_window.update_plot() self.window.close_window() self.main_window.beam_setup = None def cancel_action(self): """ Handle Cancel button - just close the window """ if self.matrix_select != None: print "Close the matrix_select window" return self.window.close_window() self.main_window.beam_setup = None def set_matrix(self, matrix): """ Set the beam matrix (updating GUI elements) - matrix a maus_cpp.covariance_matrix.CovarianceMatrix object """ self.matrix = matrix for i, var_i in enumerate(["t", "e", "x", "px", "y", "py"]): for j, var_j in enumerate(["t", "e", "x", "px", "y", "py"]): value = matrix.get_element(i+1, j+1) self.window.set_text_entry(var_i+var_j, value) def get_matrix(self): """ Get the beam matrix (reading from GUI elements) Returns a maus_cpp.covariance_matrix.CovarianceMatrix object """ np_matrix = numpy.zeros([6, 6]) for i, var_i in enumerate(["t", "e", "x", "px", "y", "py"]): for j, var_j in enumerate(["t", "e", "x", "px", "y", "py"]): value1 = self.window.get_text_entry(var_i+var_j, type(1.)) value2 = self.window.get_text_entry(var_j+var_i, type(1.)) delta = abs(value1 - value2) if delta > 1e-6: err = "Matrix has non-symmetric element Cov("+\ var_i+","+var_j+") with delta "+str(delta)+"." err += "This element must be symmetric - upper "+\ "diagonal should be equal to lower diagonal." raise GuiError(err) else: np_matrix[i, j] = value1 evals = numpy.linalg.eigvals(np_matrix) if not numpy.all(evals > 0): evals = [i for i in evals] raise GuiError("Beam ellipse should be positive definite but "+\ " eigenvalues were not all positive: "+str(evals)) return maus_cpp.covariance_matrix.create_from_matrix(np_matrix) def set_reference(self, ref_hit): """ Get the reference particle (writing to GUI elements) - ref_hit an xboa.Hit.Hit object """ for var in ["x", "y", "z", "px", "py", "pz", "pid"]: self.window.set_text_entry(var, ref_hit[var]) def get_reference(self): """ Get the reference particle (reading from GUI elements) Returns an xboa.Hit.Hit object """ ref_dict = {} for var in ["x", "y", "z", "px", "py", "pz"]: var_dict = self.window.get_frame_dict(var, "named_text_entry") ref_dict[var] = float(var_dict["text_entry"].text_entry.GetText()) pid_dict = self.window.get_frame_dict("pid", "named_text_entry") try: ref_dict["pid"] = int(pid_dict["text_entry"].text_entry.GetText()) ref_dict["mass"] = common.pdg_pid_to_mass[abs(ref_dict["pid"])] ref_dict["charge"] = common.pdg_pid_to_charge[abs(ref_dict["pid"])] except KeyError: raise GuiError("Did not recognise reference particle pid") try: hit = Hit.new_from_dict(ref_dict, "energy") except Exception: raise GuiError("Failed to generate a reference particle") return hit