""" BeamlineSimulation simulates MICE beam from Target to GVA1 """ #!/usr/bin/env python # 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 . import os import json import Queue from CallG4bl import CallG4bl class MapPyBeamlineSimulation: #pylint: disable = R0902 """ Class takes beam as defined by user in Configuration file and simulates MICE experiment from Target to Geneva 1 Counter using G4beamline. The output is written to a json document. This is read by BeamMaker allowing the entire MICE experiment to be simulated end-to-end. -q_1,q_2,q_3,d_1 & d_s correspond to the currents in each of the magnets. Can be positive or negative to change magnet polarity -rotation_angle is the angle with which the MAUS coordinates are rotated clockwise with respect to the G4BL coordinates around the y-axis. -translation_z is the the distance between the MAUS center and the G4BL center. It assumes the G4BL center is in front of the MAUS center. -run_number is the spill number, starting from 0 -get_magnet_currents_pa_cdb if set to 'True' magnet currents and proton_absorber_thickness will be retrieved from CDB -particles_per_spill takes particles out of buffer for each spill, if set to zero then all particles are taken from buffer each spill -proton_number is the number of protons generated in the g4bl input file By default it generates 79k protons -Particle Charge refers to the charge of the simulated particle. Users have the following three options: positive-simulate only positive charges. negative-simulate only negative charges. all-simulate both charges of particles. -short particles is used to keep track of the number of particles needed if the buffer runs out -queue is used to define the buffer Initialize and read in default configuration files and overide with data card parameters -protonabsorberin set to 1 for proton absorber to be included in deck and 0 for no proton absorber """ def __init__(self): self.q_1 = 0 self.q_2 = 0 self.q_3 = 0 self.d_1 = 0 self.d_s = 0 self.proton_weight = 0 self.particles_per_spill = 0 self.proton_absorber_thickness = 0 self.proton_number = 0 self.particle_charge = '' self.rotation_angle = 0 self.translation_z = 0 self.run_number = 0 self.get_magnet_currents_pa_cdb = 0 self.random_seed = 0 self.queue = 0 self.file_path = '' self.path_g4bl = '' self.output_path = '' self.charge = 3 self.newline = '' self.grid_job = 0 self.protonabsorberin = 1 def birth(self, json_configuration): #pylint: disable=R0912, R0915 "birth doc string" good_birth = True try: config_doc = json.loads(json_configuration) except Exception: #pylint: disable=W0703 print("Error: No configuration file!") good_birth = False try: self.protonabsorberin = config_doc["g4bl"]["protonabsorberin"] except Exception: #pylint: disable=W0703 print("Error: protonabsorberin is not found in the config file!") good_birth = False try: self.q_1 = config_doc["g4bl"]["q_1"] except Exception: #pylint: disable=W0703 print("Error: q_1 is not found in the config file!") good_birth = False try: self.run_number = config_doc["g4bl"]["run_number"] except Exception: #pylint: disable=W0703 print("Error: run_number is not found in the config file!") good_birth = False try: self.get_magnet_currents_pa_cdb = config_doc["g4bl"]\ ["get_magnet_currents_pa_cdb"] except Exception: #pylint: disable=W0703, C0301 print("Error: get_magnet_currents_pa_cdb is not \ found in the config file!") good_birth = False try: self.q_2 = config_doc["g4bl"]["q_2"] except Exception: #pylint: disable=W0703 print("Error: q_2 is not found in the config file!") good_birth = False try: self.q_3 = config_doc["g4bl"]["q_3"] except Exception: #pylint: disable=W0703 print("Error: q_3 is not found in the config file!") good_birth = False try: self.d_1 = config_doc["g4bl"]["d_1"] except Exception: #pylint: disable=W0703 print("Error: d_1 is not found in the config file!") good_birth = False try: self.d_s = config_doc["g4bl"]["d_s"] except Exception: #pylint: disable=W0703 print("Error: d_s current is not found in" +\ " the config file!") good_birth = False try: self.particles_per_spill = config_doc["g4bl"]["particles_per_spill"] except Exception: #pylint: disable=W0703 print("Error: particles_per_spill is not found in the config file!") good_birth = False try: self.file_path = os.path.join(os.environ['MAUS_ROOT_DIR'], \ 'src', 'map', 'MapPyBeamlineSimulation', 'G4bl') except Exception: #pylint: disable=W0703 print('Error: Cannot find file path'+\ ' /src/map/MapPyBeamlineSimulation/G4bl') good_birth = False # try: # self.grid_job = config_doc["g4bl"]["grid_job"] # except Exception: #pylint: disable=W0703 # print("Error: grid_job is not found in the config file!") # good_birth = False # if str(grid_job) in ['True']: # try: # self.file_path_param = '' # except Exception: #pylint: disable=W0703 # print('Error: Cannot find file path'+\ # ' /src/map/MapPyBeamlineSimulation/G4bl') # good_birth = False try: self.path_g4bl = os.path.join(os.environ['MAUS_ROOT_DIR'], \ 'third_party', 'build', 'G4beamline-2.12-source', 'bin') except Exception: #pylint: disable=W0703 print('Error: Cannot find file path'+\ ' /third_party/install/bin') good_birth = False try: self.output_path = os.path.join(os.getcwd()) except Exception: #pylint: disable=W0703 print('Error: Cannot find output path'+\ ' /bin') good_birth = False try: self.rotation_angle = config_doc["g4bl"]["rotation_angle"] except Exception: #pylint: disable=W0703 print("Error: rotation_angle is not found in the config file!") good_birth = False try: self.translation_z = config_doc["g4bl"]["translation_z"] except Exception: #pylint: disable=W0703 print("Error: translation_z is not found in the config file!") good_birth = False try: self.proton_absorber_thickness = config_doc["g4bl"]\ ["proton_absorber_thickness"] if self.proton_absorber_thickness < 0: print('Error: proton_absorber_thickness is negative!') good_birth = False except Exception: #pylint: disable=W0703 print("Error: proton_absorber_thickness is not found in"+\ " the config file!") good_birth = False try: self.proton_weight = config_doc["g4bl"]["proton_weight"] if self.proton_weight <= 0: print('Error: Number of protons must be greater than zero!') good_birth = False except Exception: #pylint: disable=W0703 print("Error: proton_weight is not found in the config file!") good_birth = False try: self.proton_number = config_doc["g4bl"]["proton_number"] if self.proton_number <= 0: print('Error: Number of protons must be greater than zero!') good_birth = False except Exception: #pylint: disable=W0703 print("Error: proton_numer is not found in the config file!") good_birth = False try: self.particle_charge = config_doc["g4bl"]["particle_charge"] if self.particle_charge != 'positive' and \ self.particle_charge != 'negative' and \ self.particle_charge != 'all': print('Error: particle_charge is not properly defined: '+\ 'positive, negative, or all.') good_birth = False else: self.charge = 3 if self.particle_charge == 'positive': self.charge = 1 elif self.particle_charge == 'negative': self.charge = 2 except Exception: #pylint: disable=W0703 print("Error: particle_charge is not found in the config file!") good_birth = False try: self.newline = "param -unset q_1="+str(self.q_1)+ \ " q_2="+str(self.q_2)+ \ " protonabsorberin="+str(self.protonabsorberin)+ \ " q_3="+str(self.q_3)+" d_1="+ str(self.d_1) +\ " proton_absorber_thickness="+str(self.proton_absorber_thickness)+\ " proton_number="+str(self.proton_number)+\ " proton_weight="+str(self.proton_weight)+\ " WRKDIR="+str(self.file_path)+\ " g4bl_output_file_name="+str(self.file_path)[:-5]+ \ '/maus_beam_output.txt'+\ " d_s="+str(self.d_s)+\ " particle_charge="+str(self.charge)+\ " DecayMapFileDir="+self.file_path+'/Magnets/DecaySolenoid'+"\n" except Exception: #pylint: disable=W0703 print('Error: Could not write G4bl parameters') good_birth = False return good_birth def process(self, json_spill_doc): #pylint: disable=R0912 """ Execute G4beamline and create a simulation based on the read in parameters. Fill buffer first time spill is called for """ spill = {} spill = json.loads(json_spill_doc) try: self.random_seed = spill["spill_number"] except Exception: #pylint: disable = W0703 print("Error: could not set random_seed") if self.queue == 0: self.queue = Queue.Queue() particles = CallG4bl(self.newline, self.file_path, \ self.rotation_angle, \ self.translation_z, \ self.path_g4bl, \ self.output_path, \ self.run_number, \ self.get_magnet_currents_pa_cdb, \ self.random_seed) print("Filling buffer. This may take a while...") self.particles = particles.particles for i in range(len(self.particles)): self.queue.put_nowait(self.particles['entry'+str(i)]) #print len(self.particles) if len(self.particles) != 0: if self.particles_per_spill == 0: spill = {} spill = json.loads(json_spill_doc) print spill spill['mc_events'] = [] for i in range(self.queue.qsize()): primary = (self.queue.get_nowait()) spill['mc_events'].append({"primary":primary}) with open('G4BLoutput.json', 'w') as outfile: json.dump(spill, outfile) #self.queue = 0 return json.dumps(spill) else: spill = {} spill = json.loads(json_spill_doc) spill['mc_events'] = [] if self.queue.qsize() < self.particles_per_spill: print("Warning: particles per spill( "\ +str(self.particles_per_spill)+\ " ) is beyond the total particles \ available in buffer("+\ " %d"%self.queue.qsize()+" ).") print("Generating more particles in buffer. \ May take a while...") while self.queue.qsize()