Coverage for pesummary/gw/cli/parser.py: 97.1%
68 statements
« prev ^ index » next coverage.py v7.4.4, created at 2025-11-05 13:38 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2025-11-05 13:38 +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 "--terrestrial_probability": {
154 "dest": "terrestrial_probability",
155 "default": None,
156 "nargs": "+",
157 "help": (
158 "Terrestrial probability for the candidate you are "
159 "analysing. This is used when computing PAstro"
160 ),
161 "key": "gw",
162 },
163 "--catch_terrestrial_probability_error": {
164 "dest": "catch_terrestrial_probability_error",
165 "default": False,
166 "action": "store_true",
167 "help": (
168 "Catch the ValueError raised when no terrestrial probability "
169 "is provided when computing PAstro"
170 ),
171 "key": "gw",
172 },
173 "--pastro_category_file": {
174 "dest": "pastro_category_file",
175 "default": None,
176 "help": (
177 "path to yml file containing summary data for each "
178 "category (BBH, BNS, NSBH). This includes e.g. rates, "
179 "mass bounds etc. This is used when computing PAstro"
180 ),
181 "key": "gw",
182 },
183 "--gracedb": {
184 "dest": "gracedb",
185 "help": "gracedb of the event",
186 "key": "gw",
187 },
188 "--gracedb_server": {
189 "dest": "gracedb_server",
190 "help": "service url to use when accessing gracedb",
191 "key": "gw",
192 },
193 "--gracedb_data": {
194 "dest": "gracedb_data",
195 "nargs": "+",
196 "default": ["t_0", "far", "created"],
197 "help": (
198 "data you wish to download from gracedb and store in the "
199 "metafile"
200 ),
201 "key": "gw",
202 },
203 "--psd": {
204 "dest": "psd",
205 "action": DictionaryAction,
206 "help": "psd files used",
207 "nargs": "+",
208 "default": {},
209 "key": "gw",
210 },
211 "--{}_psd": {
212 "dest": "example_psd",
213 "metavar": "IFO:PATH_to_PSD.dat",
214 "help": (
215 "psd files used for a specific label. '{}' should be "
216 "replaced with the label of interest. For example "
217 "--IMRPhenomPv3_psd H1:IF0_psd.dat"
218 ),
219 "key": "gw",
220 },
221 "--calibration_definition": {
222 "dest": "calibration_definition",
223 "help": "Definition for each calibration envelope",
224 "nargs": "+",
225 "default": ["data"],
226 "key": "gw",
227 },
228 "--calibration": {
229 "dest": "calibration",
230 "help": "files for the calibration envelope",
231 "nargs": "+",
232 "default": {},
233 "action": DictionaryAction,
234 "key": "gw",
235 },
236 "--{}_calibration": {
237 "dest": "example_calibration",
238 "metavar": "IFO:PATH_to_CAL.txt",
239 "help": (
240 "calibration files used for a specific label. '{}' should "
241 "be replaced with the label of interest. For example "
242 "--IMRPhenomPv3_calibration H1:IF0_cal.dat"
243 ),
244 "key": "gw",
245 },
246 "--trigfile": {
247 "dest": "inj_file",
248 "help": "xml file containing the trigger values",
249 "nargs": "+",
250 "key": "gw",
251 },
252 "--gwdata": {
253 "dest": "gwdata",
254 "help": "channels and paths to strain cache files",
255 "action": DictionaryAction,
256 "metavar": "CHANNEL:CACHEFILE or PICKLEFILE",
257 "nargs": "+",
258 "key": "gw",
259 },
260 "--multi_threading_for_skymap": {
261 "action": "store_true",
262 "default": False,
263 "help": (
264 "use multi-threading to speed up generation of ligo.skymap"
265 ),
266 "key": "gw"
267 },
268 "--nsamples_for_skymap": {
269 "dest": "nsamples_for_skymap",
270 "help": (
271 "The number of samples used to generate the ligo.skymap. "
272 "These samples will be randomly drawn from the posterior "
273 "distributions"
274 ),
275 "key": "gw",
276 },
277 "--calculate_multipole_snr": {
278 "action": "store_true",
279 "default": False,
280 "help": (
281 "Calculate the SNR in the (ell, m) = [(2, 1), (3, 3), "
282 "(4, 4)] subdominant multipoles based on the posterior "
283 "samples"
284 ),
285 "key": "gw",
286 },
287 "--calculate_precessing_snr": {
288 "action": "store_true",
289 "default": False,
290 "help": (
291 "Calculate the precessing SNR based on the posterior "
292 "samples"
293 ),
294 "key": "gw",
295 },
296 "--psd_default": {
297 "dest": "psd_default",
298 "default": "aLIGOZeroDetHighPower",
299 "help": (
300 "The PSD to use for conversions when no psd file is "
301 "provided. Default aLIGOZeroDetHighPower"
302 ),
303 "key": "gw",
304 },
305 "--f_start": {
306 "dest": "f_start",
307 "nargs": "+",
308 "help": "Starting frequency of the supplied waveform",
309 "key": "gw",
310 },
311 "--f_low": {
312 "dest": "f_low",
313 "nargs": "+",
314 "help": (
315 "Low frequency cutoff for likelihood integration used to generate "
316 "the samples"
317 ),
318 "key": "gw",
319 },
320 "--f_ref": {
321 "dest": "f_ref",
322 "help": (
323 "Reference frequency of the waveform used to generate the samples"
324 ),
325 "nargs": "+",
326 "key": "gw",
327 },
328 "--f_final": {
329 "dest": "f_final",
330 "nargs": "+",
331 "type": float,
332 "help": (
333 "Final frequency of the waveform. Used when calculating the precessing snr"
334 ),
335 "key": "gw"
336 },
337 "--delta_f": {
338 "dest": "delta_f",
339 "help": (
340 "Difference in frequency samples when calculating the "
341 "precessing snr"
342 ),
343 "nargs": "+",
344 "type": float,
345 "key": "gw",
346 },
347 "--no_ligo_skymap": {
348 "action": "store_true",
349 "default": False,
350 "help": "do not generate a skymap with ligo.skymap",
351 "key": "gw",
352 },
353 "--gw": {
354 "action": "store_true",
355 "help": "run with the gravitational wave pipeline",
356 "default": False,
357 "key": "gw",
358 },
359 "--public": {
360 "action": "store_true",
361 "help": "generate public facing summary pages",
362 "default": False,
363 "key": "gw"
364 },
365 "--redshift_method": {
366 "dest": "redshift_method",
367 "help": "The method to use when estimating the redshift",
368 "choices": ["approx", "exact"],
369 "default": "approx",
370 "key": "gw",
371 },
372 "--cosmology": {
373 "dest": "cosmology",
374 "help": "The cosmology to use when calculating the redshift",
375 "default": "Planck15",
376 "key": "gw"
377 },
378 "--no_conversion": {
379 "action": "store_true",
380 "default": False,
381 "help": "Do not generate any conversions",
382 "key": "gw"
383 }
384 }
385 options.update(gw_options)
386 return options
388 def add_gw_group(self):
389 gw_group = self.add_argument_group(
390 "\n\n=====================================================\n"
391 "Options specific for gravitational wave results files\n"
392 "====================================================="
393 )
394 return self.add_known_options_to_parser_from_key(gw_group, "gw")
396 def add_remnant_group(self):
397 remnant_group = self.add_argument_group(
398 "Options specific for calculating the remnant properties\n"
399 "-------------------------------------------------------"
400 )
401 return self.add_known_options_to_parser_from_key(
402 remnant_group, "remnant"
403 )
405 def add_all_groups_to_parser(self):
406 super(ArgumentParser, self).add_all_groups_to_parser()
407 self.add_gw_group()
408 self.add_remnant_group()
411class TGRArgumentParser(ArgumentParser):
412 """Extension of the pesummary.gw.cli.parser.ArgumentParser object to handle
413 TGR specific command line arguments.
415 Properties
416 ----------
417 fallback_options: dict
418 dictionary of default kwargs
419 pesummary_options: dict
420 dictionary giving pesummary options
421 command_line: str
422 command line run
423 command_line_arguments: list
424 list giving command line arguments
425 dynamic_argparse: list
426 list of dynamic argparse functions that you wish to add to the
427 argparse.Namespace object
428 """
429 @property
430 def dynamic_argparse(self):
431 return [add_dynamic_tgr_kwargs_to_namespace]
433 def _pesummary_options(self):
434 TESTS = ["imrct"]
435 _options = super(TGRArgumentParser, self)._pesummary_options()
436 options = {
437 "--test": {
438 "short": "-t",
439 "help": (
440 "What test do you want to run? Currently only supports "
441 "{}".format(", ".join(TESTS))
442 ),
443 "required": True,
444 "choices": TESTS,
445 },
446 "--{test}_kwargs": {
447 "dest": "example_test_kwargs",
448 "help": (
449 "Kwargs you wish to use when postprocessing the results. "
450 "Kwargs should be provided as a dictionary 'kwarg:value'. "
451 "For example `--imrct_kwargs N_bins:201 multi_process:4` "
452 "would pass the kwargs N_bins=201, multi_process=4 to the "
453 "IMRCT function. The test name '{test}' should match the "
454 "test provided with the --test flag"
455 ),
456 },
457 "--labels": {
458 "help": (
459 "Labels used to distinguish runs. The label format is "
460 "dependent on the TGR test you wish to use. For the IMRCT "
461 "test, labels need to be inspiral and postinspiral if "
462 "analysing a single event or {label1}:inspiral,"
463 "{label1}:postinspiral,{label2}:inspiral,"
464 "{label2}:postinspiral,... if analysing two or more events "
465 "(where label1/label2 is a unique string to distinguish "
466 "files from a single event). If a metafile is provided, "
467 "labels need to be {inspiral_label}:inspiral "
468 "{postinspiral_label}:postinspiral where inspiral_label "
469 "and postinspiral_label are the pesummary labels for the "
470 "inspiral and postinspiral analyses respectively."
471 ),
472 "nargs": "+",
473 },
474 "--cutoff_frequency": {
475 "type": float,
476 "nargs": "+",
477 "help": (
478 "Cutoff Frequency for IMRCT. Overrides any cutoff "
479 "frequency present in the supplied files. The supplied "
480 "cutoff frequency will only be used as metadata and "
481 "does not affect the cutoff frequency used in the "
482 "analysis. If only one number is supplied, the inspiral "
483 "maximum frequency and the postinspiral maximum frequency "
484 "are set to the same number. If a list of length 2 is "
485 "supplied, this assumes that the one corresponding to the "
486 "inspiral label is the maximum frequency for the inspiral "
487 "and that corresponding to the postinspiral label is "
488 "the minimum frequency for the postinspiral"
489 )
490 },
491 "--links_to_pe_pages": {
492 "help": "URLs for PE results pages separated by spaces.",
493 "nargs": "+",
494 "default": [],
495 },
496 "--disable_pe_page_generation": {
497 "action": "store_true",
498 "help": (
499 "Disable PE page generation for the input samples. This "
500 "option is only relevant if no URLs for PE results pages "
501 "are provided using --links_to_pe_pages."
502 )
503 },
504 "--pe_page_options": {
505 "type": str,
506 "default": "",
507 "help": (
508 "Additional options to pass to 'summarypages' when "
509 "generating PE webpages. All options should be wrapped in "
510 "quotation marks like, --pe_page_options='--no_ligo_skymap "
511 "--nsamples 1000 --psd...'. See 'summarypages --help' for "
512 "details. These options are added to base executable: "
513 "'summarypages --webdir {} --samples {} --labels {} --gw'"
514 ),
515 },
516 "--make_diagnostic_plots": {
517 "action": "store_true",
518 "help": "Make extra diagnostic plots"
519 }
520 }
521 extra_options = [
522 "--webdir", "--approximant", "--evolve_spins_forwards", "--f_low",
523 "--samples"
524 ]
525 for key in extra_options:
526 options[key] = _options[key]
527 return options
530def add_dynamic_argparse(
531 existing_namespace, pattern, example="--{}_psd", default={},
532 nargs='+', action=DictionaryAction, command_line=None
533):
534 """Add a dynamic argparse argument and add it to an existing
535 argparse.Namespace object
537 Parameters
538 ----------
539 existing_namespace: argparse.Namespace
540 existing namespace you wish to add the dynamic arguments too
541 pattern: str
542 generic pattern for customg argparse. For example '--*_psd'
543 example: str, optional
544 example string to demonstrate usage
545 default: obj, optional
546 the default argument for the dynamic argparse object
547 nargs: str
548 action: argparse.Action
549 argparse action to use for the dynamic argparse
550 command_line: str, optional
551 command line you wish to pass. If None, command line taken from
552 sys.argv
553 """
554 import fnmatch
555 import collections
556 import argparse
557 if command_line is None:
558 from pesummary.utils.utils import command_line_arguments
559 command_line = command_line_arguments()
560 commands = fnmatch.filter(command_line, pattern)
561 duplicates = [
562 item for item, count in collections.Counter(commands).items() if
563 count > 1
564 ]
565 if example in commands:
566 commands.remove(example)
567 if len(duplicates) > 0:
568 raise Exception(
569 "'{}' has been repeated. Please give a unique argument".format(
570 duplicates[0]
571 )
572 )
573 parser = argparse.ArgumentParser()
574 for i in commands:
575 parser.add_argument(
576 i, help=argparse.SUPPRESS, action=action, nargs=nargs,
577 default=default
578 )
579 args, unknown = parser.parse_known_args(args=command_line)
580 existing_namespace.__dict__.update(vars(args))
581 return args, unknown
584def add_dynamic_PSD_to_namespace(existing_namespace, command_line=None):
585 """Add a dynamic PSD argument to the argparse namespace
587 Parameters
588 ----------
589 existing_namespace: argparse.Namespace
590 existing namespace you wish to add the dynamic arguments too
591 command_line: str, optional
592 The command line which you are passing. Default None
593 """
594 return add_dynamic_argparse(
595 existing_namespace, "--*_psd", command_line=command_line
596 )
599def add_dynamic_calibration_to_namespace(existing_namespace, command_line=None):
600 """Add a dynamic calibration argument to the argparse namespace
602 Parameters
603 ----------
604 existing_namespace: argparse.Namespace
605 existing namespace you wish to add the dynamic arguments too
606 command_line: str, optional
607 The command line which you are passing. Default None
608 """
609 return add_dynamic_argparse(
610 existing_namespace, "--*_calibration", example="--{}_calibration",
611 command_line=command_line
612 )
615def add_dynamic_tgr_kwargs_to_namespace(existing_namespace, command_line=None):
616 """Add a dynamic TGR kwargs argument to the argparse namespace
618 Parameters
619 ----------
620 existing_namespace: argparse.Namespace
621 existing namespace you wish to add the dynamic arguments to
622 command_line: str, optional
623 The command line which you are passing. Default None
624 """
625 return add_dynamic_argparse(
626 existing_namespace, "--*_kwargs", example="--{}_kwargs",
627 command_line=command_line
628 )