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
23 """Main routine. Not called, if this module is loaded via `import`. 26 - `argv`: Command line arguments passed to the script. 33 setup_alignment.setup()
38 """Class encapsulating the alignment campaign setup procedure.""" 44 - `argv`: command line arguments 75 """Setup the alignment campaign.""" 83 if self._override_gt.strip() !=
"":
84 msg = (
"Overriding global tag with single-IOV tags extracted from " 94 """Create ConfigParser object from command line arguments.""" 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."),
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"))
113 self.
_config = ConfigParser.ConfigParser()
114 self._config.optionxform = str
116 self._config.read(self._args.alignmentConfig)
117 self._config.config_path = self._args.alignmentConfig
121 """Determine directory paths and create the ones that are needed.""" 123 mpsTemplates = os.path.join(
"src",
"Alignment",
124 "MillePedeAlignmentAlgorithm",
"templates")
126 mpsTemplates = os.path.join(os.environ[
"CMSSW_BASE"], mpsTemplates)
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")
133 currentDir = os.getcwd()
134 match = re.search(re.compile(
'mpproduction\/mp(.+?)$', re.M|re.I),currentDir)
138 print "Current location does not seem to be a MillePede campaign directory:",
144 """Create and fill `general_options` dictionary.""" 154 """Fetch information about external datasets.""" 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)
166 weight = splitted[1]
if len(splitted) > 1
else None 167 config = ConfigParser.ConfigParser()
168 config.optionxform = str
170 config.config_path = dataset
178 Create MPS mass storage directory where, e.g., mille binaries are 183 self.
_mss_dir = self._general_options.get(
"massStorageDir",
184 "/eos/cms/store/caf/user/" 189 cmd = [
"mkdir",
"-p", self.
_mss_dir]
192 if not self._general_options.get(
"testMode",
False):
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 202 """Extract different weight configurations from `self._config`.""" 204 weights_list = [[(name, weight)
for weight
in self.
_weight_dict[name]]
207 common_weights_list = [[(name, weight)
211 common_weights_dicts = []
212 for item
in itertools.product(*common_weights_list):
214 for name,weight
in item:
216 common_weights_dicts.append(d)
219 for weight_conf
in itertools.product(*weights_list):
220 number_of_configs = len(weight_configs)
221 for common_weight
in common_weights_dicts:
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)
231 if len(weight_configs) == number_of_configs:
232 weight_configs.append(weight_conf)
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)
242 """Fetch 'pedesettings' from general section in `self._config`.""" 244 self._pede_settings \
246 for x
in self._config.get(
"general",
"pedesettings").
split(
",")]
247 if self._config.has_option(
"general",
"pedesettings")
else [
None])
251 """Create the mille jobs based on the [dataset:<name>] sections.""" 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)
262 for name, dataset
in six.iteritems(self.
_datasets):
266 with open(dataset[
"configTemplate"],
"r") as f: 269 print "The config-template called",
270 print dataset[
"configTemplate"],
"cannot be found." 273 tmpFile = re.sub(gt_regex,
274 'setupGlobaltag = \"'+dataset[
"globaltag"]+
'\"',
276 tmpFile = re.sub(sg_regex,
277 "setupRunStartGeometry = "+
279 tmpFile = re.sub(collection_regex,
280 'setupCollection = \"'+dataset[
"collection"]+
'\"',
282 if dataset[
'cosmicsZeroTesla']:
283 tmpFile = re.sub(czt_regex,
284 'setupCosmicsZeroTesla = True',
286 if dataset[
'cosmicsDecoMode']:
287 tmpFile = re.sub(cdm_regex,
288 'setupCosmicsDecoMode = True',
290 if dataset[
'primaryWidth'] > 0.0:
291 tmpFile = re.sub(pw_regex,
292 'setupPrimaryWidth = '+
str(dataset[
"primaryWidth"]),
294 if dataset[
'json'] !=
'':
295 tmpFile = re.sub(json_regex,
296 'setupJson = \"'+dataset[
"json"]+
'\"',
299 thisCfgTemplate =
"tmp.py" 300 with open(thisCfgTemplate,
"w")
as f:
308 first_dataset =
False 310 self.
_cms_process = mps_tools.get_process_object(thisCfgTemplate)
313 with open(thisCfgTemplate,
"a")
as f: f.write(self.
_override_gt)
317 command = [
"mps_setup.py",
324 dataset[
"inputFileList"],
325 str(dataset[
"njobs"]),
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]
335 print "Creating jobs for dataset:", name
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)
359 """Create pede jobs from the given input.""" 361 for setting
in self._pede_settings:
365 print "Creating pede job{}.".
format(
369 print "Creating pede jobs using settings from '{0}'.".
format(setting)
374 thisCfgTemplate =
"tmp.py" 377 self.
_cms_process = mps_tools.get_process_object(thisCfgTemplate)
379 with open(thisCfgTemplate,
"a")
as f: f.write(self.
_override_gt)
381 for name,weight
in weight_conf:
389 lib = mpslib.jobdatabase()
393 jobm_path = os.path.join(
"jobData", lib.JOBDIR[-1])
396 command = [
"rm",
"-f", os.path.join(jobm_path,
"alignment_merge.py")]
402 "-w", thisCfgTemplate,
403 os.path.join(jobm_path,
"alignment_merge.py"),
407 if setting
is not None: command.extend([
"-a", setting])
409 print " ".
join(command)
414 os.path.abspath(os.path.join(jobm_path,
415 ".TrackerTree.root")))
419 with open(os.path.join(jobm_path,
".weights.pkl"),
"wb")
as f:
420 cPickle.dump(weight_conf, f, 2)
429 Create pede jobs in addition to already existing ones. Return GT 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." 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." 444 config_template = firstDataset[
"configTemplate"]
445 collection = firstDataset[
"collection"]
448 with open(config_template,
"r") as f: 451 print "The config-template '"+config_template+
"' cannot be found." 454 tmpFile = re.sub(
'setupGlobaltag\s*\=\s*[\"\'](.*?)[\"\']',
457 tmpFile = re.sub(
'setupCollection\s*\=\s*[\"\'](.*?)[\"\']',
458 'setupCollection = \"'+collection+
'\"',
460 tmpFile = re.sub(re.compile(
"setupRunStartGeometry\s*\=\s*.*$", re.M),
472 Wrapper around subprocess calls which treats output depending on verbosity 476 - `command`: list of command items 477 - `verbose`: flag to turn on verbosity 480 call_method = subprocess.check_call
if verbose
else subprocess.check_output
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)
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 498 if not run_number > 0:
499 print "'FirstRunForStartGeometry' must be positive, but is", run_number
502 input_db_name = os.path.abspath(
"alignment_input.db")
504 run_number, input_db_name)
507 for record,tag
in six.iteritems(tags):
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")
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. 526 print "Checking consistency of IOV definition..." 527 iovs = mps_tools.make_unique_runranges(self._cms_process.AlignmentProducer)
530 "TrackerAlignmentRcd":
None,
531 "TrackerSurfaceDeformationRcd":
None,
532 "TrackerAlignmentErrorExtendedRcd":
None,
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(),
540 if not condition.hasParameter(
"connect")
541 else condition.connect.value())
544 inputs_from_gt = [record
for record
in inputs
if inputs[record]
is None]
546 mps_tools.get_tags(self._cms_process.GlobalTag.globaltag.value(),
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",
555 for inp
in inputs: inputs[inp][
"problematic"] =
True 557 print "Value of 'FirstRunForStartGeometry' has to match first",
558 print "defined output IOV:",
562 for inp
in six.itervalues(inputs):
563 inp[
"iovs"] = mps_tools.get_iovs(inp[
"connect"], inp[
"tag"])
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):
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." 580 input_iov = inputs[inp][
"iovs"][input_indices[inp]]
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." 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",
601 print "Please check your run range selection." 603 elif iov == input_iov:
604 input_indices[inp] -= 1
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]]
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." 622 elif iov == input_iov:
623 input_indices[inp] -= 1
625 print " -> IOV consistency check successful." 628 return problematic_gt_inputs
632 """Method to create hidden 'TrackerTree.root'.""" 635 print "Trying to create the tracker tree before setting the global",
636 print "tag or the run to determine the geometry IOV." 639 config = mpsv_iniparser.ConfigData()
640 config.jobDataPath =
"." 647 """Fetch general options from config file.""" 649 for var
in (
"classInf",
"pedeMem",
"jobname",
"FirstRunForStartGeometry"):
652 except ConfigParser.NoOptionError:
653 print "No", var,
"found in [general] section.",
654 print "Please check ini-file." 660 """Fetch default general options from config file.""" 662 for var
in (
"globaltag",
"configTemplate",
"json",
"massStorageDir",
666 except ConfigParser.NoOptionError:
667 if var ==
"testMode":
continue 668 print "No '" + var +
"' given in [general] section." 671 dataset[
"general"] = {}
672 for var
in (
"globaltag",
"configTemplate",
"json"):
674 dataset[
"general"][var] = dataset[
"config"].
get(
"general", var)
675 except (ConfigParser.NoSectionError,ConfigParser.NoOptionError):
681 Fetch 'datasetDir' variable from general section and add it to the 682 'os.environ' dictionary. 685 if self._config.has_option(
"general",
"datasetdir"):
686 dataset_directory = self._config.get(
"general",
"datasetdir")
688 os.environ[
"datasetdir"] = dataset_directory
691 print "No datasetdir given in [general] section.",
692 print "Be sure to give a full path in inputFileList." 697 """Fetch internal and external dataset configurations.""" 699 all_configs = collections.OrderedDict()
700 all_configs[
"main"] = {
"config": self.
_config,
705 for config
in six.itervalues(all_configs):
706 global_weight =
"1" if config[
"weight"]
is None else config[
"weight"]
709 self._config.config_path]
713 global_weight = (global_weight,)
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:"):
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):
740 if config[
"config"].has_option(section,
"weight"):
742 = [x.strip()
for x
in 743 config[
"config"].
get(section,
"weight").
split(
",")]
748 for global_w
in global_weight]
752 for var
in (
"inputFileList",
"collection"):
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." 761 for var
in (
"configTemplate",
"globaltag"):
763 self.
_datasets[name][var] = config[
"config"].
get(section, var)
764 except (ConfigParser.NoSectionError,ConfigParser.NoOptionError):
766 self.
_datasets[name][var] = config[
"general"][var]
770 = all_configs[
"main"][
"general"][var]
772 print "No",var,
"found in ["+section+
"]",
773 print "and no default in [general] section." 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")
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")
787 self.
_datasets[name][
"primaryWidth"] = -1.0
788 if config[
"config"].has_option(section,
"primaryWidth"):
790 = config[
"config"].getfloat(section,
"primaryWidth")
792 self.
_datasets[name][
"numberOfEvents"] = -1
793 if config[
"config"].has_option(section,
"numberOfEvents"):
795 = config[
"config"].getint(section,
"numberOfEvents")
799 self.
_datasets[name][
"json"] = config[
"config"].
get(section,
"json")
800 except ConfigParser.NoOptionError:
802 self.
_datasets[name][
"json"] = config[
"general"][
"json"]
806 = all_configs[
"main"][
"general"][
"json"]
808 print "No json given in either [general] or",
809 print "["+section+
"] sections." 810 print " -> Proceeding without json-file." 814 for var
in (
"inputFileList",
"json",
"configTemplate"):
816 = os.path.expandvars(self.
_datasets[name][var])
822 with open(self.
_datasets[name][
"inputFileList"],
"r") as filelist: 823 for line
in filelist:
824 if "CastorPool" in line:
827 if not line.strip()==
"":
830 print "Inputfilelist", self.
_datasets[name][
"inputFileList"],
831 print "does not exist." 834 print "Number of jobs is 0. There may be a problem with the inputfilelist:" 835 print self.
_datasets[name][
"inputFileList"]
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")
843 print "'njobs' is bigger than the number of files for this",
844 print "dataset:", self.
_datasets[name][
"njobs"]
845 print "Using default." 847 print "No number of jobs specified. Using number of files in",
848 print "inputfilelist as the number of jobs." 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
857 weight_name+config[
"config"].config_path)
863 os.environ[
"datasetdir"] = cache_datasetdir
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." 875 if __name__ ==
"__main__":
878 except KeyboardInterrupt:
def _check_iov_definition(self)
def _create_mass_storage_directory(self)
def _create_input_db(self)
def _fetch_essentials(self)
bool any(const std::vector< T > &v, const T &what)
def _fetch_external_datasets(self)
def _fetch_pede_settings(self)
static void pop(std::vector< T > &vec, unsigned int index)
def _fetch_dataset_directory(self)
def _create_weight_configs(self)
def _fetch_defaults(self)
def _handle_process_call(self, command, verbose=False)
def _create_additional_pede_jobs(self)
def _create_mille_jobs(self)
static std::string join(char **cmd)
def _fill_general_options(self)
def _construct_paths(self)
def _create_tracker_tree(self)
def _fetch_datasets(self)
def _create_pede_jobs(self)
T get(const Candidate &c)