Coverage for pesummary/gw/cli/parser.py: 97.1%
68 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# Licensed under an MIT style license -- see LICENSE.md
3from ...core.cli.parser import ArgumentParser as _ArgumentParser
4from ...core.cli.actions import DictionaryAction, DeprecatedStoreTrueAction
6__author__ = ["Charlie Hoy <charlie.hoy@ligo.org>"]
9class ArgumentParser(_ArgumentParser):
10 """Extension of the pesummary.core.cli.parser.ArgumentParser object to handle
11 gw specific command line arguments.
13 Properties
14 ----------
15 fallback_options: dict
16 dictionary of default kwargs
17 pesummary_options: dict
18 dictionary giving pesummary options
19 command_line: str
20 command line run
21 command_line_arguments: list
22 list giving command line arguments
23 dynamic_argparse: list
24 list of dynamic argparse functions that you wish to add to the
25 argparse.Namespace object
26 """
27 @property
28 def dynamic_argparse(self):
29 return [
30 add_dynamic_PSD_to_namespace,
31 add_dynamic_calibration_to_namespace
32 ]
34 @property
35 def gw_options(self):
36 parser = ArgumentParser()
37 parser.add_known_options_to_parser_from_key(parser, "gw")
38 parser.add_known_options_to_parser_from_key(parser, "remnant")
39 opts = [i.dest for i in vars(parser)["_actions"]]
40 defaults = [i.default for i in vars(parser)["_actions"]]
41 return opts, defaults
43 def _pesummary_options(self):
44 core_options = super(ArgumentParser, self)._pesummary_options()
45 options = core_options.copy()
46 gw_options = {
47 "--disable_remnant": {
48 "action": "store_true",
49 "default": False,
50 "help": (
51 "Prevent remnant quantities from being calculated when the "
52 "conversions module is used"
53 ),
54 "key": "remnant",
55 },
56 "--force_BBH_remnant_computation": {
57 "default": False,
58 "action": "store_true",
59 "help": (
60 "Use BBH fits to calculate remnant quantities for systems "
61 "that include tidal deformability parameters"
62 ),
63 "key": "remnant",
64 },
65 "--force_BH_spin_evolution": {
66 "default": False,
67 "action": "store_true",
68 "help": (
69 "Use BH spin evolution methods to evolve spins in systems "
70 "that include tidal deformability parameters"
71 ),
72 "key": "remnant",
73 },
74 "--evolve_spins": {
75 "dest": "evolve_spins_forwards",
76 "action": DeprecatedStoreTrueAction(
77 new_option="--evolve_spins_forwards"
78 ),
79 "help": (
80 "Evolve the spins up to the Schwarzschild ISCO frequency "
81 "for remnant fits evaluation"
82 ),
83 "default": False,
84 "key": "remnant",
85 },
86 "--evolve_spins_forwards": {
87 "action": "store_true",
88 "help": (
89 "Evolve the spins up to the Schwarzschild ISCO frequency "
90 "for remnant fits evaluation"
91 ),
92 "default": False,
93 "key": "remnant",
94 },
95 "--evolve_spins_backwards": {
96 "nargs": "?",
97 "dest": "evolve_spins_backwards",
98 "choices": ["precession_averaged", "hybrid_orbit_averaged"],
99 "default": False,
100 "help": (
101 "Method to use when evolving spins backwards to infinite "
102 "separation. Default 'precession_averaged'."
103 ),
104 "key": "remnant",
105 },
106 "--NRSur_fits": {
107 "nargs": "?",
108 "dest": "NRSur_fits",
109 "default": False,
110 "help": (
111 "The NRSurrogate you wish to use to calculate the remnant "
112 "quantities from your posterior samples. If not passed, "
113 "the average NR fits are used"
114 ),
115 "key": "remnant",
116 },
117 "--waveform_fits": {
118 "action": "store_true",
119 "default": False,
120 "help": (
121 "Use the provided approximant (either from command line or "
122 "stored in the result file) to calculate the remnant "
123 "quantities from your posterior samples. If not passed, "
124 "the average NR fits are used"
125 ),
126 "key": "remnant",
127 },
128 "--approximant": {
129 "dest": "approximant",
130 "help": "waveform approximant used to generate samples",
131 "nargs": "+",
132 "short": "-a",
133 "key": "gw",
134 },
135 "--approximant_flags": {
136 "dest": "approximant_flags",
137 "help": (
138 "flags used to control variant of waveform approximant used. Must "
139 "be in the form LABEL:FLAG:VALUE where LABEL is the analysis label "
140 "that you wish to assign FLAG:VALUE to"
141 ),
142 "nargs": "+",
143 "action": DictionaryAction,
144 "default": {},
145 "key": "gw",
146 },
147 "--sensitivity": {
148 "action": "store_true",
149 "default": False,
150 "help": "generate sky sensitivities for HL, HLV",
151 "key": "gw",
152 },
153 "--gracedb": {
154 "dest": "gracedb",
155 "help": "gracedb of the event",
156 "key": "gw",
157 },
158 "--gracedb_server": {
159 "dest": "gracedb_server",
160 "help": "service url to use when accessing gracedb",
161 "key": "gw",
162 },
163 "--gracedb_data": {
164 "dest": "gracedb_data",
165 "nargs": "+",
166 "default": ["t_0", "far", "created"],
167 "help": (
168 "data you wish to download from gracedb and store in the "
169 "metafile"
170 ),
171 "key": "gw",
172 },
173 "--psd": {
174 "dest": "psd",
175 "action": DictionaryAction,
176 "help": "psd files used",
177 "nargs": "+",
178 "default": {},
179 "key": "gw",
180 },
181 "--{}_psd": {
182 "dest": "example_psd",
183 "metavar": "IFO:PATH_to_PSD.dat",
184 "help": (
185 "psd files used for a specific label. '{}' should be "
186 "replaced with the label of interest. For example "
187 "--IMRPhenomPv3_psd H1:IF0_psd.dat"
188 ),
189 "key": "gw",
190 },
191 "--calibration_definition": {
192 "dest": "calibration_definition",
193 "help": "Definition for each calibration envelope",
194 "nargs": "+",
195 "default": ["data"],
196 "key": "gw",
197 },
198 "--calibration": {
199 "dest": "calibration",
200 "help": "files for the calibration envelope",
201 "nargs": "+",
202 "default": {},
203 "action": DictionaryAction,
204 "key": "gw",
205 },
206 "--{}_calibration": {
207 "dest": "example_calibration",
208 "metavar": "IFO:PATH_to_CAL.txt",
209 "help": (
210 "calibration files used for a specific label. '{}' should "
211 "be replaced with the label of interest. For example "
212 "--IMRPhenomPv3_calibration H1:IF0_cal.dat"
213 ),
214 "key": "gw",
215 },
216 "--trigfile": {
217 "dest": "inj_file",
218 "help": "xml file containing the trigger values",
219 "nargs": "+",
220 "key": "gw",
221 },
222 "--gwdata": {
223 "dest": "gwdata",
224 "help": "channels and paths to strain cache files",
225 "action": DictionaryAction,
226 "metavar": "CHANNEL:CACHEFILE or PICKLEFILE",
227 "nargs": "+",
228 "key": "gw",
229 },
230 "--multi_threading_for_skymap": {
231 "action": "store_true",
232 "default": False,
233 "help": (
234 "use multi-threading to speed up generation of ligo.skymap"
235 ),
236 "key": "gw"
237 },
238 "--nsamples_for_skymap": {
239 "dest": "nsamples_for_skymap",
240 "help": (
241 "The number of samples used to generate the ligo.skymap. "
242 "These samples will be randomly drawn from the posterior "
243 "distributions"
244 ),
245 "key": "gw",
246 },
247 "--calculate_multipole_snr": {
248 "action": "store_true",
249 "default": False,
250 "help": (
251 "Calculate the SNR in the (ell, m) = [(2, 1), (3, 3), "
252 "(4, 4)] subdominant multipoles based on the posterior "
253 "samples"
254 ),
255 "key": "gw",
256 },
257 "--calculate_precessing_snr": {
258 "action": "store_true",
259 "default": False,
260 "help": (
261 "Calculate the precessing SNR based on the posterior "
262 "samples"
263 ),
264 "key": "gw",
265 },
266 "--psd_default": {
267 "dest": "psd_default",
268 "default": "aLIGOZeroDetHighPower",
269 "help": (
270 "The PSD to use for conversions when no psd file is "
271 "provided. Default aLIGOZeroDetHighPower"
272 ),
273 "key": "gw",
274 },
275 "--f_start": {
276 "dest": "f_start",
277 "nargs": "+",
278 "help": "Starting frequency of the supplied waveform",
279 "key": "gw",
280 },
281 "--f_low": {
282 "dest": "f_low",
283 "nargs": "+",
284 "help": (
285 "Low frequency cutoff for likelihood integration used to generate "
286 "the samples"
287 ),
288 "key": "gw",
289 },
290 "--f_ref": {
291 "dest": "f_ref",
292 "help": (
293 "Reference frequency of the waveform used to generate the samples"
294 ),
295 "nargs": "+",
296 "key": "gw",
297 },
298 "--f_final": {
299 "dest": "f_final",
300 "nargs": "+",
301 "type": float,
302 "help": (
303 "Final frequency of the waveform. Used when calculating the precessing snr"
304 ),
305 "key": "gw"
306 },
307 "--delta_f": {
308 "dest": "delta_f",
309 "help": (
310 "Difference in frequency samples when calculating the "
311 "precessing snr"
312 ),
313 "nargs": "+",
314 "type": float,
315 "key": "gw",
316 },
317 "--no_ligo_skymap": {
318 "action": "store_true",
319 "default": False,
320 "help": "do not generate a skymap with ligo.skymap",
321 "key": "gw",
322 },
323 "--gw": {
324 "action": "store_true",
325 "help": "run with the gravitational wave pipeline",
326 "default": False,
327 "key": "gw",
328 },
329 "--public": {
330 "action": "store_true",
331 "help": "generate public facing summary pages",
332 "default": False,
333 "key": "gw"
334 },
335 "--redshift_method": {
336 "dest": "redshift_method",
337 "help": "The method to use when estimating the redshift",
338 "choices": ["approx", "exact"],
339 "default": "approx",
340 "key": "gw",
341 },
342 "--cosmology": {
343 "dest": "cosmology",
344 "help": "The cosmology to use when calculating the redshift",
345 "default": "Planck15",
346 "key": "gw"
347 },
348 "--no_conversion": {
349 "action": "store_true",
350 "default": False,
351 "help": "Do not generate any conversions",
352 "key": "gw"
353 }
354 }
355 options.update(gw_options)
356 return options
358 def add_gw_group(self):
359 gw_group = self.add_argument_group(
360 "\n\n=====================================================\n"
361 "Options specific for gravitational wave results files\n"
362 "====================================================="
363 )
364 return self.add_known_options_to_parser_from_key(gw_group, "gw")
366 def add_remnant_group(self):
367 remnant_group = self.add_argument_group(
368 "Options specific for calculating the remnant properties\n"
369 "-------------------------------------------------------"
370 )
371 return self.add_known_options_to_parser_from_key(
372 remnant_group, "remnant"
373 )
375 def add_all_groups_to_parser(self):
376 super(ArgumentParser, self).add_all_groups_to_parser()
377 self.add_gw_group()
378 self.add_remnant_group()
381class TGRArgumentParser(ArgumentParser):
382 """Extension of the pesummary.gw.cli.parser.ArgumentParser object to handle
383 TGR specific command line arguments.
385 Properties
386 ----------
387 fallback_options: dict
388 dictionary of default kwargs
389 pesummary_options: dict
390 dictionary giving pesummary options
391 command_line: str
392 command line run
393 command_line_arguments: list
394 list giving command line arguments
395 dynamic_argparse: list
396 list of dynamic argparse functions that you wish to add to the
397 argparse.Namespace object
398 """
399 @property
400 def dynamic_argparse(self):
401 return [add_dynamic_tgr_kwargs_to_namespace]
403 def _pesummary_options(self):
404 TESTS = ["imrct"]
405 _options = super(TGRArgumentParser, self)._pesummary_options()
406 options = {
407 "--test": {
408 "short": "-t",
409 "help": (
410 "What test do you want to run? Currently only supports "
411 "{}".format(", ".join(TESTS))
412 ),
413 "required": True,
414 "choices": TESTS,
415 },
416 "--{test}_kwargs": {
417 "dest": "example_test_kwargs",
418 "help": (
419 "Kwargs you wish to use when postprocessing the results. "
420 "Kwargs should be provided as a dictionary 'kwarg:value'. "
421 "For example `--imrct_kwargs N_bins:201 multi_process:4` "
422 "would pass the kwargs N_bins=201, multi_process=4 to the "
423 "IMRCT function. The test name '{test}' should match the "
424 "test provided with the --test flag"
425 ),
426 },
427 "--labels": {
428 "help": (
429 "Labels used to distinguish runs. The label format is "
430 "dependent on the TGR test you wish to use. For the IMRCT "
431 "test, labels need to be inspiral and postinspiral if "
432 "analysing a single event or {label1}:inspiral,"
433 "{label1}:postinspiral,{label2}:inspiral,"
434 "{label2}:postinspiral,... if analysing two or more events "
435 "(where label1/label2 is a unique string to distinguish "
436 "files from a single event). If a metafile is provided, "
437 "labels need to be {inspiral_label}:inspiral "
438 "{postinspiral_label}:postinspiral where inspiral_label "
439 "and postinspiral_label are the pesummary labels for the "
440 "inspiral and postinspiral analyses respectively."
441 ),
442 "nargs": "+",
443 },
444 "--cutoff_frequency": {
445 "type": float,
446 "nargs": "+",
447 "help": (
448 "Cutoff Frequency for IMRCT. Overrides any cutoff "
449 "frequency present in the supplied files. The supplied "
450 "cutoff frequency will only be used as metadata and "
451 "does not affect the cutoff frequency used in the "
452 "analysis. If only one number is supplied, the inspiral "
453 "maximum frequency and the postinspiral maximum frequency "
454 "are set to the same number. If a list of length 2 is "
455 "supplied, this assumes that the one corresponding to the "
456 "inspiral label is the maximum frequency for the inspiral "
457 "and that corresponding to the postinspiral label is "
458 "the minimum frequency for the postinspiral"
459 )
460 },
461 "--links_to_pe_pages": {
462 "help": "URLs for PE results pages separated by spaces.",
463 "nargs": "+",
464 "default": [],
465 },
466 "--disable_pe_page_generation": {
467 "action": "store_true",
468 "help": (
469 "Disable PE page generation for the input samples. This "
470 "option is only relevant if no URLs for PE results pages "
471 "are provided using --links_to_pe_pages."
472 )
473 },
474 "--pe_page_options": {
475 "type": str,
476 "default": "",
477 "help": (
478 "Additional options to pass to 'summarypages' when "
479 "generating PE webpages. All options should be wrapped in "
480 "quotation marks like, --pe_page_options='--no_ligo_skymap "
481 "--nsamples 1000 --psd...'. See 'summarypages --help' for "
482 "details. These options are added to base executable: "
483 "'summarypages --webdir {} --samples {} --labels {} --gw'"
484 ),
485 },
486 "--make_diagnostic_plots": {
487 "action": "store_true",
488 "help": "Make extra diagnostic plots"
489 }
490 }
491 extra_options = [
492 "--webdir", "--approximant", "--evolve_spins_forwards", "--f_low",
493 "--samples"
494 ]
495 for key in extra_options:
496 options[key] = _options[key]
497 return options
500def add_dynamic_argparse(
501 existing_namespace, pattern, example="--{}_psd", default={},
502 nargs='+', action=DictionaryAction, command_line=None
503):
504 """Add a dynamic argparse argument and add it to an existing
505 argparse.Namespace object
507 Parameters
508 ----------
509 existing_namespace: argparse.Namespace
510 existing namespace you wish to add the dynamic arguments too
511 pattern: str
512 generic pattern for customg argparse. For example '--*_psd'
513 example: str, optional
514 example string to demonstrate usage
515 default: obj, optional
516 the default argument for the dynamic argparse object
517 nargs: str
518 action: argparse.Action
519 argparse action to use for the dynamic argparse
520 command_line: str, optional
521 command line you wish to pass. If None, command line taken from
522 sys.argv
523 """
524 import fnmatch
525 import collections
526 import argparse
527 if command_line is None:
528 from pesummary.utils.utils import command_line_arguments
529 command_line = command_line_arguments()
530 commands = fnmatch.filter(command_line, pattern)
531 duplicates = [
532 item for item, count in collections.Counter(commands).items() if
533 count > 1
534 ]
535 if example in commands:
536 commands.remove(example)
537 if len(duplicates) > 0:
538 raise Exception(
539 "'{}' has been repeated. Please give a unique argument".format(
540 duplicates[0]
541 )
542 )
543 parser = argparse.ArgumentParser()
544 for i in commands:
545 parser.add_argument(
546 i, help=argparse.SUPPRESS, action=action, nargs=nargs,
547 default=default
548 )
549 args, unknown = parser.parse_known_args(args=command_line)
550 existing_namespace.__dict__.update(vars(args))
551 return args, unknown
554def add_dynamic_PSD_to_namespace(existing_namespace, command_line=None):
555 """Add a dynamic PSD argument to the argparse namespace
557 Parameters
558 ----------
559 existing_namespace: argparse.Namespace
560 existing namespace you wish to add the dynamic arguments too
561 command_line: str, optional
562 The command line which you are passing. Default None
563 """
564 return add_dynamic_argparse(
565 existing_namespace, "--*_psd", command_line=command_line
566 )
569def add_dynamic_calibration_to_namespace(existing_namespace, command_line=None):
570 """Add a dynamic calibration argument to the argparse namespace
572 Parameters
573 ----------
574 existing_namespace: argparse.Namespace
575 existing namespace you wish to add the dynamic arguments too
576 command_line: str, optional
577 The command line which you are passing. Default None
578 """
579 return add_dynamic_argparse(
580 existing_namespace, "--*_calibration", example="--{}_calibration",
581 command_line=command_line
582 )
585def add_dynamic_tgr_kwargs_to_namespace(existing_namespace, command_line=None):
586 """Add a dynamic TGR kwargs argument to the argparse namespace
588 Parameters
589 ----------
590 existing_namespace: argparse.Namespace
591 existing namespace you wish to add the dynamic arguments to
592 command_line: str, optional
593 The command line which you are passing. Default None
594 """
595 return add_dynamic_argparse(
596 existing_namespace, "--*_kwargs", example="--{}_kwargs",
597 command_line=command_line
598 )