Commit b8b92464b8d449e7e2ce77af8b93559d5531ab5b
1 parent
8ff45cf6
Support Python list slicing of obs containers (#2128)
Showing
6 changed files
with
294 additions
and
12 deletions
pyext/GEbounds.i
| ... | ... | @@ -93,6 +93,35 @@ public: |
| 93 | 93 | * @brief GEbounds class extension |
| 94 | 94 | ***************************************************************************/ |
| 95 | 95 | %extend GEbounds { |
| 96 | + GEbounds* __getitem__(PyObject *param) { | |
| 97 | + if (PySlice_Check(param)) { | |
| 98 | + Py_ssize_t start = 0; | |
| 99 | + Py_ssize_t stop = 0; | |
| 100 | + Py_ssize_t step = 0; | |
| 101 | + Py_ssize_t len = self->size(); | |
| 102 | + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) { | |
| 103 | + GEbounds* ebounds = new GEbounds; | |
| 104 | + if (step > 0) { | |
| 105 | + for (int i = (int)start; i < (int)stop; i += (int)step) { | |
| 106 | + ebounds->append(self->emin(i), self->emax(i)); | |
| 107 | + } | |
| 108 | + } | |
| 109 | + else { | |
| 110 | + for (int i = (int)start; i > (int)stop; i += (int)step) { | |
| 111 | + ebounds->append(self->emin(i), self->emax(i)); | |
| 112 | + } | |
| 113 | + } | |
| 114 | + return ebounds; | |
| 115 | + } | |
| 116 | + else { | |
| 117 | + throw GException::invalid_argument("__getitem__(PyObject)", | |
| 118 | + "Invalid slice indices"); | |
| 119 | + } | |
| 120 | + } | |
| 121 | + else { | |
| 122 | + throw GException::invalid_argument("__getitem__(PyObject)",""); | |
| 123 | + } | |
| 124 | + } | |
| 96 | 125 | GEbounds copy() { |
| 97 | 126 | return (*self); |
| 98 | 127 | } | ... | ... |
pyext/GGti.i
| ... | ... | @@ -85,8 +85,34 @@ public: |
| 85 | 85 | * @brief GGti class extension |
| 86 | 86 | ***************************************************************************/ |
| 87 | 87 | %extend GGti { |
| 88 | - int __len__() { | |
| 89 | - return (self->size()); | |
| 88 | + GGti* __getitem__(PyObject *param) { | |
| 89 | + if (PySlice_Check(param)) { | |
| 90 | + Py_ssize_t start = 0; | |
| 91 | + Py_ssize_t stop = 0; | |
| 92 | + Py_ssize_t step = 0; | |
| 93 | + Py_ssize_t len = self->size(); | |
| 94 | + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) { | |
| 95 | + GGti* gti = new GGti; | |
| 96 | + if (step > 0) { | |
| 97 | + for (int i = (int)start; i < (int)stop; i += (int)step) { | |
| 98 | + gti->append(self->tstart(i), self->tstop(i)); | |
| 99 | + } | |
| 100 | + } | |
| 101 | + else { | |
| 102 | + for (int i = (int)start; i > (int)stop; i += (int)step) { | |
| 103 | + gti->append(self->tstart(i), self->tstop(i)); | |
| 104 | + } | |
| 105 | + } | |
| 106 | + return gti; | |
| 107 | + } | |
| 108 | + else { | |
| 109 | + throw GException::invalid_argument("__getitem__(PyObject)", | |
| 110 | + "Invalid slice indices"); | |
| 111 | + } | |
| 112 | + } | |
| 113 | + else { | |
| 114 | + throw GException::invalid_argument("__getitem__(PyObject)",""); | |
| 115 | + } | |
| 90 | 116 | } |
| 91 | 117 | GGti copy() { |
| 92 | 118 | return (*self); | ... | ... |
pyext/GPhases.i
| ... | ... | @@ -63,8 +63,34 @@ public: |
| 63 | 63 | * @brief GPhases class extension |
| 64 | 64 | ***************************************************************************/ |
| 65 | 65 | %extend GPhases { |
| 66 | - int __len__() { | |
| 67 | - return (self->size()); | |
| 66 | + GPhases* __getitem__(PyObject *param) { | |
| 67 | + if (PySlice_Check(param)) { | |
| 68 | + Py_ssize_t start = 0; | |
| 69 | + Py_ssize_t stop = 0; | |
| 70 | + Py_ssize_t step = 0; | |
| 71 | + Py_ssize_t len = self->size(); | |
| 72 | + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) { | |
| 73 | + GPhases* phases = new GPhases; | |
| 74 | + if (step > 0) { | |
| 75 | + for (int i = (int)start; i < (int)stop; i += (int)step) { | |
| 76 | + phases->append(self->pmin(i), self->pmax(i)); | |
| 77 | + } | |
| 78 | + } | |
| 79 | + else { | |
| 80 | + for (int i = (int)start; i > (int)stop; i += (int)step) { | |
| 81 | + phases->append(self->pmin(i), self->pmax(i)); | |
| 82 | + } | |
| 83 | + } | |
| 84 | + return phases; | |
| 85 | + } | |
| 86 | + else { | |
| 87 | + throw GException::invalid_argument("__getitem__(PyObject)", | |
| 88 | + "Invalid slice indices"); | |
| 89 | + } | |
| 90 | + } | |
| 91 | + else { | |
| 92 | + throw GException::invalid_argument("__getitem__(PyObject)",""); | |
| 93 | + } | |
| 68 | 94 | } |
| 69 | 95 | GPhases copy() { |
| 70 | 96 | return (*self); | ... | ... |
test/test_GApplication.py
| ... | ... | @@ -297,8 +297,8 @@ class Test(gammalib.GPythonTestSuite): |
| 297 | 297 | self.append(self._test_log, 'Test GLog') |
| 298 | 298 | self.append(self._test_app, 'Test GApplication') |
| 299 | 299 | self.append(self._test_pars, 'Test GApplicationPars') |
| 300 | - self.append(self._test_pars_access, 'Test GApplicationPars class parameter access') | |
| 301 | - self.append(self._test_pars_access, 'Test GApplicationPars class slicing') | |
| 300 | + self.append(self._test_pars_access, 'Test GApplicationPars parameter access') | |
| 301 | + self.append(self._test_pars_access, 'Test GApplicationPars slicing') | |
| 302 | 302 | |
| 303 | 303 | # Return |
| 304 | 304 | return | ... | ... |
test/test_GModel.py
| ... | ... | @@ -115,8 +115,8 @@ class Test(gammalib.GPythonTestSuite): |
| 115 | 115 | self.name('model') |
| 116 | 116 | |
| 117 | 117 | # Append tests |
| 118 | - self.append(self._test_models_access, 'Test GModels class model access') | |
| 119 | - self.append(self._test_models_slicing, 'Test GModels class slicing') | |
| 118 | + self.append(self._test_models_access, 'Test GModels model access') | |
| 119 | + self.append(self._test_models_slicing, 'Test GModels slicing') | |
| 120 | 120 | |
| 121 | 121 | # Return |
| 122 | 122 | return | ... | ... |
test/test_GObservation.py
| ... | ... | @@ -90,6 +90,46 @@ class Test(gammalib.GPythonTestSuite): |
| 90 | 90 | # Return times container |
| 91 | 91 | return times |
| 92 | 92 | |
| 93 | + # Setup GGti container | |
| 94 | + def _setup_gti(self): | |
| 95 | + """ | |
| 96 | + Setup GGti container | |
| 97 | + | |
| 98 | + Returns | |
| 99 | + ------- | |
| 100 | + gti : `~gammalib.GGti` | |
| 101 | + GGti container | |
| 102 | + """ | |
| 103 | + # Setup GTI container | |
| 104 | + gti = gammalib.GGti() | |
| 105 | + for i in range(10): | |
| 106 | + tstart = gammalib.GTime(float(i), 'sec') | |
| 107 | + tstop = gammalib.GTime(float(i+1), 'sec') | |
| 108 | + gti.append(tstart, tstop) | |
| 109 | + | |
| 110 | + # Return GTI container | |
| 111 | + return gti | |
| 112 | + | |
| 113 | + # Setup GPhases container | |
| 114 | + def _setup_phases(self): | |
| 115 | + """ | |
| 116 | + Setup GPhases container | |
| 117 | + | |
| 118 | + Returns | |
| 119 | + ------- | |
| 120 | + phases : `~gammalib.GPhases` | |
| 121 | + GPhases container | |
| 122 | + """ | |
| 123 | + # Setup phases container | |
| 124 | + phases = gammalib.GPhases() | |
| 125 | + for i in range(10): | |
| 126 | + pmin = float(i) | |
| 127 | + pmax = float(i+1) | |
| 128 | + phases.append(pmin, pmax) | |
| 129 | + | |
| 130 | + # Return phases container | |
| 131 | + return phases | |
| 132 | + | |
| 93 | 133 | # Setup GPhotons container |
| 94 | 134 | def _setup_photons(self): |
| 95 | 135 | """ |
| ... | ... | @@ -289,6 +329,60 @@ class Test(gammalib.GPythonTestSuite): |
| 289 | 329 | # Return |
| 290 | 330 | return |
| 291 | 331 | |
| 332 | + # Test GEbounds class slicing | |
| 333 | + def _test_ebounds_slicing(self): | |
| 334 | + """ | |
| 335 | + Test GEbounds class slicing | |
| 336 | + """ | |
| 337 | + # Setup energies container | |
| 338 | + ebounds = gammalib.GEbounds(10, gammalib.GEnergy(1.0, 'MeV'), | |
| 339 | + gammalib.GEnergy(11.0, 'MeV'), False) | |
| 340 | + | |
| 341 | + # Test ebounds[start:end] | |
| 342 | + self.test_value(len(ebounds[3:5]), 2) | |
| 343 | + self.test_value(ebounds[3:5].emin(0).MeV(), 4.0) | |
| 344 | + self.test_value(ebounds[3:5].emin(1).MeV(), 5.0) | |
| 345 | + | |
| 346 | + # Test ebounds[start:] | |
| 347 | + self.test_value(len(ebounds[7:]), 3) | |
| 348 | + self.test_value(ebounds[7:].emin(0).MeV(), 8.0) | |
| 349 | + self.test_value(ebounds[7:].emin(1).MeV(), 9.0) | |
| 350 | + self.test_value(ebounds[7:].emin(2).MeV(), 10.0) | |
| 351 | + | |
| 352 | + # Test ebounds[:end] | |
| 353 | + self.test_value(len(ebounds[:2]), 2) | |
| 354 | + self.test_value(ebounds[:2].emin(0).MeV(), 1.0) | |
| 355 | + self.test_value(ebounds[:2].emin(1).MeV(), 2.0) | |
| 356 | + | |
| 357 | + # Test ebounds[:] | |
| 358 | + self.test_value(len(ebounds[:]), 10) | |
| 359 | + for i in range(10): | |
| 360 | + self.test_value(ebounds[:].emin(i).MeV(), float(i+1)) | |
| 361 | + | |
| 362 | + # Test ebounds[start:end:step] | |
| 363 | + self.test_value(len(ebounds[3:7:2]), 2) | |
| 364 | + self.test_value(ebounds[3:7:2].emin(0).MeV(), 4.0) | |
| 365 | + self.test_value(ebounds[3:7:2].emin(1).MeV(), 6.0) | |
| 366 | + | |
| 367 | + # Test ebounds[start:end:step] | |
| 368 | + self.test_value(len(ebounds[6:3:-2]), 2) | |
| 369 | + self.test_value(ebounds[6:3:-2].emin(0).MeV(), 7.0) | |
| 370 | + self.test_value(ebounds[6:3:-2].emin(1).MeV(), 5.0) | |
| 371 | + | |
| 372 | + # Test ebounds[-start:] | |
| 373 | + self.test_value(len(ebounds[-2:]), 2) | |
| 374 | + self.test_value(ebounds[-2:].emin(0).MeV(), 9.0) | |
| 375 | + self.test_value(ebounds[-2:].emin(1).MeV(), 10.0) | |
| 376 | + | |
| 377 | + # Test ebounds[:-end] | |
| 378 | + self.test_value(len(ebounds[:-7]), 3) | |
| 379 | + self.test_value(ebounds[:-7].emin(0).MeV(), 1.0) | |
| 380 | + self.test_value(ebounds[:-7].emin(1).MeV(), 2.0) | |
| 381 | + self.test_value(ebounds[:-7].emin(2).MeV(), 3.0) | |
| 382 | + | |
| 383 | + # Return | |
| 384 | + return | |
| 385 | + | |
| 292 | 386 | # Test GTime class |
| 293 | 387 | def _test_time(self): |
| 294 | 388 | """ |
| ... | ... | @@ -441,6 +535,112 @@ class Test(gammalib.GPythonTestSuite): |
| 441 | 535 | # Return |
| 442 | 536 | return |
| 443 | 537 | |
| 538 | + # Test GGti class slicing | |
| 539 | + def _test_gti_slicing(self): | |
| 540 | + """ | |
| 541 | + Test GGti class slicing | |
| 542 | + """ | |
| 543 | + # Setup GTI container | |
| 544 | + gti = self._setup_gti() | |
| 545 | + | |
| 546 | + # Test gti[start:end] | |
| 547 | + self.test_value(len(gti[3:5]), 2) | |
| 548 | + self.test_value(gti[3:5].tstop(0).secs(), 4.0) | |
| 549 | + self.test_value(gti[3:5].tstop(1).secs(), 5.0) | |
| 550 | + | |
| 551 | + # Test gti[start:] | |
| 552 | + self.test_value(len(gti[7:]), 3) | |
| 553 | + self.test_value(gti[7:].tstop(0).secs(), 8.0) | |
| 554 | + self.test_value(gti[7:].tstop(1).secs(), 9.0) | |
| 555 | + self.test_value(gti[7:].tstop(2).secs(), 10.0) | |
| 556 | + | |
| 557 | + # Test gti[:end] | |
| 558 | + self.test_value(len(gti[:2]), 2) | |
| 559 | + self.test_value(gti[:2].tstop(0).secs(), 1.0) | |
| 560 | + self.test_value(gti[:2].tstop(1).secs(), 2.0) | |
| 561 | + | |
| 562 | + # Test gti[:] | |
| 563 | + self.test_value(len(gti[:]), 10) | |
| 564 | + for i in range(10): | |
| 565 | + self.test_value(gti[:].tstop(i).secs(), float(i+1)) | |
| 566 | + | |
| 567 | + # Test gti[start:end:step] | |
| 568 | + self.test_value(len(gti[3:7:2]), 2) | |
| 569 | + self.test_value(gti[3:7:2].tstop(0).secs(), 4.0) | |
| 570 | + self.test_value(gti[3:7:2].tstop(1).secs(), 6.0) | |
| 571 | + | |
| 572 | + # Test gti[start:end:step] | |
| 573 | + self.test_value(len(gti[6:3:-2]), 2) | |
| 574 | + self.test_value(gti[6:3:-2].tstop(0).secs(), 7.0) | |
| 575 | + self.test_value(gti[6:3:-2].tstop(1).secs(), 5.0) | |
| 576 | + | |
| 577 | + # Test gti[-start:] | |
| 578 | + self.test_value(len(gti[-2:]), 2) | |
| 579 | + self.test_value(gti[-2:].tstop(0).secs(), 9.0) | |
| 580 | + self.test_value(gti[-2:].tstop(1).secs(), 10.0) | |
| 581 | + | |
| 582 | + # Test gti[:-end] | |
| 583 | + self.test_value(len(gti[:-7]), 3) | |
| 584 | + self.test_value(gti[:-7].tstop(0).secs(), 1.0) | |
| 585 | + self.test_value(gti[:-7].tstop(1).secs(), 2.0) | |
| 586 | + self.test_value(gti[:-7].tstop(2).secs(), 3.0) | |
| 587 | + | |
| 588 | + # Return | |
| 589 | + return | |
| 590 | + | |
| 591 | + # Test GPhases class slicing | |
| 592 | + def _test_phases_slicing(self): | |
| 593 | + """ | |
| 594 | + Test GPhases class slicing | |
| 595 | + """ | |
| 596 | + # Setup phase container | |
| 597 | + phases = self._setup_phases() | |
| 598 | + | |
| 599 | + # Test phases[start:end] | |
| 600 | + self.test_value(len(phases[3:5]), 2) | |
| 601 | + self.test_value(phases[3:5].pmax(0), 4.0) | |
| 602 | + self.test_value(phases[3:5].pmax(1), 5.0) | |
| 603 | + | |
| 604 | + # Test phases[start:] | |
| 605 | + self.test_value(len(phases[7:]), 3) | |
| 606 | + self.test_value(phases[7:].pmax(0), 8.0) | |
| 607 | + self.test_value(phases[7:].pmax(1), 9.0) | |
| 608 | + self.test_value(phases[7:].pmax(2), 10.0) | |
| 609 | + | |
| 610 | + # Test phases[:end] | |
| 611 | + self.test_value(len(phases[:2]), 2) | |
| 612 | + self.test_value(phases[:2].pmax(0), 1.0) | |
| 613 | + self.test_value(phases[:2].pmax(1), 2.0) | |
| 614 | + | |
| 615 | + # Test phases[:] | |
| 616 | + self.test_value(len(phases[:]), 10) | |
| 617 | + for i in range(10): | |
| 618 | + self.test_value(phases[:].pmax(i), float(i+1)) | |
| 619 | + | |
| 620 | + # Test phases[start:end:step] | |
| 621 | + self.test_value(len(phases[3:7:2]), 2) | |
| 622 | + self.test_value(phases[3:7:2].pmax(0), 4.0) | |
| 623 | + self.test_value(phases[3:7:2].pmax(1), 6.0) | |
| 624 | + | |
| 625 | + # Test phases[start:end:step] | |
| 626 | + self.test_value(len(phases[6:3:-2]), 2) | |
| 627 | + self.test_value(phases[6:3:-2].pmax(0), 7.0) | |
| 628 | + self.test_value(phases[6:3:-2].pmax(1), 5.0) | |
| 629 | + | |
| 630 | + # Test phases[-start:] | |
| 631 | + self.test_value(len(phases[-2:]), 2) | |
| 632 | + self.test_value(phases[-2:].pmax(0), 9.0) | |
| 633 | + self.test_value(phases[-2:].pmax(1), 10.0) | |
| 634 | + | |
| 635 | + # Test phases[:-end] | |
| 636 | + self.test_value(len(phases[:-7]), 3) | |
| 637 | + self.test_value(phases[:-7].pmax(0), 1.0) | |
| 638 | + self.test_value(phases[:-7].pmax(1), 2.0) | |
| 639 | + self.test_value(phases[:-7].pmax(2), 3.0) | |
| 640 | + | |
| 641 | + # Return | |
| 642 | + return | |
| 643 | + | |
| 444 | 644 | # Test GPhotons class access operators |
| 445 | 645 | def _test_photons_access(self): |
| 446 | 646 | """ |
| ... | ... | @@ -584,14 +784,15 @@ class Test(gammalib.GPythonTestSuite): |
| 584 | 784 | # Append tests |
| 585 | 785 | self.append(self._test_energy, 'Test GEnergy') |
| 586 | 786 | self.append(self._test_energies, 'Test GEnergies') |
| 587 | - self.append(self._test_energies_access, 'Test GEnergies energy access') | |
| 588 | - self.append(self._test_energies_slicing, 'Test GEnergies slicing') | |
| 589 | 787 | self.append(self._test_time, 'Test GTime') |
| 788 | + self.append(self._test_energies_access, 'Test GEnergies energy access') | |
| 590 | 789 | self.append(self._test_times_access, 'Test GTimes time access') |
| 591 | - self.append(self._test_times_slicing, 'Test GTimes slicing') | |
| 592 | 790 | self.append(self._test_photons_access, 'Test GPhotons photon access') |
| 593 | - self.append(self._test_photons_slicing, 'Test GPhotons slicing') | |
| 594 | 791 | self.append(self._test_observations_access, 'Test GObservations observation access') |
| 792 | + self.append(self._test_energies_slicing, 'Test GEnergies slicing') | |
| 793 | + self.append(self._test_ebounds_slicing, 'Test GEbounds slicing') | |
| 794 | + self.append(self._test_times_slicing, 'Test GTimes slicing') | |
| 795 | + self.append(self._test_photons_slicing, 'Test GPhotons slicing') | |
| 595 | 796 | self.append(self._test_observations_slicing, 'Test GObservations slicing') |
| 596 | 797 | |
| 597 | 798 | # Return | ... | ... |