Commit cfa7379fa139515e72e707a703b2d574cc4794b7
1 parent
1e00ea3d
Increase ctool branch coverage (#1828)
Showing
12 changed files
with
404 additions
and
122 deletions
src/cterror/cterror.cpp
| @@ -250,85 +250,80 @@ void cterror::run(void) | @@ -250,85 +250,80 @@ void cterror::run(void) | ||
| 250 | log_value(NORMAL, "Maximum log likelihood", gammalib::str(m_best_logL,3)); | 250 | log_value(NORMAL, "Maximum log likelihood", gammalib::str(m_best_logL,3)); |
| 251 | log_string(NORMAL, m_obs.models().print(m_chatter)); | 251 | log_string(NORMAL, m_obs.models().print(m_chatter)); |
| 252 | 252 | ||
| 253 | - // Continue only if source model exists | ||
| 254 | - if (m_obs.models().contains(m_srcname)) { | 253 | + // Save best fitting models |
| 254 | + GModels models_best = m_obs.models(); | ||
| 255 | 255 | ||
| 256 | - // Save best fitting models | ||
| 257 | - GModels models_best = m_obs.models(); | 256 | + // Get pointer on model |
| 257 | + GModel* model = models_best[m_srcname]; | ||
| 258 | 258 | ||
| 259 | - // Get pointer on model | ||
| 260 | - GModel* model = models_best[m_srcname]; | 259 | + // Get number of parameters |
| 260 | + int npars = model->size(); | ||
| 261 | 261 | ||
| 262 | - // Get number of parameters | ||
| 263 | - int npars = model->size(); | 262 | + // Loop over parameters of sky model |
| 263 | + for (int i = 0; i < npars; ++i) { | ||
| 264 | 264 | ||
| 265 | - // Loop over parameters of sky model | ||
| 266 | - for (int i = 0; i < npars; ++i) { | ||
| 267 | - | ||
| 268 | - // Skip parameter if it is fixed | ||
| 269 | - if (model->at(i).is_fixed()) { | ||
| 270 | - continue; | ||
| 271 | - } | 265 | + // Skip parameter if it is fixed |
| 266 | + if (model->at(i).is_fixed()) { | ||
| 267 | + continue; | ||
| 268 | + } | ||
| 272 | 269 | ||
| 273 | - // Initialise with best fitting models | ||
| 274 | - m_obs.models(models_best); | ||
| 275 | - | ||
| 276 | - // Get pointer on model parameter | ||
| 277 | - GModels& current_models = const_cast<GModels&>(m_obs.models()); | ||
| 278 | - m_model_par = &(current_models[m_srcname]->at(i)); | ||
| 279 | - | ||
| 280 | - // Extract current value | ||
| 281 | - m_value = m_model_par->factor_value(); | ||
| 282 | - | ||
| 283 | - // Compute parameter bracketing | ||
| 284 | - double parmin = std::max(m_model_par->factor_min(), | ||
| 285 | - m_value - 10.0*m_model_par->factor_error()); | ||
| 286 | - double parmax = std::min(m_model_par->factor_max(), | ||
| 287 | - m_value + 10.0*m_model_par->factor_error()); | ||
| 288 | - | ||
| 289 | - // Write header and initial parameters into logger | ||
| 290 | - log_header1(TERSE, "Compute error for source \""+m_srcname+"\"" | ||
| 291 | - " parameter \""+m_model_par->name()+"\""); | ||
| 292 | - log_value(NORMAL, "Confidence level", | ||
| 293 | - gammalib::str(m_confidence*100.0)+" %"); | ||
| 294 | - log_value(NORMAL, "Log-likelihood difference", m_dlogL); | ||
| 295 | - log_value(NORMAL, "Initial factor range", | ||
| 296 | - "["+gammalib::str(parmin)+", "+gammalib::str(parmax)+"]"); | ||
| 297 | - | ||
| 298 | - // Compute lower and upper boundaries | ||
| 299 | - double value_lo = error_bisection(parmin, m_value); | ||
| 300 | - double value_hi = error_bisection(m_value, parmax); | ||
| 301 | - | ||
| 302 | - // Compute errors | ||
| 303 | - double error = 0.5 * (value_hi - value_lo); | ||
| 304 | - double error_neg = m_value - value_lo; | ||
| 305 | - double error_pos = value_hi - m_value; | ||
| 306 | - double error_value = std::abs(error*m_model_par->scale()); | ||
| 307 | - double error_value_neg = std::abs(error_neg*m_model_par->scale()); | ||
| 308 | - double error_value_pos = std::abs(error_pos*m_model_par->scale()); | ||
| 309 | - | ||
| 310 | - // Write results into logger | ||
| 311 | - std::string unit = " " + m_model_par->unit(); | ||
| 312 | - log_value(NORMAL, "Lower parameter factor", value_lo); | ||
| 313 | - log_value(NORMAL, "Upper parameter factor", value_hi); | ||
| 314 | - log_value(NORMAL, "Error from curvature", | ||
| 315 | - gammalib::str(m_model_par->error()) + unit); | ||
| 316 | - log_value(NORMAL, "Error from profile", | ||
| 317 | - gammalib::str(error_value) + unit); | ||
| 318 | - log_value(NORMAL, "Negative profile error", | ||
| 319 | - gammalib::str(error_value_neg) + unit); | ||
| 320 | - log_value(NORMAL, "Positive profile error", | ||
| 321 | - gammalib::str(error_value_pos) + unit); | ||
| 322 | - | ||
| 323 | - // Save error result | ||
| 324 | - model->at(i).factor_error(error); | ||
| 325 | - | ||
| 326 | - } // endfor: looped over spectral parameters | ||
| 327 | - | ||
| 328 | - // Restore best fitting models (now with new errors computed) | 270 | + // Initialise with best fitting models |
| 329 | m_obs.models(models_best); | 271 | m_obs.models(models_best); |
| 330 | 272 | ||
| 331 | - } // endif: source model exists | 273 | + // Get pointer on model parameter |
| 274 | + GModels& current_models = const_cast<GModels&>(m_obs.models()); | ||
| 275 | + m_model_par = &(current_models[m_srcname]->at(i)); | ||
| 276 | + | ||
| 277 | + // Extract current value | ||
| 278 | + m_value = m_model_par->factor_value(); | ||
| 279 | + | ||
| 280 | + // Compute parameter bracketing | ||
| 281 | + double parmin = std::max(m_model_par->factor_min(), | ||
| 282 | + m_value - 10.0*m_model_par->factor_error()); | ||
| 283 | + double parmax = std::min(m_model_par->factor_max(), | ||
| 284 | + m_value + 10.0*m_model_par->factor_error()); | ||
| 285 | + | ||
| 286 | + // Write header and initial parameters into logger | ||
| 287 | + log_header1(TERSE, "Compute error for source \""+m_srcname+"\"" | ||
| 288 | + " parameter \""+m_model_par->name()+"\""); | ||
| 289 | + log_value(NORMAL, "Confidence level", | ||
| 290 | + gammalib::str(m_confidence*100.0)+" %"); | ||
| 291 | + log_value(NORMAL, "Log-likelihood difference", m_dlogL); | ||
| 292 | + log_value(NORMAL, "Initial factor range", | ||
| 293 | + "["+gammalib::str(parmin)+", "+gammalib::str(parmax)+"]"); | ||
| 294 | + | ||
| 295 | + // Compute lower and upper boundaries | ||
| 296 | + double value_lo = error_bisection(parmin, m_value); | ||
| 297 | + double value_hi = error_bisection(m_value, parmax); | ||
| 298 | + | ||
| 299 | + // Compute errors | ||
| 300 | + double error = 0.5 * (value_hi - value_lo); | ||
| 301 | + double error_neg = m_value - value_lo; | ||
| 302 | + double error_pos = value_hi - m_value; | ||
| 303 | + double error_value = std::abs(error*m_model_par->scale()); | ||
| 304 | + double error_value_neg = std::abs(error_neg*m_model_par->scale()); | ||
| 305 | + double error_value_pos = std::abs(error_pos*m_model_par->scale()); | ||
| 306 | + | ||
| 307 | + // Write results into logger | ||
| 308 | + std::string unit = " " + m_model_par->unit(); | ||
| 309 | + log_value(NORMAL, "Lower parameter factor", value_lo); | ||
| 310 | + log_value(NORMAL, "Upper parameter factor", value_hi); | ||
| 311 | + log_value(NORMAL, "Error from curvature", | ||
| 312 | + gammalib::str(m_model_par->error()) + unit); | ||
| 313 | + log_value(NORMAL, "Error from profile", | ||
| 314 | + gammalib::str(error_value) + unit); | ||
| 315 | + log_value(NORMAL, "Negative profile error", | ||
| 316 | + gammalib::str(error_value_neg) + unit); | ||
| 317 | + log_value(NORMAL, "Positive profile error", | ||
| 318 | + gammalib::str(error_value_pos) + unit); | ||
| 319 | + | ||
| 320 | + // Save error result | ||
| 321 | + model->at(i).factor_error(error); | ||
| 322 | + | ||
| 323 | + } // endfor: looped over spectral parameters | ||
| 324 | + | ||
| 325 | + // Restore best fitting models (now with new errors computed) | ||
| 326 | + m_obs.models(models_best); | ||
| 332 | 327 | ||
| 333 | // Recover optimizer | 328 | // Recover optimizer |
| 334 | m_opt = best_opt; | 329 | m_opt = best_opt; |
src/cterror/cterror.par
| @@ -35,7 +35,7 @@ outmodel, f, a, "results.xml",,, "Output model XML file" | @@ -35,7 +35,7 @@ outmodel, f, a, "results.xml",,, "Output model XML file" | ||
| 35 | #============================= | 35 | #============================= |
| 36 | confidence, r, h, 0.68,0.0,1.0, "Confidence level" | 36 | confidence, r, h, 0.68,0.0,1.0, "Confidence level" |
| 37 | tol, r, h, 1e-3,,, "Computation tolerance" | 37 | tol, r, h, 1e-3,,, "Computation tolerance" |
| 38 | -max_iter, i, h, 50,,, "Maximum number of iterations" | 38 | +max_iter, i, h, 50,1,1000, "Maximum number of iterations" |
| 39 | 39 | ||
| 40 | # | 40 | # |
| 41 | # Standard parameters | 41 | # Standard parameters |
src/ctulimit/ctulimit.cpp
| @@ -228,17 +228,9 @@ void ctulimit::run(void) | @@ -228,17 +228,9 @@ void ctulimit::run(void) | ||
| 228 | // Get task parameters | 228 | // Get task parameters |
| 229 | get_parameters(); | 229 | get_parameters(); |
| 230 | 230 | ||
| 231 | - // Set energy dispersion flag for all CTA observations and save old | 231 | + // Set energy dispersion flags of all CTA observations and save old |
| 232 | // values in save_edisp vector | 232 | // values in save_edisp vector |
| 233 | - std::vector<bool> save_edisp; | ||
| 234 | - save_edisp.assign(m_obs.size(), false); | ||
| 235 | - for (int i = 0; i < m_obs.size(); ++i) { | ||
| 236 | - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]); | ||
| 237 | - if (obs != NULL) { | ||
| 238 | - save_edisp[i] = obs->response()->apply_edisp(); | ||
| 239 | - obs->response()->apply_edisp(m_apply_edisp); | ||
| 240 | - } | ||
| 241 | - } | 233 | + std::vector<bool> save_edisp = set_edisp(m_obs, m_apply_edisp); |
| 242 | 234 | ||
| 243 | // Write input observation container into logger | 235 | // Write input observation container into logger |
| 244 | log_observations(NORMAL, m_obs, "Input observation"); | 236 | log_observations(NORMAL, m_obs, "Input observation"); |
| @@ -338,13 +330,8 @@ void ctulimit::run(void) | @@ -338,13 +330,8 @@ void ctulimit::run(void) | ||
| 338 | // Recover optimizer | 330 | // Recover optimizer |
| 339 | m_opt = best_opt; | 331 | m_opt = best_opt; |
| 340 | 332 | ||
| 341 | - // Restore energy dispersion flag for all CTA observations | ||
| 342 | - for (int i = 0; i < m_obs.size(); ++i) { | ||
| 343 | - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]); | ||
| 344 | - if (obs != NULL) { | ||
| 345 | - obs->response()->apply_edisp(save_edisp[i]); | ||
| 346 | - } | ||
| 347 | - } | 333 | + // Restore energy dispersion flags of all CTA observations |
| 334 | + restore_edisp(m_obs, save_edisp); | ||
| 348 | 335 | ||
| 349 | // Return | 336 | // Return |
| 350 | return; | 337 | return; |
test/test_ctedispcube.py
| @@ -206,6 +206,7 @@ class Test(test): | @@ -206,6 +206,7 @@ class Test(test): | ||
| 206 | edispcube['yref'] = 22.01 | 206 | edispcube['yref'] = 22.01 |
| 207 | edispcube['migramax'] = 2.0 | 207 | edispcube['migramax'] = 2.0 |
| 208 | edispcube['migrabins'] = 10 | 208 | edispcube['migrabins'] = 10 |
| 209 | + edispcube['addbounds'] = True | ||
| 209 | edispcube['outcube'] = 'ctedispcube_py3.fits' | 210 | edispcube['outcube'] = 'ctedispcube_py3.fits' |
| 210 | edispcube['logfile'] = 'ctedispcube_py3.log' | 211 | edispcube['logfile'] = 'ctedispcube_py3.log' |
| 211 | edispcube['chatter'] = 4 | 212 | edispcube['chatter'] = 4 |
test/test_cterror.py
| @@ -161,6 +161,41 @@ class Test(test): | @@ -161,6 +161,41 @@ class Test(test): | ||
| 161 | # Check that the cleared copy has also cleared the observations | 161 | # Check that the cleared copy has also cleared the observations |
| 162 | self._check_obs(cpy_error.obs(), nobs=0, nmodels=0) | 162 | self._check_obs(cpy_error.obs(), nobs=0, nmodels=0) |
| 163 | 163 | ||
| 164 | + # Prepare observation container with a single event list | ||
| 165 | + obs = gammalib.GObservations() | ||
| 166 | + obs.append(gammalib.GCTAObservation(self._events)) | ||
| 167 | + obs.models(gammalib.GModels(self._model)) | ||
| 168 | + | ||
| 169 | + # Setup cterror tool from observation container | ||
| 170 | + error = ctools.cterror(obs) | ||
| 171 | + error['srcname'] = 'Crab' | ||
| 172 | + error['caldb'] = self._caldb | ||
| 173 | + error['irf'] = self._irf | ||
| 174 | + error['outmodel'] = 'cterror_py3.xml' | ||
| 175 | + error['logfile'] = 'cterror_py3.log' | ||
| 176 | + error['chatter'] = 4 | ||
| 177 | + | ||
| 178 | + # Execute cterror tool | ||
| 179 | + error.logFileOpen() # Make sure we get a log file | ||
| 180 | + error.execute() | ||
| 181 | + | ||
| 182 | + # Check result file | ||
| 183 | + self._check_result_file('cterror_py3.xml') | ||
| 184 | + | ||
| 185 | + # And now a run with not enough iterations | ||
| 186 | + error['max_iter'] = 1 | ||
| 187 | + error['outmodel'] = 'cterror_py4.xml' | ||
| 188 | + error['logfile'] = 'cterror_py4.log' | ||
| 189 | + | ||
| 190 | + # Execute cterror tool and catch the exception | ||
| 191 | + error.logFileOpen() # Make sure we get a log file | ||
| 192 | + self.test_try('Test cterror with not enough iterations') | ||
| 193 | + try: | ||
| 194 | + error.execute() | ||
| 195 | + self.test_try_failure('Exception not thrown') | ||
| 196 | + except ValueError: | ||
| 197 | + self.test_try_success() | ||
| 198 | + | ||
| 164 | # Return | 199 | # Return |
| 165 | return | 200 | return |
| 166 | 201 |
test/test_ctlike.py
| @@ -160,6 +160,32 @@ class Test(test): | @@ -160,6 +160,32 @@ class Test(test): | ||
| 160 | # Check that the cleared copy has also cleared the observations | 160 | # Check that the cleared copy has also cleared the observations |
| 161 | self._check_obs(cpy_like.obs(), nobs=0, nmodels=0) | 161 | self._check_obs(cpy_like.obs(), nobs=0, nmodels=0) |
| 162 | 162 | ||
| 163 | + # Prepare observation container with a single event list | ||
| 164 | + obs = gammalib.GObservations() | ||
| 165 | + obs.append(gammalib.GCTAObservation(self._events)) | ||
| 166 | + | ||
| 167 | + # Prepare a special model to enforce TS computation | ||
| 168 | + models = gammalib.GModels(self._model) | ||
| 169 | + models['Crab'].tscalc(True) | ||
| 170 | + obs.models(models) | ||
| 171 | + | ||
| 172 | + # Allocate ctlike tool from observation container | ||
| 173 | + like = ctools.ctlike(obs) | ||
| 174 | + like['caldb'] = self._caldb | ||
| 175 | + like['irf'] = self._irf | ||
| 176 | + like['refit'] = True | ||
| 177 | + like['fix_spat_for_ts'] = True | ||
| 178 | + like['outmodel'] = 'ctlike_py3.xml' | ||
| 179 | + like['logfile'] = 'ctlike_py3.log' | ||
| 180 | + like['chatter'] = 4 | ||
| 181 | + | ||
| 182 | + # Execute ctlike | ||
| 183 | + like.logFileOpen() # Needed to get a new log file | ||
| 184 | + like.execute() | ||
| 185 | + | ||
| 186 | + # Check result file | ||
| 187 | + self._check_result_file('ctlike_py3.xml') | ||
| 188 | + | ||
| 163 | # Return | 189 | # Return |
| 164 | return | 190 | return |
| 165 | 191 |
test/test_ctmapcube.py
| @@ -177,6 +177,36 @@ class Test(test): | @@ -177,6 +177,36 @@ class Test(test): | ||
| 177 | # Check that the cleared copy has also cleared the map cube | 177 | # Check that the cleared copy has also cleared the map cube |
| 178 | self._check_cube(cpy_mapcube.mapcube(), nmaps=0, npixels=0) | 178 | self._check_cube(cpy_mapcube.mapcube(), nmaps=0, npixels=0) |
| 179 | 179 | ||
| 180 | + # Allocate ctmapcube tools, set models and do now a linear | ||
| 181 | + # binning; also do not use Gaussian point sources | ||
| 182 | + mapcube = ctools.ctmapcube() | ||
| 183 | + mapcube.models(gammalib.GModels(self._model)) | ||
| 184 | + mapcube['ebinalg'] = 'LIN' | ||
| 185 | + mapcube['emin'] = 0.1 | ||
| 186 | + mapcube['emax'] = 100.0 | ||
| 187 | + mapcube['enumbins'] = 10 | ||
| 188 | + mapcube['nxpix'] = 100 | ||
| 189 | + mapcube['nypix'] = 100 | ||
| 190 | + mapcube['binsz'] = 0.04 | ||
| 191 | + mapcube['coordsys'] = 'CEL' | ||
| 192 | + mapcube['proj'] = 'CAR' | ||
| 193 | + mapcube['xref'] = 83.63 | ||
| 194 | + mapcube['yref'] = 22.01 | ||
| 195 | + mapcube['ptsrcsig'] = 0.0 | ||
| 196 | + mapcube['outcube'] = 'ctmapcube_py3.fits' | ||
| 197 | + mapcube['logfile'] = 'ctmapcube_py3.log' | ||
| 198 | + mapcube['chatter'] = 4 | ||
| 199 | + | ||
| 200 | + # Execute mapcube | ||
| 201 | + mapcube.logFileOpen() # Needed to get a new log file | ||
| 202 | + mapcube.execute() | ||
| 203 | + | ||
| 204 | + # Check result file | ||
| 205 | + self._check_result_file('ctmapcube_py3.fits') | ||
| 206 | + | ||
| 207 | + # Publish with a name | ||
| 208 | + mapcube.publish('My map cube') | ||
| 209 | + | ||
| 180 | # Return | 210 | # Return |
| 181 | return | 211 | return |
| 182 | 212 |
test/test_ctmodel.py
| @@ -189,11 +189,38 @@ class Test(test): | @@ -189,11 +189,38 @@ class Test(test): | ||
| 189 | # Check that the cleared copy has also cleared the model cube | 189 | # Check that the cleared copy has also cleared the model cube |
| 190 | self._check_cube(cpy_model.cube(), nx=0, ny=0, nebins=0) | 190 | self._check_cube(cpy_model.cube(), nx=0, ny=0, nebins=0) |
| 191 | 191 | ||
| 192 | + # Get mixed observation container | ||
| 193 | + obs = self._obs_mixed() | ||
| 194 | + | ||
| 195 | + # Setup ctmodel tool from observation container and get model cube | ||
| 196 | + # definition from counts cube | ||
| 197 | + model = ctools.ctmodel(obs) | ||
| 198 | + model.models(gammalib.GModels(self._model)) | ||
| 199 | + model['incube'] = self._cntcube | ||
| 200 | + model['expcube'] = 'NONE' | ||
| 201 | + model['psfcube'] = 'NONE' | ||
| 202 | + model['bkgcube'] = 'NONE' | ||
| 203 | + model['caldb'] = self._caldb | ||
| 204 | + model['irf'] = self._irf | ||
| 205 | + model['outcube'] = 'ctmodel_py3.fits' | ||
| 206 | + model['logfile'] = 'ctmodel_py3.log' | ||
| 207 | + model['chatter'] = 4 | ||
| 208 | + | ||
| 209 | + # Execute ctmodel tool | ||
| 210 | + model.logFileOpen() # Needed to get a new log file | ||
| 211 | + model.execute() | ||
| 212 | + | ||
| 213 | + # Check result file | ||
| 214 | + self._check_result_file('ctmodel_py3.fits', nx=200, ny=200, nebins=20) | ||
| 215 | + | ||
| 216 | + # Publish with name | ||
| 217 | + model.publish('My model') | ||
| 218 | + | ||
| 192 | # Return | 219 | # Return |
| 193 | return | 220 | return |
| 194 | 221 | ||
| 195 | # Check result file | 222 | # Check result file |
| 196 | - def _check_result_file(self, filename): | 223 | + def _check_result_file(self, filename, nx=40, ny=40, nebins=10): |
| 197 | """ | 224 | """ |
| 198 | Check result file | 225 | Check result file |
| 199 | 226 | ||
| @@ -201,12 +228,18 @@ class Test(test): | @@ -201,12 +228,18 @@ class Test(test): | ||
| 201 | ---------- | 228 | ---------- |
| 202 | filename : str | 229 | filename : str |
| 203 | Model cube file name | 230 | Model cube file name |
| 231 | + nx : int, optional | ||
| 232 | + Number of pixels in X direction | ||
| 233 | + ny : int, optional | ||
| 234 | + Number of pixels in Y direction | ||
| 235 | + nebins : int, optional | ||
| 236 | + Number of energy bins | ||
| 204 | """ | 237 | """ |
| 205 | # Open result file | 238 | # Open result file |
| 206 | cube = gammalib.GCTAEventCube(filename) | 239 | cube = gammalib.GCTAEventCube(filename) |
| 207 | 240 | ||
| 208 | # Check cube | 241 | # Check cube |
| 209 | - self._check_cube(cube) | 242 | + self._check_cube(cube, nx=nx, ny=ny, nebins=nebins) |
| 210 | 243 | ||
| 211 | # Return | 244 | # Return |
| 212 | return | 245 | return |
test/test_ctobssim.py
| @@ -154,6 +154,12 @@ class Test(test): | @@ -154,6 +154,12 @@ class Test(test): | ||
| 154 | sim['logfile'] = 'ctobssim_py2.log' | 154 | sim['logfile'] = 'ctobssim_py2.log' |
| 155 | sim['chatter'] = 3 | 155 | sim['chatter'] = 3 |
| 156 | 156 | ||
| 157 | + # Double maximum event range | ||
| 158 | + max_rate = sim.max_rate() | ||
| 159 | + sim.max_rate(2*max_rate) | ||
| 160 | + self.test_value(sim.max_rate(), 2*max_rate, 1.0e-3, | ||
| 161 | + 'Check setting of maximum event rate') | ||
| 162 | + | ||
| 157 | # Run tool | 163 | # Run tool |
| 158 | sim.logFileOpen() | 164 | sim.logFileOpen() |
| 159 | sim.run() | 165 | sim.run() |
test/test_ctpsfcube.py
| @@ -187,27 +187,29 @@ class Test(test): | @@ -187,27 +187,29 @@ class Test(test): | ||
| 187 | # Get mixed observation container | 187 | # Get mixed observation container |
| 188 | obs = self._obs_mixed() | 188 | obs = self._obs_mixed() |
| 189 | 189 | ||
| 190 | - # Set-up ctpsfcube from observation container | 190 | + # Set-up ctpsfcube from observation container and input counts |
| 191 | + # cube | ||
| 191 | psfcube = ctools.ctpsfcube(obs) | 192 | psfcube = ctools.ctpsfcube(obs) |
| 192 | - psfcube['incube'] = 'NONE' | ||
| 193 | - psfcube['caldb'] = self._caldb | ||
| 194 | - psfcube['irf'] = self._irf | ||
| 195 | - psfcube['ebinalg'] = 'LOG' | ||
| 196 | - psfcube['emin'] = 0.1 | ||
| 197 | - psfcube['emax'] = 100 | ||
| 198 | - psfcube['enumbins'] = 20 | ||
| 199 | - psfcube['nxpix'] = 10 | ||
| 200 | - psfcube['nypix'] = 10 | ||
| 201 | - psfcube['binsz'] = 0.4 | ||
| 202 | - psfcube['coordsys'] = 'CEL' | ||
| 203 | - psfcube['proj'] = 'CAR' | ||
| 204 | - psfcube['xref'] = 83.63 | ||
| 205 | - psfcube['yref'] = 22.01 | ||
| 206 | - psfcube['amax'] = 0.3 | ||
| 207 | - psfcube['anumbins'] = 10 | ||
| 208 | - psfcube['outcube'] = 'ctpsfcube_py3.fits' | ||
| 209 | - psfcube['logfile'] = 'ctpsfcube_py3.log' | ||
| 210 | - psfcube['chatter'] = 4 | 193 | + psfcube['incube'] = self._cntcube |
| 194 | + psfcube['caldb'] = self._caldb | ||
| 195 | + psfcube['irf'] = self._irf | ||
| 196 | + #psfcube['ebinalg'] = 'LOG' | ||
| 197 | + #psfcube['emin'] = 0.1 | ||
| 198 | + #psfcube['emax'] = 100 | ||
| 199 | + #psfcube['enumbins'] = 20 | ||
| 200 | + #psfcube['nxpix'] = 10 | ||
| 201 | + #psfcube['nypix'] = 10 | ||
| 202 | + #psfcube['binsz'] = 0.4 | ||
| 203 | + #psfcube['coordsys'] = 'CEL' | ||
| 204 | + #psfcube['proj'] = 'CAR' | ||
| 205 | + #psfcube['xref'] = 83.63 | ||
| 206 | + #psfcube['yref'] = 22.01 | ||
| 207 | + psfcube['amax'] = 0.3 | ||
| 208 | + psfcube['anumbins'] = 10 | ||
| 209 | + psfcube['addbounds'] = True | ||
| 210 | + psfcube['outcube'] = 'ctpsfcube_py3.fits' | ||
| 211 | + psfcube['logfile'] = 'ctpsfcube_py3.log' | ||
| 212 | + psfcube['chatter'] = 4 | ||
| 211 | 213 | ||
| 212 | # Execute ctpsfcube tool | 214 | # Execute ctpsfcube tool |
| 213 | psfcube.logFileOpen() # Make sure we get a log file | 215 | psfcube.logFileOpen() # Make sure we get a log file |
test/test_ctskymap.py
| @@ -18,6 +18,7 @@ | @@ -18,6 +18,7 @@ | ||
| 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 19 | # | 19 | # |
| 20 | # ========================================================================== | 20 | # ========================================================================== |
| 21 | +import os | ||
| 21 | import gammalib | 22 | import gammalib |
| 22 | import ctools | 23 | import ctools |
| 23 | from testing import test | 24 | from testing import test |
| @@ -103,10 +104,25 @@ class Test(test): | @@ -103,10 +104,25 @@ class Test(test): | ||
| 103 | """ | 104 | """ |
| 104 | Test ctskymap from Python | 105 | Test ctskymap from Python |
| 105 | """ | 106 | """ |
| 106 | - # Set-up ctskymap | 107 | + # Allocate ctskymap |
| 107 | skymap = ctools.ctskymap() | 108 | skymap = ctools.ctskymap() |
| 109 | + | ||
| 110 | + # Check that empty ctskymap tool holds a map that has no pixels | ||
| 111 | + self._check_map(skymap.map(), nx=0, ny=0) | ||
| 112 | + | ||
| 113 | + # Check that saving does not nothing | ||
| 114 | + skymap['outmap'] = 'ctskymap_py0.fits' | ||
| 115 | + skymap['logfile'] = 'ctskymap_py0.log' | ||
| 116 | + skymap.logFileOpen() | ||
| 117 | + skymap.save() | ||
| 118 | + self.test_assert(not os.path.isfile('ctskymap_py0.fits'), | ||
| 119 | + 'Check that no sky map has been created') | ||
| 120 | + | ||
| 121 | + # Check that clearing does not lead to an exception or segfault | ||
| 122 | + skymap.clear() | ||
| 123 | + | ||
| 124 | + # Now set ctskymap parameters | ||
| 108 | skymap['inobs'] = self._events | 125 | skymap['inobs'] = self._events |
| 109 | - skymap['outmap'] = 'ctskymap_py1.fits' | ||
| 110 | skymap['emin'] = 0.1 | 126 | skymap['emin'] = 0.1 |
| 111 | skymap['emax'] = 100 | 127 | skymap['emax'] = 100 |
| 112 | skymap['nxpix'] = 200 | 128 | skymap['nxpix'] = 200 |
| @@ -116,6 +132,7 @@ class Test(test): | @@ -116,6 +132,7 @@ class Test(test): | ||
| 116 | skymap['proj'] = 'CAR' | 132 | skymap['proj'] = 'CAR' |
| 117 | skymap['xref'] = 83.63 | 133 | skymap['xref'] = 83.63 |
| 118 | skymap['yref'] = 22.01 | 134 | skymap['yref'] = 22.01 |
| 135 | + skymap['outmap'] = 'ctskymap_py1.fits' | ||
| 119 | skymap['logfile'] = 'ctskymap_py1.log' | 136 | skymap['logfile'] = 'ctskymap_py1.log' |
| 120 | skymap['chatter'] = 2 | 137 | skymap['chatter'] = 2 |
| 121 | 138 | ||
| @@ -127,21 +144,111 @@ class Test(test): | @@ -127,21 +144,111 @@ class Test(test): | ||
| 127 | # Check result file | 144 | # Check result file |
| 128 | self._check_result_file('ctskymap_py1.fits') | 145 | self._check_result_file('ctskymap_py1.fits') |
| 129 | 146 | ||
| 147 | + # Copy ctskymap tool | ||
| 148 | + cpy_skymap = skymap.copy() | ||
| 149 | + | ||
| 150 | + # Check sky map of ctskymap copy | ||
| 151 | + self._check_map(cpy_skymap.map()) | ||
| 152 | + | ||
| 153 | + # Execute copy of ctskymap tool again, now with a higher chatter | ||
| 154 | + # level than before | ||
| 155 | + cpy_skymap['usepnt'] = True | ||
| 156 | + cpy_skymap['emin'] = 0.2 | ||
| 157 | + cpy_skymap['emax'] = 150.0 | ||
| 158 | + cpy_skymap['outmap'] = 'ctskymap_py2.fits' | ||
| 159 | + cpy_skymap['logfile'] = 'ctskymap_py2.log' | ||
| 160 | + cpy_skymap['publish'] = True | ||
| 161 | + cpy_skymap['chatter'] = 3 | ||
| 162 | + cpy_skymap.logFileOpen() # Needed to get a new log file | ||
| 163 | + cpy_skymap.execute() | ||
| 164 | + | ||
| 165 | + # Check result file | ||
| 166 | + self._check_result_file('ctskymap_py2.fits') | ||
| 167 | + | ||
| 168 | + # Now clear copy of ctskymap tool | ||
| 169 | + cpy_skymap.clear() | ||
| 170 | + | ||
| 171 | + # Check that cleared ctskymap tool holds a map that has no pixels | ||
| 172 | + self._check_map(cpy_skymap.map(), nx=0, ny=0) | ||
| 173 | + | ||
| 174 | + # Get mixed observation container | ||
| 175 | + obs = self._obs_mixed() | ||
| 176 | + | ||
| 177 | + # Allocate ctskymap tool from observation container | ||
| 178 | + skymap = ctools.ctskymap(obs) | ||
| 179 | + skymap['emin'] = 0.1 | ||
| 180 | + skymap['emax'] = 100 | ||
| 181 | + skymap['nxpix'] = 200 | ||
| 182 | + skymap['nypix'] = 200 | ||
| 183 | + skymap['binsz'] = 0.02 | ||
| 184 | + skymap['coordsys'] = 'CEL' | ||
| 185 | + skymap['proj'] = 'CAR' | ||
| 186 | + skymap['xref'] = 83.63 | ||
| 187 | + skymap['yref'] = 22.01 | ||
| 188 | + skymap['outmap'] = 'ctskymap_py3.fits' | ||
| 189 | + skymap['logfile'] = 'ctskymap_py3.log' | ||
| 190 | + skymap['chatter'] = 4 | ||
| 191 | + | ||
| 192 | + # Execute tool | ||
| 193 | + skymap.logFileOpen() # Needed to get a new log file | ||
| 194 | + skymap.execute() | ||
| 195 | + | ||
| 196 | + # Check result file | ||
| 197 | + self._check_result_file('ctskymap_py3.fits') | ||
| 198 | + | ||
| 199 | + # Publish with name | ||
| 200 | + skymap.publish('My sky map') | ||
| 201 | + | ||
| 130 | # Return | 202 | # Return |
| 131 | return | 203 | return |
| 132 | 204 | ||
| 133 | # Check result file | 205 | # Check result file |
| 134 | - def _check_result_file(self, filename): | 206 | + def _check_result_file(self, filename, nx=200, ny=200): |
| 135 | """ | 207 | """ |
| 136 | Check result file | 208 | Check result file |
| 209 | + | ||
| 210 | + Parameters | ||
| 211 | + ---------- | ||
| 212 | + filename : str | ||
| 213 | + Sky map file name | ||
| 214 | + nx : int, optional | ||
| 215 | + Number of X pixels | ||
| 216 | + ny : int, optional | ||
| 217 | + Number of Y pixels | ||
| 137 | """ | 218 | """ |
| 138 | # Open result file | 219 | # Open result file |
| 139 | - result = gammalib.GSkyMap(filename) | 220 | + skymap = gammalib.GSkyMap(filename) |
| 140 | 221 | ||
| 222 | + # Check sky map | ||
| 223 | + self._check_map(skymap, nx=nx, ny=ny) | ||
| 224 | + | ||
| 225 | + # Return | ||
| 226 | + return | ||
| 227 | + | ||
| 228 | + # Check sky map | ||
| 229 | + def _check_map(self, skymap, nx=200, ny=200): | ||
| 230 | + """ | ||
| 231 | + Check sky map | ||
| 232 | + | ||
| 233 | + Parameters | ||
| 234 | + ---------- | ||
| 235 | + skymap : `~gammalib.GSkyMap` | ||
| 236 | + Sky map | ||
| 237 | + nx : int, optional | ||
| 238 | + Number of X pixels | ||
| 239 | + ny : int, optional | ||
| 240 | + Number of Y pixels | ||
| 241 | + """ | ||
| 242 | + # Determine number of maps | ||
| 243 | + if nx > 0 and ny > 0: | ||
| 244 | + nmaps = 1 | ||
| 245 | + else: | ||
| 246 | + nmaps = 0 | ||
| 247 | + | ||
| 141 | # Check dimensions | 248 | # Check dimensions |
| 142 | - self.test_value(result.nmaps(), 1, 'Check for one map') | ||
| 143 | - self.test_value(result.nx(), 200, 'Check for 200 pixels in X') | ||
| 144 | - self.test_value(result.ny(), 200, 'Check for 200 pixels in Y') | 249 | + self.test_value(skymap.nmaps(), nmaps, 'Check number of maps') |
| 250 | + self.test_value(skymap.nx(), nx, 'Check for number of X pixels') | ||
| 251 | + self.test_value(skymap.ny(), ny, 'Check for number of Y pixels') | ||
| 145 | 252 | ||
| 146 | # Return | 253 | # Return |
| 147 | return | 254 | return |
test/test_ctulimit.py
| @@ -99,7 +99,25 @@ class Test(test): | @@ -99,7 +99,25 @@ class Test(test): | ||
| 99 | """ | 99 | """ |
| 100 | Test ctulimit from Python | 100 | Test ctulimit from Python |
| 101 | """ | 101 | """ |
| 102 | - # Set-up ctulimit | 102 | + # Allocate ctulimit |
| 103 | + ulimit = ctools.ctulimit() | ||
| 104 | + | ||
| 105 | + # Check that empty ctulimit tool holds zero upper limits | ||
| 106 | + self.test_value(ulimit.diff_ulimit(), 0.0, 1.0e-23, | ||
| 107 | + 'Check differential upper limit') | ||
| 108 | + self.test_value(ulimit.flux_ulimit(), 0.0, 1.0e-17, | ||
| 109 | + 'Check upper limit on photon flux') | ||
| 110 | + self.test_value(ulimit.eflux_ulimit(), 0.0, 1.0e-16, | ||
| 111 | + 'Check upper limit on energy flux') | ||
| 112 | + | ||
| 113 | + # Check that saving does not nothing | ||
| 114 | + ulimit.logFileOpen() | ||
| 115 | + ulimit.save() | ||
| 116 | + | ||
| 117 | + # Check that clearing does not lead to an exception or segfault | ||
| 118 | + ulimit.clear() | ||
| 119 | + | ||
| 120 | + # Now set ctulimit parameters | ||
| 103 | ulimit = ctools.ctulimit() | 121 | ulimit = ctools.ctulimit() |
| 104 | ulimit['inobs'] = self._events | 122 | ulimit['inobs'] = self._events |
| 105 | ulimit['inmodel'] = self._model | 123 | ulimit['inmodel'] = self._model |
| @@ -114,8 +132,50 @@ class Test(test): | @@ -114,8 +132,50 @@ class Test(test): | ||
| 114 | ulimit.run() | 132 | ulimit.run() |
| 115 | ulimit.save() | 133 | ulimit.save() |
| 116 | 134 | ||
| 117 | - # Check result file | ||
| 118 | - self._check_result_file('ctulimit_py1.log') | 135 | + # Check results |
| 136 | + self.test_value(ulimit.diff_ulimit(), 8.86803e-18, 1.0e-23, | ||
| 137 | + 'Check differential upper limit') | ||
| 138 | + self.test_value(ulimit.flux_ulimit(), 6.10509e-12, 1.0e-17, | ||
| 139 | + 'Check upper limit on photon flux') | ||
| 140 | + self.test_value(ulimit.eflux_ulimit(), 2.75669e-11, 1.0e-16, | ||
| 141 | + 'Check upper limit on energy flux') | ||
| 142 | + | ||
| 143 | + # Copy ctulimit tool | ||
| 144 | + cpy_ulimit = ulimit.copy() | ||
| 145 | + | ||
| 146 | + # Check results of copy | ||
| 147 | + self.test_value(cpy_ulimit.diff_ulimit(), 8.86803e-18, 1.0e-23, | ||
| 148 | + 'Check differential upper limit') | ||
| 149 | + self.test_value(cpy_ulimit.flux_ulimit(), 6.10509e-12, 1.0e-17, | ||
| 150 | + 'ulimit upper limit on photon flux') | ||
| 151 | + self.test_value(cpy_ulimit.eflux_ulimit(), 2.75669e-11, 1.0e-16, | ||
| 152 | + 'Check upper limit on energy flux') | ||
| 153 | + | ||
| 154 | + # Execute copy of ctulimit tool again, now with a higher chatter | ||
| 155 | + # level than before | ||
| 156 | + cpy_ulimit['logfile'] = 'ctulimit_py2.log' | ||
| 157 | + cpy_ulimit['chatter'] = 3 | ||
| 158 | + cpy_ulimit.logFileOpen() # Needed to get a new log file | ||
| 159 | + cpy_ulimit.execute() | ||
| 160 | + | ||
| 161 | + # Check results | ||
| 162 | + self.test_value(cpy_ulimit.diff_ulimit(), 8.86803e-18, 1.0e-23, | ||
| 163 | + 'Check differential upper limit') | ||
| 164 | + self.test_value(cpy_ulimit.flux_ulimit(), 6.10509e-12, 1.0e-17, | ||
| 165 | + 'ulimit upper limit on photon flux') | ||
| 166 | + self.test_value(cpy_ulimit.eflux_ulimit(), 2.75669e-11, 1.0e-16, | ||
| 167 | + 'Check upper limit on energy flux') | ||
| 168 | + | ||
| 169 | + # Now clear copy of ctulimit tool | ||
| 170 | + cpy_ulimit.clear() | ||
| 171 | + | ||
| 172 | + # Check that empty ctulimit tool holds zero upper limits | ||
| 173 | + self.test_value(cpy_ulimit.diff_ulimit(), 0.0, 1.0e-23, | ||
| 174 | + 'Check differential upper limit') | ||
| 175 | + self.test_value(cpy_ulimit.flux_ulimit(), 0.0, 1.0e-17, | ||
| 176 | + 'Check upper limit on photon flux') | ||
| 177 | + self.test_value(cpy_ulimit.eflux_ulimit(), 0.0, 1.0e-16, | ||
| 178 | + 'Check upper limit on energy flux') | ||
| 119 | 179 | ||
| 120 | # Return | 180 | # Return |
| 121 | return | 181 | return |