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
22 """Main routine. Not called, if this module is loaded via `import`. 25 - `argv`: Command line arguments passed to the script. 32 setup_alignment.setup()
37 """Class encapsulating the alignment campaign setup procedure.""" 43 - `argv`: command line arguments 74 """Setup the alignment campaign.""" 82 if self._override_gt.strip() !=
"":
83 msg = (
"Overriding global tag with single-IOV tags extracted from " 93 """Create ConfigParser object from command line arguments.""" 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.""" 99 description = (
"Setup the alignment as configured in the " 100 "alignment_config file."),
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"))
112 self.
_config = ConfigParser.ConfigParser()
113 self._config.optionxform = str
115 self._config.read(self._args.alignmentConfig)
116 self._config.config_path = self._args.alignmentConfig
120 """Determine directory paths and create the ones that are needed.""" 122 mpsTemplates = os.path.join(
"src",
"Alignment",
123 "MillePedeAlignmentAlgorithm",
"templates")
125 mpsTemplates = os.path.join(os.environ[
"CMSSW_BASE"], mpsTemplates)
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")
132 currentDir = os.getcwd()
133 match = re.search(re.compile(
'mpproduction\/mp(.+?)$', re.M|re.I),currentDir)
137 print "Current location does not seem to be a MillePede campaign directory:",
143 """Create and fill `general_options` dictionary.""" 153 """Fetch information about external datasets.""" 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)
165 weight = splitted[1]
if len(splitted) > 1
else None 166 config = ConfigParser.ConfigParser()
167 config.optionxform = str
169 config.config_path = dataset
177 Create MPS mass storage directory where, e.g., mille binaries are 182 self.
_mss_dir = self._general_options.get(
"massStorageDir",
183 "/eos/cms/store/caf/user/" 188 cmd = [
"mkdir",
"-p", self.
_mss_dir]
191 if not self._general_options.get(
"testMode",
False):
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 201 """Extract different weight configurations from `self._config`.""" 203 weights_list = [[(name, weight)
for weight
in self.
_weight_dict[name]]
206 common_weights_list = [[(name, weight)
210 common_weights_dicts = []
211 for item
in itertools.product(*common_weights_list):
213 for name,weight
in item:
215 common_weights_dicts.append(d)
218 for weight_conf
in itertools.product(*weights_list):
219 number_of_configs = len(weight_configs)
220 for common_weight
in common_weights_dicts:
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)
230 if len(weight_configs) == number_of_configs:
231 weight_configs.append(weight_conf)
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)
241 """Fetch 'pedesettings' from general section in `self._config`.""" 243 self._pede_settings \
245 for x
in self._config.get(
"general",
"pedesettings").
split(
",")]
246 if self._config.has_option(
"general",
"pedesettings")
else [
None])
250 """Create the mille jobs based on the [dataset:<name>] sections.""" 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)
261 for name, dataset
in self._datasets.iteritems():
265 with open(dataset[
"configTemplate"],
"r") as f: 268 print "The config-template called",
269 print dataset[
"configTemplate"],
"cannot be found." 272 tmpFile = re.sub(gt_regex,
273 'setupGlobaltag = \"'+dataset[
"globaltag"]+
'\"',
275 tmpFile = re.sub(sg_regex,
276 "setupRunStartGeometry = "+
278 tmpFile = re.sub(collection_regex,
279 'setupCollection = \"'+dataset[
"collection"]+
'\"',
281 if dataset[
'cosmicsZeroTesla']:
282 tmpFile = re.sub(czt_regex,
283 'setupCosmicsZeroTesla = True',
285 if dataset[
'cosmicsDecoMode']:
286 tmpFile = re.sub(cdm_regex,
287 'setupCosmicsDecoMode = True',
289 if dataset[
'primaryWidth'] > 0.0:
290 tmpFile = re.sub(pw_regex,
291 'setupPrimaryWidth = '+
str(dataset[
"primaryWidth"]),
293 if dataset[
'json'] !=
'':
294 tmpFile = re.sub(json_regex,
295 'setupJson = \"'+dataset[
"json"]+
'\"',
298 thisCfgTemplate =
"tmp.py" 299 with open(thisCfgTemplate,
"w")
as f:
307 first_dataset =
False 309 self.
_cms_process = mps_tools.get_process_object(thisCfgTemplate)
312 with open(thisCfgTemplate,
"a")
as f: f.write(self.
_override_gt)
316 command = [
"mps_setup.py",
323 dataset[
"inputFileList"],
324 str(dataset[
"njobs"]),
329 if dataset[
"numberOfEvents"] > 0:
330 command.extend([
"--max-events",
str(dataset[
"numberOfEvents"])])
331 command =
filter(
lambda x: len(x.strip()) > 0, command)
334 print "Creating jobs for dataset:", name
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)
358 """Create pede jobs from the given input.""" 360 for setting
in self._pede_settings:
364 print "Creating pede job{}.".
format(
368 print "Creating pede jobs using settings from '{0}'.".
format(setting)
373 thisCfgTemplate =
"tmp.py" 376 self.
_cms_process = mps_tools.get_process_object(thisCfgTemplate)
378 with open(thisCfgTemplate,
"a")
as f: f.write(self.
_override_gt)
380 for name,weight
in weight_conf:
388 lib = mpslib.jobdatabase()
392 jobm_path = os.path.join(
"jobData", lib.JOBDIR[-1])
395 command = [
"rm",
"-f", os.path.join(jobm_path,
"alignment_merge.py")]
401 "-w", thisCfgTemplate,
402 os.path.join(jobm_path,
"alignment_merge.py"),
406 if setting
is not None: command.extend([
"-a", setting])
408 print " ".
join(command)
413 os.path.abspath(os.path.join(jobm_path,
414 ".TrackerTree.root")))
418 with open(os.path.join(jobm_path,
".weights.pkl"),
"wb")
as f:
419 cPickle.dump(weight_conf, f, 2)
428 Create pede jobs in addition to already existing ones. Return GT 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." 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." 442 firstDataset =
next(self._datasets.itervalues())
443 config_template = firstDataset[
"configTemplate"]
444 collection = firstDataset[
"collection"]
447 with open(config_template,
"r") as f: 450 print "The config-template '"+config_template+
"' cannot be found." 453 tmpFile = re.sub(
'setupGlobaltag\s*\=\s*[\"\'](.*?)[\"\']',
456 tmpFile = re.sub(
'setupCollection\s*\=\s*[\"\'](.*?)[\"\']',
457 'setupCollection = \"'+collection+
'\"',
459 tmpFile = re.sub(re.compile(
"setupRunStartGeometry\s*\=\s*.*$", re.M),
471 Wrapper around subprocess calls which treats output depending on verbosity 475 - `command`: list of command items 476 - `verbose`: flag to turn on verbosity 479 call_method = subprocess.check_call
if verbose
else subprocess.check_output
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)
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 497 if not run_number > 0:
498 print "'FirstRunForStartGeometry' must be positive, but is", run_number
501 input_db_name = os.path.abspath(
"alignment_input.db")
503 run_number, input_db_name)
506 for record,tag
in tags.iteritems():
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")
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. 525 print "Checking consistency of IOV definition..." 526 iovs = mps_tools.make_unique_runranges(self._cms_process.AlignmentProducer)
529 "TrackerAlignmentRcd":
None,
530 "TrackerSurfaceDeformationRcd":
None,
531 "TrackerAlignmentErrorExtendedRcd":
None,
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(),
539 if not condition.hasParameter(
"connect")
540 else condition.connect.value())
543 inputs_from_gt = [record
for record
in inputs
if inputs[record]
is None]
545 mps_tools.get_tags(self._cms_process.GlobalTag.globaltag.value(),
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",
554 for inp
in inputs: inputs[inp][
"problematic"] =
True 556 print "Value of 'FirstRunForStartGeometry' has to match first",
557 print "defined output IOV:",
561 for inp
in inputs.itervalues():
562 inp[
"iovs"] = mps_tools.get_iovs(inp[
"connect"], inp[
"tag"])
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):
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." 579 input_iov = inputs[inp][
"iovs"][input_indices[inp]]
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." 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",
600 print "Please check your run range selection." 602 elif iov == input_iov:
603 input_indices[inp] -= 1
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]]
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." 621 elif iov == input_iov:
622 input_indices[inp] -= 1
624 print " -> IOV consistency check successful." 627 return problematic_gt_inputs
631 """Method to create hidden 'TrackerTree.root'.""" 634 print "Trying to create the tracker tree before setting the global",
635 print "tag or the run to determine the geometry IOV." 638 config = mpsv_iniparser.ConfigData()
639 config.jobDataPath =
"." 646 """Fetch general options from config file.""" 648 for var
in (
"classInf",
"pedeMem",
"jobname",
"FirstRunForStartGeometry"):
651 except ConfigParser.NoOptionError:
652 print "No", var,
"found in [general] section.",
653 print "Please check ini-file." 659 """Fetch default general options from config file.""" 661 for var
in (
"globaltag",
"configTemplate",
"json",
"massStorageDir",
665 except ConfigParser.NoOptionError:
666 if var ==
"testMode":
continue 667 print "No '" + var +
"' given in [general] section." 669 for dataset
in self._external_datasets.itervalues():
670 dataset[
"general"] = {}
671 for var
in (
"globaltag",
"configTemplate",
"json"):
673 dataset[
"general"][var] = dataset[
"config"].
get(
"general", var)
674 except (ConfigParser.NoSectionError,ConfigParser.NoOptionError):
680 Fetch 'datasetDir' variable from general section and add it to the 681 'os.environ' dictionary. 684 if self._config.has_option(
"general",
"datasetdir"):
685 dataset_directory = self._config.get(
"general",
"datasetdir")
687 os.environ[
"datasetdir"] = dataset_directory
690 print "No datasetdir given in [general] section.",
691 print "Be sure to give a full path in inputFileList." 696 """Fetch internal and external dataset configurations.""" 698 all_configs = collections.OrderedDict()
699 all_configs[
"main"] = {
"config": self.
_config,
704 for config
in all_configs.itervalues():
705 global_weight =
"1" if config[
"weight"]
is None else config[
"weight"]
708 self._config.config_path]
712 global_weight = (global_weight,)
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:"):
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):
739 if config[
"config"].has_option(section,
"weight"):
741 = [x.strip()
for x
in 742 config[
"config"].
get(section,
"weight").
split(
",")]
747 for global_w
in global_weight]
751 for var
in (
"inputFileList",
"collection"):
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." 760 for var
in (
"configTemplate",
"globaltag"):
762 self.
_datasets[name][var] = config[
"config"].
get(section, var)
763 except (ConfigParser.NoSectionError,ConfigParser.NoOptionError):
765 self.
_datasets[name][var] = config[
"general"][var]
769 = all_configs[
"main"][
"general"][var]
771 print "No",var,
"found in ["+section+
"]",
772 print "and no default in [general] section." 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")
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")
786 self.
_datasets[name][
"primaryWidth"] = -1.0
787 if config[
"config"].has_option(section,
"primaryWidth"):
789 = config[
"config"].getfloat(section,
"primaryWidth")
791 self.
_datasets[name][
"numberOfEvents"] = -1
792 if config[
"config"].has_option(section,
"numberOfEvents"):
794 = config[
"config"].getint(section,
"numberOfEvents")
798 self.
_datasets[name][
"json"] = config[
"config"].
get(section,
"json")
799 except ConfigParser.NoOptionError:
801 self.
_datasets[name][
"json"] = config[
"general"][
"json"]
805 = all_configs[
"main"][
"general"][
"json"]
807 print "No json given in either [general] or",
808 print "["+section+
"] sections." 809 print " -> Proceeding without json-file." 813 for var
in (
"inputFileList",
"json",
"configTemplate"):
815 = os.path.expandvars(self.
_datasets[name][var])
821 with open(self.
_datasets[name][
"inputFileList"],
"r") as filelist: 822 for line
in filelist:
823 if "CastorPool" in line:
826 if not line.strip()==
"":
829 print "Inputfilelist", self.
_datasets[name][
"inputFileList"],
830 print "does not exist." 833 print "Number of jobs is 0. There may be a problem with the inputfilelist:" 834 print self.
_datasets[name][
"inputFileList"]
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")
842 print "'njobs' is bigger than the number of files for this",
843 print "dataset:", self.
_datasets[name][
"njobs"]
844 print "Using default." 846 print "No number of jobs specified. Using number of files in",
847 print "inputfilelist as the number of jobs." 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
856 weight_name+config[
"config"].config_path)
862 os.environ[
"datasetdir"] = cache_datasetdir
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." 874 if __name__ ==
"__main__":
877 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)