548 if ((*
this)[
"emin"].is_valid() && (*
this)[
"emax"].is_valid()) {
549 m_emin = (*this)[
"emin"].real();
550 m_emax = (*this)[
"emax"].real();
558 std::string phase_expr = gammalib::strip_whitespace(gammalib::tolower(
559 (*
this)[
"phase"].
string()));
562 if ((phase_expr.length() > 0) && (phase_expr !=
"none")) {
565 std::string phase_expr = (*this)[
"phase"].string();
568 std::vector<std::string> phase_splits = gammalib::split(phase_expr,
",");
569 for (
int i = 0; i < phase_splits.size(); ++i) {
572 std::vector<std::string> phase_toks =
573 gammalib::split(phase_splits[i],
":");
576 if (phase_toks.size() != 2) {
577 std::string msg =
"Invalid phase selection string \""+
578 phase_splits[i]+
"\" encountered. The phase "
579 "selection string requires a minimum and "
580 "maximum value separated by a colon, e.g. "
586 if (gammalib::strip_whitespace(phase_toks[0]).length() == 0) {
587 std::string msg =
"Invalid phase selection string \""+
588 phase_splits[i]+
"\" encountered. The phase "
589 "selection string requires a minimum and "
590 "maximum value separated by a colon, e.g. "
594 if (gammalib::strip_whitespace(phase_toks[1]).length() == 0) {
595 std::string msg =
"Invalid phase selection string \""+
596 phase_splits[i]+
"\" encountered. The phase "
597 "selection string requires a minimum and "
598 "maximum value separated by a colon, e.g. "
604 double phase_min = gammalib::todouble(phase_toks[0]);
605 double phase_max = gammalib::todouble(phase_toks[1]);
609 if (phase_min < 0.0 || phase_min > 1.0) {
610 std::string msg =
"Phase minimum "+gammalib::str(phase_min)+
611 " outside the valid range [0,1]. Please "
612 "specify phase interval boundaries comprised "
616 if (phase_max < 0.0 || phase_max > 1.0) {
617 std::string msg =
"Phase maximum "+gammalib::str(phase_max)+
618 " outside the valid range [0,1]. Please "
619 "specify phase interval boundaries comprised "
625 m_phases.append(phase_min, phase_max);
635 m_expr = (*this)[
"expr"].string();
636 m_chatter =
static_cast<GChatter
>((*this)[
"chatter"].integer());
640 (*this)[
"outobs"].query();
641 (*this)[
"prefix"].query();
674 const std::string& filename,
675 const std::string& evtname,
676 const std::string& gtiname)
679 log_header3(NORMAL,
"Event selection");
682 std::string selection;
686 bool remove_all =
false;
689 GCTAEventList* list =
690 static_cast<GCTAEventList*
>(
const_cast<GEvents*
>(
obs->events()));
694 GGti user_gti =
get_gti(list->gti().reference());
695 GTime timemin = user_gti.tstart();
696 GTime timemax = user_gti.tstop();
700 GCTARoi old_roi = list->roi();
701 GEbounds old_ebounds = list->ebounds();
708 if (ebounds.size() >= 1) {
709 emin = ebounds.emin(0).TeV();
710 emax = ebounds.emax(0).TeV();
714 bool select_expr = (gammalib::strip_whitespace(
m_expr).length() > 0);
718 double ra = roi.centre().dir().ra_deg();
719 double dec = roi.centre().dir().dec_deg();
720 double rad = roi.radius();
723 bool select_roi = roi.is_valid();
727 bool enforced_roi =
false;
732 if (!user_gti.is_empty()) {
737 ((GGti*)(&list->gti()))->reduce(timemin, timemax);
742 GGti gti = list->gti();
745 if (!user_gti.is_empty()) {
748 if (list->gti().is_empty()) {
750 log_value(NORMAL,
"Time range",
"None. There is no overlap "
751 "between existing and requested time interval.");
759 double tmin = gti.tstart().convert(gti.reference());
760 double tmax = gti.tstop().convert(gti.reference());
765 sprintf(cmin,
"%.8f", tmin);
766 sprintf(cmax,
"%.8f", tmax);
767 selection =
"TIME >= "+std::string(cmin)+
" && TIME <= "+std::string(cmax);
769 log_value(NORMAL,
"Time range (MJD)",
770 gammalib::str(gti.tstart().mjd())+
" - "+
771 gammalib::str(gti.tstop().mjd())+
" days");
772 log_value(NORMAL,
"Time range (UTC)",
773 gti.tstart().utc()+
" - "+gti.tstop().utc());
774 log_value(NORMAL,
"Time range (MET)",
775 gammalib::str(tmin)+
" - "+gammalib::str(tmax)+
" seconds");
785 if (list->has_phase()) {
788 for (
int i = 0; i <
m_phases.size(); ++i) {
792 selection += add +
"( ";
801 sprintf(cmin,
"%.8f",
m_phases.pmin(i));
802 sprintf(cmax,
"%.8f",
m_phases.pmax(i));
803 selection +=
"(PHASE >= "+std::string(cmin)+
" && PHASE <= "+
804 std::string(cmax)+
")";
806 log_value(NORMAL,
"Phase range "+gammalib::str(i+1),
807 gammalib::str(
m_phases.pmin(i))+
" - "+
823 log_value(NORMAL,
"Phase range",
"Event list has no \"PHASE\" "
824 "column. Phase selection skipped.");
834 log << gammalib::parformat(
"Selected energy range");
835 if (emin > 0.0 && emax > 0.0) {
837 log <<
"None. There is no overlap between existing ";
838 log <<
"and requested energy range." << std::endl;
841 log << emin <<
" - " << emax <<
" TeV" << std::endl;
844 else if (emin > 0.0) {
845 log <<
"> " << emin <<
" TeV" << std::endl;
847 else if (emax > 0.0) {
848 log <<
"< " << emax <<
" TeV" << std::endl;
851 log <<
"None" << std::endl;
856 if (emin > 0.0 && emax > 0.0) {
863 sprintf(cmin,
"%.8f", emin);
864 sprintf(cmax,
"%.8f", emax);
865 selection += add +
"ENERGY >= " + std::string(cmin)+
866 " && ENERGY <= " + std::string(cmax);
870 else if (emin > 0.0) {
872 sprintf(cmin,
"%.8f", emin);
873 selection += add +
"ENERGY >= " + std::string(cmin);
876 else if (emax > 0.0) {
878 sprintf(cmax,
"%.8f", emax);
879 selection += add +
"ENERGY <= " + std::string(cmax);
892 double original_rad = rad;
895 log_value(NORMAL,
"Requested RoI",
896 "Centre(RA,DEC)=("+gammalib::str(ra)+
", "+
897 gammalib::str(dec)+
") deg, Radius="+gammalib::str(rad)+
902 double roi_radius = list->roi().radius();
903 if (roi_radius > 0.0) {
904 GSkyDir roi_centre = list->roi().centre().dir();
905 log_value(NORMAL,
"RoI of data",
906 "Centre(RA,DEC)=("+gammalib::str(roi_centre.ra_deg())+
907 ", "+gammalib::str(roi_centre.dec_deg())+
") deg, Radius="+
908 gammalib::str(roi_radius)+
" deg");
910 centre.radec_deg(ra, dec);
911 double distance = centre.dist_deg(roi_centre);
918 if ((distance < 1.e-4) && (rad >= roi_radius)) {
926 else if ((distance + rad - roi_radius) > 1.e-4) {
932 "WARNING: Enforced RoI selection leading to inconsis" \
934 " RoI of data: Centre(RA,DEC)=("+ \
935 gammalib::str(ra)+
", "+gammalib::str(dec)+
") deg, " \
936 "Radius="+gammalib::str(rad)+
" deg.\n" \
937 " Requested RoI: Centre(RA,DEC)=("+ \
938 gammalib::str(roi_centre.ra_deg())+
", "+ \
939 gammalib::str(roi_centre.dec_deg())+
") deg, " \
940 "Radius="+gammalib::str(roi_radius)+
" deg.\n" \
941 " The resulting event list file is not usable " \
942 "for likelihood analysis";
943 log_string(TERSE, msg);
949 "Invalid RoI selection: the new RoI must be enclosed "
950 "in the original RoI";
951 throw GException::invalid_value(
G_PROCESS, msg);
963 log_value(NORMAL,
"Selected RoI",
"None. There is no overlap "
964 "between existing and requested RoI.");
967 log_value(NORMAL,
"Selected RoI",
"Centre(RA,DEC)=("+
968 gammalib::str(ra)+
", "+gammalib::str(dec)+
") deg, "
969 "Radius="+gammalib::str(rad)+
" deg");
976 sprintf(cra,
"%.6f", ra);
977 sprintf(cdec,
"%.6f", dec);
978 sprintf(crad,
"%.6f", rad);
979 selection += add +
"ANGSEP("+std::string(cra)+
"," +
980 std::string(cdec)+
",RA,DEC) <= " +
990 selection += add +
"("+gammalib::strip_whitespace(
m_expr)+
")";
995 log_value(NORMAL,
"cfitsio selection", selection);
998 std::string expression = filename +
"[" + evtname +
"]";
999 if (selection.length() > 0) {
1000 expression +=
"["+selection+
"]";
1004 log_value(NORMAL,
"FITS filename", expression);
1007 GFits file(expression);
1010 log_header3(EXPLICIT,
"FITS file content after selection");
1011 log_string(EXPLICIT, file.print(
m_chatter));
1014 if (!file.contains(evtname)) {
1015 std::string msg =
"No events extension \""+evtname+
"\" found in "
1016 "FITS file. The expression \""+expression+
"\" "
1017 "was used to open the FITS file.";
1023 int nevents = (remove_all) ? 0 : file.table(evtname)->nrows();
1030 GCTAEventList eventlist;
1033 obs->events(eventlist);
1043 list =
static_cast<GCTAEventList*
>(
const_cast<GEvents*
>(
obs->events()));
1051 if (select_roi && !enforced_roi) {
1053 skydir.radec_deg(ra, dec);
1054 GCTAInstDir instdir(skydir);
1055 list->roi(GCTARoi(instdir, rad));
1059 else if (old_roi.is_valid()) {
1069 ebounds.append(GEnergy(emin,
"TeV"), GEnergy(emax,
"TeV"));
1070 list->ebounds(ebounds);
1074 else if (old_ebounds.size() > 0) {
1075 list->ebounds(old_ebounds);
1084 obs->ontime(list->gti().ontime());
1085 obs->livetime(list->gti().ontime() *
obs->deadc());
1127 if (ebounds.size() > 0) {
1130 if ((emin == 0.0) ||
1131 ((ebounds.emin(0).TeV() > 0.0) && (emin < ebounds.emin(0).TeV()))) {
1132 emin = ebounds.emin(0).TeV();
1136 if ((emax == 0.0) ||
1137 ((ebounds.emax(0).TeV() > 0.0) && (emax > ebounds.emax(0).TeV()))) {
1138 emax = ebounds.emax(0).TeV();
1149 const GCTAResponseIrf* rsp =
dynamic_cast<const GCTAResponseIrf*
>
1152 std::string msg =
"No IRF response attached to given observation.";
1157 double lo_safe_thres = rsp->lo_safe_thres();
1158 double hi_safe_thres = rsp->hi_safe_thres();
1161 if ((lo_safe_thres > 0.0) &&
1162 (hi_safe_thres > 0.0) &&
1163 (lo_safe_thres >= hi_safe_thres)) {
1164 std::string msg =
"IRF \""+
obs->name()+
"\" contains an invalid "
1165 "energy range ["+gammalib::str(lo_safe_thres)+
","+
1166 gammalib::str(hi_safe_thres)+
"] TeV.";
1171 if ((emin == 0.0) ||
1172 ((lo_safe_thres > 0.0) && (emin < lo_safe_thres))) {
1173 emin = lo_safe_thres;
1177 if ((emax == 0.0) ||
1178 ((hi_safe_thres > 0.0) && (emax > hi_safe_thres))) {
1179 emax = hi_safe_thres;
1188 double lo_user_thres =
obs->lo_user_thres();
1189 double hi_user_thres =
obs->hi_user_thres();
1192 if ((lo_user_thres > 0.0) &&
1193 (hi_user_thres > 0.0) &&
1194 (lo_user_thres >= hi_user_thres)) {
1195 std::string msg =
"User energy range ["+gammalib::str(lo_user_thres)+
1196 ","+gammalib::str(hi_user_thres)+
"] TeV is invalid.";
1201 if ((emin == 0.0) ||
1202 ((lo_user_thres > 0.0) && (emin < lo_user_thres))) {
1203 emin = lo_user_thres;
1207 if ((emax == 0.0) ||
1208 ((hi_user_thres > 0.0) && (emax > hi_user_thres))) {
1209 emax = hi_user_thres;
1217 result.append(GEnergy(emin,
"TeV"), GEnergy(emax,
"TeV"));