Commit 90c2e5d8972603060ae47fb0b749b6812890ada8

Authored by Jürgen Knödlseder
1 parent d135a149

Integrate ctfindvar tool

.gitignore
@@ -57,6 +57,7 @@ pyext/ctools/tools.py @@ -57,6 +57,7 @@ pyext/ctools/tools.py
57 pyext/ctools/tools_wrap.cpp 57 pyext/ctools/tools_wrap.cpp
58 cscripts/__init__.py 58 cscripts/__init__.py
59 src/ctbin/ctbin 59 src/ctbin/ctbin
  60 +src/ctfindvar/ctfindvar
60 src/ctlike/ctlike 61 src/ctlike/ctlike
61 src/cttsmap/cttsmap 62 src/cttsmap/cttsmap
62 src/ctmodel/ctmodel 63 src/ctmodel/ctmodel
src/ctfindvar/ctfindvar.cpp
1 /*************************************************************************** 1 /***************************************************************************
2 - * ctfindvar - search time variability tool * 2 + * ctfindvar - Time variability search tool *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2018 by Simon Bonnefoy * 4 * copyright (C) 2018 by Simon Bonnefoy *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 ***************************************************************************/ 20 ***************************************************************************/
21 /** 21 /**
22 * @file ctfindvar.cpp 22 * @file ctfindvar.cpp
23 - * @brief search time variability tool implementation 23 + * @brief Time variability search tool implementation
24 * @author Simon Bonnefoy 24 * @author Simon Bonnefoy
25 */ 25 */
26 26
@@ -40,7 +40,8 @@ @@ -40,7 +40,8 @@
40 40
41 /* __ Method name definitions ____________________________________________ */ 41 /* __ Method name definitions ____________________________________________ */
42 #define G_FILL_CUBE "ctfindvar::fill_cube(GCTAObservation*)" 42 #define G_FILL_CUBE "ctfindvar::fill_cube(GCTAObservation*)"
43 -#define G_FILL_ALPHA_VECTOR "ctfindvar::fill_alpha_vector(const int&, vector<double>&)" 43 +#define G_FILL_ALPHA_VECTOR "ctfindvar::fill_alpha_vector(const int&, "\
  44 + "vector<double>&)"
