ATLAS Offline Software
powheg_base.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
2 
3 from AthenaCommon import Logging
4 from .configurable import Configurable
5 from ..utility import check_svn_revision, FileParser
6 import math
7 import os
8 import glob
9 
10 
11 logger = Logging.logging.getLogger("PowhegControl")
12 
13 
15  """! Base class for PowhegBox processes.
16 
17  All process types inherit from this class.
18 
19  @author James Robinson <james.robinson@cern.ch>
20  @author Stefan Richter <stefan.richter@cern.ch>
21  """
22 
23  def hoppet_info(self):
24  '''
25  Returns a list of strings to be treated as info messages in the log
26  They otherwise throw an error with HOPPET v. 1.2.0
27  Cf. AGENE-2016
28  '''
29  return ["-----------------------------------------------------------",
30  "Welcome to HOPPET v. 1.2.0",
31  "Higher Order Perturbative Parton Evolution Toolkit",
32  "Written by Gavin P. Salam (2001-2012)",
33  "with contributions from Juan Rojo",
34  "Frederic Dreyer and Alexander Karlberg",
35  "It is made available under the GNU public license,",
36  "with the additional request that if you use it or any",
37  "derivative of it in scientific work then you should cite:",
38  "G.P. Salam & J. Rojo, CPC 180(2009)120 (arXiv:0804.3755).",
39  "You are also encouraged to cite the original references,",
40  "for LO, NLO and NNLO splitting functions, the QCD",
41  "1, 2 and 3 loop beta functions and the coupling and",
42  "PDF and coupling mass threshold matching functions."]
43 
44  def hoppet_warning(self):
45  '''
46  Returns a list of strings to be treated as warning messages in the log
47  They otherwise throw an error
48  '''
49  return ["WARNING in InitMTMNNLO: using parametrisation (less accuracte) for A2PShg"]
50 
51  def openloops_error(self):
52  '''
53  Returns a list of strings to be treated as error messages in the log
54  They otherwise do not throw an error
55  '''
56  return ["[POWHEG-BOX+OpenLoops] Process not found!"]
57 
59  '''
60  Manual fix for OpenLoops libraries path, avoiding issues when /afs not available
61  This is NOT a viable long-term solution and should be made obsolete after the migration
62  away from AFS is more advanced.
63  '''
64  import os
65  logger.warning("Applying manual, hard-coded fixes for OpenLoops library paths")
66  logger.info("OpenLoopsPath (before) = {0}".format(os.getenv('OpenLoopsPath')))
67  logger.debug("LD_LIBRARY_PATH (before) = {0}".format(os.getenv('LD_LIBRARY_PATH')))
68  OLPath = os.path.dirname(self.executable)+"/obj-gfortran"
69  os.environ['OpenLoopsPath'] = OLPath
70  ldpath = os.getenv('LD_LIBRARY_PATH')
71  ldpath_new = OLPath+ ":" + OLPath + "/proclib:" + ldpath
72  os.environ['LD_LIBRARY_PATH'] = ldpath_new
73  logger.info("OpenLoopsPath (after) = {0}".format(os.getenv('OpenLoopsPath')))
74  logger.debug("LD_LIBRARY_PATH (after) = {0}".format(os.getenv('LD_LIBRARY_PATH')))
75 
77  '''
78  Manual fix for OpenLoops libraries path, avoiding issues when /afs not available
79  This is NOT a viable long-term solution and should be made obsolete after the migration
80  away from AFS is more advanced.
81  '''
82  import os
83  logger.warning("Applying manual, hard-coded fixes for OpenLoops library paths")
84  logger.info("OpenLoopsPath (before) = {0}".format(os.getenv('OpenLoopsPath')))
85  logger.debug("LD_LIBRARY_PATH (before) = {0}".format(os.getenv('LD_LIBRARY_PATH')))
86  OLPath = os.path.dirname(self.executable)+"/obj-gnu"
87  os.environ['OpenLoopsPath'] = OLPath
88  ldpath = os.getenv('LD_LIBRARY_PATH')
89  ldpath_new = OLPath+ ":" + OLPath + "/proclib:" + ldpath
90  os.environ['LD_LIBRARY_PATH'] = ldpath_new
91  logger.info("OpenLoopsPath (after) = {0}".format(os.getenv('OpenLoopsPath')))
92  logger.debug("LD_LIBRARY_PATH (after) = {0}".format(os.getenv('LD_LIBRARY_PATH')))
93 
94 
96  '''
97  Manual fix for MadLoop libraries, avoiding issues when /afs not available
98  This is NOT a viable long-term solution and should be made obsolete after the migration
99  The trick consists in making a symbolic link of some directory in the installation
100  which contains some files needed by MadLoop
101  '''
102  import os
103  logger.warning("Applying manual, hard-coded fixes for MadLoop library paths")
104  MadLoop_virtual = os.path.dirname(self.executable)+"/virtual"
105  logger.info("Trying to link directory {} locally".format(MadLoop_virtual))
106  if not os.access(MadLoop_virtual,os.R_OK):
107  logger.fatal("Impossible to access directory {} needed for this process which uses MadLoop".format(MadLoop_virtual))
108  if os.access("virtual",os.R_OK):# checking if link already exists
109  logger.info("Found \"virtual\" probably from previous run - deleting it to recreate it with correct path")
110  try:
111  os.remove("virtual")
112  except Exception:
113  logger.fatal("Impossible to remove \"virtual\" symbolic link - exiting...")
114  raise
115  os.symlink(MadLoop_virtual, "virtual")
116  link = os.readlink("virtual")
117  if link != MadLoop_virtual:
118  logger.fatal("Symbolic link \"virtual\" points to {0} while it should point to {1} - linking probably didn't work. Exiting...".format(link,MadLoop_virtual))
119  raise
120  else:
121  logger.info("Local directory \"virtual\" now points to {}".format(MadLoop_virtual))
122 
123  def link_external_powheg_libraries(self, librarypath):
124  '''
125  Manual fix for external libraries path.
126  This library is expected to be installed in the POWHEGPATH folder.
127  Needs to be adjusted if the version of the library changes.
128  '''
129  logger.warning("Applying manual fixes for library paths:" + librarypath)
130  logger.debug("LD_LIBRARY_PATH (before) = {0}".format(os.getenv('LD_LIBRARY_PATH')))
131  ldpath = os.getenv('LD_LIBRARY_PATH')
132  powhegpath = os.getenv('POWHEGPATH')
133  librarypath = glob.glob(powhegpath+librarypath)
134  ldpath_new = ldpath+ ":" + librarypath[0]
135  os.environ['LD_LIBRARY_PATH'] = ldpath_new
136  logger.debug("LD_LIBRARY_PATH (after) = {0}".format(os.getenv('LD_LIBRARY_PATH')))
137 
138  def __init__(self, base_directory, version, executable_name, cores, powheg_executable="pwhg_main", is_reweightable=True, warning_output = [], info_output = [], error_output = [], **kwargs):
139  """! Constructor.
140 
141  @param base_directory path to PowhegBox code.
142  @param version PowhegBox version.
143  @param executable_name folder containing appropriate PowhegBox executable.
144  @param powheg_executable name of the powheg executable.
145  @param warning_output list of patterns which if found in the output will be treated as warning in the log.
146  @param error_output list of patterns which if found in the output will be treated as error in the log.
147  @param info_output list of patterns which if found in the output will be treated as info in the log.
148  """
149  super(PowhegBase, self).__init__()
150 
151 
152  self.executable = os.path.join(base_directory, version, executable_name, powheg_executable)
153 
154 
155  self.process_revision = check_svn_revision(os.path.dirname(self.executable))
156 
157 
159  one_character_version = self.powheg_version.replace('V', '')[0]
160  POWHEGVER = '{v}_r{rev}'.format(v=one_character_version, rev=self.process_revision)
161  logger.info('MetaData: POWHEGVER = {0}'.format(POWHEGVER))
162  os.environ["POWHEGVER"] = POWHEGVER # does not export to parent shell, but might be sufficient inside job?
163 
164 
165  self.powhegbox_revision = check_svn_revision(os.path.dirname(os.path.dirname(self.executable)))
166 
167 
168  self.cores = cores
169 
170 
171  self.algorithms = []
172 
173 
174  self.externals = {}
175 
176 
178 
179  # Universal keywords that are set from the run arguments
180  self.add_keyword("ebeam1", kwargs.get("beam_energy", None))
181  self.add_keyword("ebeam2", kwargs.get("beam_energy", None))
182  self.add_keyword("iseed", int(kwargs.get("random_seed", None)))
183  self.add_keyword("numevts", kwargs.get("nEvents", None))
184 
185  # Add parameter validation functions
186  self.validation_functions.append("validate_integration_parameters")
187 
188 
189  self.is_reweightable = is_reweightable
190 
191 
193 
194 
196 
197 
198  self.warning_output = warning_output
199  self.info_output = info_output
200  self.error_output = error_output
201 
202 
205 
206  def add_algorithm(self, alg_or_process):
207  """! Add an algorithm or external process to the sequence.
208 
209  @param process Algorithm or external process to add.
210  """
211  # Either add to the list of algorithms to schedule
212  if isinstance(alg_or_process, str):
213  self.algorithms.append(alg_or_process)
214  # ... or add as an external process
215  else:
216  self.externals[alg_or_process.name] = alg_or_process
217 
218  @property
219  def files_for_cleanup(self):
220  """! Wildcarded list of files created by this process that can be deleted."""
221  raise AttributeError("Names of unneeded files are not known for this process!")
222 
223  @property
225  """! Wildcarded list of integration files that might be created by this process."""
226  raise AttributeError("Integration file names are not known for this process!")
227 
228  @property
230  """! Wildcarded list of integration files that are needed for this process."""
231  raise AttributeError("Integration file names are not known for this process!")
232 
233  @property
234  def powheg_version(self):
235  """! Version of PowhegBox process."""
236  raise AttributeError("Powheg version is not known!")
237 
238  @property
239  def default_PDFs(self):
240  """! Default PDFs for this process."""
241  raise AttributeError("Default PDFs are not known for this process!")
242 
243  @property
244  def default_scales(self):
245  """! Default scale variations for this process."""
246  raise AttributeError("Default scales are not known for this process!")
247 
248  def prepare_to_parallelise(self, n_cores):
249  """! Scale calculation parameters by n_cores."""
250  __nEvents_unscaled = self.parameters_by_keyword("numevts")[0].value
251  for keyword in ["ncall1", "ncall1rm", "ncall2", "ncall2rm", "nubound", "numevts"]:
252  for parameter in self.parameters_by_keyword(keyword):
253  if int(parameter.value) > 0:
254  parameter.value = int(math.ceil(float(parameter.value) / n_cores))
255  __nEvents_scaled = self.parameters_by_keyword("numevts")[0].value
256  logger.info("Scaling number of events per job from {} down to {}".format(__nEvents_unscaled, __nEvents_scaled))
257  # Freeze parallelstage parameters before printing list for user
258  [parameter.freeze() for parameter in self.parameters_by_name("parallelstage")]
259 
260  def stage_is_completed(self, stage):
261  """! Set whether the specified POWHEG-BOX generation stage is complete."""
262  # Perform manual check to allow re-use of grids in multicore mode
263  return False
264 
266  """! Validate any parameters which need it before preparing runcard."""
267  for function_name in self.validation_functions:
268  getattr(self, function_name)()
269 
271  """! Validate integration keywords by forcing to integer values."""
272  self.expose() # convenience call to simplify syntax
273  for name in ("foldcsi", "foldphi", "foldy", "itmx1", "itmx2", "ncall1", "ncall2", "nEvents"):
274  for parameter in self.parameters_by_name(name):
275  try:
276  parameter.value = int(parameter.value)
277  except TypeError:
278  logger.fatal("Failed to validate {} with value {}".format(name, parameter.value))
279  raise
280 
281  def check_decay_mode(self, decay_mode, allowed_decay_modes=None):
282  """! Check whether a decay mode is allowed an raise an exception if it is not."""
283  if allowed_decay_modes is None:
284  allowed_decay_modes = self.allowed_decay_modes
285  if decay_mode not in allowed_decay_modes:
286  logger.warning("Decay mode {} not recognised!".format(decay_mode))
287  logger.info("Allowed decay modes are:")
288  for allowed_decay_mode in allowed_decay_modes:
289  logger.info("... {}".format(allowed_decay_mode))
290  raise ValueError("Decay mode {} not recognised!".format(decay_mode))
291 
293 
294  search_strings = [] # list of filename patters to be searched for
295  found_files = [] # list of found files will be printed out for info
296  missing_patterns = [] # list of filename patters which hasn't been found but would be needed for pre-made integration grids
297  try:
298  search_strings = self.mandatory_integration_file_names
299  except AttributeError:
300  logger.fatal("No integration grid file name patterns defined for this process.")
301  raise
302  for s in search_strings:
303  found = glob.glob(s)
304  if found != []:
305  found_files += found
306  else:
307  missing_patterns.append(s)
308  if missing_patterns == []:
309  logger.info("Integration grid files found locally. Event generation shall continue, skipping the integration step.")
310  logger.info("Integration grid files found locally: {}".format(found_files))
311  else:
312  logger.info("Integration grid files needed were not found locally. Event generation shall continue, starting by the integration step.")
313  logger.info("Missing integration grid files with these patterns: {}".format(missing_patterns))
314  logger.info("Integration grid files found locally (if any): {}".format(found_files))
315 
316 
317  def modify_parameter(self, stage = 0):
318 
319  #skip modifying if dict is empty
320  if not bool(self.parameterStageDict):
321  return
322 
323  logger.info("Modifying parameters for the stages : {0}".format(self.parameterStageDict))
324 
325 
326  for key in self.parameterStageDict:
327  settingsList = self.parameterStageDict[key]
328  if abs(settingsList[2] - stage) <=1e-09:
329  self.set_parameter_in_config(key,settingsList[1])
330  else:
331  self.set_parameter_in_config(key,settingsList[0])
332 
333  def set_parameter_in_config(self, key, value):
334  FileParser("powheg.input").text_replace(key+".*", key+" {}".format(value))
replace
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition: hcg.cxx:307
python.processes.configurable.Configurable.expose
def expose(self)
Add all names to the interface of this object.
Definition: configurable.py:46
python.processes.powheg_base.PowhegBase.hoppet_info
def hoppet_info(self)
Definition: powheg_base.py:23
python.processes.powheg_base.PowhegBase.validate_parameters
def validate_parameters(self)
Validate any parameters which need it before preparing runcard.
Definition: powheg_base.py:265
python.utility.revision_checking.check_svn_revision
def check_svn_revision(path)
Definition: revision_checking.py:6
python.processes.powheg_base.PowhegBase.warning_output
warning_output
Special treatment for some log messages.
Definition: powheg_base.py:198
python.processes.powheg_base.PowhegBase.add_algorithm
def add_algorithm(self, alg_or_process)
Add an algorithm or external process to the sequence.
Definition: powheg_base.py:206
python.processes.powheg_base.PowhegBase.hoppet_warning
def hoppet_warning(self)
Definition: powheg_base.py:44
python.processes.powheg_base.PowhegBase.manually_set_openloops_gnu_paths
def manually_set_openloops_gnu_paths(self)
Definition: powheg_base.py:76
python.processes.powheg_base.PowhegBase
Base class for PowhegBox processes.
Definition: powheg_base.py:14
vtune_athena.format
format
Definition: vtune_athena.py:14
python.processes.configurable.Configurable.parameters_by_name
def parameters_by_name(self, name)
Retrieve all parameters that use a given name.
Definition: configurable.py:64
python.processes.powheg_base.PowhegBase.error_output
error_output
Definition: powheg_base.py:200
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
python.processes.powheg_base.PowhegBase.default_scales
def default_scales(self)
Default scale variations for this process.
Definition: powheg_base.py:244
python.processes.powheg_base.PowhegBase.check_using_integration_files
def check_using_integration_files(self)
Definition: powheg_base.py:292
python.processes.configurable.Configurable.add_keyword
def add_keyword(self, keyword, value=None, name=None, frozen=None, hidden=None, description=None, **kwargs)
Register configurable parameter that is exposed to the user.
Definition: configurable.py:21
python.processes.powheg_base.PowhegBase.integration_file_names
def integration_file_names(self)
Wildcarded list of integration files that might be created by this process.
Definition: powheg_base.py:224
python.processes.powheg_base.PowhegBase.parameterStageDict
parameterStageDict
Dictionary used to change parameters of the Powheg input.
Definition: powheg_base.py:204
python.processes.powheg_base.PowhegBase.use_XML_reweighting
use_XML_reweighting
Switch to determine whether XML reweighting should be used.
Definition: powheg_base.py:192
python.processes.powheg_base.PowhegBase.prepare_to_parallelise
def prepare_to_parallelise(self, n_cores)
Scale calculation parameters by n_cores.
Definition: powheg_base.py:248
dumpHVPathFromNtuple.append
bool append
Definition: dumpHVPathFromNtuple.py:91
python.processes.powheg_base.PowhegBase.openloops_error
def openloops_error(self)
Definition: powheg_base.py:51
python.processes.powheg_base.PowhegBase.set_parameter_in_config
def set_parameter_in_config(self, key, value)
Definition: powheg_base.py:333
python.processes.configurable.Configurable.parameters_by_keyword
def parameters_by_keyword(self, keyword)
Retrieve all parameters that use a given keyword.
Definition: configurable.py:57
python.processes.powheg_base.PowhegBase.powheg_version
def powheg_version(self)
Version of PowhegBox process.
Definition: powheg_base.py:234
python.processes.powheg_base.PowhegBase.process_revision
process_revision
SVN revision of process code.
Definition: powheg_base.py:155
python.processes.powheg_base.PowhegBase.__init__
def __init__(self, base_directory, version, executable_name, cores, powheg_executable="pwhg_main", is_reweightable=True, warning_output=[], info_output=[], error_output=[], **kwargs)
Constructor.
Definition: powheg_base.py:138
python.processes.powheg_base.PowhegBase.mandatory_integration_file_names
def mandatory_integration_file_names(self)
Wildcarded list of integration files that are needed for this process.
Definition: powheg_base.py:229
python.processes.powheg_base.PowhegBase.validation_functions
validation_functions
List of validation functions to run before preparing runcard.
Definition: powheg_base.py:177
python.processes.powheg_base.PowhegBase.check_decay_mode
def check_decay_mode(self, decay_mode, allowed_decay_modes=None)
Check whether a decay mode is allowed an raise an exception if it is not.
Definition: powheg_base.py:281
python.processes.powheg_base.PowhegBase.powhegbox_revision
powhegbox_revision
Log the PowhegBox version and process-code revision for AMI etc.
Definition: powheg_base.py:165
python.processes.powheg_base.PowhegBase.validate_integration_parameters
def validate_integration_parameters(self)
Validate integration keywords by forcing to integer values.
Definition: powheg_base.py:270
python.processes.powheg_base.PowhegBase.remove_oldStyle_rwt_comments
remove_oldStyle_rwt_comments
Switch to determine if the #rwgt and #pdf comments should be kept in lhe files despite using xml rewe...
Definition: powheg_base.py:195
python.processes.powheg_base.PowhegBase.info_output
info_output
Definition: powheg_base.py:199
python.processes.powheg_base.PowhegBase.algorithms
algorithms
List of additional algorithms to schedule.
Definition: powheg_base.py:171
python.processes.powheg_base.PowhegBase.link_external_powheg_libraries
def link_external_powheg_libraries(self, librarypath)
Definition: powheg_base.py:123
python.processes.powheg_base.PowhegBase.is_reweightable
is_reweightable
Switch to determine whether reweighting is allowed.
Definition: powheg_base.py:189
python.processes.powheg_base.PowhegBase.link_madloop_libraries
def link_madloop_libraries(self)
Definition: powheg_base.py:95
python.processes.powheg_base.PowhegBase.externals
externals
List of external processes to schedule.
Definition: powheg_base.py:174
python.processes.powheg_base.PowhegBase.default_PDFs
def default_PDFs(self)
Default PDFs for this process.
Definition: powheg_base.py:239
python.processes.powheg_base.PowhegBase.cores
cores
Number of cores to use.
Definition: powheg_base.py:168
python.processes.powheg_base.PowhegBase.executable
executable
Powheg executable that will be used.
Definition: powheg_base.py:152
python.processes.powheg_base.PowhegBase.modify_parameter
def modify_parameter(self, stage=0)
Definition: powheg_base.py:317
python.processes.powheg_base.PowhegBase.files_for_cleanup
def files_for_cleanup(self)
Wildcarded list of files created by this process that can be deleted.
Definition: powheg_base.py:219
python.processes.powheg_base.PowhegBase.manually_set_openloops_paths
def manually_set_openloops_paths(self)
Definition: powheg_base.py:58
xAOD::bool
setBGCode setTAP setLVL2ErrorBits bool
Definition: TrigDecision_v1.cxx:60
readCCLHist.float
float
Definition: readCCLHist.py:83
python.processes.powheg_base.PowhegBase.stage_is_completed
def stage_is_completed(self, stage)
Set whether the specified POWHEG-BOX generation stage is complete.
Definition: powheg_base.py:260
python.processes.configurable.Configurable
Class for any process which can be configured.
Definition: configurable.py:10