Commit adf6ef3aeab7262b8d6aed911fccbe520ad8e3c9
1 parent
cfa7379f
Increase ctools coverage (#1828)
Showing
4 changed files
with
191 additions
and
57 deletions
src/ctobssim/ctobssim.cpp
| ... | ... | @@ -1418,8 +1418,9 @@ void ctobssim::simulate_background(GCTAObservation* obs, |
| 1418 | 1418 | ***************************************************************************/ |
| 1419 | 1419 | void ctobssim::save_fits(void) |
| 1420 | 1420 | { |
| 1421 | - // Save only if event list has not yet been saved and disposed | |
| 1422 | - if (!m_save_and_dispose) { | |
| 1421 | + // Save only if event list has not yet been saved and disposed and if | |
| 1422 | + // there are observations | |
| 1423 | + if (!m_save_and_dispose && m_obs.size() > 0) { | |
| 1423 | 1424 | |
| 1424 | 1425 | // Get output filename |
| 1425 | 1426 | m_outevents = (*this)["outevents"].filename(); | ... | ... |
src/ctselect/ctselect.cpp
| ... | ... | @@ -314,8 +314,7 @@ void ctselect::run(void) |
| 314 | 314 | // Log saved FITS file. |
| 315 | 315 | if (logExplicit()) { |
| 316 | 316 | GFits tmpfile(filename); |
| 317 | - log << std::endl; | |
| 318 | - log.header1("FITS file content of temporary file"); | |
| 317 | + log.header3("FITS file content of temporary file"); | |
| 319 | 318 | log << tmpfile << std::endl; |
| 320 | 319 | tmpfile.close(); |
| 321 | 320 | } |
| ... | ... | @@ -609,6 +608,9 @@ void ctselect::select_events(GCTAObservation* obs, |
| 609 | 608 | const std::string& evtname, |
| 610 | 609 | const std::string& gtiname) |
| 611 | 610 | { |
| 611 | + // Write header into logger | |
| 612 | + log_header3(NORMAL, "Events selection"); | |
| 613 | + | |
| 612 | 614 | // Initialise selection string |
| 613 | 615 | std::string selection; |
| 614 | 616 | |
| ... | ... | @@ -818,9 +820,9 @@ void ctselect::select_events(GCTAObservation* obs, |
| 818 | 820 | log_value(NORMAL, "cfitsio selection", selection); |
| 819 | 821 | |
| 820 | 822 | // Build input filename including selection expression |
| 821 | - std::string expression = filename; | |
| 823 | + std::string expression = filename + "[" + evtname + "]"; | |
| 822 | 824 | if (selection.length() > 0) { |
| 823 | - expression += "["+evtname+"]["+selection+"]"; | |
| 825 | + expression += "["+selection+"]"; | |
| 824 | 826 | } |
| 825 | 827 | |
| 826 | 828 | // Dump FITS filename including selection expression |
| ... | ... | @@ -830,7 +832,7 @@ void ctselect::select_events(GCTAObservation* obs, |
| 830 | 832 | GFits file(expression); |
| 831 | 833 | |
| 832 | 834 | // Log selected FITS file |
| 833 | - log_header1(EXPLICIT, "FITS file content after selection"); | |
| 835 | + log_header3(EXPLICIT, "FITS file content after selection"); | |
| 834 | 836 | log_string(EXPLICIT, file.print(m_chatter)); |
| 835 | 837 | |
| 836 | 838 | // Check if we have an events HDU |
| ... | ... | @@ -864,7 +866,11 @@ void ctselect::select_events(GCTAObservation* obs, |
| 864 | 866 | // Get CTA event list pointer |
| 865 | 867 | list = static_cast<GCTAEventList*>(const_cast<GEvents*>(obs->events())); |
| 866 | 868 | |
| 867 | - // If ROI selection has been applied then set the event list ROI | |
| 869 | + // Make sure that events are fetched since the temporary file will be | |
| 870 | + // closed later | |
| 871 | + list->fetch(); | |
| 872 | + | |
| 873 | + // If RoI selection has been applied then set the event list RoI | |
| 868 | 874 | if (m_select_roi) { |
| 869 | 875 | GCTAInstDir instdir; |
| 870 | 876 | instdir.dir().radec_deg(ra, dec); |
| ... | ... | @@ -872,7 +878,7 @@ void ctselect::select_events(GCTAObservation* obs, |
| 872 | 878 | } // endif: Roi selection was performed |
| 873 | 879 | |
| 874 | 880 | else if (old_roi.is_valid()) { |
| 875 | - // Restore old Roi information in case no selection was performed | |
| 881 | + // Restore old RoI information in case no selection was performed | |
| 876 | 882 | // and RoI was existing before |
| 877 | 883 | list->roi(old_roi); |
| 878 | 884 | } |
| ... | ... | @@ -1178,43 +1184,48 @@ std::string ctselect::get_gtiname(const std::string& filename, |
| 1178 | 1184 | ***************************************************************************/ |
| 1179 | 1185 | void ctselect::save_fits(void) |
| 1180 | 1186 | { |
| 1181 | - // Get output filename | |
| 1182 | - m_outobs = (*this)["outobs"].filename(); | |
| 1187 | + // Save only if there are observations | |
| 1188 | + if (m_obs.size() > 0) { | |
| 1183 | 1189 | |
| 1184 | - // Get CTA observation from observation container | |
| 1185 | - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[0]); | |
| 1190 | + // Get output filename | |
| 1191 | + m_outobs = (*this)["outobs"].filename(); | |
| 1186 | 1192 | |
| 1187 | - // Save only if it's a CTA observation | |
| 1188 | - if (obs != NULL) { | |
| 1193 | + // Get CTA observation from observation container | |
| 1194 | + GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[0]); | |
| 1195 | + | |
| 1196 | + // Save only if it's a CTA observation | |
| 1197 | + if (obs != NULL) { | |
| 1189 | 1198 | |
| 1190 | - // Save only if file name is non-empty | |
| 1191 | - if (m_infiles[0].length() > 0) { | |
| 1199 | + // Save only if file name is non-empty | |
| 1200 | + if (m_infiles[0].length() > 0) { | |
| 1192 | 1201 | |
| 1193 | - // Create file name object | |
| 1194 | - GFilename fname(m_outobs); | |
| 1202 | + // Create file name object | |
| 1203 | + GFilename fname(m_outobs); | |
| 1195 | 1204 | |
| 1196 | - // Extract filename and event extension name | |
| 1197 | - std::string outfile = fname.url(); | |
| 1205 | + // Extract filename and event extension name | |
| 1206 | + std::string outfile = fname.url(); | |
| 1198 | 1207 | |
| 1199 | - // Append event extension name. We handle here the possibility | |
| 1200 | - // to write the events into a different extension. | |
| 1201 | - if (fname.has_extname()) { | |
| 1202 | - outfile += "["+fname.extname()+"]"; | |
| 1203 | - } | |
| 1204 | - else { | |
| 1205 | - outfile += "["+m_evtname[0]+"]"; | |
| 1206 | - } | |
| 1208 | + // Append event extension name. We handle here the possibility | |
| 1209 | + // to write the events into a different extension. | |
| 1210 | + if (fname.has_extname()) { | |
| 1211 | + outfile += "["+fname.extname()+"]"; | |
| 1212 | + } | |
| 1213 | + else { | |
| 1214 | + outfile += "["+m_evtname[0]+"]"; | |
| 1215 | + } | |
| 1216 | + | |
| 1217 | + // Log filename | |
| 1218 | + log_value(NORMAL, "Event list file", outfile); | |
| 1207 | 1219 | |
| 1208 | - // Log filename | |
| 1209 | - log_value(NORMAL, "Event list file", outfile); | |
| 1220 | + // Save event list | |
| 1221 | + save_event_list(obs, m_infiles[0], m_evtname[0], m_gtiname[0], | |
| 1222 | + outfile); | |
| 1210 | 1223 | |
| 1211 | - // Save event list | |
| 1212 | - save_event_list(obs, m_infiles[0], m_evtname[0], m_gtiname[0], | |
| 1213 | - outfile); | |
| 1224 | + } // endif: filename was non empty | |
| 1214 | 1225 | |
| 1215 | - } // endif: filename was non empty | |
| 1226 | + } // endif: observation was CTA observation | |
| 1216 | 1227 | |
| 1217 | - } // endif: observation was CTA observation | |
| 1228 | + } // endif: there were observations | |
| 1218 | 1229 | |
| 1219 | 1230 | // Return |
| 1220 | 1231 | return; | ... | ... |
test/test_ctobssim.py
| ... | ... | @@ -18,6 +18,7 @@ |
| 18 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 19 | 19 | # |
| 20 | 20 | # ========================================================================== |
| 21 | +import os | |
| 21 | 22 | import gammalib |
| 22 | 23 | import ctools |
| 23 | 24 | from cscripts import obsutils |
| ... | ... | @@ -71,7 +72,7 @@ class Test(test): |
| 71 | 72 | |
| 72 | 73 | # Setup ctobssim command |
| 73 | 74 | cmd = ctobssim+' inmodel="'+self._model+'" '+ \ |
| 74 | - ' outevents="events.fits"'+ \ | |
| 75 | + ' outevents="ctobssim_cmd1.fits"'+ \ | |
| 75 | 76 | ' caldb="'+self._caldb+'" irf="'+self._irf+'" '+ \ |
| 76 | 77 | ' ra=83.63 dec=22.01 rad=10.0'+ \ |
| 77 | 78 | ' tmin=0.0 tmax=1800.0 emin=0.1 emax=100.0'+ \ |
| ... | ... | @@ -86,12 +87,12 @@ class Test(test): |
| 86 | 87 | 'Check successful execution from command line') |
| 87 | 88 | |
| 88 | 89 | # Load counts cube and check content. |
| 89 | - evt = gammalib.GCTAEventList('events.fits') | |
| 90 | + evt = gammalib.GCTAEventList('ctobssim_cmd1.fits') | |
| 90 | 91 | self._test_list(evt, 6881) |
| 91 | 92 | |
| 92 | 93 | # Setup ctobssim command |
| 93 | 94 | cmd = ctobssim+' inmodel="model_that_does_not_exist.xml"'+ \ |
| 94 | - ' outevents="events.fits"'+ \ | |
| 95 | + ' outevents="ctobssim_cmd2.fits"'+ \ | |
| 95 | 96 | ' caldb="'+self._caldb+'" irf="'+self._irf+'" '+ \ |
| 96 | 97 | ' ra=83.63 dec=22.01 rad=10.0'+ \ |
| 97 | 98 | ' tmin=0.0 tmax=1800.0 emin=0.1 emax=100.0'+ \ |
| ... | ... | @@ -109,10 +110,26 @@ class Test(test): |
| 109 | 110 | """ |
| 110 | 111 | Test ctobssim from Python |
| 111 | 112 | """ |
| 112 | - # Set-up ctobssim | |
| 113 | + # Allocate ctobssim | |
| 114 | + sim = ctools.ctobssim() | |
| 115 | + | |
| 116 | + # Check that empty ctobssim tool holds an empty observation | |
| 117 | + self.test_value(sim.obs().size(), 0, 'Check number of observations') | |
| 118 | + | |
| 119 | + # Check that saving saves an empty model definition file | |
| 120 | + sim['outevents'] = 'ctobssim_py0.fits' | |
| 121 | + sim['logfile'] = 'ctobssim_py0.log' | |
| 122 | + sim.logFileOpen() | |
| 123 | + sim.save() | |
| 124 | + self.test_assert(not os.path.isfile('ctobssim_py0.fits'), | |
| 125 | + 'Check that no event list has been created') | |
| 126 | + | |
| 127 | + # Check that clearing does not lead to an exception or segfault | |
| 128 | + sim.clear() | |
| 129 | + | |
| 130 | + # Now set ctobssim parameters | |
| 113 | 131 | sim = ctools.ctobssim() |
| 114 | 132 | sim['inmodel'] = self._model |
| 115 | - sim['outevents'] = 'events.fits' | |
| 116 | 133 | sim['caldb'] = self._caldb |
| 117 | 134 | sim['irf'] = self._irf |
| 118 | 135 | sim['ra'] = 83.63 |
| ... | ... | @@ -122,6 +139,7 @@ class Test(test): |
| 122 | 139 | sim['tmax'] = 1800.0 |
| 123 | 140 | sim['emin'] = 0.1 |
| 124 | 141 | sim['emax'] = 100.0 |
| 142 | + sim['outevents'] = 'ctobssim_py1.fits' | |
| 125 | 143 | sim['logfile'] = 'ctobssim_py1.log' |
| 126 | 144 | sim['chatter'] = 2 |
| 127 | 145 | |
| ... | ... | @@ -137,7 +155,7 @@ class Test(test): |
| 137 | 155 | sim.save() |
| 138 | 156 | |
| 139 | 157 | # Load counts cube and check content. |
| 140 | - evt = gammalib.GCTAEventList('events.fits') | |
| 158 | + evt = gammalib.GCTAEventList('ctobssim_py1.fits') | |
| 141 | 159 | self._test_list(evt, 6881) |
| 142 | 160 | |
| 143 | 161 | # Set-up observation container |
| ... | ... | @@ -149,7 +167,7 @@ class Test(test): |
| 149 | 167 | |
| 150 | 168 | # Set-up ctobssim from observation container |
| 151 | 169 | sim = ctools.ctobssim(obs) |
| 152 | - sim['outevents'] = 'sim_events.xml' | |
| 170 | + sim['outevents'] = 'ctobssim_py2.xml' | |
| 153 | 171 | sim['inmodel'] = self._model |
| 154 | 172 | sim['logfile'] = 'ctobssim_py2.log' |
| 155 | 173 | sim['chatter'] = 3 |
| ... | ... | @@ -175,7 +193,7 @@ class Test(test): |
| 175 | 193 | sim.save() |
| 176 | 194 | |
| 177 | 195 | # Load events |
| 178 | - obs = gammalib.GObservations('sim_events.xml') | |
| 196 | + obs = gammalib.GObservations('ctobssim_py2.xml') | |
| 179 | 197 | |
| 180 | 198 | # Retrieve observation and check content |
| 181 | 199 | self._test_list(obs[0].events(), 6003) |
| ... | ... | @@ -186,7 +204,6 @@ class Test(test): |
| 186 | 204 | # Set-up ctobssim with invalid event file |
| 187 | 205 | sim = ctools.ctobssim() |
| 188 | 206 | sim['inmodel'] = 'model_file_that_does_not_exist.xml' |
| 189 | - sim['outevents'] = 'events.fits' | |
| 190 | 207 | sim['caldb'] = self._caldb |
| 191 | 208 | sim['irf'] = self._irf |
| 192 | 209 | sim['ra'] = 83.63 |
| ... | ... | @@ -196,6 +213,7 @@ class Test(test): |
| 196 | 213 | sim['tmax'] = 1800.0 |
| 197 | 214 | sim['emin'] = 0.1 |
| 198 | 215 | sim['emax'] = 100.0 |
| 216 | + sim['outevents'] = 'ctobssim_py3.fits' | |
| 199 | 217 | sim['logfile'] = 'ctobssim_py3.log' |
| 200 | 218 | sim['chatter'] = 4 |
| 201 | 219 | ... | ... |
test/test_ctselect.py
| ... | ... | @@ -18,6 +18,7 @@ |
| 18 | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 19 | 19 | # |
| 20 | 20 | # ========================================================================== |
| 21 | +import os | |
| 21 | 22 | import gammalib |
| 22 | 23 | import ctools |
| 23 | 24 | from testing import test |
| ... | ... | @@ -103,10 +104,26 @@ class Test(test): |
| 103 | 104 | """ |
| 104 | 105 | Test ctselect from Python |
| 105 | 106 | """ |
| 106 | - # Set-up ctselect | |
| 107 | + # Allocate ctselect | |
| 108 | + select = ctools.ctselect() | |
| 109 | + | |
| 110 | + # Check that empty ctselect tool holds an empty observation | |
| 111 | + self._check_obs(select.obs(), nobs=0) | |
| 112 | + | |
| 113 | + # Check that saving does nothing | |
| 114 | + select['outobs'] = 'ctselect_py0.fits' | |
| 115 | + select['logfile'] = 'ctselect_py0.log' | |
| 116 | + select.logFileOpen() | |
| 117 | + select.save() | |
| 118 | + self.test_assert(not os.path.isfile('ctselect_py0.fits'), | |
| 119 | + 'Check that no event list has been created') | |
| 120 | + | |
| 121 | + # Check that clearing does not lead to an exception or segfault | |
| 122 | + select.clear() | |
| 123 | + | |
| 124 | + # Now set ctselect parameters | |
| 107 | 125 | select = ctools.ctselect() |
| 108 | 126 | select['inobs'] = self._events |
| 109 | - select['outobs'] = 'ctselect_py1.fits' | |
| 110 | 127 | select['ra'] = 83.63 |
| 111 | 128 | select['dec'] = 22.01 |
| 112 | 129 | select['rad'] = 3 |
| ... | ... | @@ -114,6 +131,7 @@ class Test(test): |
| 114 | 131 | select['tmax'] = 1800 |
| 115 | 132 | select['emin'] = 0.1 |
| 116 | 133 | select['emax'] = 100 |
| 134 | + select['outobs'] = 'ctselect_py1.fits' | |
| 117 | 135 | select['logfile'] = 'ctselect_py1.log' |
| 118 | 136 | select['chatter'] = 2 |
| 119 | 137 | |
| ... | ... | @@ -125,6 +143,49 @@ class Test(test): |
| 125 | 143 | # Check result file |
| 126 | 144 | self._check_result_file('ctselect_py1.fits') |
| 127 | 145 | |
| 146 | + # Copy ctselect tool | |
| 147 | + cpy_select = select.copy() | |
| 148 | + | |
| 149 | + # Check observation of ctselect copy | |
| 150 | + self._check_obs(cpy_select.obs()) | |
| 151 | + | |
| 152 | + # Execute copy of ctselect tool again, now with a higher chatter | |
| 153 | + # level than before and without any selection | |
| 154 | + cpy_select['ra'] = 'NONE' | |
| 155 | + cpy_select['dec'] = 'NONE' | |
| 156 | + cpy_select['rad'] = 'NONE' | |
| 157 | + cpy_select['tmin'] = 'NONE' | |
| 158 | + cpy_select['tmax'] = 'NONE' | |
| 159 | + cpy_select['emin'] = 'NONE' | |
| 160 | + cpy_select['emax'] = 'NONE' | |
| 161 | + cpy_select['outobs'] = 'ctselect_py2.fits' | |
| 162 | + cpy_select['logfile'] = 'ctselect_py2.log' | |
| 163 | + cpy_select['chatter'] = 3 | |
| 164 | + cpy_select.logFileOpen() # Needed to get a new log file | |
| 165 | + cpy_select.execute() | |
| 166 | + | |
| 167 | + # Check result file | |
| 168 | + self._check_result_file('ctselect_py2.fits') | |
| 169 | + print('Step3') | |
| 170 | + | |
| 171 | + # Execute again the copy of ctselect tool again, now using the pointing | |
| 172 | + # information in the input observation | |
| 173 | + cpy_select['usepnt'] = True | |
| 174 | + cpy_select['outobs'] = 'ctselect_py3.fits' | |
| 175 | + cpy_select['logfile'] = 'ctselect_py3.log' | |
| 176 | + cpy_select['chatter'] = 4 | |
| 177 | + cpy_select.logFileOpen() # Needed to get a new log file | |
| 178 | + cpy_select.execute() | |
| 179 | + | |
| 180 | + # Check result file | |
| 181 | + self._check_result_file('ctselect_py3.fits') | |
| 182 | + | |
| 183 | + # Now clear copy of ctselect tool | |
| 184 | + cpy_select.clear() | |
| 185 | + | |
| 186 | + # Check that cleared ctselect tool holds no observations and events | |
| 187 | + self._check_obs(cpy_select.obs(), nobs=0) | |
| 188 | + | |
| 128 | 189 | # Return |
| 129 | 190 | return |
| 130 | 191 | |
| ... | ... | @@ -134,16 +195,59 @@ class Test(test): |
| 134 | 195 | Check result file |
| 135 | 196 | """ |
| 136 | 197 | # Open result file |
| 137 | - result = gammalib.GCTAEventList(filename) | |
| 138 | - | |
| 139 | - # Check file | |
| 140 | - self.test_value(result.size(), 6127, 'Check for 6127 events') | |
| 141 | - self.test_value(result.roi().centre().dir().ra_deg(), 83.63, 1.0e-6, | |
| 142 | - 'Check for ROI Right Ascension') | |
| 143 | - self.test_value(result.roi().centre().dir().dec_deg(), 22.01, 1.0e-6, | |
| 144 | - 'Check for ROI Declination') | |
| 145 | - self.test_value(result.roi().radius(), 3.0, 1.0e-6, | |
| 146 | - 'Check for ROI Radius') | |
| 198 | + events = gammalib.GCTAEventList(filename) | |
| 199 | + | |
| 200 | + # Check event list | |
| 201 | + self._check_events(events, nevents=6127) | |
| 202 | + | |
| 203 | + # Return | |
| 204 | + return | |
| 205 | + | |
| 206 | + # Check observation and event list | |
| 207 | + def _check_obs(self, obs, nobs=1, nevents=6127): | |
| 208 | + """ | |
| 209 | + Check observation and event list | |
| 210 | + | |
| 211 | + Parameters | |
| 212 | + ---------- | |
| 213 | + obs : `~gammalib.GObservations` | |
| 214 | + Models | |
| 215 | + nobs : int, optional | |
| 216 | + Expected number of observations | |
| 217 | + nevents : int, optional | |
| 218 | + Expected number of events | |
| 219 | + """ | |
| 220 | + # Check number of observations | |
| 221 | + self.test_value(obs.size(), nobs, 'Check number of observations') | |
| 222 | + | |
| 223 | + # If there is an observation then check the event list of the first | |
| 224 | + # one | |
| 225 | + if obs.size() > 0: | |
| 226 | + self._check_events(obs[0].events(), nevents=nevents) | |
| 227 | + | |
| 228 | + # Return | |
| 229 | + return | |
| 230 | + | |
| 231 | + # Check events | |
| 232 | + def _check_events(self, events, nevents=6127): | |
| 233 | + """ | |
| 234 | + Check event list | |
| 235 | + | |
| 236 | + Parameters | |
| 237 | + ---------- | |
| 238 | + events : `~gammalib.GCTAEventList` | |
| 239 | + Event list | |
| 240 | + nevents : int, optional | |
| 241 | + Expected number of events | |
| 242 | + """ | |
| 243 | + # Check event list | |
| 244 | + self.test_value(events.size(), nevents, 'Check number of events') | |
| 245 | + self.test_value(events.roi().centre().dir().ra_deg(), 83.63, 1.0e-6, | |
| 246 | + 'Check for RoI centre Right Ascension') | |
| 247 | + self.test_value(events.roi().centre().dir().dec_deg(), 22.01, 1.0e-6, | |
| 248 | + 'Check for RoI centre Declination') | |
| 249 | + self.test_value(events.roi().radius(), 3.0, 1.0e-6, | |
| 250 | + 'Check for RoI radius') | |
| 147 | 251 | |
| 148 | 252 | # Return |
| 149 | 253 | return | ... | ... |