44 #define G_INIT_CUBE "ctfindvar::init_cube(void)" 45 #define G_INIT_CUBE "ctfindvar::init_cube(void)"
45 #define G_INIT_GTIS "ctfindvar::init_gtis(void)" 46 #define G_INIT_GTIS "ctfindvar::init_gtis(void)"
46 47
@@ -60,10 +61,9 @@ @@ -60,10 +61,9 @@
60 /***********************************************************************//** 61 /***********************************************************************//**
61 * @brief Void constructor 62 * @brief Void constructor
62 * 63 *
63 - * Constructs empty search time variability tool. 64 + * Constructs empty time variability search tool.
64 ***************************************************************************/ 65 ***************************************************************************/
65 -ctfindvar::ctfindvar(void) :  
66 - ctobservation(CTFINDVAR_NAME, VERSION) 66 +ctfindvar::ctfindvar(void) : ctobservation(CTFINDVAR_NAME, VERSION)
67 { 67 {
68 // Initialise members 68 // Initialise members
69 init_members(); 69 init_members();
@@ -78,10 +78,10 @@ ctfindvar::ctfindvar(void) : @@ -78,10 +78,10 @@ ctfindvar::ctfindvar(void) :
78 * 78 *
79 * param[in] obs Observation container. 79 * param[in] obs Observation container.
80 * 80 *
81 - * Constructs search time variability tool from an observation container. 81 + * Constructs time variability search tool from an observation container.
82 ***************************************************************************/ 82 ***************************************************************************/
83 ctfindvar::ctfindvar(const GObservations& obs) : 83 ctfindvar::ctfindvar(const GObservations& obs) :
84 - ctobservation(CTFINDVAR_NAME, VERSION, obs) 84 + ctobservation(CTFINDVAR_NAME, VERSION, obs)
85 { 85 {
86 // Initialise members 86 // Initialise members
87 init_members(); 87 init_members();
@@ -97,11 +97,11 @@ ctfindvar::ctfindvar(const GObservations&amp; obs) : @@ -97,11 +97,11 @@ ctfindvar::ctfindvar(const GObservations&amp; obs) :
97 * @param[in] argc Number of arguments in command line. 97 * @param[in] argc Number of arguments in command line.
98 * @param[in] argv Array of command line arguments. 98 * @param[in] argv Array of command line arguments.
99 * 99 *
100 - * Constructs search time variability tool using command line arguments for user  
101 - * parameter setting. 100 + * Constructs time variability search tool using command line arguments for
  101 + * user parameter setting.
102 ***************************************************************************/ 102 ***************************************************************************/
103 ctfindvar::ctfindvar(int argc, char *argv[]) : 103 ctfindvar::ctfindvar(int argc, char *argv[]) :
104 - ctobservation(CTFINDVAR_NAME, VERSION, argc, argv) 104 + ctobservation(CTFINDVAR_NAME, VERSION, argc, argv)
105 { 105 {
106 // Initialise members 106 // Initialise members
107 init_members(); 107 init_members();
@@ -116,11 +116,10 @@ ctfindvar::ctfindvar(int argc, char *argv[]) : @@ -116,11 +116,10 @@ ctfindvar::ctfindvar(int argc, char *argv[]) :
116 * 116 *
117 * @param[in] app search time variability tool. 117 * @param[in] app search time variability tool.
118 * 118 *
119 - * Constructs search time variability tool from another search time variability  
120 - * tool. 119 + * Constructs time variability search tool from another time variability
  120 + * search tool.
121 ***************************************************************************/ 121 ***************************************************************************/
122 -ctfindvar::ctfindvar(const ctfindvar& app) :  
123 - ctobservation(app) 122 +ctfindvar::ctfindvar(const ctfindvar& app) : ctobservation(app)
124 { 123 {
125 // Initialise members 124 // Initialise members
126 init_members(); 125 init_members();
@@ -157,10 +156,10 @@ ctfindvar::~ctfindvar(void) @@ -157,10 +156,10 @@ ctfindvar::~ctfindvar(void)
157 /***********************************************************************//** 156 /***********************************************************************//**
158 * @brief Assignment operator 157 * @brief Assignment operator
159 * 158 *
160 - * @param[in] app search time variability tool.  
161 - * @return search time variability tool. 159 + * @param[in] app Time variability search tool.
  160 + * @return Time variability search tool.
162 * 161 *
163 - * Assigns search time variability tool. 162 + * Assigns time variability search tool.
164 ***************************************************************************/ 163 ***************************************************************************/
165 ctfindvar& ctfindvar::operator=(const ctfindvar& app) 164 ctfindvar& ctfindvar::operator=(const ctfindvar& app)
166 { 165 {
@@ -193,9 +192,9 @@ ctfindvar&amp; ctfindvar::operator=(const ctfindvar&amp; app) @@ -193,9 +192,9 @@ ctfindvar&amp; ctfindvar::operator=(const ctfindvar&amp; app)
193 ==========================================================================*/ 192 ==========================================================================*/
194 193
195 /***********************************************************************//** 194 /***********************************************************************//**
196 - * @brief Clear search time variability tool 195 + * @brief Clear time variability search tool
197 * 196 *
198 - * Clears search time variability tool. 197 + * Clears time variability search tool.
199 ***************************************************************************/ 198 ***************************************************************************/
200 void ctfindvar::clear(void) 199 void ctfindvar::clear(void)
201 { 200 {
@@ -221,7 +220,7 @@ void ctfindvar::clear(void) @@ -221,7 +220,7 @@ void ctfindvar::clear(void)
221 220
222 221
223 /***********************************************************************//** 222 /***********************************************************************//**
224 - * @brief Run search time variability tool 223 + * @brief Run time variability search tool
225 ***************************************************************************/ 224 ***************************************************************************/
226 void ctfindvar::run(void) 225 void ctfindvar::run(void)
227 { 226 {
@@ -258,6 +257,7 @@ void ctfindvar::run(void) @@ -258,6 +257,7 @@ void ctfindvar::run(void)
258 (*this)["smoothpar"].real()); 257 (*this)["smoothpar"].real());
259 } 258 }
260 259
  260 + // Get number of maps
261 const int nbins = m_counts.nmaps(); 261 const int nbins = m_counts.nmaps();
262 262
263 // creating GSkyDir to get the position of the source and each pixels 263 // creating GSkyDir to get the position of the source and each pixels
@@ -265,7 +265,7 @@ void ctfindvar::run(void) @@ -265,7 +265,7 @@ void ctfindvar::run(void)
265 // Extract which pixel in the map each source is located in 265 // Extract which pixel in the map each source is located in
266 std::vector<int> srcInxPix; 266 std::vector<int> srcInxPix;
267 if (m_inmodel.size() > 0) { 267 if (m_inmodel.size() > 0) {
268 - for (int mod=0; mod<m_inmodel.size(); mod++) { 268 + for (int mod = 0; mod < m_inmodel.size(); ++mod) {
269 269
270 // Extract the model 270 // Extract the model
271 GModelSky* model = dynamic_cast<GModelSky*>(m_inmodel[mod]); 271 GModelSky* model = dynamic_cast<GModelSky*>(m_inmodel[mod]);
@@ -380,196 +380,50 @@ void ctfindvar::run(void) @@ -380,196 +380,50 @@ void ctfindvar::run(void)
380 380
381 381
382 /***********************************************************************//** 382 /***********************************************************************//**
383 - * @brief Obtain the significance of variability in a given bin  
384 - *  
385 - * @param[in] pix_number Pixel in the skymap  
386 - * @param[in] nbins Number of bins in the skymap  
387 - * @param[out] sig_histogram Histogram for storing returned significances  
388 - *  
389 - * Significance is computed according to Li & Ma equation 17:  
390 - * see: https://doi.org/10.1086/161295  
391 - * Some modification is made in order to handle the case where Non = 0,  
392 - * but Noff != 0.  
393 - ***************************************************************************/  
394 -void ctfindvar::get_variability_sig(const int& pix_number,  
395 - const int& nbins,  
396 - GNdarray& sig_histogram)  
397 -{  
398 - std::vector<bool> accepted_bin_bckg_vector(nbins, true);  
399 - bool background_validated = false;  
400 - double non, noff;  
401 - double alpha, sig;  
402 -  
403 - // Fill the alpha values for each vector  
404 - std::vector<double> alpha_vector(nbins, 0.0);  
405 - fill_alpha_vector(pix_number, alpha_vector);  
406 -  
407 - // Loop over pixels until all background pixls are removed  
408 - while (background_validated == false) {  
409 - background_validated = true;  
410 -  
411 - // Loop over all the GTIs of the pixel  
412 - for (int i = 0; i < nbins; i++) {  
413 -  
414 - // The GTI is discared from bckg calculation and not checked again.  
415 - if (!accepted_bin_bckg_vector[i]) {  
416 - continue;  
417 - }  
418 - // Check if bin fails minoff check or no observations overlap it  
419 - else if (m_counts(pix_number, i) < m_minoff || alpha_vector[i] == 0) {  
420 - accepted_bin_bckg_vector[i] = false;  
421 - continue;  
422 - }  
423 -  
424 - noff = 0.0;  
425 - alpha = 0.0;  
426 - // Gor one GTI selected (i), looping over all the others (j).  
427 - for (int j = 0; j < nbins; j++) {  
428 - if (j != i && accepted_bin_bckg_vector[j] == 1) {  
429 - noff += m_counts(pix_number, j);  
430 - alpha += alpha_vector[j];  
431 - }  
432 - }  
433 -  
434 - // The background is averaged on the number of bins -1  
435 - non = m_counts(pix_number, i);  
436 - alpha = alpha_vector[i]/alpha;  
437 -  
438 - // Compute sensitivity in Gaussian sigma using Li & Ma  
439 - double alpha1 = alpha + 1.0;  
440 - double ntotal = non+noff;  
441 - double arg1 = non/ntotal;  
442 - double arg2 = noff/ntotal;  
443 - if (noff == 0.0) {  
444 - sig = 0.0;  
445 - } else if (non > 0.0) {  
446 - double term1 = non * std::log((alpha1/alpha)*arg1);  
447 - double term2 = noff * std::log(alpha1*arg2);  
448 - sig = std::sqrt(2.0 * (term1 + term2));  
449 - } else {  
450 - sig = std::sqrt(2.0 * noff * std::log(alpha1));  
451 - }  
452 -  
453 - // Specify the sign of the significance  
454 - sig *= (non < alpha*noff) ? -1.0 : 1.0;  
455 -  
456 - if (alpha == 0.0) {  
457 - sig = 0.0;  
458 - }  
459 -  
460 - // Update the significance  
461 - sig_histogram(i) = sig;  
462 -  
463 - // If bin is significant, it's removed from bckg and we loop again.  
464 - if (sig > m_sig_threshold) {  
465 - accepted_bin_bckg_vector[i] = false;  
466 - background_validated = false;  
467 - }  
468 - }  
469 -  
470 - }  
471 -}  
472 -  
473 -/***********************************************************************//**  
474 - * @brief Save the current sky direction to model if significance > thr  
475 - *  
476 - * @param[in] dir_pix pixel sky direction  
477 - * @param[out] m_model_sig_above_thr model position with sig>thr  
478 - ***************************************************************************/  
479 -void ctfindvar::fill_model_sig_pos(const GSkyDir& dir_pix)  
480 -{  
481 - //Set spatial components  
482 - GModelSpatialPointSource spatial(dir_pix);  
483 -  
484 - //Set fake spectral component (powerlaw with 1% of Crab)  
485 - GModelSpectralPlaw spectral(5.7e-18, -2.48, GEnergy(0.3, "TeV"));  
486 -  
487 - //Creat a sky model  
488 - GModelSky model(spatial, spectral);  
489 -  
490 - //Extracting the coordinate to name the model  
491 - double ra = dir_pix.ra_deg();  
492 - double dec = dir_pix.dec_deg();  
493 - std::string name = "Sky_direction_" + gammalib::str(ra, 4) +  
494 - "_" + gammalib::str(dec, 4);  
495 - model.name(name);  
496 -  
497 - //Add the model for this pixel to the output mode  
498 - m_model_above_thr.append(model);  
499 -  
500 -}  
501 -/***********************************************************************//**  
502 - * @brief Get the map index associated with a given time 383 + * @brief Save peak significance map and significance distributions
503 * 384 *
504 - * @param[in] pix_number Spatial pixel  
505 - * @param[out] alpha_vector Vector containing effective exposure 385 + * Saves the peak significance and source signficance distributions.
  386 + * Optionally, the generated counts cube can also be saved if 'outcube' has
  387 + * been specified.
506 ***************************************************************************/ 388 ***************************************************************************/
507 -void ctfindvar::fill_alpha_vector(const int& pix_number,  
508 - std::vector<double>& alpha_vector) 389 +void ctfindvar::save(void)
509 { 390 {
510 - // Pixel position  
511 - GSkyDir pix_dir = m_counts.inx2dir(pix_number);  
512 -  
513 - // Loop over all observations  
514 - for (int i = 0; i < m_obs.size(); i++) {  
515 - // Skip if observation does not overlap with this pixel position  
516 - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]);  
517 - GCTARoi roi = obs->roi();  
518 - GSkyDir roi_centre = roi.centre().dir();  
519 -  
520 - if (roi_centre.dist_deg(pix_dir) > roi.radius()) {  
521 - continue;  
522 - }  
523 -  
524 - // Convert sky direction to instrument direction  
525 - GCTAInstDir instdir = obs->pointing().instdir(pix_dir);  
526 -  
527 - // Extract the good time intervals of the observation  
528 - const GGti& obs_gti(obs->gti()); 391 + log_header1(TERSE, "Saving results");
529 392
530 - // Loop over all time bins  
531 - for (int j = 0; j < m_gti.size(); j++) { 393 + // Filenames
  394 + std::string prefix((*this)["prefix"].string());
532 395
533 - // Make sure observation overlaps with this time interval  
534 - double exposure = gti_overlap(m_gti[j], obs_gti);  
535 - if (exposure > 0.0) { 396 + // Write counts cube
  397 + if ((*this)["outcube"].is_valid()) {
  398 + GFilename outcube = (*this)["outcube"].filename();
  399 + log_value(TERSE, "Saving counts cube", outcube);
  400 + m_counts.save(outcube, (*this)["clobber"].boolean());
  401 + }
536 402
537 - // Get IRF response  
538 - const GCTAResponseIrf* rsp = dynamic_cast<const GCTAResponseIrf*>  
539 - (obs->response()); 403 + // Create a FITS file for storing the output
  404 + m_outfile.clear();
540 405
541 - // Throw an exception if observation has no instrument response function  
542 - if (rsp == NULL) {  
543 - std::string msg =  
544 - "No response information available for "+  
545 - get_obs_header(obs)+" to compute IRF background. "  
546 - "Please specify response information or use "  
547 - "another background subtraction method.";  
548 - throw GException::invalid_value(G_FILL_ALPHA_VECTOR, msg);  
549 - } 406 + // Write the most significant values for each pixel
  407 + log_string(TERSE, "Appending maximum significances map to output file");
  408 + m_peaksigmap.write(m_outfile, "PEAKSIGMAP");
550 409
551 - // Get IRF background template  
552 - const GCTABackground* bkg = rsp->background(); 410 + // Write individual source distributions
  411 + write_srchist();
553 412
554 - // Throw an exception if observation has no IRF background template  
555 - if (bkg == NULL) {  
556 - std::string msg =  
557 - "No IRF background template found in instrument "  
558 - "response function for "+  
559 - get_obs_header(obs)+". Please specify an instrument "  
560 - "response function containing a background template.";  
561 - throw GException::invalid_value(G_FILL_ALPHA_VECTOR, msg);  
562 - } 413 + // Write the output file
  414 + GFilename outfilename = prefix + "signifmap.fits";
  415 + log_value(TERSE, "Saving results to ", outfilename);
  416 + m_outfile.saveto(outfilename, (*this)["clobber"].boolean());
563 417
564 - // Multiply background rate with livetime and solid angle  
565 - #pragma omp critical(ctfindvar_alpha_vector)  
566 - alpha_vector[j] += exposure * bkg->rate_ebin(instdir, m_emin, m_emax);  
567 - }  
568 - } 418 + //Save the model file with position with significance
  419 + if (m_model_above_thr.size() > 2) {
  420 + GFilename model_filename = prefix + "model_significant_directions.xml";
  421 + m_model_above_thr.save(model_filename);
569 } 422 }
570 423
  424 + // Return
571 return; 425 return;
572 -} 426 +}
573 427
574 428
575 /***********************************************************************//** 429 /***********************************************************************//**
@@ -611,53 +465,6 @@ GGti ctfindvar::inx2gti(const int&amp; index) @@ -611,53 +465,6 @@ GGti ctfindvar::inx2gti(const int&amp; index)
611 } 465 }
612 466
613 467
614 -/***********************************************************************//**  
615 - * @brief Save peak significance map and significance distributions  
616 - *  
617 - * Saves the peak significance and source signficance distributions.  
618 - * Optionally, the generated counts cube can also be saved if 'outcube' has  
619 - * been specified.  
620 - ***************************************************************************/  
621 -void ctfindvar::save(void)  
622 -{  
623 - log_header1(TERSE, "Saving results");  
624 -  
625 - // Filenames  
626 - std::string prefix((*this)["prefix"].string());  
627 -  
628 - // Write counts cube  
629 - if ((*this)["outcube"].is_valid()) {  
630 - GFilename outcube = (*this)["outcube"].filename();  
631 - log_value(TERSE, "Saving counts cube", outcube);  
632 - m_counts.save(outcube, (*this)["clobber"].boolean());  
633 - }  
634 -  
635 - // Create a FITS file for storing the output  
636 - m_outfile.clear();  
637 -  
638 - // Write the most significant values for each pixel  
639 - log_string(TERSE, "Appending maximum significances map to output file");  
640 - m_peaksigmap.write(m_outfile, "PEAKSIGMAP");  
641 -  
642 - // Write individual source distributions  
643 - write_srchist();  
644 -  
645 - // Write the output file  
646 - GFilename outfilename = prefix + "signifmap.fits";  
647 - log_value(TERSE, "Saving results to ", outfilename);  
648 - m_outfile.saveto(outfilename, (*this)["clobber"].boolean());  
649 -  
650 - //Save the model file with position with significance  
651 - if (m_model_above_thr.size() > 2) {  
652 - GFilename model_filename = prefix + "model_significant_directions.xml";  
653 - m_model_above_thr.save(model_filename);  
654 - }  
655 -  
656 - // Return  
657 - return;  
658 -}  
659 -  
660 -  
661 /*========================================================================== 468 /*==========================================================================
662 = = 469 = =
663 = Private methods = 470 = Private methods =
@@ -673,10 +480,17 @@ void ctfindvar::init_members(void) @@ -673,10 +480,17 @@ void ctfindvar::init_members(void)
673 m_counts.clear(); 480 m_counts.clear();
674 m_gti.clear(); 481 m_gti.clear();
675 m_inmodel.clear(); 482 m_inmodel.clear();
  483 + m_max_sig_dir.clear();
  484 + m_minoff = 0.0;
  485 + m_sig_threshold = 0.0;
  486 + m_outfile.clear();
676 m_peaksigmap.clear(); 487 m_peaksigmap.clear();
677 m_pixsigsrc.clear(); 488 m_pixsigsrc.clear();
678 m_tstart.clear(); 489 m_tstart.clear();
679 m_tstop.clear(); 490 m_tstop.clear();
  491 + m_emin.clear();
  492 + m_emax.clear();
  493 + m_model_above_thr.clear();
680 494
681 // Return 495 // Return
682 return; 496 return;
@@ -690,8 +504,21 @@ void ctfindvar::init_members(void) @@ -690,8 +504,21 @@ void ctfindvar::init_members(void)
690 ***************************************************************************/ 504 ***************************************************************************/
691 void ctfindvar::copy_members(const ctfindvar& app) 505 void ctfindvar::copy_members(const ctfindvar& app)
692 { 506 {
693 - // Copy attributes  
694 - // TODO: Your code goes here 507 + // Copy members
  508 + m_counts = app.m_counts;
  509 + m_gti = app.m_gti;
  510 + m_inmodel = app.m_inmodel;
  511 + m_max_sig_dir = app.m_max_sig_dir;
  512 + m_minoff = app.m_minoff;
  513 + m_sig_threshold = app.m_sig_threshold;
  514 + m_outfile = app.m_outfile;
  515 + m_peaksigmap = app.m_peaksigmap;
  516 + m_pixsigsrc = app.m_pixsigsrc;
  517 + m_tstart = app.m_tstart;
  518 + m_tstop = app.m_tstop;
  519 + m_emin = app.m_emin;
  520 + m_emax = app.m_emax;
  521 + m_model_above_thr = app.m_model_above_thr;
695 522
696 // Return 523 // Return
697 return; 524 return;
@@ -761,6 +588,113 @@ void ctfindvar::get_parameters(void) @@ -761,6 +588,113 @@ void ctfindvar::get_parameters(void)
761 588
762 589
763 /***********************************************************************//** 590 /***********************************************************************//**
  591 + * @brief Initialize counts cube
  592 + *
  593 + * Sets up the required event cube and time interval storage objects
  594 + * associated with this object
  595 + ***************************************************************************/
  596 +void ctfindvar::init_cube(void)
  597 +{
  598 + // Create the basic skymap
  599 + m_counts = create_map(m_obs);
  600 +
  601 + // Resize to the appropriate number of time intervals
  602 + m_counts.nmaps(m_gti.size());
  603 +
  604 + // Create the peaksigmap
  605 + m_peaksigmap = m_counts.extract(1);
  606 +}
  607 +
  608 +
  609 +/***********************************************************************//**
  610 + * @brief Initialize counts cube
  611 + *
  612 + * Sets up the required event cube and time interval storage objects
  613 + * associated with this object
  614 + ***************************************************************************/
  615 +void ctfindvar::init_gtis(void)
  616 +{
  617 + double tinterval = (*this)["tinterval"].real();
  618 + m_tstart = GTime("JD 999999999"); // large unreasonable Julian date
  619 + m_tstop = GTime("JD 0"); // small unreasonable Julian date
  620 +
  621 + // Set the start time
  622 + if ((*this)["tmin"].is_valid()) {
  623 + log_string(NORMAL, "Setting start time from command line");
  624 + m_tstart = (*this)["tmin"].time();
  625 + } else {
  626 + log_string(NORMAL, "Setting start time from observations");
  627 + for (int o=0; o<m_obs.size(); o++) {
  628 + GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[o]);
  629 +
  630 + // Check that the start time of the run is less than tstart
  631 + if (obs->gti().tstart() < m_tstart) {
  632 + m_tstart = obs->gti().tstart();
  633 + }
  634 + }
  635 + }
  636 +
  637 + // Set the stop time
  638 + if ((*this)["tmax"].is_valid()) {
  639 + log_string(NORMAL, "Setting stop time from command line");
  640 + m_tstop = (*this)["tmax"].time();
  641 + } else {
  642 +
  643 + log_string(NORMAL, "Setting stop time from observations");
  644 + for (int o=0; o<m_obs.size(); o++) {
  645 + GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[o]);
  646 +
  647 + // Check that the stop time of the run is larger than tstop
  648 + if (obs->gti().tstop() > m_tstop) {
  649 + m_tstop = obs->gti().tstop();
  650 + }
  651 + }
  652 + }
  653 +
  654 + // Fill the number of good time intervals
  655 + double tstart_sec = m_tstart.secs();
  656 + double tstop_sec = m_tstop.secs();
  657 + int bins = (tstop_sec - tstart_sec) / tinterval + 0.5;
  658 +
  659 + // Log information
  660 + log_value(NORMAL, "treference (mjd)", m_tstart.reference().mjdref());
  661 + log_value(NORMAL, "tstart (sec)", tstart_sec);
  662 + log_value(NORMAL, "tstop (sec)", tstop_sec);
  663 + log_value(NORMAL, "Total time", tstop_sec-tstart_sec);
  664 + log_value(NORMAL, "Time interval", tinterval);
  665 + log_value(NORMAL, "nbins", bins);
  666 +
  667 + // Throw if tstart == tstop
  668 + if (m_tstart == m_tstop) {
  669 + throw GException::invalid_value(G_INIT_GTIS,
  670 + "Start time is equal to stop time");
  671 + } else if (bins < 2) {
  672 + std::string msg = "Method requires at least two time bins (" +
  673 + gammalib::str(bins) + " bins found).";
  674 + throw GException::invalid_value(G_INIT_GTIS, msg);
  675 + }
  676 +
  677 + for (int i=0; i<bins; i++) {
  678 +
  679 + // Get the next time interval
  680 + GTime next_tstart(m_tstart + i*tinterval);
  681 + GTime next_tstop(m_tstart + (i+1.0)*tinterval);
  682 + GGti next_gti(next_tstart, next_tstop);
  683 +
  684 + // Make sure there's an observation that overlaps with this GTI
  685 + for (int o=0; o<m_obs.size(); o++) {
  686 + GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[o]);
  687 +
  688 + if (gti_overlap(obs->gti(), next_gti) > 0.0) {
  689 + m_gti.push_back(next_gti);
  690 + break;
  691 + }
  692 + }
  693 + }
  694 +}
  695 +
  696 +
  697 +/***********************************************************************//**
764 * @brief Fill the cube from the events in the map 698 * @brief Fill the cube from the events in the map
765 * 699 *
766 * Sets up the required event cube and time interval storage objects 700 * Sets up the required event cube and time interval storage objects
@@ -884,108 +818,197 @@ void ctfindvar::fill_cube(GCTAObservation* obs) @@ -884,108 +818,197 @@ void ctfindvar::fill_cube(GCTAObservation* obs)
884 818
885 819
886 /***********************************************************************//** 820 /***********************************************************************//**
887 - * @brief Initialize counts cube 821 + * @brief Save the current sky direction to model if significance > thr
888 * 822 *
889 - * Sets up the required event cube and time interval storage objects  
890 - * associated with this object 823 + * @param[in] dir_pix pixel sky direction
  824 + * @param[out] m_model_sig_above_thr model position with sig>thr
891 ***************************************************************************/ 825 ***************************************************************************/
892 -void ctfindvar::init_cube(void) 826 +void ctfindvar::fill_model_sig_pos(const GSkyDir& dir_pix)
893 { 827 {
894 - // Create the basic skymap  
895 - m_counts = create_map(m_obs); 828 + //Set spatial components
  829 + GModelSpatialPointSource spatial(dir_pix);
896 830
897 - // Resize to the appropriate number of time intervals  
898 - m_counts.nmaps(m_gti.size()); 831 + //Set fake spectral component (powerlaw with 1% of Crab)
  832 + GModelSpectralPlaw spectral(5.7e-18, -2.48, GEnergy(0.3, "TeV"));
899 833
900 - // Create the peaksigmap  
901 - m_peaksigmap = m_counts.extract(1); 834 + //Creat a sky model
  835 + GModelSky model(spatial, spectral);
  836 +
  837 + //Extracting the coordinate to name the model
  838 + double ra = dir_pix.ra_deg();
  839 + double dec = dir_pix.dec_deg();
  840 + std::string name = "Sky_direction_" + gammalib::str(ra, 4) +
  841 + "_" + gammalib::str(dec, 4);
  842 + model.name(name);
  843 +
  844 + //Add the model for this pixel to the output mode
  845 + m_model_above_thr.append(model);
  846 +
902 } 847 }
903 -  
904 -  
905 /***********************************************************************//** 848 /***********************************************************************//**
906 - * @brief Initialize counts cube 849 + * @brief Get the map index associated with a given time
907 * 850 *
908 - * Sets up the required event cube and time interval storage objects  
909 - * associated with this object 851 + * @param[in] pix_number Spatial pixel
  852 + * @param[out] alpha_vector Vector containing effective exposure
910 ***************************************************************************/ 853 ***************************************************************************/
911 -void ctfindvar::init_gtis(void) 854 +void ctfindvar::fill_alpha_vector(const int& pix_number,
  855 + std::vector<double>& alpha_vector)
912 { 856 {
913 - double tinterval = (*this)["tinterval"].real();  
914 - m_tstart = GTime("JD 999999999"); // large unreasonable Julian date  
915 - m_tstop = GTime("JD 0"); // small unreasonable Julian date 857 + // Pixel position
  858 + GSkyDir pix_dir = m_counts.inx2dir(pix_number);
916 859
917 - // Set the start time  
918 - if ((*this)["tmin"].is_valid()) {  
919 - log_string(NORMAL, "Setting start time from command line");  
920 - m_tstart = (*this)["tmin"].time();  
921 - } else {  
922 - log_string(NORMAL, "Setting start time from observations");  
923 - for (int o=0; o<m_obs.size(); o++) {  
924 - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[o]);  
925 -  
926 - // Check that the start time of the run is less than tstart  
927 - if (obs->gti().tstart() < m_tstart) {  
928 - m_tstart = obs->gti().tstart();  
929 - } 860 + // Loop over all observations
  861 + for (int i = 0; i < m_obs.size(); i++) {
  862 + // Skip if observation does not overlap with this pixel position
  863 + GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]);
  864 + GCTARoi roi = obs->roi();
  865 + GSkyDir roi_centre = roi.centre().dir();
  866 +
  867 + if (roi_centre.dist_deg(pix_dir) > roi.radius()) {
  868 + continue;
930 } 869 }
931 - } 870 +
  871 + // Convert sky direction to instrument direction
  872 + GCTAInstDir instdir = obs->pointing().instdir(pix_dir);
932 873
933 - // Set the stop time  
934 - if ((*this)["tmax"].is_valid()) {  
935 - log_string(NORMAL, "Setting stop time from command line");  
936 - m_tstop = (*this)["tmax"].time();  
937 - } else { 874 + // Extract the good time intervals of the observation
  875 + const GGti& obs_gti(obs->gti());
938 876
939 - log_string(NORMAL, "Setting stop time from observations");  
940 - for (int o=0; o<m_obs.size(); o++) {  
941 - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[o]);  
942 -  
943 - // Check that the stop time of the run is larger than tstop  
944 - if (obs->gti().tstop() > m_tstop) {  
945 - m_tstop = obs->gti().tstop(); 877 + // Loop over all time bins
  878 + for (int j = 0; j < m_gti.size(); j++) {
  879 +
  880 + // Make sure observation overlaps with this time interval
  881 + double exposure = gti_overlap(m_gti[j], obs_gti);
  882 + if (exposure > 0.0) {
  883 +
  884 + // Get IRF response
  885 + const GCTAResponseIrf* rsp = dynamic_cast<const GCTAResponseIrf*>
  886 + (obs->response());
  887 +
  888 + // Throw an exception if observation has no instrument response function
  889 + if (rsp == NULL) {
  890 + std::string msg =
  891 + "No response information available for "+
  892 + get_obs_header(obs)+" to compute IRF background. "
  893 + "Please specify response information or use "
  894 + "another background subtraction method.";
  895 + throw GException::invalid_value(G_FILL_ALPHA_VECTOR, msg);
  896 + }
  897 +
  898 + // Get IRF background template
  899 + const GCTABackground* bkg = rsp->background();
  900 +
  901 + // Throw an exception if observation has no IRF background template
  902 + if (bkg == NULL) {
  903 + std::string msg =
  904 + "No IRF background template found in instrument "
  905 + "response function for "+
  906 + get_obs_header(obs)+". Please specify an instrument "
  907 + "response function containing a background template.";
  908 + throw GException::invalid_value(G_FILL_ALPHA_VECTOR, msg);
  909 + }
  910 +
  911 + // Multiply background rate with livetime and solid angle
  912 + #pragma omp critical(ctfindvar_alpha_vector)
  913 + alpha_vector[j] += exposure * bkg->rate_ebin(instdir, m_emin, m_emax);
946 } 914 }
947 } 915 }
948 } 916 }
949 917
950 - // Fill the number of good time intervals  
951 - double tstart_sec = m_tstart.secs();  
952 - double tstop_sec = m_tstop.secs();  
953 - int bins = (tstop_sec - tstart_sec) / tinterval + 0.5; 918 + return;
  919 +}
954 920
955 - // Log information  
956 - log_value(NORMAL, "treference (mjd)", m_tstart.reference().mjdref());  
957 - log_value(NORMAL, "tstart (sec)", tstart_sec);  
958 - log_value(NORMAL, "tstop (sec)", tstop_sec);  
959 - log_value(NORMAL, "Total time", tstop_sec-tstart_sec);  
960 - log_value(NORMAL, "Time interval", tinterval);  
961 - log_value(NORMAL, "nbins", bins);  
962 921
963 - // Throw if tstart == tstop  
964 - if (m_tstart == m_tstop) {  
965 - throw GException::invalid_value(G_INIT_GTIS,  
966 - "Start time is equal to stop time");  
967 - } else if (bins < 2) {  
968 - std::string msg = "Method requires at least two time bins (" +  
969 - gammalib::str(bins) + " bins found).";  
970 - throw GException::invalid_value(G_INIT_GTIS, msg);  
971 - }  
972 922
973 - for (int i=0; i<bins; i++) {  
974 -  
975 - // Get the next time interval  
976 - GTime next_tstart(m_tstart + i*tinterval);  
977 - GTime next_tstop(m_tstart + (i+1.0)*tinterval);  
978 - GGti next_gti(next_tstart, next_tstop);  
979 923
980 - // Make sure there's an observation that overlaps with this GTI  
981 - for (int o=0; o<m_obs.size(); o++) {  
982 - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[o]);  
983 -  
984 - if (gti_overlap(obs->gti(), next_gti) > 0.0) {  
985 - m_gti.push_back(next_gti);  
986 - break; 924 +/***********************************************************************//**
  925 + * @brief Obtain the significance of variability in a given bin
  926 + *
  927 + * @param[in] pix_number Pixel in the skymap
  928 + * @param[in] nbins Number of bins in the skymap
  929 + * @param[out] sig_histogram Histogram for storing returned significances
  930 + *
  931 + * Significance is computed according to Li & Ma equation 17:
  932 + * see: https://doi.org/10.1086/161295
  933 + * Some modification is made in order to handle the case where Non = 0,
  934 + * but Noff != 0.
  935 + ***************************************************************************/
  936 +void ctfindvar::get_variability_sig(const int& pix_number,
  937 + const int& nbins,
  938 + GNdarray& sig_histogram)
  939 +{
  940 + std::vector<bool> accepted_bin_bckg_vector(nbins, true);
  941 + bool background_validated = false;
  942 + double non, noff;
  943 + double alpha, sig;
  944 +
  945 + // Fill the alpha values for each vector
  946 + std::vector<double> alpha_vector(nbins, 0.0);
  947 + fill_alpha_vector(pix_number, alpha_vector);
  948 +
  949 + // Loop over pixels until all background pixls are removed
  950 + while (background_validated == false) {
  951 + background_validated = true;
  952 +
  953 + // Loop over all the GTIs of the pixel
  954 + for (int i = 0; i < nbins; i++) {
  955 +
  956 + // The GTI is discared from bckg calculation and not checked again.
  957 + if (!accepted_bin_bckg_vector[i]) {
  958 + continue;
  959 + }
  960 + // Check if bin fails minoff check or no observations overlap it
  961 + else if (m_counts(pix_number, i) < m_minoff || alpha_vector[i] == 0) {
  962 + accepted_bin_bckg_vector[i] = false;
  963 + continue;
  964 + }
  965 +
  966 + noff = 0.0;
  967 + alpha = 0.0;
  968 + // Gor one GTI selected (i), looping over all the others (j).
  969 + for (int j = 0; j < nbins; j++) {
  970 + if (j != i && accepted_bin_bckg_vector[j] == 1) {
  971 + noff += m_counts(pix_number, j);
  972 + alpha += alpha_vector[j];
  973 + }
  974 + }
  975 +
  976 + // The background is averaged on the number of bins -1
  977 + non = m_counts(pix_number, i);
  978 + alpha = alpha_vector[i]/alpha;
  979 +
  980 + // Compute sensitivity in Gaussian sigma using Li & Ma
  981 + double alpha1 = alpha + 1.0;
  982 + double ntotal = non+noff;
  983 + double arg1 = non/ntotal;
  984 + double arg2 = noff/ntotal;
  985 + if (noff == 0.0) {
  986 + sig = 0.0;
  987 + } else if (non > 0.0) {
  988 + double term1 = non * std::log((alpha1/alpha)*arg1);
  989 + double term2 = noff * std::log(alpha1*arg2);
  990 + sig = std::sqrt(2.0 * (term1 + term2));
  991 + } else {
  992 + sig = std::sqrt(2.0 * noff * std::log(alpha1));
  993 + }
  994 +
  995 + // Specify the sign of the significance
  996 + sig *= (non < alpha*noff) ? -1.0 : 1.0;
  997 +
  998 + if (alpha == 0.0) {
  999 + sig = 0.0;
  1000 + }
  1001 +
  1002 + // Update the significance
  1003 + sig_histogram(i) = sig;
  1004 +
  1005 + // If bin is significant, it's removed from bckg and we loop again.
  1006 + if (sig > m_sig_threshold) {
  1007 + accepted_bin_bckg_vector[i] = false;
  1008 + background_validated = false;
987 } 1009 }
988 } 1010 }
  1011 +
989 } 1012 }
990 } 1013 }
991 1014
src/ctfindvar/ctfindvar.hpp
1 /*************************************************************************** 1 /***************************************************************************
2 - * ctfindvar - search time variability tool * 2 + * ctfindvar - Time variability search tool *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2018 by Simon Bonnefoy * 4 * copyright (C) 2018 by Simon Bonnefoy *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 ***************************************************************************/ 20 ***************************************************************************/
21 /** 21 /**
22 * @file ctfindvar.hpp 22 * @file ctfindvar.hpp
23 - * @brief search time variability tool definition 23 + * @brief Time variability search tool definition
24 * @author Simon Bonnefoy 24 * @author Simon Bonnefoy
25 */ 25 */
26 26
@@ -40,7 +40,7 @@ @@ -40,7 +40,7 @@
40 /***********************************************************************//** 40 /***********************************************************************//**
41 * @class ctfindvar 41 * @class ctfindvar
42 * 42 *
43 - * @brief search time variability tool 43 + * @brief Time variability search tool
44 * 44 *
45 * @todo Add tool description. 45 * @todo Add tool description.
46 ***************************************************************************/ 46 ***************************************************************************/
@@ -68,17 +68,17 @@ public: @@ -68,17 +68,17 @@ public:
68 68
69 protected: 69 protected:
70 // Protected methods 70 // Protected methods
71 - void init_cube(void);  
72 - void fill_model_sig_pos(const GSkyDir& dir_pix);  
73 - void init_gtis(void);  
74 void init_members(void); 71 void init_members(void);
75 void copy_members(const ctfindvar& app); 72 void copy_members(const ctfindvar& app);
76 void free_members(void); 73 void free_members(void);
  74 + void get_parameters(void);
  75 + void init_cube(void);
  76 + void init_gtis(void);
77 void fill_cube(GCTAObservation* obs); 77 void fill_cube(GCTAObservation* obs);
  78 + void fill_model_sig_pos(const GSkyDir& dir_pix);
78 void fill_alpha_vector(const int& pix_number, 79 void fill_alpha_vector(const int& pix_number,
79 std::vector<double>& alpha_vector); 80 std::vector<double>& alpha_vector);
80 - void get_parameters(void);  
81 - void get_variability_sig(const int& pix_number, 81 + void get_variability_sig(const int& pix_number,
82 const int& nbins, 82 const int& nbins,
83 GNdarray& sig_histogram); 83 GNdarray& sig_histogram);
84 double gti_overlap(const GGti& gti1, 84 double gti_overlap(const GGti& gti1,
src/ctfindvar/ctfindvar.par
@@ -22,6 +22,10 @@ outcube, f, h, NONE,,, &quot;Filename for counts cube&quot; @@ -22,6 +22,10 @@ outcube, f, h, NONE,,, &quot;Filename for counts cube&quot;
22 caldb, s, a, prod2,,, "Calibration database" 22 caldb, s, a, prod2,,, "Calibration database"
23 irf, s, a, South_0.5h,,, "Instrument response function" 23 irf, s, a, South_0.5h,,, "Instrument response function"
24 prefix, s, a, findvar_,,, "Prefix for output files" 24 prefix, s, a, findvar_,,, "Prefix for output files"
  25 +
  26 +#
  27 +# Variability search parameters
  28 +#==============================
25 minoff, r, h, 0,,, "Minimum required events in off bin for computing Noff and alpha" 29 minoff, r, h, 0,,, "Minimum required events in off bin for computing Noff and alpha"
26 emin, r, a, 0,,, "Lower energy limit (units of TeV; 0 => no cut)" 30 emin, r, a, 0,,, "Lower energy limit (units of TeV; 0 => no cut)"
27 emax, r, a, 0,,, "Upper energy limit (units of TeV; 0 => no cut)" 31 emax, r, a, 0,,, "Upper energy limit (units of TeV; 0 => no cut)"
src/ctfindvar/main.cpp
1 /*************************************************************************** 1 /***************************************************************************
2 - *ctfindvar - search time variability tool main code * 2 + * ctfindvar - Time variability search tool main code *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2018 by Simon Bonnefoy * 4 * copyright (C) 2018 by Simon Bonnefoy *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 ***************************************************************************/ 20 ***************************************************************************/
21 /** 21 /**
22 * @file ctfindvar/main.cpp 22 * @file ctfindvar/main.cpp
23 - * @brief search time variability tool main code 23 + * @brief Time variability search tool main code
24 * @author Simon Bonnefoy 24 * @author Simon Bonnefoy
25 */ 25 */
26 26