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 import six
20 
21 ################################################################################
22 def main(argv = None):
23  """Main routine. Not called, if this module is loaded via `import`.
24 
25  Arguments:
26  - `argv`: Command line arguments passed to the script.
27  """
28 
29  if argv == None:
30  argv = sys.argv[1:]
31 
32  setup_alignment = SetupAlignment(argv)
33  setup_alignment.setup()
34 
35 
36 ################################################################################
38  """Class encapsulating the alignment campaign setup procedure."""
39 
40  def __init__(self, argv):
41  """Constructor
42 
43  Arguments:
44  - `argv`: command line arguments
45  """
46 
47  self._argv = argv # raw command line arguments
48  self._args = None # parsed command line arguments
49  self._config = None # ConfigParser object
50  self._mss_dir = None # mass storage directory
51  self._datasets = collections.OrderedDict() # final dataset configs
52  self._first_run = None # first run for start geometry
53  self._cms_process = None # cms.Process extracted from CMSSW config
54  self._override_gt = None # snippet to append to config
55  self._pede_script = None # path to pede batch script template
56  self._weight_dict = collections.OrderedDict() # dictionary with dataset weights
57  self._mille_script = None # path to mille batch script template
58  self._mps_dir_name = None # MP campaign name (mp<ID>)
59  self._common_weights = {} # dictionary with dataset weights from [weights] section
60  self._weight_configs = [] # list with combinations of dataset weights
61  self._general_options = {} # general options extracted from ini file
62  self._external_datasets = collections.OrderedDict() # external dataset configs
63  self._first_pede_config = True # does a pede job exist already?
64 
65  self._create_config()
67  self._fetch_datasets()
68  self._construct_paths()
72 
73 
74  def setup(self):
75  """Setup the alignment campaign."""
76 
77  if self._args.weight:
79  else:
80  self._create_mille_jobs()
81  self._create_pede_jobs()
82 
83  if self._override_gt.strip() != "":
84  msg = ("Overriding global tag with single-IOV tags extracted from "
85  "'{}' for run number '{}'.".format(self._global_tag,
86  self._first_run))
87  print msg
88  print "-"*75
89  print self._override_gt
90  print "="*75
91 
92 
93  def _create_config(self):
94  """Create ConfigParser object from command line arguments."""
95 
96  helpEpilog ="""Builds the config-templates from a universal
97  config-template for each dataset specified in .ini-file that is passed
98  to this script. Then calls mps_setup.py for all datasets."""
99  parser = argparse.ArgumentParser(
100  description = ("Setup the alignment as configured in the "
101  "alignment_config file."),
102  epilog = helpEpilog)
103  parser.add_argument("-v", "--verbose", action="store_true",
104  help="display detailed output of mps_setup")
105  parser.add_argument("-w", "--weight", action="store_true",
106  help=("creates additional merge job(s) with "
107  "(possibly new) weights from .ini-config"))
108  parser.add_argument("alignmentConfig",
109  help=("name of the .ini config file that specifies "
110  "the datasets to be used"))
111 
112  self._args = parser.parse_args(self._argv)
113  self._config = ConfigParser.ConfigParser()
114  self._config.optionxform = str # default would give lowercase options
115  # -> not wanted
116  self._config.read(self._args.alignmentConfig)
117  self._config.config_path = self._args.alignmentConfig
118 
119 
120  def _construct_paths(self):
121  """Determine directory paths and create the ones that are needed."""
122 
123  mpsTemplates = os.path.join("src", "Alignment",
124  "MillePedeAlignmentAlgorithm", "templates")
125  if checked_out_MPS()[0]:
126  mpsTemplates = os.path.join(os.environ["CMSSW_BASE"], mpsTemplates)
127  else:
128  mpsTemplates = os.path.join(os.environ["CMSSW_RELEASE_BASE"], mpsTemplates)
129  self._mille_script = os.path.join(mpsTemplates, "mps_runMille_template.sh")
130  self._pede_script = os.path.join(mpsTemplates, "mps_runPede_rfcp_template.sh")
131 
132  # get working directory name
133  currentDir = os.getcwd()
134  match = re.search(re.compile('mpproduction\/mp(.+?)$', re.M|re.I),currentDir)
135  if match:
136  self._mps_dir_name = 'mp'+match.group(1)
137  else:
138  print "Current location does not seem to be a MillePede campaign directory:",
139  print currentDir
140  sys.exit(1)
141 
142 
144  """Create and fill `general_options` dictionary."""
145 
146  print "="*75
149  self._fetch_essentials()
150  self._fetch_defaults()
151 
152 
154  """Fetch information about external datasets."""
155 
156  if self._config.has_option("general", "externalDatasets"):
157  datasets = map(lambda x: x.strip(),
158  self._config.get("general",
159  "externalDatasets").split(","))
160  datasets = [x for x in datasets if len(x.strip()) > 0]
161  for item in datasets:
162  splitted = item.split("|")
163  dataset = splitted[0].strip()
164  dataset = os.path.expandvars(dataset)
165 
166  weight = splitted[1] if len(splitted) > 1 else None
167  config = ConfigParser.ConfigParser()
168  config.optionxform = str
169  config.read(dataset)
170  config.config_path = dataset
171  self._external_datasets[dataset] = {"config": config,
172  "weight": weight}
173 
174 
175 
177  """
178  Create MPS mass storage directory where, e.g., mille binaries are
179  stored.
180  """
181 
182  # set directory on eos
183  self._mss_dir = self._general_options.get("massStorageDir",
184  "/eos/cms/store/caf/user/"
185  +os.environ["USER"])
186  self._mss_dir = os.path.join(self._mss_dir, "MPproduction",
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",
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.",
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.",
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",
552  print "'FirstRunForStartGeometry' is not 1."
553  print "Creating single IOV output from input conditions in run",
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",
558  print "defined output IOV:",
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,
576  print "is before the first input IOV boundary at",
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,
586  print "for '"+inp+"' is within output IOV starting",
587  print "with run", str(iov)+"."
588  print "Deriving an alignment with coarse IOV",
589  print "granularity starting from finer granularity",
590  print "leads to wrong results."
591  print "A single IOV input using the IOV of",
592  print "'FirstRunForStartGeometry' ("+self._first_run+")",
593  print "is automatically created and used."
594  continue
595  print "Found input IOV boundary at run",input_iov,
596  print "for '"+inp+"' which is within output IOV starting",
597  print "with run", str(iov)+"."
598  print "Deriving an alignment with coarse IOV granularity",
599  print "starting from finer granularity leads to wrong",
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,
616  print "for '"+inp+"' which is within 'TrackerAlignmentRcd'",
617  print "IOV starting with run", str(iov)+"."
618  print "Deriving an alignment with inconsistent IOV boundaries",
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",
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.",
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.",
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+"]",
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",
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"],
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",
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",
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:40
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:22
#define str(s)
double split
Definition: MVATrainer.cc:139
T get(const Candidate &c)
Definition: component.h:55