CMS 3D CMS Logo

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