예제 #1
0
    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)
예제 #2
0
    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)')
예제 #3
0
    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')
예제 #4
0
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)