3 from __future__
import print_function
13 import Alignment.MillePedeAlignmentAlgorithm.mpslib.tools
as mps_tools
14 import Alignment.MillePedeAlignmentAlgorithm.mpslib.Mpslibclass
as mpslib
15 import Alignment.MillePedeAlignmentAlgorithm.mpsvalidate.iniparser
as mpsv_iniparser
16 import Alignment.MillePedeAlignmentAlgorithm.mpsvalidate.trackerTree
as mpsv_trackerTree
17 from Alignment.MillePedeAlignmentAlgorithm.alignmentsetup.helper
import checked_out_MPS
18 from functools
import reduce
24 """Main routine. Not called, if this module is loaded via `import`. 27 - `argv`: Command line arguments passed to the script. 34 setup_alignment.setup()
39 """Class encapsulating the alignment campaign setup procedure.""" 45 - `argv`: command line arguments 76 """Setup the alignment campaign.""" 84 if self._override_gt.strip() !=
"":
85 msg = (
"Overriding global tag with single-IOV tags extracted from " 95 """Create ConfigParser object from command line arguments.""" 97 helpEpilog =
"""Builds the config-templates from a universal 98 config-template for each dataset specified in .ini-file that is passed 99 to this script. Then calls mps_setup.py for all datasets.""" 100 parser = argparse.ArgumentParser(
101 description = (
"Setup the alignment as configured in the " 102 "alignment_config file."),
104 parser.add_argument(
"-v",
"--verbose", action=
"store_true",
105 help=
"display detailed output of mps_setup")
106 parser.add_argument(
"-w",
"--weight", action=
"store_true",
107 help=(
"creates additional merge job(s) with " 108 "(possibly new) weights from .ini-config"))
109 parser.add_argument(
"alignmentConfig",
110 help=(
"name of the .ini config file that specifies " 111 "the datasets to be used"))
114 self.
_config = ConfigParser.ConfigParser()
115 self._config.optionxform = str
117 self._config.read(self._args.alignmentConfig)
118 self._config.config_path = self._args.alignmentConfig
122 """Determine directory paths and create the ones that are needed.""" 124 mpsTemplates = os.path.join(
"src",
"Alignment",
125 "MillePedeAlignmentAlgorithm",
"templates")
127 mpsTemplates = os.path.join(os.environ[
"CMSSW_BASE"], mpsTemplates)
129 mpsTemplates = os.path.join(os.environ[
"CMSSW_RELEASE_BASE"], mpsTemplates)
130 self.
_mille_script = os.path.join(mpsTemplates,
"mps_runMille_template.sh")
131 self.
_pede_script = os.path.join(mpsTemplates,
"mps_runPede_rfcp_template.sh")
134 currentDir = os.getcwd()
135 match = re.search(re.compile(
'mpproduction\/mp(.+?)$', re.M|re.I),currentDir)
139 print(
"Current location does not seem to be a MillePede campaign directory:", end=
' ')
145 """Create and fill `general_options` dictionary.""" 155 """Fetch information about external datasets.""" 157 if self._config.has_option(
"general",
"externalDatasets"):
158 datasets =
map(
lambda x: x.strip(),
159 self._config.get(
"general",
160 "externalDatasets").
split(
","))
161 datasets = [x
for x
in datasets
if len(x.strip()) > 0]
162 for item
in datasets:
163 splitted = item.split(
"|")
164 dataset = splitted[0].
strip()
165 dataset = os.path.expandvars(dataset)
167 weight = splitted[1]
if len(splitted) > 1
else None 168 config = ConfigParser.ConfigParser()
169 config.optionxform = str
171 config.config_path = dataset
179 Create MPS mass storage directory where, e.g., mille binaries are 184 self.
_mss_dir = self._general_options.get(
"massStorageDir",
185 "/eos/cms/store/group/alca_millepede/")
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", end=
' ')
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:
366 "s" if len(self._pede_settings)*len(self.
_weight_configs) > 1
else ""))
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])
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.", end=
' ')
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.", end=
' ')
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", end=
' ')
552 print(
"'FirstRunForStartGeometry' is not 1.")
553 print(
"Creating single IOV output from input conditions in run", end=
' ')
555 for inp
in inputs: inputs[inp][
"problematic"] =
True 557 print(
"Value of 'FirstRunForStartGeometry' has to match first", end=
' ')
558 print(
"defined output IOV:", end=
' ')
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, end=
' ')
576 print(
"is before the first input IOV boundary at", end=
' ')
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, end=
' ')
586 print(
"for '"+inp+
"' is within output IOV starting", end=
' ')
588 print(
"Deriving an alignment with coarse IOV", end=
' ')
589 print(
"granularity starting from finer granularity", end=
' ')
590 print(
"leads to wrong results.")
591 print(
"A single IOV input using the IOV of", end=
' ')
593 print(
"is automatically created and used.")
595 print(
"Found input IOV boundary at run",input_iov, end=
' ')
596 print(
"for '"+inp+
"' which is within output IOV starting", end=
' ')
598 print(
"Deriving an alignment with coarse IOV granularity", end=
' ')
599 print(
"starting from finer granularity leads to wrong", end=
' ')
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, end=
' ')
616 print(
"for '"+inp+
"' which is within 'TrackerAlignmentRcd'", end=
' ')
617 print(
"IOV starting with run",
str(iov)+
".")
618 print(
"Deriving an alignment with inconsistent IOV boundaries", end=
' ')
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", end=
' ')
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.", end=
' ')
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.", end=
' ')
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))
734 for k,v
in config[
"config"].
items(section):
735 print(
" ", k,
"=", v)
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+
"]", end=
' ')
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", end=
' ')
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"], end=
' ')
831 print(
"does not exist.")
834 print(
"Number of jobs is 0. There may be a problem with the 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", end=
' ')
845 print(
"Using default.")
847 print(
"No number of jobs specified. Using number of files in", end=
' ')
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)
def _fetch_dataset_directory(self)
S & print(S &os, JobReport::InputFile const &f)
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)