32 #include "GammaLib.hpp"
33 #include "GCTALib.hpp"
42 #define G_INX2GTI "ctfindvar::inx2gti(int&)"
43 #define G_FILL_CUBE "ctfindvar::fill_cube(GCTAObservation*)"
44 #define G_FILL_ALPHA_VECTOR "ctfindvar::fill_alpha_vector(const int&, "\
46 #define G_INIT_CUBE "ctfindvar::init_cube(void)"
47 #define G_INIT_GTIS "ctfindvar::init_gtis(void)"
208 this->GApplication::clear();
258 log_header1(TERSE,
"Saving results");
262 if ((*
this)[
"outcube"].is_valid()) {
265 GFilename outcube = (*this)[
"outcube"].filename();
270 m_counts.save(outcube, (*
this)[
"clobber"].
boolean());
272 log_value(TERSE,
"Counts cube file", outcube.url());
275 log_value(TERSE,
"Counts cube file",
276 outcube.url()+
" (cube is empty, no file created)");
282 GFilename outmap = (*this)[
"outmap"].filename();
283 GFilename outmodel = (*this)[
"outmodel"].filename();
301 fits.saveto(outmap, (*
this)[
"clobber"].
boolean());
304 log_value(TERSE,
"Output map file", outmap.url());
308 log_value(TERSE,
"Output map file",
309 outmap.url()+
" (map is empty, no file created)");
321 log_value(TERSE,
"Model definition file", outmodel.url());
325 log_value(TERSE,
"Model definition file",
326 outmodel.url()+
" (map is empty, no file created)");
411 if ((*
this)[
"inmodel"].is_valid()) {
412 m_inmodel = GModels((*
this)[
"inmodel"].filename());
415 (*this)[
"coordsys"].string();
416 (*this)[
"xsrc"].real();
417 (*this)[
"ysrc"].real();
421 (*this)[
"tinterval"].real();
422 if ((*
this)[
"tmin"].is_valid()) {
423 (*this)[
"tmin"].time();
425 if ((*
this)[
"tmax"].is_valid()) {
426 (*this)[
"tmax"].time();
433 m_emin = GEnergy((*
this)[
"emin"].real(),
"TeV");
434 m_emax = GEnergy((*
this)[
"emax"].real(),
"TeV");
437 m_minoff = (*this)[
"minoff"].real();
443 (*this)[
"smooth_kernel"].string();
444 (*this)[
"smooth_rad"].real();
448 (*this)[
"outcube"].query();
449 (*this)[
"outmap"].query();
450 (*this)[
"outmodel"].query();
455 int nthreads = (*this)[
"nthreads"].integer();
457 omp_set_num_threads(nthreads);
480 log_header1(NORMAL,
"Initialise Good Time Intervals");
490 double tinterval = (*this)[
"tinterval"].real();
493 double tstart_sec =
m_tstart.secs();
494 double tstop_sec =
m_tstop.secs();
495 int bins = (tstop_sec - tstart_sec) / tinterval + 0.5;
498 log_value(NORMAL,
"Reference time (mjd)",
m_tstart.reference().mjdref());
499 log_value(NORMAL,
"Start time (sec)", tstart_sec);
500 log_value(NORMAL,
"Stop time (sec)", tstop_sec);
501 log_value(NORMAL,
"Total time (sec)", tstop_sec-tstart_sec);
502 log_value(NORMAL,
"Time interval (sec)", tinterval);
503 log_value(NORMAL,
"Number of time bins", bins);
508 "Start time is equal to stop time");
511 std::string msg =
"Method requires at least two time bins (" +
512 gammalib::str(bins) +
" bins found).";
518 for (
int i = 0; i < bins; ++i) {
521 GTime tstart(
m_tstart + i*tinterval);
522 GTime tstop(
m_tstart + (i+1.0)*tinterval);
523 GGti gti(tstart, tstop);
526 for (
int k = 0; k <
m_obs.size(); ++k) {
529 GCTAObservation*
obs =
dynamic_cast<GCTAObservation*
>(
m_obs[k]);
536 m_gti.push_back(gti);
559 log_header1(NORMAL,
"Create counts cube");
571 #pragma omp parallel for
572 for (
int i = 0; i <
m_obs.size(); ++i) {
575 GCTAObservation*
obs =
dynamic_cast<GCTAObservation*
>(
m_obs[i]);
581 obs->dispose_events();
586 if ((*
this)[
"smooth_kernel"].
string() !=
"NONE") {
587 m_counts.smooth((*
this)[
"smooth_kernel"].
string(),
588 (*
this)[
"smooth_rad"].real());
607 const GCTAEventList* events =
dynamic_cast<const GCTAEventList*
>
609 if (events == NULL) {
610 std::string msg =
"CTA Observation does not contain an event "
611 "list. An event list is needed to fill the "
617 const GCTARoi& roi = events->roi();
620 if (!roi.is_valid()) {
621 std::string msg =
"No valid RoI found in input observation "
622 "\""+obs->name()+
"\". Run ctselect to specify "
623 "an RoI for this observation before running "
629 int num_outside_roi = 0;
630 int num_invalid_wcs = 0;
631 int num_outside_ecut = 0;
632 int num_outside_map = 0;
633 int num_outside_time = 0;
637 for (
int i = 0; i < events->size(); ++i) {
640 const GCTAEventAtom*
event = (*events)[i];
643 if ((event->energy() <
m_emin) || (event->energy() >
m_emax)) {
649 int time_indx =
time2inx(event->time());
652 if ((time_indx > -1) && (time_indx <
m_counts.nmaps())) {
655 GSkyDir evnt_dir = GCTAInstDir(event->dir()).dir();
658 if (roi.centre().dir().dist_deg(evnt_dir) > roi.radius()) {
668 catch (std::exception &e) {
675 if (pixel.x() < -0.5 || pixel.x() > (
m_counts.nx()-0.5) ||
676 pixel.y() < -0.5 || pixel.y() > (
m_counts.ny()-0.5)) {
682 #pragma omp critical(ctfindvar_fill_cube)
698 #pragma omp critical(ctfindvar_fill_cube)
701 log_value(NORMAL,
"Events in list", obs->events()->size());
702 log_value(NORMAL,
"Events in cube", num_in_map);
703 log_value(NORMAL,
"Events outside RoI", num_outside_roi);
704 log_value(NORMAL,
"Events outside energy", num_outside_ecut);
705 log_value(NORMAL,
"Events with invalid WCS", num_invalid_wcs);
706 log_value(NORMAL,
"Events outside cube area", num_outside_map);
707 log_value(NORMAL,
"Events outside time bins", num_outside_time);
721 log_header1(NORMAL,
"Analyse sky map pixels");
724 const int nbins =
m_gti.size();
738 #pragma omp parallel for
739 for (
int ipix = 0; ipix <
m_counts.npix(); ++ipix) {
745 for (
int src = 0; src < srcInxPix.size(); ++src) {
748 if (srcInxPix[src] == ipix) {
750 #pragma omp critical(ctfindvar_analyse_cube)
751 for (
int i = 0; i < nbins; i++) {
759 #pragma omp critical(ctfindvar_analyse_cube)
762 if (max(pixSig) > max_sig) {
763 max_sig = max(pixSig);
765 m_pixsigmax = pixSig;
774 GSkyDir dir_pix =
m_counts.inx2dir(ipix);
782 log_value(NORMAL,
"Maximum significance", max_sig);
783 log_value(NORMAL,
"Right Ascension of maximum",
m_max_sig_dir.ra_deg());
784 log_value(NORMAL,
"Declination of maximum",
m_max_sig_dir.dec_deg());
802 std::vector<int> srcInxPix;
808 for (
int i = 0; i <
m_inmodel.size(); ++i) {
811 GModelSky* model =
dynamic_cast<GModelSky*
>(
m_inmodel[i]);
819 const GModelSpatial* spatial = model->spatial();
820 const GSkyRegion* region = spatial->region();
821 const GSkyRegionCircle* circle =
dynamic_cast<const GSkyRegionCircle*
>(region);
824 if (circle != NULL) {
825 int ipix =
m_counts.dir2inx(circle->centre());
826 srcInxPix.push_back(ipix);
846 if ((*
this)[
"coordsys"].
string() ==
"CEL") {
847 dir.radec_deg((*
this)[
"xsrc"].real(),(*
this)[
"ysrc"].real());
850 dir.lb_deg((*
this)[
"xsrc"].real(),(*
this)[
"ysrc"].real());
855 srcInxPix.push_back(ipix);
878 GModelSpatialPointSource spatial(dir);
881 GModelSpectralPlaw spectral(5.7e-18, -2.48, GEnergy(0.3,
"TeV"));
884 GModelSky model(spatial, spectral);
887 double ra = dir.ra_deg();
888 double dec = dir.dec_deg();
889 std::string name = gammalib::str(ra, 4);
896 name += gammalib::str(std::abs(dec), 4);
920 GNdarray sig_histogram(
m_gti.size());
923 std::vector<bool> accepted_bin_bckg_vector(
m_gti.size(),
true);
926 std::vector<double> alphas =
get_alphas(ipix);
930 for (
int i = 0; i <
m_gti.size(); ++i) {
932 accepted_bin_bckg_vector[i] =
false;
937 bool background_validated =
false;
938 while (background_validated ==
false) {
941 background_validated =
true;
944 for (
int i = 0; i <
m_gti.size(); ++i) {
948 if (!accepted_bin_bckg_vector[i]) {
956 for (
int j = 0; j <
m_gti.size(); ++j) {
957 if (j != i && accepted_bin_bckg_vector[j]) {
965 alpha = alphas[i]/alpha;
968 double alpha1 = alpha + 1.0;
969 double ntotal = non+noff;
970 double arg1 = non/ntotal;
971 double arg2 = noff/ntotal;
977 else if (non > 0.0) {
978 double term1 = non * std::log((alpha1/alpha)*arg1);
979 double term2 = noff * std::log(alpha1*arg2);
980 sig = std::sqrt(2.0 * (term1 + term2));
983 sig = std::sqrt(2.0 * noff * std::log(alpha1));
985 sig *= (non < alpha*noff) ? -1.0 : 1.0;
989 sig_histogram(i) = sig;
994 accepted_bin_bckg_vector[i] =
false;
995 background_validated =
false;
1003 return sig_histogram;
1016 std::vector<double> alphas(
m_gti.size(), 0.0);
1019 GSkyDir pix_dir =
m_counts.inx2dir(ipix);
1022 for (
int i = 0; i <
m_obs.size(); ++i) {
1025 const GCTAObservation*
obs =
dynamic_cast<const GCTAObservation*
>(
m_obs[i]);
1034 GCTARoi roi = obs->roi();
1035 GSkyDir roi_centre = roi.centre().dir();
1036 if (roi_centre.dist_deg(pix_dir) > roi.radius()) {
1041 GCTAInstDir instdir = obs->pointing().instdir(pix_dir);
1044 const GGti& obs_gti(obs->gti());
1047 for (
int j = 0; j <
m_gti.size(); ++j) {
1051 if (exposure > 0.0) {
1054 const GCTAResponseIrf* rsp =
1055 dynamic_cast<const GCTAResponseIrf*
>(obs->response());
1060 "No response information available for "+
1062 "Please specify response information or use "
1063 "another background subtraction method.";
1068 const GCTABackground* bkg = rsp->background();
1073 "No IRF background template found in instrument "
1074 "response function for "+
1076 "response function containing a background template.";
1081 #pragma omp critical(ctfindvar_get_alphas)
1082 alphas[j] += exposure * bkg->rate_ebin(instdir,
m_emin,
m_emax);
1105 double overlap = 0.0;
1108 const GGti& gti_1st = (gti1.tstart() <= gti2.tstart()) ? gti1 : gti2;
1109 const GGti& gti_2nd = (gti1.tstart() > gti2.tstart()) ? gti1 : gti2;
1112 if (gti_1st.tstop() > gti_2nd.tstart()) {
1113 if (gti_1st.tstop() <= gti_2nd.tstop()) {
1114 overlap = gti_1st.tstop() - gti_2nd.tstart();
1116 else if (gti_1st.tstop() > gti_2nd.tstop()) {
1117 overlap = gti_2nd.tstop() - gti_2nd.tstart();
1134 GTime tstart(
"JD 999999999");
1137 if ((*
this)[
"tmin"].is_valid()) {
1140 tstart = (*this)[
"tmin"].time();
1143 log_string(NORMAL,
"Setting start time \"tmin\" parameter");
1151 for (
int k = 0; k <
m_obs.size(); ++k) {
1154 GCTAObservation*
obs =
dynamic_cast<GCTAObservation*
>(
m_obs[k]);
1161 if (obs->gti().tstart() < tstart) {
1162 tstart = obs->gti().tstart();
1170 log_string(NORMAL,
"Setting start time from observations");
1187 GTime tstop(
"JD 0");
1190 if ((*
this)[
"tmax"].is_valid()) {
1193 tstop = (*this)[
"tmax"].time();
1196 log_string(NORMAL,
"Setting stop time \"tmax\" parameter");
1204 for (
int k = 0; k <
m_obs.size(); ++k) {
1207 GCTAObservation*
obs =
dynamic_cast<GCTAObservation*
>(
m_obs[k]);
1214 if (obs->gti().tstop() > tstop) {
1215 tstop = obs->gti().tstop();
1223 log_string(NORMAL,
"Setting stop time from observations");
1251 double tinterval = (*this)[
"tinterval"].real();
1254 GNdarray time_info(2, nbins);
1255 GNdarray max_pixel_info(nbins);
1256 GNdarray src_info(nsrc, nbins);
1259 for (
int i = 0; i < nbins; ++i) {
1262 GTime tstart_bin(
m_tstart + i * tinterval);
1263 GTime tstop_bin(
m_tstart + (i+1) * tinterval);
1264 GTime midpoint((tstop_bin.secs()+tstart_bin.secs())*0.5);
1267 time_info(0,i) = tstart_bin.mjd();
1268 time_info(1,i) = tstop_bin.mjd();
1274 for (
int k = 0; k < nsrc; ++k) {
1275 src_info(k,i) = (index >= 0) ?
m_pixsigsrc(k,index) : 0.0;
1279 max_pixel_info(i) = (index >= 0) ?
m_pixsigmax(index) : 0.0;
1284 GFitsBinTable table_signif(nbins);
1285 GFitsBinTable table_pos(nsrc+1);
1286 table_signif.extname(
"SOURCE SIGNIFICANCE");
1287 table_pos.extname(
"SOURCE POSITION");
1290 GFitsTableDoubleCol time_start(
"TSTART", nbins);
1291 GFitsTableDoubleCol time_stop(
"TSTOP", nbins);
1292 GFitsTableDoubleCol time_sigma(
"MAXSIGPIXEL", nbins);
1293 time_start.unit(
"MJD");
1294 time_stop.unit(
"MJD");
1295 time_sigma.unit(
"sigma");
1298 GFitsTableStringCol pos_name(
"SOURCE", nsrc+1, 20);
1299 GFitsTableDoubleCol pos_ra(
"RA", nsrc+1);
1300 GFitsTableDoubleCol pos_dec(
"DEC", nsrc+1);
1302 pos_dec.unit(
"deg");
1305 for (
int i = 0; i < nbins; ++i) {
1306 time_start(i) = time_info(0,i);
1307 time_stop(i) = time_info(1,i);
1308 time_sigma(i) = max_pixel_info(i);
1312 pos_name(0) =
"MAXSIGPIXEL";
1317 table_signif.append(time_start);
1318 table_signif.append(time_stop);
1319 table_signif.append(time_sigma);
1322 for (
int k = 0; k < nsrc; ++k) {
1325 std::string src_name(
"SOURCE");
1332 GModelSky* model =
dynamic_cast<GModelSky*
>(
m_inmodel[k]);
1337 if (model != NULL) {
1340 const GModelSpatial* spatial = model->spatial();
1341 const GSkyRegion* region = spatial->region();
1342 const GSkyRegionCircle* circle =
dynamic_cast<const GSkyRegionCircle*
>(region);
1346 if (circle != NULL) {
1348 src_dir = circle->centre();
1357 if ((*
this)[
"coordsys"].
string() ==
"CEL") {
1358 src_dir.radec_deg((*
this)[
"xsrc"].real(), (*
this)[
"ysrc"].real());
1361 src_dir.lb_deg((*
this)[
"xsrc"].real(), (*
this)[
"ysrc"].real());
1366 GFitsTableDoubleCol column(src_name, nbins);
1367 column.unit(
"sigma");
1370 for (
int i = 0; i < nbins; ++i) {
1371 column(i) = src_info(k, i);
1375 table_signif.append(column);
1378 pos_name(k+1) = src_name;
1379 pos_ra(k+1) = src_dir.ra_deg();
1380 pos_dec(k+1) = src_dir.dec_deg();
1385 table_pos.append(pos_name);
1386 table_pos.append(pos_ra);
1387 table_pos.append(pos_dec);
1390 fits.append(table_signif);
1391 fits.append(table_pos);
1410 for (
int i = 0; i <
m_gti.size(); ++i) {
1413 if (
m_gti[i].contains(time)) {
Time variability search tool.
std::vector< double > get_alphas(const int &ipix) const
Get alpha vector.
GTime m_tstart
Start time for variability study.
GNdarray m_pixsigsrc
Store distributions of the source significances.
int time2inx(const GTime &time) const
Get the map index associated with a given time.
ctfindvar(void)
Void constructor.
#define G_FILL_ALPHA_VECTOR
void save(void)
Save peak significance map and significance distributions.
GTime get_tstart(void)
Get start time.
const GObservations & obs(void) const
Return observation container.
void process(void)
Process time variability search tool.
void analyse_cube(void)
Analyse all pixels of counts cube.
void clear(void)
Clear time variability search tool.
ctfindvar & operator=(const ctfindvar &app)
Assignment operator.
GNdarray m_pixsigmax
Store distribution for pixel with max significance.
GEnergy m_emin
Minimum energy for events.
GModelSky sky_model(const GSkyDir &dir) const
Return sky model for a given sky direction.
void copy_members(const ctfindvar &app)
Copy class members.
GTime get_tstop(void)
Get stop time.
GSkyMap m_peaksigmap
Skymap holding the maximum significance.
void init_gtis(void)
Initialize Good Time Intervals.
Base class for observation tools.
GModels m_model_above_thr
Model storing position with significance above thr.
void free_members(void)
Delete class members.
virtual ~ctfindvar(void)
Destructor.
void init_members(void)
Initialise class members.
double m_sig_threshold
Minimum significance required to set source as variable.
void create_cube(void)
Create counts cube.
void free_members(void)
Delete class members.
void init_members(void)
Initialise class members.
std::vector< int > get_pixels(void)
Return pixel vector.
std::vector< GGti > m_gti
List of time intervals.
ctobservation & operator=(const ctobservation &app)
Assignment operator.
GTime m_tstop
Stop time for variability study.
GSkyMap m_counts
Counts for each time interval.
GNdarray get_variability_sig(const int &ipix)
Get the significance of variability for a given skymap pixel.
double m_minoff
Minimum counts for use in significance calculation.
double gti_overlap(const GGti >i1, const GGti >i2) const
Returns number of seconds that two GTIs overlap.
GObservations m_obs
Observation container.
Time variability search tool definition.
void get_parameters(void)
Get application parameters.
void fill_cube(GCTAObservation *obs)
Fill the cube from the events in an observation.
void write_source_histograms(GFits &fits)
Write source histograms in FITS format.
GSkyDir m_max_sig_dir
Sky direction associated with maximum significance.
GModels m_inmodel
List of models for source positions.
GEnergy m_emax
Maximum energy for events.