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