def test_InvalidCmd(self): """test that the Invalid Command are dealt with correctly""" master = cmd.MasterCmd() master.no_notification() self.assertRaises(master.InvalidCmd, master.do_generate, ('aa')) try: master.run_cmd('aa') except Exception as error: print(error) self.assertTrue(False, 'error are not treated correctly') # Madspin master = ms_cmd.MadSpinInterface() master.no_notification() self.assertRaises(Exception, master.do_define, ('aa')) with misc.MuteLogger(['fatalerror'], [40], ['/tmp/fatalerror.log'], keep=False): try: master.run_cmd('define aa') except Exception as error: self.assertTrue(False, 'error are not treated correctly: %s' % error) text = open('/tmp/fatalerror.log').read() self.assertTrue('{' not in text) self.assertTrue('MS_debug' in text)
def test_get_proc_with_decay_LO(self): cmd = Cmd.MasterCmd() cmd.do_import('sm') # Note the ; at the end of the line is important! #1 simple case out = madspin.decay_all_events.get_proc_with_decay('generate p p > t t~', 't> w+b', cmd._curr_model) self.assertEqual(['generate p p > t t~, t> w+b --no_warning=duplicate;'],[out]) #2 with @0 out = madspin.decay_all_events.get_proc_with_decay('generate p p > t t~ @0', 't> w+b', cmd._curr_model) self.assertEqual(['generate p p > t t~ , t> w+b @0 --no_warning=duplicate;'],[out]) #3 with @0 and --no_warning=duplicate out = madspin.decay_all_events.get_proc_with_decay('generate p p > t t~ @0 --no_warning=duplicate', 't> w+b', cmd._curr_model) self.assertEqual(['generate p p > t t~ , t> w+b @0 --no_warning=duplicate;'],[out]) #4 test with already present decay chain out = madspin.decay_all_events.get_proc_with_decay('generate p p > t t~, t > w+ b @0 --no_warning=duplicate', 't~ > w+b', cmd._curr_model) self.assertEqual(['generate p p > t t~, t~ > w+b, ( t > w+ b , t~ > w+b) @0 --no_warning=duplicate;'],[out]) #4 test with already present decay chain out = madspin.decay_all_events.get_proc_with_decay('generate p p > t t~, t > w+ b, t~ > w- b~ @0 --no_warning=duplicate', 'w > all all', cmd._curr_model) self.assertEqual(['generate p p > t t~, w > all all, ( t > w+ b, w > all all), ( t~ > w- b~ , w > all all) @0 --no_warning=duplicate;'],[out]) #6 case with noborn=QCD # This is technically not yet supported by MS, but it is nice that this functions supports it. out = madspin.decay_all_events.get_proc_with_decay('generate g g > h QED=1 [noborn=QCD]', 'h > b b~', cmd._curr_model) self.assertEqual(['add process g g > h QED=1 [sqrvirt=QCD], h > b b~ --no_warning=duplicate;'], [out]) # simple case but failing initial implementation. Handle it now but raising a critical message [mute here] with misc.MuteLogger(['decay'], [60]): out = madspin.decay_all_events.get_proc_with_decay('p p > t t~', 't~ > w- b~ QCD=99, t > w+ b QCD=99', cmd._curr_model) self.assertEqual(['add process p p > t t~, t~ > w- b~ QCD=99, t > w+ b QCD=99 --no_warning=duplicate;'],[out]) self.assertRaises(Exception, madspin.decay_all_events.get_proc_with_decay, 'generate p p > t t~, (t> w+ b, w+ > e+ ve)')
def run_bridge(self, line): """Run the Bridge Algorithm""" # 1. Read the event file to check which decay to perform and the number # of event to generate for each type of particle. # 2. Generate the events requested # 3. perform the merge of the events. # if not enough events. re-generate the missing one. # First define an utility function for generating events when needed def generate_events(pdg, nb_event, mg5, restrict_file=None, cumul=False): """generate new events for this particle restrict_file allow to only generate a subset of the definition cumul allow to merge all the definition in one run (add process) to generate events according to cross-section """ part = self.model.get_particle(pdg) name = part.get_name() out = {} logger.info("generate %s decay event for particle %s" % (nb_event, name)) if name not in self.list_branches: return out for i, proc in enumerate(self.list_branches[name]): if restrict_file and i not in restrict_file: continue decay_dir = pjoin( self.path_me, "decay_%s_%s" % (str(pdg).replace("-", "x"), i)) if not os.path.exists(decay_dir): if cumul: mg5.exec_cmd("generate %s" % proc) for j, proc2 in enumerate( self.list_branches[name][1:]): if restrict_file and j not in restrict_file: raise Exception # Do not see how this can happen mg5.exec_cmd("add process %s" % proc2) mg5.exec_cmd("output %s -f" % decay_dir) else: mg5.exec_cmd("generate %s" % proc) mg5.exec_cmd("output %s -f" % decay_dir) options = dict(mg5.options) if self.options['ms_dir']: misc.sprint("start gridpack!") # we are in gridpack mode -> create it me5_cmd = madevent_interface.MadEventCmdShell(me_dir=os.path.realpath(\ decay_dir), options=options) me5_cmd.options["automatic_html_opening"] = False if self.options["run_card"]: run_card = self.options["run_card"] else: run_card = banner.RunCard( pjoin(decay_dir, "Cards", "run_card.dat")) run_card["iseed"] = self.seed run_card['gridpack'] = True run_card.write( pjoin(decay_dir, "Cards", "run_card.dat")) param_card = self.banner['slha'] open(pjoin(decay_dir, "Cards", "param_card.dat"), "w").write(param_card) self.seed += 1 # actually creation me5_cmd.exec_cmd("generate_events run_01 -f") me5_cmd.exec_cmd("exit") #remove pointless informat misc.call( ["rm", "Cards", "bin", 'Source', 'SubProcesses'], cwd=decay_dir) misc.call(['tar', '-xzpvf', 'run_01_gridpack.tar.gz'], cwd=decay_dir) # Now generate the events if not self.options['ms_dir']: me5_cmd = madevent_interface.MadEventCmdShell(me_dir=os.path.realpath(\ decay_dir), options=mg5.options) me5_cmd.options["automatic_html_opening"] = False if self.options["run_card"]: run_card = self.options["run_card"] else: run_card = banner.RunCard( pjoin(decay_dir, "Cards", "run_card.dat")) run_card["nevents"] = int(1.2 * nb_event) run_card["iseed"] = self.seed run_card.write(pjoin(decay_dir, "Cards", "run_card.dat")) param_card = self.banner['slha'] open(pjoin(decay_dir, "Cards", "param_card.dat"), "w").write(param_card) self.seed += 1 me5_cmd.exec_cmd("generate_events run_01 -f") me5_cmd.exec_cmd("exit") out[i] = lhe_parser.EventFile( pjoin(decay_dir, "Events", 'run_01', 'unweighted_events.lhe.gz')) else: misc.call( ['run.sh', str(int(1.2 * nb_event)), str(self.seed)], cwd=decay_dir) out[i] = lhe_parser.EventFile( pjoin(decay_dir, 'events.lhe.gz')) if cumul: break return out args = self.split_arg(line) #0. Define the path where to write the file self.path_me = os.path.realpath(self.options['curr_dir']) if self.options['ms_dir']: self.path_me = os.path.realpath(self.options['ms_dir']) if not os.path.exists(self.path_me): os.mkdir(self.path_me) else: # cleaning for name in misc.glob("decay_*_*", self.path_me): shutil.rmtree(name) self.events_file.close() orig_lhe = lhe_parser.EventFile(self.events_file.name) to_decay = collections.defaultdict(int) nb_event = 0 for event in orig_lhe: nb_event += 1 for particle in event: if particle.status == 1 and particle.pdg in self.final_state: # final state and tag as to decay to_decay[particle.pdg] += 1 # Handle the banner of the output file if not self.seed: self.seed = random.randint(0, int(30081 * 30081)) self.do_set('seed %s' % self.seed) logger.info('Will use seed %s' % self.seed) self.history.insert(0, 'set seed %s' % self.seed) if self.seed > 30081 * 30081: # can't use too big random number msg = 'Random seed too large ' + str(self.seed) + ' > 30081*30081' raise Exception, msg self.options['seed'] = self.seed text = '%s\n' % '\n'.join([line for line in self.history if line]) self.banner.add_text('madspin', text) # 2. Generate the events requested with misc.MuteLogger(["madgraph", "madevent", "ALOHA", "cmdprint"], [50, 50, 50, 50]): mg5 = self.mg5cmd modelpath = self.model.get('modelpath+restriction') mg5.exec_cmd("import model %s" % modelpath) to_event = {} for pdg, nb_needed in to_decay.items(): #check if a splitting is needed if nb_needed == nb_event: to_event[pdg] = generate_events(pdg, nb_needed, mg5) elif nb_needed % nb_event == 0: nb_mult = nb_needed // nb_event part = self.model.get_particle(pdg) name = part.get_name() if name not in self.list_branches: continue elif len(self.list_branches[name]) == nb_mult: to_event[pdg] = generate_events(pdg, nb_event, mg5) else: to_event[pdg] = generate_events(pdg, nb_needed, mg5, cumul=True) else: part = self.model.get_particle(pdg) name = part.get_name() if name not in self.list_branches or len( self.list_branches[name]) == 0: continue raise self.InvalidCmd( "The bridge mode of MadSpin does not support event files where events do not *all* share the same set of final state particles to be decayed." ) # Compute the branching ratio. br = 1 for (pdg, event_files) in to_event.items(): if not event_files: continue totwidth = float(self.banner.get('param', 'decay', abs(pdg)).value) if to_decay[pdg] == nb_event: # Exactly one particle of this type to decay by event pwidth = sum([event_files[k].cross for k in event_files]) if pwidth > 1.01 * totwidth: logger.critical("Branching ratio larger than one for %s " % pdg) br *= pwidth / totwidth elif to_decay[pdg] % nb_event == 0: # More than one particle of this type to decay by event # Need to check the number of event file to check if we have to # make separate type of decay or not. nb_mult = to_decay[pdg] // nb_event if nb_mult == len(event_files): for k in event_files: pwidth = event_files[k].cross if pwidth > 1.01 * totwidth: logger.critical( "Branching ratio larger than one for %s " % pdg) br *= pwidth / totwidth br *= math.factorial(nb_mult) else: pwidth = sum(event_files[k].cross for k in event_files) if pwidth > 1.01 * totwidth: logger.critical( "Branching ratio larger than one for %s " % pdg) br *= (pwidth / totwidth)**nb_mult else: raise self.InvalidCmd( "The bridge mode of MadSpin does not support event files where events do not *all* share the same set of final state particles to be decayed." ) self.branching_ratio = br # modify the cross-section in the init block of the banner self.banner.scale_init_cross(self.branching_ratio) # 3. Merge the various file together. output_lhe = lhe_parser.EventFile( orig_lhe.name.replace('.lhe', '_decayed.lhe.gz'), 'w') self.banner.write(output_lhe, close_tag=False) # initialise object which store not use event due to wrong helicity bufferedEvents_decay = {} for pdg in to_event: bufferedEvents_decay[pdg] = [{}] * len(to_event[pdg]) import time start = time.time() counter = 0 orig_lhe.seek(0) for event in orig_lhe: if counter and counter % 1000 == 0 and float( str(counter)[1:]) == 0: print "decaying event number %s [%s s]" % (counter, time.time() - start) counter += 1 # use random order for particles to avoid systematics when more than # one type of decay is asked. particles = [p for p in event if int(p.status) == 1.0] random.shuffle(particles) ids = [particle.pid for particle in particles] for i, particle in enumerate(particles): # check if we need to decay the particle if particle.pdg not in self.final_state or particle.pdg not in to_event: continue # nothing to do for this particle # check how the decay need to be done nb_decay = len(to_event[particle.pdg]) if nb_decay == 0: continue #nothing to do for this particle if nb_decay == 1: decay_file = to_event[particle.pdg][0] decay_file_nb = 0 elif ids.count(particle.pdg) == nb_decay: decay_file = to_event[particle.pdg][ids[:i].count( particle.pdg)] decay_file_nb = ids[:i].count(particle.pdg) else: #need to select the file according to the associate cross-section r = random.random() tot = sum(to_event[particle.pdg][key].cross for key in to_event[particle.pdg]) r = r * tot cumul = 0 for j, events in to_event[particle.pdg].items(): cumul += events.cross if r < cumul: decay_file = events decay_file_nb = j else: break # ok start the procedure helicity = particle.helicity bufferedEvents = bufferedEvents_decay[ particle.pdg][decay_file_nb] # now that we have the file to read. find the associate event # checks if we have one event in memory if helicity in bufferedEvents and bufferedEvents[helicity]: decay = bufferedEvents[helicity].pop() else: # read the event file up to completion while 1: try: decay = decay_file.next() except StopIteration: # check how far we are ratio = counter / nb_event needed = 1.05 * to_decay[ particle.pdg] / ratio - counter needed = min(1000, max(needed, 1000)) with misc.MuteLogger( ["madgraph", "madevent", "ALOHA", "cmdprint"], [50, 50, 50, 50]): new_file = generate_events( particle.pdg, needed, mg5, [decay_file_nb]) to_event[particle.pdg].update(new_file) decay_file = to_event[particle.pdg][decay_file_nb] continue if helicity == decay[0].helicity or helicity==9 or \ self.options["spinmode"] == "none": break # use that event # not valid event store it for later if helicity not in bufferedEvents: bufferedEvents[helicity] = [decay] elif len(bufferedEvents[helicity]) < 200: # only add to the buffering if the buffer is not too large bufferedEvents[helicity].append(decay) # now that we have the event make the merge particle.add_decay(decay) # change the weight associate to the event event.wgt *= self.branching_ratio wgts = event.parse_reweight() for key in wgts: wgts[key] *= self.branching_ratio # all particle have been decay if needed output_lhe.write(str(event)) output_lhe.write('</LesHouchesEvent>\n')
class TestValidCmd(unittest.TestCase): """ check if the ValidCmd works correctly """ def setUp(self): if not hasattr(self, 'cmd'): TestValidCmd.cmd = cmd.MasterCmd() TestValidCmd.cmd.no_notification() def wrong(self, *opt): self.assertRaises(madgraph.MadGraph5Error, *opt) def do(self, line): """ exec a line in the cmd under test """ self.cmd.exec_cmd(line) def test_shell_and_continuation_line(self): """ check that the cmd line interpret shell and ; correctly """ #Those tests are important for this type of launch: # cd DIR; ./bin/generate_events try: os.remove('/tmp/tmp_file') except: pass self.do('! cd /tmp; touch tmp_file') self.assertTrue(os.path.exists('/tmp/tmp_file')) try: os.remove('/tmp/tmp_file') except: pass self.do(' ! cd /tmp; touch tmp_file') self.assertTrue(os.path.exists('/tmp/tmp_file')) def test_cleaning_history(self): """check that the cleaning of the history command works as expected""" # Test the call present inside do_generate history = """set cluster_queue 2 import model mssm generate p p > go go add process p p > go go j set gauge Feynman check p p > go go output standalone display particles generate p p > go go""" history = [l.strip() for l in history.split('\n')] self.cmd.history[:] = history self.cmd.history.clean( remove_bef_last='generate', keep_switch=True, allow_for_removal=['generate', 'add process', 'output']) goal = """set cluster_queue 2 import model mssm set gauge Feynman generate p p > go go""" goal = [l.strip() for l in goal.split('\n')] self.assertEqual(self.cmd.history, goal) # Test the call present in do_import model history = """set cluster_queue 2 import model mssm define SW = May The Force Be With You generate p p > go go import model mssm --modelname add process p p > go go j set gauge Feynman check p p > go go output standalone display particles generate p p > go go import heft""" history = [l.strip() for l in history.split('\n')] self.cmd.history[:] = history self.cmd.history.clean( remove_bef_last='import', keep_switch=True, allow_for_removal=['generate', 'add process', 'output']) # Test the call present in do_import model goal = """set cluster_queue 2 import model mssm define SW = May The Force Be With You import model mssm --modelname set gauge Feynman import heft""" goal = [l.strip() for l in goal.split('\n')] self.assertEqual(self.cmd.history, goal) # Test the call present in do_output history = """set cluster_queue 2 import model mssm define SW = May The Force Be With You generate p p > go go import model mssm --modelname output standalone launch output""" history = [l.strip() for l in history.split('\n')] self.cmd.history[:] = history self.cmd.history.clean(allow_for_removal=['output'], keep_switch=True, remove_bef_last='output') goal = """set cluster_queue 2 import model mssm define SW = May The Force Be With You generate p p > go go import model mssm --modelname output""" goal = [l.strip() for l in goal.split('\n')] self.assertEqual(self.cmd.history, goal) def test_InvalidCmd(self): """test that the Invalid Command are dealt with correctly""" master = cmd.MasterCmd() master.no_notification() self.assertRaises(master.InvalidCmd, master.do_generate, ('aa')) try: master.run_cmd('aa') except Exception, error: print error self.assertTrue(False, 'error are not treated correctly') # Madspin master = ms_cmd.MadSpinInterface() master.no_notification() self.assertRaises(Exception, master.do_define, ('aa')) with misc.MuteLogger(['fatalerror'], [40], ['/tmp/fatalerror.log'], keep=False): try: master.run_cmd('define aa') except Exception, error: self.assertTrue(False, 'error are not treated correctly: %s' % error) text = open('/tmp/fatalerror.log').read() self.assertTrue('{' not in text) self.assertTrue('MS_debug' in text)