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 'there seems to be a problem to determine the current directory name:',currentDir
126  sys.exit(1)
127 
128 # set directory on eos
129 mssDir = '/store/caf/user/'+os.environ['USER']+'/MPproduction/'+mpsdirname
130 
131 # create directory on eos if it doesn't exist already
132 eos = '/afs/cern.ch/project/eos/installation/cms/bin/eos.select'
133 os.system(eos+' mkdir -p '+mssDir)
134 
135 
136 
137 #------------------------------------------------------------------------------
138 # read general-section
139 generalOptions = {}
140 
141 # essential variables
142 for var in ['classInf','pedeMem','jobname']:
143  try:
144  generalOptions[var] = config.get('general',var)
145  except ConfigParser.NoOptionError:
146  print "No", var, "found in [general] section. Please check ini-file."
147  raise SystemExit
148 
149 # check if datasetdir is given
150 generalOptions['datasetdir'] = ''
151 if config.has_option('general','datasetdir'):
152  generalOptions['datasetdir'] = config.get('general','datasetdir')
153  # add it to environment for later variable expansion:
154  os.environ["datasetdir"] = generalOptions['datasetdir']
155 else:
156  print "No datasetdir given in [general] section.",
157  print "Be sure to give a full path in inputFileList."
158 
159 # check for default options
160 for var in ['globaltag','configTemplate','json']:
161  try:
162  generalOptions[var] = config.get('general',var)
163  except ConfigParser.NoOptionError:
164  print 'No default', var, 'given in [general] section.'
165 
166 
167 
168 pedesettings = ([x.strip() for x in config.get("general", "pedesettings").split(",")]
169  if config.has_option("general", "pedesettings") else [None])
170 
171 weight_confs = get_weight_configs(config)
172 
173 
174 #------------------------------------------------------------------------------
175 # -w option: Get new weights from .ini and create additional mergejob with these
176 if args.weight:
177 
178  # do some basic checks
179  if not os.path.isdir("jobData"):
180  print "No jobData-folder found. Properly set up the alignment before using the -w option."
181  raise SystemExit
182  if not os.path.exists("mps.db"):
183  print "No mps.db found. Properly set up the alignment before using the -w option."
184  raise SystemExit
185 
186  # check if default configTemplate is given
187  try:
188  configTemplate = config.get('general','configTemplate')
189  except ConfigParser.NoOptionError:
190  print 'No default configTemplate given in [general] section.'
191  print 'When using -w, a default configTemplate is needed to build a merge-config.'
192  raise SystemExit
193 
194  # check if default globaltag is given
195  try:
196  globalTag = config.get('general','globaltag')
197  except ConfigParser.NoOptionError:
198  print "No default 'globaltag' given in [general] section."
199  print "When using -w, a default configTemplate is needed to build a merge-config."
200  raise SystemExit
201 
202  try:
203  with open(configTemplate,"r") as f:
204  tmpFile = f.read()
205  except IOError:
206  print "The config-template '"+configTemplate+"' cannot be found."
207  raise SystemExit
208 
209  tmpFile = re.sub('setupGlobaltag\s*\=\s*[\"\'](.*?)[\"\']',
210  'setupGlobaltag = \"'+globalTag+'\"',
211  tmpFile)
212 
213  thisCfgTemplate = "tmp.py"
214  with open(thisCfgTemplate, "w") as f:
215  f.write(tmpFile)
216 
217  for setting in pedesettings:
218  print
219  print "="*60
220  if setting is None:
221  print "Creating pede job."
222  else:
223  print "Creating pede jobs using settings from '{0}'.".format(setting)
224  for weight_conf in weight_confs:
225  print "-"*60
226  # blank weights
227  os.system("mps_weight.pl -c > /dev/null")
228 
229  for name,weight in weight_conf:
230  os.system("mps_weight.pl -N "+name+" "+weight)
231 
232  # create new mergejob
233  os.system("mps_setupm.pl")
234 
235  # read mps.db to find directory of new mergejob
236  lib = mpslib.jobdatabase()
237  lib.read_db()
238 
239  # delete old merge-config
240  command = "rm -f jobData/"+lib.JOBDIR[-1]+"/alignment_merge.py"
241  print command
242  os.system(command)
243 
244  # create new merge-config
245  command = ("mps_merge.py -w "+thisCfgTemplate+" jobData/"+
246  lib.JOBDIR[-1]+"/alignment_merge.py jobData/"+
247  lib.JOBDIR[-1]+" "+str(lib.nJobs))
248  if setting is not None: command += " -a "+setting
249  print command
250  if args.verbose:
251  subprocess.call(command, stderr=subprocess.STDOUT, shell=True)
252  else:
253  with open(os.devnull, 'w') as FNULL:
254  subprocess.call(command, stdout=FNULL,
255  stderr=subprocess.STDOUT, shell=True)
256 
257  # remove temporary file
258  os.system("rm "+thisCfgTemplate)
259  sys.exit()
260 
261 
262 #------------------------------------------------------------------------------
263 # loop over dataset-sections
264 firstDataset = True
265 for section in config.sections():
266  if 'general' in section:
267  continue
268  elif section.startswith("dataset:"):
269  datasetOptions={}
270  print "-"*60
271 
272  # set name from section-name
273  datasetOptions['name'] = section[8:]
274 
275  # extract essential variables
276  for var in ['inputFileList','collection']:
277  try:
278  datasetOptions[var] = config.get(section,var)
279  except ConfigParser.NoOptionError:
280  print 'No', var, 'found in', section+'. Please check ini-file.'
281  raise SystemExit
282 
283  # get globaltag and configTemplate. If none in section, try to get default from [general] section.
284  for var in ['configTemplate','globaltag']:
285  if config.has_option(section,var):
286  datasetOptions[var] = config.get(section,var)
287  else:
288  try:
289  datasetOptions[var] = generalOptions[var]
290  except KeyError:
291  print "No",var,"found in ["+section+"]",
292  print "and no default in [general] section."
293  raise SystemExit
294 
295  # extract non-essential options
296  datasetOptions['cosmicsZeroTesla'] = False
297  if config.has_option(section,'cosmicsZeroTesla'):
298  datasetOptions['cosmicsZeroTesla'] = config.getboolean(section,'cosmicsZeroTesla')
299 
300  datasetOptions['cosmicsDecoMode'] = False
301  if config.has_option(section,'cosmicsDecoMode'):
302  datasetOptions['cosmicsDecoMode'] = config.getboolean(section,'cosmicsDecoMode')
303 
304  datasetOptions['primaryWidth'] = -1.0
305  if config.has_option(section,'primaryWidth'):
306  datasetOptions['primaryWidth'] = config.getfloat(section,'primaryWidth')
307 
308  datasetOptions['json'] = ''
309  if config.has_option(section, 'json'):
310  datasetOptions['json'] = config.get(section,'json')
311  else:
312  try:
313  datasetOptions['json'] = generalOptions['json']
314  except KeyError:
315  print "No json given in either [general] or ["+section+"] sections.",
316  print "Proceeding without json-file."
317 
318 
319  # replace '${datasetdir}' and other variables in inputFileList-path
320  datasetOptions['inputFileList'] = os.path.expandvars(datasetOptions['inputFileList'])
321 
322  # replace variables in configTemplate-path, e.g. $CMSSW_BASE
323  datasetOptions['configTemplate'] = os.path.expandvars(datasetOptions['configTemplate'])
324 
325 
326  # Get number of jobs from lines in inputfilelist
327  datasetOptions['njobs'] = 0
328  try:
329  with open(datasetOptions['inputFileList'],'r') as filelist:
330  for line in filelist:
331  if 'CastorPool' in line:
332  continue
333  # ignore empty lines
334  if not line.strip()=='':
335  datasetOptions['njobs'] += 1
336  except IOError:
337  print 'Inputfilelist', datasetOptions['inputFileList'], 'does not exist.'
338  raise SystemExit
339  if datasetOptions['njobs'] == 0:
340  print 'Number of jobs is 0. There may be a problem with the inputfilelist:'
341  print datasetOptions['inputFileList']
342  raise SystemExit
343 
344  # Check if njobs gets overwritten in .ini-file
345  if config.has_option(section,'njobs'):
346  if config.getint(section,'njobs')<=datasetOptions['njobs']:
347  datasetOptions['njobs'] = config.getint(section,'njobs')
348  else:
349  print 'njobs is bigger than the default',datasetOptions['njobs'],'. Using default.'
350  else:
351  print 'No number of jobs specified. Using number of files in inputfilelist as the number of jobs.'
352 
353 
354  # Build config from template/Fill in variables
355  try:
356  with open(datasetOptions['configTemplate'],'r') as INFILE:
357  tmpFile = INFILE.read()
358  except IOError:
359  print 'The config-template called',datasetOptions['configTemplate'],'cannot be found.'
360  raise SystemExit
361 
362  tmpFile = re.sub('setupGlobaltag\s*\=\s*[\"\'](.*?)[\"\']',
363  'setupGlobaltag = \"'+datasetOptions['globaltag']+'\"',
364  tmpFile)
365  tmpFile = re.sub('setupCollection\s*\=\s*[\"\'](.*?)[\"\']',
366  'setupCollection = \"'+datasetOptions['collection']+'\"',
367  tmpFile)
368  if datasetOptions['cosmicsZeroTesla']:
369  tmpFile = re.sub(re.compile('setupCosmicsZeroTesla\s*\=\s*.*$', re.M),
370  'setupCosmicsZeroTesla = True',
371  tmpFile)
372  if datasetOptions['cosmicsDecoMode']:
373  tmpFile = re.sub(re.compile('setupCosmicsDecoMode\s*\=\s*.*$', re.M),
374  'setupCosmicsDecoMode = True',
375  tmpFile)
376  if datasetOptions['primaryWidth'] > 0.0:
377  tmpFile = re.sub(re.compile('setupPrimaryWidth\s*\=\s*.*$', re.M),
378  'setupPrimaryWidth = '+str(datasetOptions['primaryWidth']),
379  tmpFile)
380  if datasetOptions['json'] != '':
381  tmpFile = re.sub(re.compile('setupJson\s*\=\s*.*$', re.M),
382  'setupJson = \"'+datasetOptions['json']+'\"',
383  tmpFile)
384 
385  thisCfgTemplate = 'tmp.py'
386  with open(thisCfgTemplate, 'w') as OUTFILE:
387  OUTFILE.write(tmpFile)
388 
389 
390  # Set mps_setup append option for datasets following the first one
391  append = ' -a'
392  if firstDataset:
393  append = ''
394  firstDataset = False
395  configTemplate = tmpFile
396 
397  # create mps_setup command
398  command = 'mps_setup.pl -m%s -M %s -N %s %s %s %s %d %s %s %s cmscafuser:%s' % (
399  append,
400  generalOptions['pedeMem'],
401  datasetOptions['name'],
402  milleScript,
403  thisCfgTemplate,
404  datasetOptions['inputFileList'],
405  datasetOptions['njobs'],
406  generalOptions['classInf'],
407  generalOptions['jobname'],
408  pedeScript,
409  mssDir)
410  # Some output:
411  print 'Submitting dataset:', datasetOptions['name']
412  print 'Baseconfig: ', datasetOptions['configTemplate']
413  print 'Collection: ', datasetOptions['collection']
414  if datasetOptions['collection']=='ALCARECOTkAlCosmicsCTF0T':
415  print 'cosmicsDecoMode: ', datasetOptions['cosmicsDecoMode']
416  print 'cosmicsZeroTesla: ', datasetOptions['cosmicsZeroTesla']
417  print 'Globaltag: ', datasetOptions['globaltag']
418  print 'Number of jobs: ', datasetOptions['njobs']
419  print 'Inputfilelist: ', datasetOptions['inputFileList']
420  if datasetOptions['json'] != '':
421  print 'Jsonfile: ', datasetOptions['json']
422  print 'Pass to mps_setup: ', command
423 
424  # call the command and toggle verbose output
425  if args.verbose:
426  subprocess.call(command, stderr=subprocess.STDOUT, shell=True)
427  else:
428  with open(os.devnull, 'w') as FNULL:
429  subprocess.call(command, stdout=FNULL,
430  stderr=subprocess.STDOUT, shell=True)
431 
432  # remove temporary file
433  os.system("rm "+thisCfgTemplate)
434 
435 if firstDataset:
436  print "No dataset section defined in '{0}'".format(aligmentConfig)
437  print "At least one section '[dataset:<name>]' is required."
438  sys.exit(1)
439 
440 firstPedeConfig = True
441 for setting in pedesettings:
442  print
443  print "="*60
444  if setting is None:
445  print "Creating pede job."
446  else:
447  print "Creating pede jobs using settings from '{0}'.".format(setting)
448  for weight_conf in weight_confs:
449  print "-"*60
450  # blank weights
451  os.system("mps_weight.pl -c > /dev/null")
452 
453  for name,weight in weight_conf:
454  os.system("mps_weight.pl -N "+name+" "+weight)
455 
456  if firstPedeConfig:
457  firstPedeConfig = False
458  else:
459  # create new mergejob
460  os.system("mps_setupm.pl")
461 
462  # read mps.db to find directory of new mergejob
463  lib = mpslib.jobdatabase()
464  lib.read_db()
465 
466  # delete old merge-config
467  command = "rm -f jobData/"+lib.JOBDIR[-1]+"/alignment_merge.py"
468  print command
469  os.system(command)
470 
471  thisCfgTemplate = "tmp.py"
472  with open(thisCfgTemplate, "w") as f:
473  f.write(configTemplate)
474 
475  # create new merge-config
476  command = ("mps_merge.py -w "+thisCfgTemplate+" jobData/"+lib.JOBDIR[-1]+
477  "/alignment_merge.py jobData/"+lib.JOBDIR[-1]+" "+
478  str(lib.nJobs))
479  if setting is not None: command += " -a "+setting
480  print command
481  if args.verbose:
482  subprocess.call(command, stderr=subprocess.STDOUT, shell=True)
483  else:
484  with open(os.devnull, 'w') as FNULL:
485  subprocess.call(command, stdout=FNULL,
486  stderr=subprocess.STDOUT, shell=True)
487 
488  # remove temporary file
489  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