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

1# Licensed under an MIT style license -- see LICENSE.md 

2 

3from ...core.cli.parser import ArgumentParser as _ArgumentParser 

4from ...core.cli.actions import DictionaryAction, DeprecatedStoreTrueAction 

5 

6__author__ = ["Charlie Hoy <charlie.hoy@ligo.org>"] 

7 

8 

9class ArgumentParser(_ArgumentParser): 

10 """Extension of the pesummary.core.cli.parser.ArgumentParser object to handle 

11 gw specific command line arguments. 

12 

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 ] 

33 

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 

42 

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 

357 

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") 

365 

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 ) 

374 

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() 

379 

380 

381class TGRArgumentParser(ArgumentParser): 

382 """Extension of the pesummary.gw.cli.parser.ArgumentParser object to handle 

383 TGR specific command line arguments. 

384 

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] 

402 

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 

498 

499 

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 

506 

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 

552 

553 

554def add_dynamic_PSD_to_namespace(existing_namespace, command_line=None): 

555 """Add a dynamic PSD argument to the argparse namespace 

556 

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 ) 

567 

568 

569def add_dynamic_calibration_to_namespace(existing_namespace, command_line=None): 

570 """Add a dynamic calibration argument to the argparse namespace 

571 

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 ) 

583 

584 

585def add_dynamic_tgr_kwargs_to_namespace(existing_namespace, command_line=None): 

586 """Add a dynamic TGR kwargs argument to the argparse namespace 

587 

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 )