CMS 3D CMS Logo

mps_alisetup.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 from __future__ import print_function
4 import os
5 import re
6 import sys
7 import cPickle
8 import argparse
9 import itertools
10 import subprocess
11 import collections
12 import ConfigParser
13 import Alignment.MillePedeAlignmentAlgorithm.mpslib.tools as mps_tools
14 import Alignment.MillePedeAlignmentAlgorithm.mpslib.Mpslibclass as mpslib
15 import Alignment.MillePedeAlignmentAlgorithm.mpsvalidate.iniparser as mpsv_iniparser
16 import Alignment.MillePedeAlignmentAlgorithm.mpsvalidate.trackerTree as mpsv_trackerTree
17 from Alignment.MillePedeAlignmentAlgorithm.alignmentsetup.helper import checked_out_MPS
18 from functools import reduce
19 
20 import six
21 
22 ################################################################################
23 def main(argv = None):
24  """Main routine. Not called, if this module is loaded via `import`.
25 
26  Arguments:
27  - `argv`: Command line arguments passed to the script.
28  """
29 
30  if argv == None:
31  argv = sys.argv[1:]
32 
33  setup_alignment = SetupAlignment(argv)
34  setup_alignment.setup()
35 
36 
37 ################################################################################
39  """Class encapsulating the alignment campaign setup procedure."""
40 
41  def __init__(self, argv):
42  """Constructor
43 
44  Arguments:
45  - `argv`: command line arguments
46  """
47 
48  self._argv = argv # raw command line arguments
49  self._args = None # parsed command line arguments
50  self._config = None # ConfigParser object
51  self._mss_dir = None # mass storage directory
52  self._datasets = collections.OrderedDict() # final dataset configs
53  self._first_run = None # first run for start geometry
54  self._cms_process = None # cms.Process extracted from CMSSW config
55  self._override_gt = None # snippet to append to config
56  self._pede_script = None # path to pede batch script template
57  self._weight_dict = collections.OrderedDict() # dictionary with dataset weights
58  self._mille_script = None # path to mille batch script template
59  self._mps_dir_name = None # MP campaign name (mp<ID>)
60  self._common_weights = {} # dictionary with dataset weights from [weights] section
61  self._weight_configs = [] # list with combinations of dataset weights
62  self._general_options = {} # general options extracted from ini file
63  self._external_datasets = collections.OrderedDict() # external dataset configs
64  self._first_pede_config = True # does a pede job exist already?
65 
66  self._create_config()
68  self._fetch_datasets()
69  self._construct_paths()
73 
74 
75  def setup(self):
76  """Setup the alignment campaign."""
77 
78  if self._args.weight:
80  else:
81  self._create_mille_jobs()
82  self._create_pede_jobs()
83 
84  if self._override_gt.strip() != "":
85  msg = ("Overriding global tag with single-IOV tags extracted from "
86  "'{}' for run number '{}'.".format(self._global_tag,
87  self._first_run))
88  print(msg)
89  print("-"*75)
90  print(self._override_gt)
91  print("="*75)
92 
93 
94  def _create_config(self):
95  """Create ConfigParser object from command line arguments."""
96 
97  helpEpilog ="""Builds the config-templates from a universal
98  config-template for each dataset specified in .ini-file that is passed
99  to this script. Then calls mps_setup.py for all datasets."""
100  parser = argparse.ArgumentParser(
101  description = ("Setup the alignment as configured in the "
102  "alignment_config file."),
103  epilog = helpEpilog)
104  parser.add_argument("-v", "--verbose", action="store_true",
105  help="display detailed output of mps_setup")
106  parser.add_argument("-w", "--weight", action="store_true",
107  help=("creates additional merge job(s) with "
108  "(possibly new) weights from .ini-config"))
109  parser.add_argument("alignmentConfig",
110  help=("name of the .ini config file that specifies "
111  "the datasets to be used"))
112 
113  self._args = parser.parse_args(self._argv)
114  self._config = ConfigParser.ConfigParser()
115  self._config.optionxform = str # default would give lowercase options
116  # -> not wanted
117  self._config.read(self._args.alignmentConfig)
118  self._config.config_path = self._args.alignmentConfig
119 
120 
121  def _construct_paths(self):
122  """Determine directory paths and create the ones that are needed."""
123 
124  mpsTemplates = os.path.join("src", "Alignment",
125  "MillePedeAlignmentAlgorithm", "templates")
126  if checked_out_MPS()[0]:
127  mpsTemplates = os.path.join(os.environ["CMSSW_BASE"], mpsTemplates)
128  else:
129  mpsTemplates = os.path.join(os.environ["CMSSW_RELEASE_BASE"], mpsTemplates)
130  self._mille_script = os.path.join(mpsTemplates, "mps_runMille_template.sh")
131  self._pede_script = os.path.join(mpsTemplates, "mps_runPede_rfcp_template.sh")
132 
133  # get working directory name
134  currentDir = os.getcwd()
135  match = re.search(re.compile('mpproduction\/mp(.+?)$', re.M|re.I),currentDir)
136  if match:
137  self._mps_dir_name = 'mp'+match.group(1)
138  else:
139  print("Current location does not seem to be a MillePede campaign directory:", end=' ')
140  print(currentDir)
141  sys.exit(1)
142 
143 
145  """Create and fill `general_options` dictionary."""
146 
147  print("="*75)
150  self._fetch_essentials()
151  self._fetch_defaults()
152 
153 
155  """Fetch information about external datasets."""
156 
157  if self._config.has_option("general", "externalDatasets"):
158  datasets = map(lambda x: x.strip(),
159  self._config.get("general",
160  "externalDatasets").split(","))
161  datasets = [x for x in datasets if len(x.strip()) > 0]
162  for item in datasets:
163  splitted = item.split("|")
164  dataset = splitted[0].strip()
165  dataset = os.path.expandvars(dataset)
166 
167  weight = splitted[1] if len(splitted) > 1 else None
168  config = ConfigParser.ConfigParser()
169  config.optionxform = str
170  config.read(dataset)
171  config.config_path = dataset
172  self._external_datasets[dataset] = {"config": config,
173  "weight": weight}
174 
175 
176 
178  """
179  Create MPS mass storage directory where, e.g., mille binaries are
180  stored.
181  """
182 
183  # set directory on eos
184  self._mss_dir = self._general_options.get("massStorageDir",
185  "/eos/cms/store/group/alca_millepede/")
186  self._mss_dir = os.path.join(self._mss_dir, "MPproductionFiles",
187  self._mps_dir_name)
188 
189  cmd = ["mkdir", "-p", self._mss_dir]
190 
191  # create directory
192  if not self._general_options.get("testMode", False):
193  try:
194  with open(os.devnull, "w") as dump:
195  subprocess.check_call(cmd, stdout = dump, stderr = dump)
196  except subprocess.CalledProcessError:
197  print("Failed to create mass storage directory:", self._mss_dir)
198  sys.exit(1)
199 
200 
202  """Extract different weight configurations from `self._config`."""
203 
204  weights_list = [[(name, weight) for weight in self._weight_dict[name]]
205  for name in self._weight_dict]
206 
207  common_weights_list = [[(name, weight)
208  for weight in self._common_weights[name]]
209  for name in self._common_weights]
210 
211  common_weights_dicts = []
212  for item in itertools.product(*common_weights_list):
213  d = {}
214  for name,weight in item:
215  d[name] = weight
216  common_weights_dicts.append(d)
217 
218  weight_configs = []
219  for weight_conf in itertools.product(*weights_list):
220  number_of_configs = len(weight_configs)
221  for common_weight in common_weights_dicts:
222  replaced_config \
223  = tuple([(dataset[0],
224  reduce(lambda x,y: mps_tools.replace_factors(x, y, common_weight[y]),
225  common_weight, dataset[1]))
226  for dataset in weight_conf])
227  if replaced_config not in weight_configs:
228  weight_configs.append(replaced_config)
229 
230  # default if config contains no common weights:
231  if len(weight_configs) == number_of_configs:
232  weight_configs.append(weight_conf)
233 
234  for weight_config in weight_configs:
235  resolved_weight_config \
236  = [(dataset[0], mps_tools.compute_product_string(dataset[1]))
237  for dataset in weight_config]
238  self._weight_configs.append(resolved_weight_config)
239 
240 
242  """Fetch 'pedesettings' from general section in `self._config`."""
243 
244  self._pede_settings \
245  = ([x.strip()
246  for x in self._config.get("general", "pedesettings").split(",")]
247  if self._config.has_option("general", "pedesettings") else [None])
248 
249 
251  """Create the mille jobs based on the [dataset:<name>] sections."""
252 
253  gt_regex = re.compile('setupGlobaltag\s*\=\s*[\"\'](.*?)[\"\']')
254  sg_regex = re.compile("setupRunStartGeometry\s*\=\s*.*$", re.M)
255  collection_regex = re.compile('setupCollection\s*\=\s*[\"\'](.*?)[\"\']')
256  czt_regex = re.compile('setupCosmicsZeroTesla\s*\=\s*.*$', re.M)
257  cdm_regex = re.compile('setupCosmicsDecoMode\s*\=\s*.*$', re.M)
258  pw_regex = re.compile('setupPrimaryWidth\s*\=\s*.*$', re.M)
259  json_regex = re.compile('setupJson\s*\=\s*.*$', re.M)
260 
261  first_dataset = True
262  for name, dataset in six.iteritems(self._datasets):
263  print("="*75)
264  # Build config from template/Fill in variables
265  try:
266  with open(dataset["configTemplate"],"r") as f:
267  tmpFile = f.read()
268  except IOError:
269  print("The config-template called", end=' ')
270  print(dataset["configTemplate"], "cannot be found.")
271  sys.exit(1)
272 
273  tmpFile = re.sub(gt_regex,
274  'setupGlobaltag = \"'+dataset["globaltag"]+'\"',
275  tmpFile)
276  tmpFile = re.sub(sg_regex,
277  "setupRunStartGeometry = "+
278  self._general_options["FirstRunForStartGeometry"], tmpFile)
279  tmpFile = re.sub(collection_regex,
280  'setupCollection = \"'+dataset["collection"]+'\"',
281  tmpFile)
282  if dataset['cosmicsZeroTesla']:
283  tmpFile = re.sub(czt_regex,
284  'setupCosmicsZeroTesla = True',
285  tmpFile)
286  if dataset['cosmicsDecoMode']:
287  tmpFile = re.sub(cdm_regex,
288  'setupCosmicsDecoMode = True',
289  tmpFile)
290  if dataset['primaryWidth'] > 0.0:
291  tmpFile = re.sub(pw_regex,
292  'setupPrimaryWidth = '+str(dataset["primaryWidth"]),
293  tmpFile)
294  if dataset['json'] != '':
295  tmpFile = re.sub(json_regex,
296  'setupJson = \"'+dataset["json"]+'\"',
297  tmpFile)
298 
299  thisCfgTemplate = "tmp.py"
300  with open(thisCfgTemplate, "w") as f:
301  f.write(tmpFile)
302 
303 
304  # Set mps_setup append option for datasets following the first one
305  append = "-a"
306  if first_dataset:
307  append = ""
308  first_dataset = False
309  self._config_template = tmpFile
310  self._cms_process = mps_tools.get_process_object(thisCfgTemplate)
311  self._create_input_db()
312 
313  with open(thisCfgTemplate, "a") as f: f.write(self._override_gt)
314 
315 
316  # create mps_setup command
317  command = ["mps_setup.py",
318  "-m",
319  append,
320  "-M", self._general_options["pedeMem"],
321  "-N", name,
322  self._mille_script,
323  thisCfgTemplate,
324  dataset["inputFileList"],
325  str(dataset["njobs"]),
326  self._general_options["classInf"],
327  self._general_options["jobname"],
328  self._pede_script,
329  "cmscafuser:"+self._mss_dir]
330  if dataset["numberOfEvents"] > 0:
331  command.extend(["--max-events", str(dataset["numberOfEvents"])])
332  command = [x for x in command if len(x.strip()) > 0]
333 
334  # Some output:
335  print("Creating jobs for dataset:", name)
336  print("-"*75)
337  print("Baseconfig: ", dataset["configTemplate"])
338  print("Collection: ", dataset["collection"])
339  if dataset["collection"] in ("ALCARECOTkAlCosmicsCTF0T",
340  "ALCARECOTkAlCosmicsInCollisions"):
341  print("cosmicsDecoMode: ", dataset["cosmicsDecoMode"])
342  print("cosmicsZeroTesla: ", dataset["cosmicsZeroTesla"])
343  print("Globaltag: ", dataset["globaltag"])
344  print("Number of jobs: ", dataset["njobs"])
345  print("Inputfilelist: ", dataset["inputFileList"])
346  if dataset["json"] != "":
347  print("Jsonfile: ", dataset["json"])
348  if self._args.verbose:
349  print("Pass to mps_setup: ", " ".join(command))
350 
351  # call the command and toggle verbose output
352  self._handle_process_call(command, self._args.verbose)
353 
354  # remove temporary file
355  self._handle_process_call(["rm", thisCfgTemplate])
356 
357 
358  def _create_pede_jobs(self):
359  """Create pede jobs from the given input."""
360 
361  for setting in self._pede_settings:
362  print()
363  print("="*75)
364  if setting is None:
365  print("Creating pede job{}.".format(
366  "s" if len(self._pede_settings)*len(self._weight_configs) > 1 else ""))
367  print("-"*75)
368  else:
369  print("Creating pede jobs using settings from '{0}'.".format(setting))
370  for weight_conf in self._weight_configs:
371  # blank weights
372  self._handle_process_call(["mps_weight.pl", "-c"])
373 
374  thisCfgTemplate = "tmp.py"
375  with open(thisCfgTemplate, "w") as f: f.write(self._config_template)
376  if self._override_gt is None:
377  self._cms_process = mps_tools.get_process_object(thisCfgTemplate)
378  self._create_input_db()
379  with open(thisCfgTemplate, "a") as f: f.write(self._override_gt)
380 
381  for name,weight in weight_conf:
382  self._handle_process_call(["mps_weight.pl", "-N", name, weight], True)
383 
384  if not self._first_pede_config:
385  # create new mergejob
386  self._handle_process_call(["mps_setupm.pl"], self._args.verbose)
387 
388  # read mps.db to find directory of new mergejob
389  lib = mpslib.jobdatabase()
390  lib.read_db()
391 
392  # short cut for jobm path
393  jobm_path = os.path.join("jobData", lib.JOBDIR[-1])
394 
395  # delete old merge-config
396  command = ["rm", "-f", os.path.join(jobm_path, "alignment_merge.py")]
397  self._handle_process_call(command, self._args.verbose)
398 
399  # create new merge-config
400  command = [
401  "mps_merge.py",
402  "-w", thisCfgTemplate,
403  os.path.join(jobm_path, "alignment_merge.py"),
404  jobm_path,
405  str(lib.nJobs),
406  ]
407  if setting is not None: command.extend(["-a", setting])
408  print("-"*75)
409  print(" ".join(command))
410  self._handle_process_call(command, self._args.verbose)
411  self._create_tracker_tree()
412  if self._first_pede_config:
413  os.symlink(self._tracker_tree_path,
414  os.path.abspath(os.path.join(jobm_path,
415  ".TrackerTree.root")))
416  self._first_pede_config = False
417 
418  # store weights configuration
419  with open(os.path.join(jobm_path, ".weights.pkl"), "wb") as f:
420  cPickle.dump(weight_conf, f, 2)
421  print("="*75)
422 
423  # remove temporary file
424  self._handle_process_call(["rm", thisCfgTemplate])
425 
426 
428  """
429  Create pede jobs in addition to already existing ones. Return GT
430  override snippet.
431  """
432 
433  # do some basic checks
434  if not os.path.isdir("jobData"):
435  print("No jobData-folder found.", end=' ')
436  print("Properly set up the alignment before using the -w option.")
437  sys.exit(1)
438  if not os.path.exists("mps.db"):
439  print("No mps.db found.", end=' ')
440  print("Properly set up the alignment before using the -w option.")
441  sys.exit(1)
442 
443  firstDataset = next(six.itervalues(self._datasets))
444  config_template = firstDataset["configTemplate"]
445  collection = firstDataset["collection"]
446 
447  try:
448  with open(config_template,"r") as f:
449  tmpFile = f.read()
450  except IOError:
451  print("The config-template '"+config_template+"' cannot be found.")
452  sys.exit(1)
453 
454  tmpFile = re.sub('setupGlobaltag\s*\=\s*[\"\'](.*?)[\"\']',
455  'setupGlobaltag = \"'+self._global_tag+'\"',
456  tmpFile)
457  tmpFile = re.sub('setupCollection\s*\=\s*[\"\'](.*?)[\"\']',
458  'setupCollection = \"'+collection+'\"',
459  tmpFile)
460  tmpFile = re.sub(re.compile("setupRunStartGeometry\s*\=\s*.*$", re.M),
461  "setupRunStartGeometry = "+self._first_run,
462  tmpFile)
463  self._config_template = tmpFile
464 
465  # first pede job exists already in this mode:
466  self._first_pede_config = False
467  self._create_pede_jobs()
468 
469 
470  def _handle_process_call(self, command, verbose = False):
471  """
472  Wrapper around subprocess calls which treats output depending on verbosity
473  level.
474 
475  Arguments:
476  - `command`: list of command items
477  - `verbose`: flag to turn on verbosity
478  """
479 
480  call_method = subprocess.check_call if verbose else subprocess.check_output
481  try:
482  call_method(command, stderr=subprocess.STDOUT)
483  except subprocess.CalledProcessError as e:
484  print("" if verbose else e.output)
485  print("Failed to execute command:", " ".join(command))
486  sys.exit(1)
487 
488 
489  def _create_input_db(self):
490  """
491  Create sqlite file with single-IOV tags and use it to override the
492  GT. If the GT is already customized by the user, the customization has
493  higher priority. Creates a snippet to be appended to the configuration
494  file.
495  """
496 
497  run_number = int(self._first_run)
498  if not run_number > 0:
499  print("'FirstRunForStartGeometry' must be positive, but is", run_number)
500  sys.exit(1)
501 
502  input_db_name = os.path.abspath("alignment_input.db")
503  tags = mps_tools.create_single_iov_db(self._check_iov_definition(),
504  run_number, input_db_name)
505 
506  self._override_gt = ""
507  for record,tag in six.iteritems(tags):
508  if self._override_gt == "":
509  self._override_gt \
510  += ("\nimport "
511  "Alignment.MillePedeAlignmentAlgorithm.alignmentsetup."
512  "SetCondition as tagwriter\n")
513  self._override_gt += ("\ntagwriter.setCondition(process,\n"
514  " connect = \""+tag["connect"]+"\",\n"
515  " record = \""+record+"\",\n"
516  " tag = \""+tag["tag"]+"\")\n")
517 
518 
520  """
521  Check consistency of input alignment payloads and IOV definition.
522  Returns a dictionary with the information needed to override possibly
523  problematic input taken from the global tag.
524  """
525 
526  print("Checking consistency of IOV definition...")
527  iovs = mps_tools.make_unique_runranges(self._cms_process.AlignmentProducer)
528 
529  inputs = {
530  "TrackerAlignmentRcd": None,
531  "TrackerSurfaceDeformationRcd": None,
532  "TrackerAlignmentErrorExtendedRcd": None,
533  }
534 
535  for condition in self._cms_process.GlobalTag.toGet.value():
536  if condition.record.value() in inputs:
537  inputs[condition.record.value()] = {
538  "tag": condition.tag.value(),
539  "connect": ("pro"
540  if not condition.hasParameter("connect")
541  else condition.connect.value())
542  }
543 
544  inputs_from_gt = [record for record in inputs if inputs[record] is None]
545  inputs.update(
546  mps_tools.get_tags(self._cms_process.GlobalTag.globaltag.value(),
547  inputs_from_gt))
548 
549  if int(self._first_run) != iovs[0]: # simple consistency check
550  if iovs[0] == 1 and len(iovs) == 1:
551  print("Single IOV output detected in configuration and", end=' ')
552  print("'FirstRunForStartGeometry' is not 1.")
553  print("Creating single IOV output from input conditions in run", end=' ')
554  print(self._first_run+".")
555  for inp in inputs: inputs[inp]["problematic"] = True
556  else:
557  print("Value of 'FirstRunForStartGeometry' has to match first", end=' ')
558  print("defined output IOV:", end=' ')
559  print(self._first_run, "!=", iovs[0])
560  sys.exit(1)
561 
562  for inp in six.itervalues(inputs):
563  inp["iovs"] = mps_tools.get_iovs(inp["connect"], inp["tag"])
564 
565  # check consistency of input with output
566  problematic_gt_inputs = {}
567  input_indices = {key: len(value["iovs"]) -1
568  for key,value in six.iteritems(inputs)}
569  for iov in reversed(iovs):
570  for inp in inputs:
571  if inputs[inp].pop("problematic", False):
572  problematic_gt_inputs[inp] = inputs[inp]
573  if inp in problematic_gt_inputs: continue
574  if input_indices[inp] < 0:
575  print("First output IOV boundary at run", iov, end=' ')
576  print("is before the first input IOV boundary at", end=' ')
577  print(inputs[inp]["iovs"][0], "for '"+inp+"'.")
578  print("Please check your run range selection.")
579  sys.exit(1)
580  input_iov = inputs[inp]["iovs"][input_indices[inp]]
581  if iov < input_iov:
582  if inp in inputs_from_gt:
583  problematic_gt_inputs[inp] = inputs[inp]
584  print("Found problematic input taken from global tag.")
585  print("Input IOV boundary at run",input_iov, end=' ')
586  print("for '"+inp+"' is within output IOV starting", end=' ')
587  print("with run", str(iov)+".")
588  print("Deriving an alignment with coarse IOV", end=' ')
589  print("granularity starting from finer granularity", end=' ')
590  print("leads to wrong results.")
591  print("A single IOV input using the IOV of", end=' ')
592  print("'FirstRunForStartGeometry' ("+self._first_run+")", end=' ')
593  print("is automatically created and used.")
594  continue
595  print("Found input IOV boundary at run",input_iov, end=' ')
596  print("for '"+inp+"' which is within output IOV starting", end=' ')
597  print("with run", str(iov)+".")
598  print("Deriving an alignment with coarse IOV granularity", end=' ')
599  print("starting from finer granularity leads to wrong", end=' ')
600  print("results.")
601  print("Please check your run range selection.")
602  sys.exit(1)
603  elif iov == input_iov:
604  input_indices[inp] -= 1
605 
606  # check consistency of 'TrackerAlignmentRcd' with other inputs
607  input_indices = {key: len(value["iovs"]) -1
608  for key,value in six.iteritems(inputs)
609  if (key != "TrackerAlignmentRcd")
610  and (inp not in problematic_gt_inputs)}
611  for iov in reversed(inputs["TrackerAlignmentRcd"]["iovs"]):
612  for inp in input_indices:
613  input_iov = inputs[inp]["iovs"][input_indices[inp]]
614  if iov < input_iov:
615  print("Found input IOV boundary at run",input_iov, end=' ')
616  print("for '"+inp+"' which is within 'TrackerAlignmentRcd'", end=' ')
617  print("IOV starting with run", str(iov)+".")
618  print("Deriving an alignment with inconsistent IOV boundaries", end=' ')
619  print("leads to wrong results.")
620  print("Please check your input IOVs.")
621  sys.exit(1)
622  elif iov == input_iov:
623  input_indices[inp] -= 1
624 
625  print(" -> IOV consistency check successful.")
626  print("="*75)
627 
628  return problematic_gt_inputs
629 
630 
632  """Method to create hidden 'TrackerTree.root'."""
633 
634  if self._global_tag is None or self._first_run is None:
635  print("Trying to create the tracker tree before setting the global", end=' ')
636  print("tag or the run to determine the geometry IOV.")
637  sys.exit(1)
638 
639  config = mpsv_iniparser.ConfigData()
640  config.jobDataPath = "." # current directory
641  config.globalTag = self._global_tag
642  config.firstRun = self._first_run
643  self._tracker_tree_path = mpsv_trackerTree.check(config)
644 
645 
646  def _fetch_essentials(self):
647  """Fetch general options from config file."""
648 
649  for var in ("classInf","pedeMem","jobname", "FirstRunForStartGeometry"):
650  try:
651  self._general_options[var] = self._config.get('general',var)
652  except ConfigParser.NoOptionError:
653  print("No", var, "found in [general] section.", end=' ')
654  print("Please check ini-file.")
655  sys.exit(1)
656  self._first_run = self._general_options["FirstRunForStartGeometry"]
657 
658 
659  def _fetch_defaults(self):
660  """Fetch default general options from config file."""
661 
662  for var in ("globaltag", "configTemplate", "json", "massStorageDir",
663  "testMode"):
664  try:
665  self._general_options[var] = self._config.get("general", var)
666  except ConfigParser.NoOptionError:
667  if var == "testMode": continue
668  print("No '" + var + "' given in [general] section.")
669 
670  for dataset in six.itervalues(self._external_datasets):
671  dataset["general"] = {}
672  for var in ("globaltag", "configTemplate", "json"):
673  try:
674  dataset["general"][var] = dataset["config"].get("general", var)
675  except (ConfigParser.NoSectionError,ConfigParser.NoOptionError):
676  pass
677 
678 
680  """
681  Fetch 'datasetDir' variable from general section and add it to the
682  'os.environ' dictionary.
683  """
684 
685  if self._config.has_option("general", "datasetdir"):
686  dataset_directory = self._config.get("general", "datasetdir")
687  # add it to environment for later variable expansion:
688  os.environ["datasetdir"] = dataset_directory
689  self._general_options["datasetdir"] = dataset_directory
690  else:
691  print("No datasetdir given in [general] section.", end=' ')
692  print("Be sure to give a full path in inputFileList.")
693  self._general_options["datasetdir"] = ""
694 
695 
696  def _fetch_datasets(self):
697  """Fetch internal and external dataset configurations."""
698 
699  all_configs = collections.OrderedDict()
700  all_configs["main"] = {"config": self._config,
701  "general": self._general_options,
702  "weight": None}
703  all_configs.update(self._external_datasets)
704 
705  for config in six.itervalues(all_configs):
706  global_weight = "1" if config["weight"] is None else config["weight"]
707  if global_weight+self._config.config_path in self._common_weights:
708  global_weight = self._common_weights[global_weight+
709  self._config.config_path]
710  elif global_weight in self._common_weights:
711  global_weight = self._common_weights[global_weight]
712  else:
713  global_weight = (global_weight,)
714  common_weights = {}
715  weight_dict = {}
716  for section in config["config"].sections():
717  cache_datasetdir = os.environ["datasetdir"]
718  if "general" in section:
719  if config["config"].has_option("general", "datasetdir"):
720  os.environ["datasetdir"] = config["config"].get("general", "datasetdir")
721  elif section == "weights":
722  for option in config["config"].options(section):
723  common_weights[option] \
724  = [x.strip() for x in
725  config["config"].get(section, option).split(",")]
726  elif section.startswith("dataset:"):
727  print("-"*75)
728  # set name from section-name
729  name = section[8:]
730  if name in self._datasets:
731  print("WARNING: Duplicate definition of dataset '{}'".format(name))
732  print(" -> Using defintion in '{}':\n".format(config["config"].config_path))
733  print(" [{}]".format(section))
734  for k,v in config["config"].items(section):
735  print(" ", k, "=", v)
736  print()
737  self._datasets[name] = {}
738 
739  # extract weight for the dataset
740  if config["config"].has_option(section, "weight"):
741  self._weight_dict[name] \
742  = [x.strip() for x in
743  config["config"].get(section, "weight").split(",")]
744  else:
745  self._weight_dict[name] = ["1.0"]
746  self._weight_dict[name] = [global_w+"*"+w
747  for w in self._weight_dict[name]
748  for global_w in global_weight]
749  weight_dict[name] = self._weight_dict[name]
750 
751  # extract essential variables
752  for var in ("inputFileList", "collection"):
753  try:
754  self._datasets[name][var] = config["config"].get(section, var)
755  except ConfigParser.NoOptionError:
756  print("No", var, "found in", section+". Please check ini-file.")
757  sys.exit(1)
758 
759  # get globaltag and configTemplate. If none in section, try to get
760  # default from [general] section.
761  for var in ("configTemplate", "globaltag"):
762  try:
763  self._datasets[name][var] = config["config"].get(section, var)
764  except (ConfigParser.NoSectionError,ConfigParser.NoOptionError):
765  try:
766  self._datasets[name][var] = config["general"][var]
767  except KeyError:
768  try:
769  self._datasets[name][var] \
770  = all_configs["main"]["general"][var]
771  except KeyError:
772  print("No",var,"found in ["+section+"]", end=' ')
773  print("and no default in [general] section.")
774  sys.exit(1)
775 
776  # extract non-essential options
777  self._datasets[name]["cosmicsZeroTesla"] = False
778  if config["config"].has_option(section,"cosmicsZeroTesla"):
779  self._datasets[name]["cosmicsZeroTesla"] \
780  = config["config"].getboolean(section,"cosmicsZeroTesla")
781 
782  self._datasets[name]["cosmicsDecoMode"] = False
783  if config["config"].has_option(section,"cosmicsDecoMode"):
784  self._datasets[name]["cosmicsDecoMode"] \
785  = config["config"].getboolean(section,"cosmicsDecoMode")
786 
787  self._datasets[name]["primaryWidth"] = -1.0
788  if config["config"].has_option(section,"primaryWidth"):
789  self._datasets[name]["primaryWidth"] \
790  = config["config"].getfloat(section,"primaryWidth")
791 
792  self._datasets[name]["numberOfEvents"] = -1
793  if config["config"].has_option(section, "numberOfEvents"):
794  self._datasets[name]["numberOfEvents"] \
795  = config["config"].getint(section, "numberOfEvents")
796 
797  self._datasets[name]["json"] = ""
798  try:
799  self._datasets[name]["json"] = config["config"].get(section,"json")
800  except ConfigParser.NoOptionError:
801  try:
802  self._datasets[name]["json"] = config["general"]["json"]
803  except KeyError:
804  try:
805  self._datasets[name]["json"] \
806  = all_configs["main"]["general"]["json"]
807  except KeyError:
808  print("No json given in either [general] or", end=' ')
809  print("["+section+"] sections.")
810  print(" -> Proceeding without json-file.")
811 
812 
813  #replace ${datasetdir} and other variables, e.g. $CMSSW_BASE
814  for var in ("inputFileList", "json", "configTemplate"):
815  self._datasets[name][var] \
816  = os.path.expandvars(self._datasets[name][var])
817 
818 
819  # Get number of jobs from lines in inputfilelist
820  self._datasets[name]["njobs"] = 0
821  try:
822  with open(self._datasets[name]["inputFileList"], "r") as filelist:
823  for line in filelist:
824  if "CastorPool" in line:
825  continue
826  # ignore empty lines
827  if not line.strip()=="":
828  self._datasets[name]["njobs"] += 1
829  except IOError:
830  print("Inputfilelist", self._datasets[name]["inputFileList"], end=' ')
831  print("does not exist.")
832  sys.exit(1)
833  if self._datasets[name]["njobs"] == 0:
834  print("Number of jobs is 0. There may be a problem with the inputfilelist:")
835  print(self._datasets[name]["inputFileList"])
836  sys.exit(1)
837 
838  # Check if njobs gets overwritten in .ini-file
839  if config["config"].has_option(section, "njobs"):
840  if config["config"].getint(section, "njobs") <= self._datasets[name]["njobs"]:
841  self._datasets[name]["njobs"] = config["config"].getint(section, "njobs")
842  else:
843  print("'njobs' is bigger than the number of files for this", end=' ')
844  print("dataset:", self._datasets[name]["njobs"])
845  print("Using default.")
846  else:
847  print("No number of jobs specified. Using number of files in", end=' ')
848  print("inputfilelist as the number of jobs.")
849 
850  # check if local weights override global weights and resolve name clashes
851  for weight_name, weight_values in six.iteritems(common_weights):
852  for key, weight in six.iteritems(weight_dict):
853  if any([weight_name in w for w in weight]):
854  self._common_weights[weight_name+config["config"].config_path] = weight_values
855  self._weight_dict[key] = [mps_tools.replace_factors(w,
856  weight_name,
857  weight_name+config["config"].config_path)
858  for w in weight]
859  else:
860  self._common_weights[weight_name] = weight_values
861  self._weight_dict[key] = weight
862 
863  os.environ["datasetdir"] = cache_datasetdir
864 
865  if len(self._datasets) == 0:
866  print("No dataset section defined in '{0}'".format(
867  ", ".join([self._args.aligmentConfig]+self._external_datasets.keys())))
868  print("At least one section '[dataset:<name>]' is required.")
869  sys.exit(1)
870 
871  self._global_tag = self._datasets[name]["globaltag"]
872 
873 
874 ################################################################################
875 if __name__ == "__main__":
876  try:
877  main()
878  except KeyboardInterrupt:
879  pass
def _create_mass_storage_directory(self)
def checked_out_MPS()
Definition: helper.py:4
bool any(const std::vector< T > &v, const T &what)
Definition: ECalSD.cc:37
def __init__(self, argv)
Definition: mps_alisetup.py:41
S & print(S &os, JobReport::InputFile const &f)
Definition: JobReport.cc:65
def _handle_process_call(self, command, verbose=False)
def _create_additional_pede_jobs(self)
static std::string join(char **cmd)
Definition: RemoteFile.cc:18
Definition: main.py:1
def main(argv=None)
Definition: mps_alisetup.py:23
#define str(s)
double split
Definition: MVATrainer.cc:139
T get(const Candidate &c)
Definition: component.h:55