~madteam/mg5amcnlo/series2.0

« back to all changes in this revision

Viewing changes to madgraph/various/combine_runs.py

merge lp:~maddevelopers/madgraph5/transfer_on_exit 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
################################################################################
 
2
#
 
3
# Copyright (c) 2012 The MadGraph Development team and Contributors
 
4
#
 
5
# This file is a part of the MadGraph 5 project, an application which 
 
6
# automatically generates Feynman diagrams and matrix elements for arbitrary
 
7
# high-energy processes in the Standard Model and beyond.
 
8
#
 
9
# It is subject to the MadGraph license which should accompany this 
 
10
# distribution.
 
11
#
 
12
# For more information, please visit: http://madgraph.phys.ucl.ac.be
 
13
#
 
14
################################################################################
 
15
"""Program to combine results from channels that have been
 
16
     split into multiple jobs. Multi-job channels are identified
 
17
     by local file mjobs.dat in the channel directory.
 
18
"""
 
19
from __future__ import division
 
20
import math
 
21
import os
 
22
import re
 
23
import logging
 
24
 
 
25
try:
 
26
    import madgraph.various.sum_html as sum_html
 
27
except:
 
28
    import internal.sum_html as sum_html
 
29
    
 
30
logger = logging.getLogger('madevent.combine_run') # -> stdout
 
31
 
 
32
#usefull shortcut
 
33
pjoin = os.path.join
 
34
 
 
35
   
 
36
def get_inc_file(path):
 
37
    """read the information of fortran inc files and returns
 
38
       the definition in a dictionary format.
 
39
       This catch PARAMETER (NAME = VALUE)"""
 
40
       
 
41
    pat = re.compile(r'''PARAMETER\s*\((?P<name>[_\w]*)\s*=\s*(?P<value>[\+\-\ded]*)\)''',
 
42
                     re.I)
 
43
        
 
44
    out = {}   
 
45
    for name, value in pat.findall(open(path).read()):
 
46
        orig_value = str(value)
 
47
        try:
 
48
            out[name.lower()] = float(value.replace('d','e'))
 
49
        except ValueError:
 
50
            out[name] = orig_value
 
51
    return out
 
52
 
 
53
class CombineRuns(object):
 
54
    
 
55
    def __init__(self, me_dir, subproc=None):
 
56
        
 
57
        self.me_dir = me_dir
 
58
        
 
59
        if not subproc:
 
60
            subproc = [l.strip() for l in open(pjoin(self.me_dir,'SubProcesses', 
 
61
                                                                 'subproc.mg'))]
 
62
        self.subproc = subproc
 
63
        maxpart = get_inc_file(pjoin(me_dir, 'Source', 'maxparticles.inc'))
 
64
        self.maxparticles = maxpart['max_particles']
 
65
    
 
66
    
 
67
        for procname in self.subproc:
 
68
            path = pjoin(self.me_dir,'SubProcesses', procname)
 
69
            channels = self.get_channels(path)
 
70
            for channel in channels:
 
71
                self.sum_multichannel(channel)
 
72
    
 
73
    def sum_multichannel(self, channel):
 
74
        """Looks in channel to see if there are multiple runs that
 
75
        need to be combined. If so combines them into single run"""
 
76
       
 
77
        alphabet = "abcdefghijklmnopqrstuvwxyz"
 
78
 
 
79
        if os.path.exists(pjoin(channel, 'multijob.dat')):
 
80
            njobs = int(open(pjoin(channel, 'multijob.dat')).read())
 
81
        else:
 
82
            return
 
83
        results = sum_html.Combine_results(channel)
 
84
        if njobs:
 
85
            logger.debug('find %s multijob in %s' % (njobs, channel))
 
86
        else:
 
87
            return
 
88
        for i in range(njobs):
 
89
            if channel.endswith(os.path.pathsep):
 
90
                path = channel[:-1] + alphabet[i] 
 
91
            else:
 
92
                path = channel + alphabet[i] 
 
93
            results.add_results(name=alphabet[i], 
 
94
                                filepath=pjoin(path, 'results.dat'))
 
95
        
 
96
        results.compute_average()
 
97
        if results.xsec:
 
98
            results.write_results_dat(pjoin(channel, 'results.dat'))
 
99
        else:
 
100
            return
 
101
        ### Adding information in the log file
 
102
        fsock = open(pjoin(channel, 'log.txt'), 'a')
 
103
        fsock.write('--------------------- Multi run with %s jobs. ---------------------\n'
 
104
                    % njobs)
 
105
        for r in results:
 
106
            fsock.write('job %s : %s %s %s\n' % (r.name, r.xsec, r.axsec, r.nunwgt))  
 
107
            
 
108
        #Now read in all of the events and write them
 
109
        #back out with the appropriate scaled weight
 
110
        fsock = open(pjoin(channel, 'events.lhe'), 'w')
 
111
        wgt = results.xsec / results.nunwgt
 
112
        tot_nevents=0
 
113
        for result in results:  
 
114
            i = result.name
 
115
            if channel.endswith(os.path.pathsep):
 
116
                path = channel[:-1] + i 
 
117
            else:
 
118
                path = channel + i 
 
119
            nw = self.copy_events(fsock, pjoin(path,'events.lhe'), wgt)
 
120
            #tot_events += nw
 
121
        #logger.debug("Combined %s events to %s " % (tot_events, channel))
 
122
 
 
123
 
 
124
    def copy_events(self, fsock, input, new_wgt):
 
125
        """ Copy events from separate runs into one file w/ appropriate wgts"""
 
126
        
 
127
        def get_fortran_str(nb):
 
128
            data = '%E' % nb
 
129
            nb, power = data.split('E')
 
130
            nb = float(nb) /10
 
131
            power = int(power) + 1
 
132
            return '%.7fE%+03i' %(nb,power)
 
133
        new_wgt = get_fortran_str(new_wgt)
 
134
        for line in open(input):
 
135
            data = line.split()
 
136
            if len(data) == 6:            
 
137
                if float(data[2]) > 0:
 
138
                    sign = ''
 
139
                else:
 
140
                    sign = '-'
 
141
                line= ' %s  %s%s  %s\n' % ('   '.join(data[:2]), sign,
 
142
                                                   new_wgt, '  '.join(data[3:]))
 
143
            fsock.write(line)
 
144
 
 
145
        
 
146
        
 
147
        
 
148
           
 
149
           
 
150
    def get_channels(self, proc_path):
 
151
        """Opens file symfact.dat to determine all channels"""
 
152
        sympath = os.path.join(proc_path, 'symfact.dat')
 
153
        
 
154
        #ncode is number of digits needed for the bw coding
 
155
        
 
156
        ncode = int(math.log10(3)*(self.maxparticles-3))+1
 
157
        channels = []
 
158
        for line in open(sympath):
 
159
            try:
 
160
                xi, j = line.split()
 
161
            except Exception:
 
162
                break
 
163
            xi, j  = float(xi), int(j)
 
164
            
 
165
            if j > 0:
 
166
                k = int(xi) 
 
167
                npos = int(math.log10(k))+1
 
168
                #Write with correct number of digits
 
169
                if xi == k:
 
170
                    dirname = 'G%i' % k
 
171
                else:
 
172
                    dirname = 'G%.{0}f'.format(ncode) % xi
 
173
                channels.append(os.path.join(proc_path,dirname))
 
174
        return channels
 
175
    
 
176
        
 
177
        
 
178