diff --git a/ChangeLog b/ChangeLog index 0f49e1a..baa09b2 100755 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,9 @@ -2018-09-22 +2018-10-17 * Version 1.6.0 released ======================== + Compute DETX and DETY in ctmodel if they are not available (#2694) Do no longer set missing boundaries in ctool::get_observations and ctool::setup_observations (#2686) Unnormalize background cube values in ctbkgcube (#2685) diff --git a/NEWS b/NEWS index f25c008..51168a4 100755 --- a/NEWS +++ b/NEWS @@ -1,6 +1,6 @@ New Features and Important Changes in ctools 1.6.0 -22 September 2018 +17 October 2018 Introduction @@ -112,6 +112,10 @@ None ctmodel - CTA counts cube modelling ----------------------------------- +The tools now computes DETX and DETY for every event bin if they are not +available so that model that rely on the existence of these parameters can +be handled (#2694). + Add hidden "nthreads" parameter to control parallel computations (#2421). diff --git a/cscripts/csresmap.py b/cscripts/csresmap.py index 4bbd2cc..3f61273 100755 --- a/cscripts/csresmap.py +++ b/cscripts/csresmap.py @@ -285,6 +285,18 @@ class csresmap(ctools.csobservation): # Return return + def resmap(self): + """ + Return residual map + + Returns + ------- + map : `~gammalib.GSkyMap' + Residual sky map + """ + # Return + return self._resmap + # ======================== # # Main routine entry point # diff --git a/cscripts/csresspec.py b/cscripts/csresspec.py index 777255b..8bf2273 100755 --- a/cscripts/csresspec.py +++ b/cscripts/csresspec.py @@ -703,6 +703,18 @@ class csresspec(ctools.csobservation): # Return return + def resspec(self): + """ + Return residual FITS file + + Returns + ------- + fits : `~gammalib.GFits' + FITS file containing residuals + """ + # Return + return self._fits + # ======================== # # Main routine entry point # diff --git a/doc/source/admin/release_history/1.6.rst b/doc/source/admin/release_history/1.6.rst index 972b70c..ca63f7b 100644 --- a/doc/source/admin/release_history/1.6.rst +++ b/doc/source/admin/release_history/1.6.rst @@ -19,6 +19,8 @@ In particular, this release provides: Bug fixes --------- +* [`2694 `_] - + Compute ``DETX`` and ``DETY`` in :ref:`ctmodel` if they are not available * [`2686 `_] - Do no longer set missing boundaries in ``ctool::get_observations`` and ``ctool::setup_observations`` diff --git a/src/ctmodel/ctmodel.cpp b/src/ctmodel/ctmodel.cpp index 674caca..b45dad5 100755 --- a/src/ctmodel/ctmodel.cpp +++ b/src/ctmodel/ctmodel.cpp @@ -852,6 +852,10 @@ void ctmodel::fill_cube(const GCTAObservation* obs, GModels& models) int npix = m_cube.npix(); int nebins = m_cube.ebins(); + // Get reference to the pointing for DETX and DETY computation, if + // required + const GCTAPointing& pnt = obs->pointing(); + // Get references to GTI and energy boundaries for the event list const GGti& gti = obs->events()->gti(); const GEbounds& obs_ebounds = obs->ebounds(); @@ -898,8 +902,15 @@ void ctmodel::fill_cube(const GCTAObservation* obs, GModels& models) continue; } + // Get instrument direction for spatial pixel. Compute DETX and DETY + // if they are not provided + GCTAInstDir dir = m_dir[i]; + if (!dir.has_detx() || !dir.has_dety()) { + dir = pnt.instdir(dir.dir()); + } + // Set instrument direction, solid angle and pixel index of bin - bin.dir(m_dir[i]); + bin.dir(dir); bin.solidangle(m_solidangle[i]); bin.ipix(i); diff --git a/src/ctselect/ctselect.cpp b/src/ctselect/ctselect.cpp index f8b4937..712ec34 100755 --- a/src/ctselect/ctselect.cpp +++ b/src/ctselect/ctselect.cpp @@ -1066,8 +1066,9 @@ void ctselect::select_events(GCTAObservation* obs, // If RoI selection has been applied without forcing then set the event // list RoI if (select_roi && !enforced_roi) { - GCTAInstDir instdir; - instdir.dir().radec_deg(ra, dec); + GSkyDir skydir; + skydir.radec_deg(ra, dec); + GCTAInstDir instdir(skydir); list->roi(GCTARoi(instdir, rad)); } diff --git a/test/test_obsutils.py b/test/test_obsutils.py index f290e2e..c929ab3 100755 --- a/test/test_obsutils.py +++ b/test/test_obsutils.py @@ -255,7 +255,7 @@ class Test(test): obs.append(run) obs.models(gammalib.GModels(self._model)) - # Simulate stacked observations + # Simulate On/Off observations res = obsutils.sim(obs, onsrc='Crab', nbins=5) # Check simulation results @@ -263,6 +263,8 @@ class Test(test): self.test_value(res.models().size(), 2, 'Check number of models') self.test_value(res.nobserved(), 46, 'Check number of observed events') self.test_value(res.npred(), 0.0, 'Check number of predicted events') + + # Check results of first observation self.test_value(res[0].on_spec().ebounds().emin().TeV(), 1.0, 'Check minimum energy of On spectrum') self.test_value(res[0].on_spec().ebounds().emax().TeV(), 10.0, @@ -277,7 +279,7 @@ class Test(test): 'Check maximum energy of Off spectrum') self.test_value(res[0].off_spec().ebounds().size(), 5, 'Check number of energy bins of Off spectrum') - self.test_value(res[0].off_spec().counts(), 2, + self.test_value(res[0].off_spec().counts(), 1, 'Check number of events in of Off spectrum') self.test_value(res[0].arf().ebounds().emin().TeV(), 0.5, 'Check minimum energy of ARF') @@ -298,6 +300,42 @@ class Test(test): self.test_value(res[0].rmf().emeasured().size(), 5, 'Check number of reconstructed energy bins of RMF') + # Check results of second observation + self.test_value(res[1].on_spec().ebounds().emin().TeV(), 1.0, + 'Check minimum energy of On spectrum') + self.test_value(res[1].on_spec().ebounds().emax().TeV(), 10.0, + 'Check maximum energy of On spectrum') + self.test_value(res[1].on_spec().ebounds().size(), 5, + 'Check number of energy bins of On spectrum') + self.test_value(res[1].on_spec().counts(), 22, + 'Check number of events in of On spectrum') + self.test_value(res[1].off_spec().ebounds().emin().TeV(), 1.0, + 'Check minimum energy of Off spectrum') + self.test_value(res[1].off_spec().ebounds().emax().TeV(), 10.0, + 'Check maximum energy of Off spectrum') + self.test_value(res[1].off_spec().ebounds().size(), 5, + 'Check number of energy bins of Off spectrum') + self.test_value(res[1].off_spec().counts(), 0, + 'Check number of events in of Off spectrum') + self.test_value(res[1].arf().ebounds().emin().TeV(), 0.5, + 'Check minimum energy of ARF') + self.test_value(res[1].arf().ebounds().emax().TeV(), 12.0, + 'Check maximum energy of ARF') + self.test_value(res[1].arf().ebounds().size(), 41, + 'Check number of energy bins of ARF') + self.test_value(res[1].rmf().etrue().emin().TeV(), 0.5, + 'Check minimum true energy of RMF') + self.test_value(res[1].rmf().etrue().emax().TeV(), 12.0, + 'Check maximum true energy of RMF') + self.test_value(res[1].rmf().etrue().size(), 41, + 'Check number of true energy bins of RMF') + self.test_value(res[1].rmf().emeasured().emin().TeV(), 1.0, + 'Check minimum reconstructed energy of RMF') + self.test_value(res[1].rmf().emeasured().emax().TeV(), 10.0, + 'Check maximum reconstructed energy of RMF') + self.test_value(res[1].rmf().emeasured().size(), 5, + 'Check number of reconstructed energy bins of RMF') + # Return return