CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
mps_alisetup.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 #############################################################################
4 ## Builds the config-templates from the universal config-template for each
5 ## dataset specified in .ini-file that is passed to this script as argument.
6 ## Then calls mps_setup.pl for all datasets.
7 ##
8 ## Usage:
9 ## mps_alisetup.py [-h] [-v] myconfig.ini
10 ##
11 
12 import argparse
13 import os
14 import re
15 import subprocess
16 import ConfigParser
17 import sys
18 import itertools
19 import collections
20 import Alignment.MillePedeAlignmentAlgorithm.mpslib.Mpslibclass as mpslib
21 from Alignment.MillePedeAlignmentAlgorithm.alignmentsetup.helper import checked_out_MPS
22 
23 
24 def get_weight_configs(config):
25  """Extracts different weight configurations from `config`.
26 
27  Arguments:
28  - `config`: ConfigParser object containing the alignment configuration
29  """
30 
31  weight_dict = collections.OrderedDict()
32  common_weights = {}
33 
34  # loop over datasets to reassign weights
35  for section in config.sections():
36  if 'general' in section:
37  continue
38  elif section == "weights":
39  for option in config.options(section):
40  common_weights[option] = [x.strip() for x in
41  config.get(section, option).split(",")]
42  elif section.startswith("dataset:"):
43  name = section[8:] # get name of dataset by stripping of "dataset:"
44  if config.has_option(section,'weight'):
45  weight_dict[name] = [x.strip() for x in
46  config.get(section, "weight").split(",")]
47  else:
48  weight_dict[name] = ['1.0']
49 
50  weights_list = [[(name, weight) for weight in weight_dict[name]]
51  for name in weight_dict]
52 
53  common_weights_list = [[(name, weight) for weight in common_weights[name]]
54  for name in common_weights]
55  common_weights_dicts = []
56  for item in itertools.product(*common_weights_list):
57  d = {}
58  for name,weight in item:
59  d[name] = weight
60  common_weights_dicts.append(d)
61 
62  configs = []
63  for weight_conf in itertools.product(*weights_list):
64  if len(common_weights) > 0:
65  for common_weight in common_weights_dicts:
66  configs.append([(dataset[0],
67  reduce(lambda x,y: x.replace(y, common_weight[y]),
68  common_weight, dataset[1]))
69  for dataset in weight_conf])
70  else:
71  configs.append(weight_conf)
72 
73  return configs
74 
75 
76 
77 # ------------------------------------------------------------------------------
78 # set up argument parser and config parser
79 
80 helpEpilog ='''Builds the config-templates from a universal config-template for each
81 dataset specified in .ini-file that is passed to this script.
82 Then calls mps_setup.pl for all datasets.'''
84  description='Setup the alignment as configured in the alignment_config file.',
85  epilog=helpEpilog)
86 # optional argmuent: verbose (toggles output of mps_setup)
87 parser.add_argument('-v', '--verbose', action='store_true',
88  help='display detailed output of mps_setup')
89 # optional argmuent: weight (new weights for additional merge job)
90 parser.add_argument('-w', '--weight', action='store_true',
91  help='create an additional mergejob with (possibly new) weights from .ini-config')
92 # positional argument: config file
93 parser.add_argument('alignmentConfig', action='store',
94  help='name of the .ini config file that specifies the datasets to be used')
95 # parse argument
96 args = parser.parse_args()
97 aligmentConfig = args.alignmentConfig
98 
99 # parse config file
100 config = ConfigParser.ConfigParser()
101 config.optionxform = str # default would give lowercase options -> not wanted
102 config.read(aligmentConfig)
103 
104 
105 
106 #------------------------------------------------------------------------------
107 # construct directories
108 
109 # set variables that are not too specific (millescript, pedescript, etc.)
110 mpsScriptsDir = os.path.join("src", "Alignment", "MillePedeAlignmentAlgorithm", "scripts")
111 if checked_out_MPS()[0]:
112  mpsScriptsDir = os.path.join(os.environ["CMSSW_BASE"], mpsScriptsDir)
113 else:
114  mpsScriptsDir = os.path.join(os.environ["CMSSW_RELEASE_BASE"], mpsScriptsDir)
115 milleScript = os.path.join(mpsScriptsDir, "mps_runMille_template.sh")
116 pedeScript = os.path.join(mpsScriptsDir, "mps_runPede_rfcp_template.sh")
117 
118 # get working directory name
119 currentDir = os.getcwd()
120 mpsdirname = ''
121 match = re.search(re.compile('mpproduction\/mp(.+?)$', re.M|re.I),currentDir)
122 if match:
123  mpsdirname = 'mp'+match.group(1)
124 else:
125  print "Current location does not seem to be a MillePede campaign directory:",
126  print currentDir
127  sys.exit(1)
128 
129 # set directory on eos
130 mssDir = '/store/caf/user/'+os.environ['USER']+'/MPproduction/'+mpsdirname
131 
132 # create directory on eos if it doesn't exist already
133 eos = '/afs/cern.ch/project/eos/installation/cms/bin/eos.select'
134 os.system(eos+' mkdir -p '+mssDir)
135 
136 
137 
138 #------------------------------------------------------------------------------
139 # read general-section
140 generalOptions = {}
141 
142 # essential variables
143 for var in ['classInf','pedeMem','jobname']:
144  try:
145  generalOptions[var] = config.get('general',var)
146  except ConfigParser.NoOptionError:
147  print "No", var, "found in [general] section. Please check ini-file."
148  raise SystemExit
149 
150 # check if datasetdir is given
151 generalOptions['datasetdir'] = ''
152 if config.has_option('general','datasetdir'):
153  generalOptions['datasetdir'] = config.get('general','datasetdir')
154  # add it to environment for later variable expansion:
155  os.environ["datasetdir"] = generalOptions['datasetdir']
156 else:
157  print "No datasetdir given in [general] section.",
158  print "Be sure to give a full path in inputFileList."
159 
160 # check for default options
161 for var in ['globaltag','configTemplate','json']:
162  try:
163  generalOptions[var] = config.get('general',var)
164  except ConfigParser.NoOptionError:
165  print 'No default', var, 'given in [general] section.'
166 
167 
168 
169 pedesettings = ([x.strip() for x in config.get("general", "pedesettings").split(",")]
170  if config.has_option("general", "pedesettings") else [None])
171 
172 weight_confs = get_weight_configs(config)
173 
174 
175 #------------------------------------------------------------------------------
176 # -w option: Get new weights from .ini and create additional mergejob with these
177 if args.weight:
178 
179  # do some basic checks
180  if not os.path.isdir("jobData"):
181  print "No jobData-folder found. Properly set up the alignment before using the -w option."
182  raise SystemExit
183  if not os.path.exists("mps.db"):
184  print "No mps.db found. Properly set up the alignment before using the -w option."
185  raise SystemExit
186 
187  # check if default configTemplate is given
188  try:
189  configTemplate = config.get('general','configTemplate')
190  except ConfigParser.NoOptionError:
191  print 'No default configTemplate given in [general] section.'
192  print 'When using -w, a default configTemplate is needed to build a merge-config.'
193  raise SystemExit
194 
195  # check if default globaltag is given
196  try:
197  globalTag = config.get('general','globaltag')
198  except ConfigParser.NoOptionError:
199  print "No default 'globaltag' given in [general] section."
200  print "When using -w, a default configTemplate is needed to build a merge-config."
201  raise SystemExit
202 
203  try:
204  with open(configTemplate,"r") as f:
205  tmpFile = f.read()
206  except IOError:
207  print "The config-template '"+configTemplate+"' cannot be found."
208  raise SystemExit
209 
210  tmpFile = re.sub('setupGlobaltag\s*\=\s*[\"\'](.*?)[\"\']',
211  'setupGlobaltag = \"'+globalTag+'\"',
212  tmpFile)
213 
214  thisCfgTemplate = "tmp.py"
215  with open(thisCfgTemplate, "w") as f:
216  f.write(tmpFile)
217 
218  for setting in pedesettings:
219  print
220  print "="*60
221  if setting is None:
222  print "Creating pede job."
223  else:
224  print "Creating pede jobs using settings from '{0}'.".format(setting)
225  for weight_conf in weight_confs:
226  print "-"*60
227  # blank weights
228  os.system("mps_weight.pl -c > /dev/null")
229 
230  for name,weight in weight_conf:
231  os.system("mps_weight.pl -N "+name+" "+weight)
232 
233  # create new mergejob
234  os.system("mps_setupm.pl")
235 
236  # read mps.db to find directory of new mergejob
237  lib = mpslib.jobdatabase()
238  lib.read_db()
239 
240  # delete old merge-config
241  command = "rm -f jobData/"+lib.JOBDIR[-1]+"/alignment_merge.py"
242  print command
243  os.system(command)
244 
245  # create new merge-config
246  command = ("mps_merge.py -w "+thisCfgTemplate+" jobData/"+
247  lib.JOBDIR[-1]+"/alignment_merge.py jobData/"+
248  lib.JOBDIR[-1]+" "+str(lib.nJobs))
249  if setting is not None: command += " -a "+setting
250  print command
251  if args.verbose:
252  subprocess.call(command, stderr=subprocess.STDOUT, shell=True)
253  else:
254  with open(os.devnull, 'w') as FNULL:
255  subprocess.call(command, stdout=FNULL,
256  stderr=subprocess.STDOUT, shell=True)
257 
258  # remove temporary file
259  os.system("rm "+thisCfgTemplate)
260  sys.exit()
261 
262 
263 #------------------------------------------------------------------------------
264 # loop over dataset-sections
265 firstDataset = True
266 for section in config.sections():
267  if 'general' in section:
268  continue
269  elif section.startswith("dataset:"):
270  datasetOptions={}
271  print "-"*60
272 
273  # set name from section-name
274  datasetOptions['name'] = section[8:]
275 
276  # extract essential variables
277  for var in ['inputFileList','collection']:
278  try:
279  datasetOptions[var] = config.get(section,var)
280  except ConfigParser.NoOptionError:
281  print 'No', var, 'found in', section+'. Please check ini-file.'
282  raise SystemExit
283 
284  # get globaltag and configTemplate. If none in section, try to get default from [general] section.
285  for var in ['configTemplate','globaltag']:
286  if config.has_option(section,var):
287  datasetOptions[var] = config.get(section,var)
288  else:
289  try:
290  datasetOptions[var] = generalOptions[var]
291  except KeyError:
292  print "No",var,"found in ["+section+"]",
293  print "and no default in [general] section."
294  raise SystemExit
295 
296  # extract non-essential options
297  datasetOptions['cosmicsZeroTesla'] = False
298  if config.has_option(section,'cosmicsZeroTesla'):
299  datasetOptions['cosmicsZeroTesla'] = config.getboolean(section,'cosmicsZeroTesla')
300 
301  datasetOptions['cosmicsDecoMode'] = False
302  if config.has_option(section,'cosmicsDecoMode'):
303  datasetOptions['cosmicsDecoMode'] = config.getboolean(section,'cosmicsDecoMode')
304 
305  datasetOptions['primaryWidth'] = -1.0
306  if config.has_option(section,'primaryWidth'):
307  datasetOptions['primaryWidth'] = config.getfloat(section,'primaryWidth')
308 
309  datasetOptions['json'] = ''
310  if config.has_option(section, 'json'):
311  datasetOptions['json'] = config.get(section,'json')
312  else:
313  try:
314  datasetOptions['json'] = generalOptions['json']
315  except KeyError:
316  print "No json given in either [general] or ["+section+"] sections.",
317  print "Proceeding without json-file."
318 
319 
320  # replace '${datasetdir}' and other variables in inputFileList-path
321  datasetOptions['inputFileList'] = os.path.expandvars(datasetOptions['inputFileList'])
322 
323  # replace variables in configTemplate-path, e.g. $CMSSW_BASE
324  datasetOptions['configTemplate'] = os.path.expandvars(datasetOptions['configTemplate'])
325 
326 
327  # Get number of jobs from lines in inputfilelist
328  datasetOptions['njobs'] = 0
329  try:
330  with open(datasetOptions['inputFileList'],'r') as filelist:
331  for line in filelist:
332  if 'CastorPool' in line:
333  continue
334  # ignore empty lines
335  if not line.strip()=='':
336  datasetOptions['njobs'] += 1
337  except IOError:
338  print 'Inputfilelist', datasetOptions['inputFileList'], 'does not exist.'
339  raise SystemExit
340  if datasetOptions['njobs'] == 0:
341  print 'Number of jobs is 0. There may be a problem with the inputfilelist:'
342  print datasetOptions['inputFileList']
343  raise SystemExit
344 
345  # Check if njobs gets overwritten in .ini-file
346  if config.has_option(section,'njobs'):
347  if config.getint(section,'njobs')<=datasetOptions['njobs']:
348  datasetOptions['njobs'] = config.getint(section,'njobs')
349  else:
350  print 'njobs is bigger than the default',datasetOptions['njobs'],'. Using default.'
351  else:
352  print 'No number of jobs specified. Using number of files in inputfilelist as the number of jobs.'
353 
354 
355  # Build config from template/Fill in variables
356  try:
357  with open(datasetOptions['configTemplate'],'r') as INFILE:
358  tmpFile = INFILE.read()
359  except IOError:
360  print 'The config-template called',datasetOptions['configTemplate'],'cannot be found.'
361  raise SystemExit
362 
363  tmpFile = re.sub('setupGlobaltag\s*\=\s*[\"\'](.*?)[\"\']',
364  'setupGlobaltag = \"'+datasetOptions['globaltag']+'\"',
365  tmpFile)
366  tmpFile = re.sub('setupCollection\s*\=\s*[\"\'](.*?)[\"\']',
367  'setupCollection = \"'+datasetOptions['collection']+'\"',
368  tmpFile)
369  if datasetOptions['cosmicsZeroTesla']:
370  tmpFile = re.sub(re.compile('setupCosmicsZeroTesla\s*\=\s*.*$', re.M),
371  'setupCosmicsZeroTesla = True',
372  tmpFile)
373  if datasetOptions['cosmicsDecoMode']:
374  tmpFile = re.sub(re.compile('setupCosmicsDecoMode\s*\=\s*.*$', re.M),
375  'setupCosmicsDecoMode = True',
376  tmpFile)
377  if datasetOptions['primaryWidth'] > 0.0:
378  tmpFile = re.sub(re.compile('setupPrimaryWidth\s*\=\s*.*$', re.M),
379  'setupPrimaryWidth = '+str(datasetOptions['primaryWidth']),
380  tmpFile)
381  if datasetOptions['json'] != '':
382  tmpFile = re.sub(re.compile('setupJson\s*\=\s*.*$', re.M),
383  'setupJson = \"'+datasetOptions['json']+'\"',
384  tmpFile)
385 
386  thisCfgTemplate = 'tmp.py'
387  with open(thisCfgTemplate, 'w') as OUTFILE:
388  OUTFILE.write(tmpFile)
389 
390 
391  # Set mps_setup append option for datasets following the first one
392  append = ' -a'
393  if firstDataset:
394  append = ''
395  firstDataset = False
396  configTemplate = tmpFile
397 
398  # create mps_setup command
399  command = 'mps_setup.pl -m%s -M %s -N %s %s %s %s %d %s %s %s cmscafuser:%s' % (
400  append,
401  generalOptions['pedeMem'],
402  datasetOptions['name'],
403  milleScript,
404  thisCfgTemplate,
405  datasetOptions['inputFileList'],
406  datasetOptions['njobs'],
407  generalOptions['classInf'],
408  generalOptions['jobname'],
409  pedeScript,
410  mssDir)
411  # Some output:
412  print 'Submitting dataset:', datasetOptions['name']
413  print 'Baseconfig: ', datasetOptions['configTemplate']
414  print 'Collection: ', datasetOptions['collection']
415  if datasetOptions['collection']=='ALCARECOTkAlCosmicsCTF0T':
416  print 'cosmicsDecoMode: ', datasetOptions['cosmicsDecoMode']
417  print 'cosmicsZeroTesla: ', datasetOptions['cosmicsZeroTesla']
418  print 'Globaltag: ', datasetOptions['globaltag']
419  print 'Number of jobs: ', datasetOptions['njobs']
420  print 'Inputfilelist: ', datasetOptions['inputFileList']
421  if datasetOptions['json'] != '':
422  print 'Jsonfile: ', datasetOptions['json']
423  print 'Pass to mps_setup: ', command
424 
425  # call the command and toggle verbose output
426  if args.verbose:
427  subprocess.call(command, stderr=subprocess.STDOUT, shell=True)
428  else:
429  with open(os.devnull, 'w') as FNULL:
430  subprocess.call(command, stdout=FNULL,
431  stderr=subprocess.STDOUT, shell=True)
432 
433  # remove temporary file
434  os.system("rm "+thisCfgTemplate)
435 
436 if firstDataset:
437  print "No dataset section defined in '{0}'".format(aligmentConfig)
438  print "At least one section '[dataset:<name>]' is required."
439  sys.exit(1)
440 
441 firstPedeConfig = True
442 for setting in pedesettings:
443  print
444  print "="*60
445  if setting is None:
446  print "Creating pede job."
447  else:
448  print "Creating pede jobs using settings from '{0}'.".format(setting)
449  for weight_conf in weight_confs:
450  print "-"*60
451  # blank weights
452  os.system("mps_weight.pl -c > /dev/null")
453 
454  for name,weight in weight_conf:
455  os.system("mps_weight.pl -N "+name+" "+weight)
456 
457  if firstPedeConfig:
458  firstPedeConfig = False
459  else:
460  # create new mergejob
461  os.system("mps_setupm.pl")
462 
463  # read mps.db to find directory of new mergejob
464  lib = mpslib.jobdatabase()
465  lib.read_db()
466 
467  # delete old merge-config
468  command = "rm -f jobData/"+lib.JOBDIR[-1]+"/alignment_merge.py"
469  print command
470  os.system(command)
471 
472  thisCfgTemplate = "tmp.py"
473  with open(thisCfgTemplate, "w") as f:
474  f.write(configTemplate)
475 
476  # create new merge-config
477  command = ("mps_merge.py -w "+thisCfgTemplate+" jobData/"+lib.JOBDIR[-1]+
478  "/alignment_merge.py jobData/"+lib.JOBDIR[-1]+" "+
479  str(lib.nJobs))
480  if setting is not None: command += " -a "+setting
481  print command
482  if args.verbose:
483  subprocess.call(command, stderr=subprocess.STDOUT, shell=True)
484  else:
485  with open(os.devnull, 'w') as FNULL:
486  subprocess.call(command, stdout=FNULL,
487  stderr=subprocess.STDOUT, shell=True)
488 
489  # remove temporary file
490  os.system("rm "+thisCfgTemplate)
def get_weight_configs
Definition: mps_alisetup.py:24
def checked_out_MPS
Definition: helper.py:3
double split
Definition: MVATrainer.cc:139