Coverage for pesummary/cli/summarypipe.py: 84.5%
426 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-12-09 22:34 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2024-12-09 22:34 +0000
1#! /usr/bin/env python
3# Licensed under an MIT style license -- see LICENSE.md
5from pesummary.core.cli.parser import ArgumentParser as _ArgumentParser
6from pesummary.utils.utils import logger, list_match
7from pesummary.utils.decorators import open_config
8import shutil
9import os
10import numpy as np
11import sys
12import re
13import ast
14import glob
15from pathlib import Path
17__author__ = ["Charlie Hoy <charlie.hoy@ligo.org>"]
18__doc__ = """This executable is used to generate a summarypages executable
19given a rundir"""
22class ArgumentParser(_ArgumentParser):
23 def _pesummary_options(self):
24 options = super(ArgumentParser, self)._pesummary_options()
25 options.update(
26 {
27 "--rundir": {
28 "--short": "-r",
29 "help": "run directory of the parameter estimation job",
30 "required": True,
31 },
32 "--config": {
33 "help": (
34 "config file to extract information from. This can "
35 "either be an absolute path to a config file, or a "
36 "pattern to search for in run directory. If not "
37 "provided, search run directory for a config file to "
38 "use."
39 ),
40 },
41 "--samples": {
42 "help": "path to posterior samples file you wish to use"
43 },
44 "--pattern": {
45 "help": "pattern to use when searching for files",
46 },
47 "--return_string": {
48 "action": "store_true",
49 "default": False,
50 "help": "Return command line as a string for testing"
51 },
52 "additional options": {
53 "nargs": "?",
54 "type": str,
55 "help": (
56 "all additional command line options are added to the "
57 "printed summarypages executable"
58 )
59 },
60 }
61 )
62 return options
65def _check_rundir(rundir, std_dirs):
66 """Check that a list of directories are stored in a given rundir
68 Parameters
69 ----------
70 rundir: str
71 base directory to start searching
72 std_dirs: list
73 list of dirs which you expect to find in rundir or a subdir of rundir
74 """
75 directories = [i[0] for i in os.walk(os.path.join(rundir, ""))]
76 if all(any(std in dd for dd in directories) for std in std_dirs):
77 return True
78 return False
81def is_lalinference_rundir(rundir):
82 """Function to check if the rundir was made by LALInference
84 Parameters
85 ----------
86 rundir: str
87 the run directory of the parameter estimation job
88 """
89 std_dirs = ["ROQdata", "engine", "posterior_samples", "caches", "log"]
90 return _check_rundir(rundir, std_dirs)
93def is_bilby_rundir(rundir):
94 """Function to check if the rundir was made by Bilby
96 Parameters
97 ----------
98 rundir: str
99 the run directory of the parameter estimation job
100 """
101 std_dirs = ["data", "result", "submit", "log_data_analysis"]
102 return _check_rundir(rundir, std_dirs)
105class Base(object):
106 """
107 """
108 __arguments__ = {
109 "samples": "samples", "config": "config", "webdir": "webdir",
110 "approximant": "approximant", "labels": "label", "{}_psd": "psd",
111 "{}_calibration": "calibration", "gwdata": "gwdata",
112 "prior_file": "prior_file", "add_existing_plot": "add_existing_plot"
113 }
115 def __init__(
116 self, rundir, webdir=None, label=None, samples=None, config=None, other="",
117 pattern=None
118 ):
119 if pattern is not None:
120 self.pattern = {
121 "posterior_file": "{}*{}".format(pattern, self.posterior_extension),
122 "config_file": "{}*.ini".format(pattern),
123 "prior_file": "{}.prior".format(pattern)
124 }
125 if "ignore_posterior_file" not in self.pattern.keys():
126 self.pattern["ignore_posterior_file"] = None
127 self.rundir = os.path.abspath(rundir)
128 self.parent_dir = Path(self.rundir).parent
129 self.samples = samples
130 self.config = config
131 self.webdir = webdir
132 self.label = label
133 self.other = other
134 self.gracedb = None
135 self.approximant = None
136 self.prior_file = None
137 self.add_existing_plot = None
138 self.psd = None
139 self.calibration = None
140 self.gwdata = None
141 self.command_line_arguments = {
142 arg.format(self.label): getattr(self, attribute, None)
143 for arg, attribute in self.__arguments__.items()
144 }
145 self.command = self.make_command(
146 self.command_line_arguments, other=self.other
147 )
148 self.print(self.command)
150 @property
151 def rundir(self):
152 return self._rundir
154 @rundir.setter
155 def rundir(self, rundir):
156 self._rundir = rundir
157 if not os.path.isdir(rundir):
158 raise ValueError(
159 "'{}' is not a valid directory.".format(rundir)
160 )
162 @property
163 def config(self):
164 return self._config
166 @config.setter
167 def config(self, config):
168 if config is not None and os.path.isfile(config):
169 logger.info("Using specified config file: '{}'".format(config))
170 self._config = config
171 return
172 else:
173 if config is not None:
174 CUSTOM = True
175 pattern = config
176 else:
177 CUSTOM = False
178 pattern = self.pattern["config_file"]
179 files, _dir = self.find_config_file(pattern)
180 if CUSTOM and not len(files):
181 raise FileNotFoundError(
182 "The supplied config file: '{}' does not exist".format(config)
183 )
184 self._config = self.check_files(
185 files, "configuration file", pattern, _dir, allow_multiple=False,
186 multiple_warn=(
187 "If you wish to use a specific config file, please add the "
188 "'--config' flag and the path to the config file you wish to "
189 "use."
190 )
191 )
193 @property
194 def webdir(self):
195 return self._webdir
197 @webdir.setter
198 def webdir(self, webdir):
199 if webdir is None:
200 self._webdir = self.webdir_fallback()
201 else:
202 logger.info("Using the supplied webdir: {}".format(webdir))
203 self._webdir = webdir
205 @property
206 def samples(self):
207 return self._samples
209 @samples.setter
210 def samples(self, samples):
211 if samples is not None and os.path.isfile(samples):
212 logger.info("Using specified posterior file: '{}'".format(samples))
213 self._samples = samples
214 return
215 elif samples is not None:
216 raise ValueError("Unable to find posterior file: {}".format(samples))
217 files = self.glob(
218 self.rundir, self.pattern["posterior_file"],
219 ignore=self.pattern["ignore_posterior_file"]
220 )
221 files = self.preferred_samples_from_options(files)
222 self._samples = self.check_files(
223 files, "result file", self.pattern["posterior_file"], self.rundir,
224 allow_multiple=False, multiple_warn=(
225 "If you wish to use a specific samples file, please add the "
226 "'--samples' flag and the path to the samples file you wish to "
227 "use."
228 )
229 )
231 @property
232 def label(self):
233 return self._label
235 @label.setter
236 def label(self, label):
237 if label is None:
238 try:
239 self._label = self.label_fallback()
240 except AttributeError:
241 logger.info("No label provided. Using default")
242 self._label = self.default_label
243 else:
244 logger.info("Using the provided label: '{}'".format(label))
245 self._label = label
247 @property
248 def gracedb(self):
249 return self._gracedb
251 @gracedb.setter
252 def gracedb(self, gracedb):
253 self._gracedb = self.gracedb_fallback()
255 @property
256 def approximant(self):
257 return self._approximant
259 @approximant.setter
260 def approximant(self, approximant):
261 self._approximant = self.approximant_fallback()
263 @property
264 def prior_file(self):
265 return self._prior_file
267 @prior_file.setter
268 def prior_file(self, prior_file):
269 self._prior_file = self.prior_file_fallback()
271 @property
272 def add_existing_plot(self):
273 return self._add_existing_plot
275 @add_existing_plot.setter
276 def add_existing_plot(self, add_existing_plot):
277 self._add_existing_plot = self.add_existing_plot_fallback()
279 @property
280 def psd(self):
281 return self._psd
283 @psd.setter
284 def psd(self, psd):
285 self._psd = self.psd_fallback()
287 @property
288 def calibration(self):
289 return self._calibration
291 @calibration.setter
292 def calibration(self, calibration):
293 self._calibration = self.calibration_fallback()
295 @property
296 def gwdata(self):
297 return self._gwdata
299 @gwdata.setter
300 def gwdata(self, gwdata):
301 self._gwdata = self.gwdata_fallback()
303 @staticmethod
304 def glob(directory, name, ignore=None):
305 """Recursively search a directory for a given file
307 Parameters
308 ----------
309 directory: str
310 directory to search in
311 name: str
312 file you wish to search for. This can include wildcards
313 ignore: list, optional
314 list of patterns to ignore
315 """
316 files = glob.glob(os.path.join(directory, "**", name), recursive=True)
317 if ignore is not None:
318 files = list_match(files, ignore, return_false=True, return_true=False)
319 return files
321 @staticmethod
322 def check_files(
323 files, description, filename, rundir, allow_failure=False,
324 allow_multiple=True, multiple_warn=None,
325 ):
326 """Check a list of files found with `glob`
328 Parameters
329 ----------
330 files: list
331 list of files to check
332 description: str
333 description for the type of file you are searching for. This could
334 be 'configuration file' for example
335 filename: str
336 pattern that was used to find the list of files with glob
337 rundir: str
338 run directory which was searched
339 allow_failure: Bool, optional
340 if True, bypass FileNotFoundError if the file does not exist
341 allow_multiple: Bool, optional
342 if True, do not raise a ValueError when multiple files are found
343 which match a given pattern
344 multiple_warn: str, optional
345 warning message to print if multiple files are found
346 """
347 if len(files) == 0:
348 if not allow_failure:
349 raise FileNotFoundError(
350 "No file called '{}' found in {}.".format(filename, rundir)
351 )
352 return None
353 elif len(files) == 1:
354 logger.info(
355 "Found the following {}: {}".format(description, files[0])
356 )
357 return files[0]
358 else:
359 if allow_multiple:
360 logger.info(
361 "Multiple {}s found: {}. Using {}".format(
362 description, ", ".join(files), files[0]
363 )
364 )
365 if multiple_warn is not None:
366 logger.warning(multiple_warn)
367 return files[0]
368 raise ValueError(
369 "Multiple {}s found in {}: {}. Please either specify one from the command "
370 "line or add a pattern unique to that file name via the '--pattern' "
371 "command line argument".format(
372 description, ", ".join(files), rundir
373 )
374 )
376 @staticmethod
377 def find_executable(executable):
378 """Return the path to a given executable
380 Parameters
381 ----------
382 executable: str
383 name of executable you wish to get the path for
384 """
385 return shutil.which(executable)
387 @staticmethod
388 def make_command(dictionary, other=""):
389 """Make the command line
391 Parameters
392 ----------
393 dictionary: dict
394 dictionary of commands and arguments
395 """
396 executable = Base.find_executable("summarypages")
397 command = "summarypages "
398 for key, val in dictionary.items():
399 cla = "--{}".format(key)
400 if cla in other:
401 ind = other.index(cla)
402 logger.warning(
403 "Ignoring {}={} extracted from config file and using input "
404 "from command line {}={}".format(
405 key, val, other[ind].replace("-", ""), other[ind + 1]
406 )
407 )
408 elif val is True:
409 command += "{} ".format(cla)
410 elif val is None:
411 continue
412 elif not len(val):
413 continue
414 else:
415 command += "{} {} ".format(cla, val)
416 if len(other):
417 command += " ".join(other)
418 command += " "
419 if "--gw" not in command:
420 command += "--gw "
421 return command
423 @staticmethod
424 def print(command):
425 """Print the command line to std.out
427 Parameters
428 ----------
429 command: str
430 command you wish to print
431 """
432 logger.info("To run PESummary, run the following command line:")
433 print("\n\t$ {}\n".format(command))
435 @staticmethod
436 @open_config(index=0)
437 def load_config(path_to_config):
438 """Load a configuration file with configparser
440 Parameters
441 ----------
442 path_to_config: str
443 path to the configuration file you wish to open
444 """
445 return path_to_config
447 @property
448 def preferred_posterior_string(self):
449 return ""
451 def find_config_file(self, pattern):
452 """Find a configuration file given a pattern
454 Parameters
455 ----------
456 pattern: str
457 pattern to find a specific config file
458 """
459 return self.glob(self.rundir, pattern), self.rundir
461 def preferred_samples_from_options(self, files):
462 """Return the preferred posterior samples file from a list of
463 options
465 Parameters
466 ----------
467 files: list
468 list of available options
469 """
470 _files = list_match(files, self.preferred_posterior_string)
471 if len(_files):
472 return _files
473 return files
475 def webdir_fallback(self):
476 return "webpage"
478 def gracedb_fallback(self):
479 return
481 def approximant_fallback(self):
482 return
484 def prior_file_fallback(self):
485 return
487 def add_existing_plot_fallback(self):
488 return
490 def psd_fallback(self):
491 return
493 def calibration_fallback(self):
494 return
496 def gwdata_fallback(self):
497 return
499 def _webdir_fallback(self, webdir):
500 """Print the webdir extracted from the config file
502 Parameters
503 ----------
504 webdir: str
505 webdir extracted from the config file
506 """
507 logger.info(
508 "Using the webdir '{}' extracted from the config file: {}".format(
509 webdir, self.config
510 )
511 )
512 return webdir
514 def _label_fallback(self, label):
515 """Print the label extracted from the config file
517 Parameters
518 ----------
519 label: str
520 label extracted from the config file
521 """
522 logger.info(
523 "Found the following label in '{}': '{}'".format(self.config, label)
524 )
525 return label
527 def _prior_file_fallback(self, prior_file):
528 """Print the prior file found in the run directory
530 Parameters
531 ----------
532 prior_file: str
533 path to prior file found in the run directory
534 """
535 logger.info(
536 "Found the following prior file': '{}'".format(prior_file)
537 )
538 return prior_file
540 def _gracedb_fallback(self, gid):
541 """Print the gracedb ID extracted from the config file
543 Parameters
544 ----------
545 gid: str
546 gracedb ID extracted from the config file
547 """
548 if gid is not None:
549 logger.info(
550 "Found the following gracedb ID in '{}': '{}'".format(
551 self.config, gid
552 )
553 )
554 return gid
555 else:
556 logger.info(
557 "Unable to find a gracedb entry in '{}'".format(self.config)
558 )
559 return None
561 def _approximant_fallback(self, approx):
562 """Print the approximant extracted from the config file
564 Parameters
565 ----------
566 approx: str
567 approximant extracted from the config file
568 """
569 approx = approx.split("pseudo")[0].split("_ROQ")[0]
570 logger.info(
571 "Found the following approximant in '{}': '{}'".format(
572 self.config, approx
573 )
574 )
575 return approx
578class Bilby(Base):
579 """Generate a `summarypages` executable for a bilby_pipe run directory
580 """
581 def __init__(self, *args, **kwargs):
582 self.default_label = "Bilby"
583 self.posterior_extension = "_result.json"
584 self.pattern = {
585 "posterior_file": "*_result.json",
586 "ignore_posterior_file": ["*checkpoint*"],
587 "config_file": "*.ini",
588 "prior_file": "*.prior"
589 }
590 super(Bilby, self).__init__(*args, **kwargs)
592 @property
593 def preferred_posterior_string(self):
594 return "*merged_result.json"
596 def find_config_file(self, pattern):
597 """Find a configuration file given a pattern
599 Parameters
600 ----------
601 pattern: str
602 pattern to find a specific config file
603 """
604 files = self.glob(self.rundir, pattern, ignore="*_complete.ini")
605 if not len(files):
606 return self.glob(
607 self.parent_dir, pattern, ignore="*_complete.ini"
608 ), self.parent_dir
609 return files, self.rundir
611 def try_underscore_and_hyphen(self, config, option):
612 """Try to find a key in a dictionary. If KeyError is raised, replace
613 underscore with a hyphen and try again
615 Parameters
616 ----------
617 config: dict
618 dictionary you wish to search
619 option: str
620 key you wish to search for
621 """
622 original = "_" if "_" in option else "-"
623 alternative = "-" if original == "_" else "_"
624 try:
625 return config[option]
626 except KeyError:
627 return config[option.replace(original, alternative)]
629 def webdir_fallback(self):
630 """Grab the web directory from a Bilby configuration file
631 """
632 config = self.load_config(self.config)
633 outdir = config["config"]["outdir"]
634 if self.rundir in outdir:
635 path = os.path.join(outdir, "webpage")
636 else:
637 path = os.path.join(self.rundir, outdir, "webpage")
638 return self._webdir_fallback(path)
640 def label_fallback(self):
641 """Grab the label from a Bilby configuration file
642 """
643 config = self.load_config(self.config)
644 label = config["config"]["label"]
645 return self._label_fallback(label)
647 def gracedb_fallback(self):
648 """Grab the gracedb entry from a Bilby configuration file
649 """
650 config = self.load_config(self.config)
651 try:
652 gid = config["config"]["gracedb"]
653 return self._gracedb_fallback(gid)
654 except KeyError:
655 return self._gracedb_fallback(None)
657 def approximant_fallback(self):
658 """Grab the approximant used from a Bilby configuration file
659 """
660 config = self.load_config(self.config)
661 option = "waveform_approximant"
662 approx = self.try_underscore_and_hyphen(config["config"], option)
663 return self._approximant_fallback(approx)
665 def prior_file_fallback(self):
666 """Grab the prior file used from a Bilby run directory
667 """
668 prior_files = self.glob(self.rundir, self.pattern["prior_file"])
669 if not len(prior_files):
670 prior_files = self.glob(self.parent_dir, self.pattern["prior_file"])
671 return self.check_files(
672 prior_files, "prior_file", self.pattern["prior_file"], self.rundir,
673 allow_failure=True
674 )
676 def add_existing_plot_fallback(self):
677 """Grab the trace checkpoint plots generated from a Bilby run directory
678 """
679 existing_plots = self.glob(self.rundir, "*checkpoint*.png")
680 return " ".join(
681 ["{}:{}".format(self.label, _plot) for _plot in existing_plots]
682 )
684 def psd_fallback(self):
685 """Try and grab PSD data from a Bilby configuration file else
686 look in the rundir for any PSD files
687 """
688 config = self.load_config(self.config)
689 try:
690 return self.grab_psd_calibration_data_from_config(config, "psd_dict")
691 except KeyError:
692 logger.info(
693 "Unable to find any PSD information in '{}'. Looking in "
694 "run directory".format(self.config)
695 )
696 return self.grab_psd_calibration_data_from_directory("PSDs")
698 def calibration_fallback(self):
699 """Try and grab calibration data from a Bilby configuration file else
700 look in the rundir for any calibration files
701 """
702 config = self.load_config(self.config)
703 try:
704 return self.grab_psd_calibration_data_from_config(
705 config, "spline_calibration_envelope_dict"
706 )
707 except KeyError:
708 logger.info(
709 "Unable to find any calibration information in '{}'. Looking "
710 "in run directory".format(self.config)
711 )
712 return self.grab_psd_calibration_data_from_directory(
713 "cal_env", _type="calibration"
714 )
716 def grab_psd_calibration_data_from_config(self, config, pattern):
717 """Grab psd/calibration data from a Bilby configuration file
719 Parameters
720 ----------
721 config: configparser.ConfigParser
722 open configuration file
723 pattern: str
724 string to identify the data stored in the configuration file
725 """
726 from pesummary.core.cli.actions import ConfigAction
728 data_dict = self.try_underscore_and_hyphen(config["config"], pattern)
729 if data_dict is None or data_dict == "None":
730 return
731 try:
732 data_dict = ConfigAction.dict_from_str(data_dict, delimiter=":")
733 except IndexError:
734 data_dict = ConfigAction.dict_from_str(data_dict, delimiter="=")
735 if not len(data_dict):
736 raise KeyError
737 for key, value in data_dict.items():
738 if not os.path.isfile(value[0]):
739 config_dir = Path(self.config).parent
740 if os.path.isfile(os.path.join(config_dir, value[0])):
741 data_dict[key] = os.path.join(config_dir, value[0])
742 else:
743 logger.warning(
744 "Found file: '{}' in the config file, but it "
745 "does not exist. This is likely because the config "
746 "was run on a different cluster. Ignoring from final "
747 "command.".format(value[0])
748 )
749 raise KeyError
750 else:
751 data_dict[key] = value[0]
752 return " ".join(
753 ["{}:{}".format(key, val) for key, val in data_dict.items()]
754 )
756 def grab_psd_calibration_data_from_directory(self, pattern, _type="PSD"):
757 """Grab psd/calibration data from a given run directory
759 Parameters
760 ----------
761 pattern: str
762 pattern to find a specific set of files
763 """
764 from pesummary.gw.cli.inputs import _GWInput
766 files = self.glob(os.path.join(self.rundir, pattern), "*")
767 if not len(files):
768 files = self.glob(os.path.join(self.parent_dir, pattern), "*")
769 if not len(files):
770 logger.info(
771 "No {} files found in '{}'".format(_type, self.rundir)
772 )
773 return None
774 data_dict = {
775 _GWInput.get_ifo_from_file_name(ff): ff for ff in files
776 }
777 return " ".join(
778 ["{}:{}".format(key, val) for key, val in data_dict.items()]
779 )
782class LALInference(Base):
783 """Generate a `summarypages` executable for a lalinference run directory
784 """
785 def __init__(self, *args, **kwargs):
786 self.default_label = "LALInference"
787 self.posterior_extension = "hdf5"
788 self.pattern = {
789 "posterior_file": "posterior*.hdf5",
790 "config_file": "config.ini"
791 }
792 super(LALInference, self).__init__(*args, **kwargs)
794 def webdir_fallback(self):
795 """Grab the web directory from a LALInference configuration file
796 """
797 config = self.load_config(self.config)
798 path = config["paths"]["webdir"]
799 return self._webdir_fallback(path)
801 def gracedb_fallback(self):
802 """Grab the gracedb entry from a LALInference configuration file
803 """
804 config = self.load_config(self.config)
805 try:
806 gid = config["input"]["gid"]
807 return self._gracedb_fallback(gid)
808 except KeyError:
809 return self._gracedb_fallback(None)
811 def approximant_fallback(self):
812 """Grab the approximant used from a LALInference configuration file
813 """
814 config = self.load_config(self.config)
815 approx = config["engine"]["approx"]
816 return self._approximant_fallback(approx)
818 def psd_fallback(self):
819 """Try and grab data from a LALInference configuration file else
820 look in the rundir for any PSD files
821 """
822 config = self.load_config(self.config)
823 try:
824 return self.grab_psd_calibration_data_from_config(config, "-psd")
825 except KeyError:
826 logger.info(
827 "Unable to find any PSD information in '{}'. Looking in "
828 "run directory".format(self.config)
829 )
830 files = self.glob(self.rundir, "*-PSD.dat")
831 if len(files) == 0:
832 logger.info(
833 "No PSD files found in '{}'".format(self.rundir)
834 )
835 return None
836 ifos = {re.split("([A-Z][0-9]+)-PSD.dat", i)[-2] for i in files}
837 return " ".join(
838 [
839 [
840 "{}:{}".format(ifo, i) for i in files if
841 "{}-PSD.dat".format(ifo) in i
842 ][0] for ifo in ifos
843 ]
844 )
846 def calibration_fallback(self):
847 """Grab calibration data from a LALInference configuration file
848 """
849 config = self.load_config(self.config)
850 try:
851 return self.grab_psd_calibration_data_from_config(
852 config, "-spcal-envelope"
853 )
854 except KeyError:
855 logger.info(
856 "Unable to find any calibration information in '{}'".format(
857 self.config
858 )
859 )
860 return None
862 def gwdata_fallback(self):
863 """Grab the GW cache files from a LALInference run directory
864 """
865 try:
866 cache_files = self.glob(self.rundir, "*.lcf")
867 logger.info(
868 "Found the following cache files in {}: {}".format(
869 self.rundir, ", ".join(cache_files)
870 )
871 )
872 ifos = {re.split("([A-Z]-[A-Z][0-9]+)", i)[-2] for i in cache_files}
873 ifos = [ifo.split("-")[-1] for ifo in ifos]
874 config = self.load_config(self.config)
875 channels = ast.literal_eval(config["data"]["channels"])
876 return " ".join(
877 [
878 "{}:{}".format(channels[ifo], path) for ifo, path
879 in zip(ifos, cache_files)
880 ]
881 )
882 except ValueError:
883 return None
885 def grab_psd_calibration_data_from_config(self, config, pattern):
886 """Grab psd/calibration data from a LALInference configuration file
888 Parameters
889 ----------
890 config: configparser.ConfigParser
891 open configuration file
892 pattern: str
893 string to identify the data stored in the configuration file
894 """
895 ifos = [i for i in list(config["engine"].keys()) if pattern in i]
896 data = {
897 ifo.split(pattern)[0].upper(): config["engine"][ifo] for ifo in
898 ifos if len(ifos)
899 }
900 if not len(ifos):
901 raise KeyError
902 return " ".join(
903 ["{}:{}".format(key, val) for key, val in data.items()]
904 )
907def main(args=None):
908 """Top level interface for `summarypipe`
909 """
910 parser = ArgumentParser(description=__doc__)
911 parser.add_known_options_to_parser(
912 [
913 "--rundir", "--webdir", "--labels", "--config", "--samples",
914 "--pattern", "--return_string", "additional options"
915 ]
916 )
917 opts, unknown = parser.parse_known_args(args=args)
918 if args is None:
919 all_options = sys.argv[1:]
920 else:
921 all_options = args
922 idxs = [all_options.index(_) for _ in unknown if "--" in _]
923 unknown = np.array([
924 [all_options[i], all_options[i + 1]] if i + 1 < len(all_options)
925 and "--" not in all_options[i + 1] else [all_options[i], ""] for i in
926 idxs
927 ]).flatten()
928 label = opts.labels[0] if opts.labels is not None else None
929 if is_lalinference_rundir(opts.rundir):
930 cl = LALInference(
931 opts.rundir, webdir=opts.webdir, label=label, samples=opts.samples,
932 config=opts.config, other=unknown, pattern=opts.pattern
933 )
934 elif is_bilby_rundir(opts.rundir):
935 cl = Bilby(
936 opts.rundir, webdir=opts.webdir, label=label, samples=opts.samples,
937 config=opts.config, other=unknown, pattern=opts.pattern
938 )
939 else:
940 raise NotImplementedError(
941 "'{}' not understood. Currently 'summarypipe' only works with a "
942 "LALInference or Bilby rundir.".format(opts.rundir)
943 )
944 if opts.return_string:
945 return cl.command