ATLAS Offline Software
powheg_base.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2024 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 
95  '''
96  Manual fix for MadLoop libraries, avoiding issues when /afs not available
97  This is NOT a viable long-term solution and should be made obsolete after the migration
98  The trick consists in making a symbolic link of some directory in the installation
99  which contains some files needed by MadLoop
100  '''
101  import os
102  logger.warning("Applying manual, hard-coded fixes for MadLoop library paths")
103  MadLoop_virtual = os.path.dirname(self.executable)+"/virtual"
104  logger.info("Trying to link directory {} locally".format(MadLoop_virtual))
105  if not os.access(MadLoop_virtual,os.R_OK):
106  logger.fatal("Impossible to access directory {} needed for this process which uses MadLoop".format(MadLoop_virtual))
107  if os.access("virtual",os.R_OK):# checking if link already exists
108  logger.info("Found \"virtual\" probably from previous run - deleting it to recreate it with correct path")
109  try:
110  os.remove("virtual")
111  except Exception:
112  logger.fatal("Impossible to remove \"virtual\" symbolic link - exiting...")
113  raise
114  os.symlink(MadLoop_virtual, "virtual")
115  link = os.readlink("virtual")
116  if link != MadLoop_virtual:
117  logger.fatal("Symbolic link \"virtual\" points to {0} while it should point to {1} - linking probably didn't work. Exiting...".format(link,MadLoop_virtual))
118  raise
119  else:
120  logger.info("Local directory \"virtual\" now points to {}".format(MadLoop_virtual))
121 
122  def link_external_powheg_libraries(self, librarypath):
123  '''
124  Manual fix for external libraries path.
125  This library is expected to be installed in the POWHEGPATH folder.
126  Needs to be adjusted if the version of the library changes.
127  '''
128  logger.warning("Applying manual fixes for library paths:" + librarypath)
129  logger.debug("LD_LIBRARY_PATH (before) = {0}".format(os.getenv('LD_LIBRARY_PATH')))
130  ldpath = os.getenv('LD_LIBRARY_PATH')
131  powhegpath = os.getenv('POWHEGPATH')
132  librarypath = glob.glob(powhegpath+librarypath)
133  ldpath_new = ldpath+ ":" + librarypath[0]
134  os.environ['LD_LIBRARY_PATH'] = ldpath_new
135  logger.debug("LD_LIBRARY_PATH (after) = {0}".format(os.getenv('LD_LIBRARY_PATH')))
136 
137  def __init__(self, base_directory, version, executable_name, cores, powheg_executable="pwhg_main", is_reweightable=True, warning_output = [], info_output = [], error_output = [], **kwargs):
138  """! Constructor.
139 
140  @param base_directory path to PowhegBox code.
141  @param version PowhegBox version.
142  @param executable_name folder containing appropriate PowhegBox executable.
143  @param powheg_executable name of the powheg executable.
144  @param warning_output list of patterns which if found in the output will be treated as warning in the log.
145  @param error_output list of patterns which if found in the output will be treated as error in the log.
146  @param info_output list of patterns which if found in the output will be treated as info in the log.
147  """
148  super(PowhegBase, self).__init__()
149 
150 
151  self.executable = os.path.join(base_directory, version, executable_name, powheg_executable)
152 
153 
154  self.process_revision = check_svn_revision(os.path.dirname(self.executable))
155 
156 
158  one_character_version = self.powheg_version.replace('V', '')[0]
159  POWHEGVER = '{v}_r{rev}'.format(v=one_character_version, rev=self.process_revision)
160  logger.info('MetaData: POWHEGVER = {0}'.format(POWHEGVER))
161  os.environ["POWHEGVER"] = POWHEGVER # does not export to parent shell, but might be sufficient inside job?
162 
163 
164  self.powhegbox_revision = check_svn_revision(os.path.dirname(os.path.dirname(self.executable)))
165 
166 
167  self.cores = cores
168 
169 
170  self.algorithms = []
171 
172 
173  self.externals = {}
174 
175 
177 
178  # Universal keywords that are set from the run arguments
179  self.add_keyword("ebeam1", kwargs.get("beam_energy", None))
180  self.add_keyword("ebeam2", kwargs.get("beam_energy", None))
181  self.add_keyword("iseed", int(kwargs.get("random_seed", None)))
182  self.add_keyword("numevts", kwargs.get("nEvents", None))
183 
184  # Add parameter validation functions
185  self.validation_functions.append("validate_integration_parameters")
186 
187 
188  self.is_reweightable = is_reweightable
189 
190 
192 
193 
195 
196 
197  self.warning_output = warning_output
198  self.info_output = info_output
199  self.error_output = error_output
200 
201 
204 
205  def add_algorithm(self, alg_or_process):
206  """! Add an algorithm or external process to the sequence.
207 
208  @param process Algorithm or external process to add.
209  """
210  # Either add to the list of algorithms to schedule
211  if isinstance(alg_or_process, str):
212  self.algorithms.append(alg_or_process)
213  # ... or add as an external process
214  else:
215  self.externals[alg_or_process.name] = alg_or_process
216 
217  @property
218  def files_for_cleanup(self):
219  """! Wildcarded list of files created by this process that can be deleted."""
220  raise AttributeError("Names of unneeded files are not known for this process!")
221 
222  @property
224  """! Wildcarded list of integration files that might be created by this process."""
225  raise AttributeError("Integration file names are not known for this process!")
226 
227  @property
229  """! Wildcarded list of integration files that are needed for this process."""
230  raise AttributeError("Integration file names are not known for this process!")
231 
232  @property
233  def powheg_version(self):
234  """! Version of PowhegBox process."""
235  raise AttributeError("Powheg version is not known!")
236 
237  @property
238  def default_PDFs(self):
239  """! Default PDFs for this process."""
240  raise AttributeError("Default PDFs are not known for this process!")
241 
242  @property
243  def default_scales(self):
244  """! Default scale variations for this process."""
245  raise AttributeError("Default scales are not known for this process!")
246 
247  def prepare_to_parallelise(self, n_cores):
248  """! Scale calculation parameters by n_cores."""
249  __nEvents_unscaled = self.parameters_by_keyword("numevts")[0].value
250  for keyword in ["ncall1", "ncall1rm", "ncall2", "ncall2rm", "nubound", "numevts"]:
251  for parameter in self.parameters_by_keyword(keyword):
252  if int(parameter.value) > 0:
253  parameter.value = int(math.ceil(float(parameter.value) / n_cores))
254  __nEvents_scaled = self.parameters_by_keyword("numevts")[0].value
255  logger.info("Scaling number of events per job from {} down to {}".format(__nEvents_unscaled, __nEvents_scaled))
256  # Freeze parallelstage parameters before printing list for user
257  [parameter.freeze() for parameter in self.parameters_by_name("parallelstage")]
258 
259  def stage_is_completed(self, stage):
260  """! Set whether the specified POWHEG-BOX generation stage is complete."""
261  # Perform manual check to allow re-use of grids in multicore mode
262  return False
263 
265  """! Validate any parameters which need it before preparing runcard."""
266  for function_name in self.validation_functions:
267  getattr(self, function_name)()
268 
270  """! Validate integration keywords by forcing to integer values."""
271  self.expose() # convenience call to simplify syntax
272  for name in ("foldcsi", "foldphi", "foldy", "itmx1", "itmx2", "ncall1", "ncall2", "nEvents"):
273  for parameter in self.parameters_by_name(name):
274  try:
275  parameter.value = int(parameter.value)
276  except TypeError:
277  logger.fatal("Failed to validate {} with value {}".format(name, parameter.value))
278  raise
279 
280  def check_decay_mode(self, decay_mode, allowed_decay_modes=None):
281  """! Check whether a decay mode is allowed an raise an exception if it is not."""
282  if allowed_decay_modes is None:
283  allowed_decay_modes = self.allowed_decay_modes
284  if decay_mode not in allowed_decay_modes:
285  logger.warning("Decay mode {} not recognised!".format(decay_mode))
286  logger.info("Allowed decay modes are:")
287  for allowed_decay_mode in allowed_decay_modes:
288  logger.info("... {}".format(allowed_decay_mode))
289  raise ValueError("Decay mode {} not recognised!".format(decay_mode))
290 
292 
293  search_strings = [] # list of filename patters to be searched for
294  found_files = [] # list of found files will be printed out for info
295  missing_patterns = [] # list of filename patters which hasn't been found but would be needed for pre-made integration grids
296  try:
297  search_strings = self.mandatory_integration_file_names
298  except AttributeError:
299  logger.fatal("No integration grid file name patterns defined for this process.")
300  raise
301  for s in search_strings:
302  found = glob.glob(s)
303  if found != []:
304  found_files += found
305  else:
306  missing_patterns.append(s)
307  if missing_patterns == []:
308  logger.info("Integration grid files found locally. Event generation shall continue, skipping the integration step.")
309  logger.info("Integration grid files found locally: {}".format(found_files))
310  else:
311  logger.info("Integration grid files needed were not found locally. Event generation shall continue, starting by the integration step.")
312  logger.info("Missing integration grid files with these patterns: {}".format(missing_patterns))
313  logger.info("Integration grid files found locally (if any): {}".format(found_files))
314 
315 
316  def modify_parameter(self, stage = 0):
317 
318  #skip modifying if dict is empty
319  if not bool(self.parameterStageDict):
320  return
321 
322  logger.info("Modifying parameters for the stages : {0}".format(self.parameterStageDict))
323 
324 
325  for key in self.parameterStageDict:
326  settingsList = self.parameterStageDict[key]
327  if abs(settingsList[2] - stage) <=1e-09:
328  self.set_parameter_in_config(key,settingsList[1])
329  else:
330  self.set_parameter_in_config(key,settingsList[0])
331 
332  def set_parameter_in_config(self, key, value):
333  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:264
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:197
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:205
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:199
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:243
python.processes.powheg_base.PowhegBase.check_using_integration_files
def check_using_integration_files(self)
Definition: powheg_base.py:291
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:223
python.processes.powheg_base.PowhegBase.parameterStageDict
parameterStageDict
Dictionary used to change parameters of the Powheg input.
Definition: powheg_base.py:203
python.processes.powheg_base.PowhegBase.use_XML_reweighting
use_XML_reweighting
Switch to determine whether XML reweighting should be used.
Definition: powheg_base.py:191
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:247
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:332
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:233
python.processes.powheg_base.PowhegBase.process_revision
process_revision
SVN revision of process code.
Definition: powheg_base.py:154
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:137
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:228
python.processes.powheg_base.PowhegBase.validation_functions
validation_functions
List of validation functions to run before preparing runcard.
Definition: powheg_base.py:176
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:280
python.processes.powheg_base.PowhegBase.powhegbox_revision
powhegbox_revision
Log the PowhegBox version and process-code revision for AMI etc.
Definition: powheg_base.py:164
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:269
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:194
python.processes.powheg_base.PowhegBase.info_output
info_output
Definition: powheg_base.py:198
python.processes.powheg_base.PowhegBase.algorithms
algorithms
List of additional algorithms to schedule.
Definition: powheg_base.py:170
python.processes.powheg_base.PowhegBase.link_external_powheg_libraries
def link_external_powheg_libraries(self, librarypath)
Definition: powheg_base.py:122
python.processes.powheg_base.PowhegBase.is_reweightable
is_reweightable
Switch to determine whether reweighting is allowed.
Definition: powheg_base.py:188
python.processes.powheg_base.PowhegBase.link_madloop_libraries
def link_madloop_libraries(self)
Definition: powheg_base.py:94
python.processes.powheg_base.PowhegBase.externals
externals
List of external processes to schedule.
Definition: powheg_base.py:173
python.processes.powheg_base.PowhegBase.default_PDFs
def default_PDFs(self)
Default PDFs for this process.
Definition: powheg_base.py:238
python.processes.powheg_base.PowhegBase.cores
cores
Number of cores to use.
Definition: powheg_base.py:167
python.processes.powheg_base.PowhegBase.executable
executable
Powheg executable that will be used.
Definition: powheg_base.py:151
python.processes.powheg_base.PowhegBase.modify_parameter
def modify_parameter(self, stage=0)
Definition: powheg_base.py:316
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:218
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:259
python.processes.configurable.Configurable
Class for any process which can be configured.
Definition: configurable.py:10