Commit b82ee38d87444dc6991a492e1c97e744ff761c3d

Authored by Jürgen Knödlseder
1 parent 3af8c312

Handle non-default event and Good Time Interval extension names (should fix #1598).

ChangeLog
1   -2016-01-11 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu>
  1 +2016-01-20 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu>
2 2  
3 3 * Version 1.1.0 released
4 4 ========================
5 5  
  6 + ctselect allows usage of non-default events and GTI extensions (#1598)
  7 +
6 8  
7 9 2016-01-11 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu>
8 10  
... ...
... ... @@ -2,7 +2,7 @@ New Features and Important Changes in ctools 1.1.0
2 2  
3 3 Author(s) : Juergen Knoedlseder
4 4  
5   -11 January 2016
  5 +20 January 2016
6 6  
7 7  
8 8 1. Introduction
... ... @@ -33,7 +33,36 @@ None
33 33  
34 34 6. ctselect - CTA event selection
35 35 ---------------------------------
36   -None
  36 +The tool now allows the usage of non-default extension names for the event
  37 +and Good Time Intervals. If the events are not located in the "EVENTS"
  38 +extension, the extension name can be provided by appending the extension
  39 +name to the input file name using the syntax
  40 +
  41 + <filename>[<event extension name>]
  42 +
  43 +where <filename> needs to be replaced by the name of the FITS file and
  44 +<event extension name> by the name of the FITS extension. ctselect also
  45 +extracts the name of the Good Time Intervals extension from the data sub-
  46 +space keywords provided in the header of the event file.
  47 +
  48 +The user has now also the possibility to specify other extension names for
  49 +the events and the Good Time intervals upon writing of the selected output
  50 +file. The format of the "outobs" parameter for this is
  51 +
  52 + <filename>[<event extension name;GTI extension name>]
  53 +
  54 +If only an event extension name is provided using
  55 +
  56 + <filename>[<event extension name>]
  57 +
  58 +the original extension name will be kept for the GTIs. Changing only the
  59 +GTI extension name can be achieved using
  60 +
  61 + <filename>[;GTI extension name>]
  62 +
  63 +The ctselect tool now can also write the output into the same file that
  64 +was input, replacing the initial event (and eventually also Good Time
  65 +Intervals) extensions.
37 66  
38 67  
39 68 7. ctbin - CTA event binning
... ...
src/ctselect/ctselect.cpp
1 1 /***************************************************************************
2 2 * ctselect - Data selection tool *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2010-2015 by Juergen Knoedlseder *
  4 + * copyright (C) 2010-2016 by Juergen Knoedlseder *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -35,7 +35,7 @@
35 35 /* __ Method name definitions ____________________________________________ */
36 36 #define G_RUN "ctselect::run()"
37 37 #define G_SELECT_EVENTS "ctselect::select_events(GCTAObservation*, "\
38   - "std::string&)"
  38 + "std::string&, std::string&, std::string&)"
39 39 #define G_SET_EBOUNDS "ctselect::set_ebounds(GCTAObservation*, GEbounds&)"
40 40 #define G_GET_PARAMETERS "ctselect::get_parameters()"
41 41  
... ... @@ -69,8 +69,8 @@ ctselect::ctselect(void) : ctool(CTSELECT_NAME, CTSELECT_VERSION)
69 69 *
70 70 * param[in] obs Observation container.
71 71 *
72   - * This constructor creates an instance of the class that is initialised from
73   - * an observation container.
  72 + * Creates an instance of the class that is initialised using the information
  73 + * provided in an observation container.
74 74 ***************************************************************************/
75 75 ctselect::ctselect(const GObservations& obs) :
76 76 ctool(CTSELECT_NAME, CTSELECT_VERSION)
... ... @@ -206,7 +206,7 @@ void ctselect::clear(void)
206 206 * selection is done by writing each observation to a temporary file and
207 207 * re-opening the temporary file using the cfitsio event filter syntax.
208 208 * The temporary file is deleted after this action so that no disk overflow
209   - * will occur.
  209 + * will occur.
210 210 ***************************************************************************/
211 211 void ctselect::run(void)
212 212 {
... ... @@ -255,8 +255,11 @@ void ctselect::run(void)
255 255 log.header3(header);
256 256 }
257 257  
258   - // Initialise event input and output filenames
  258 + // Initialise event input and output filenames and the event
  259 + // and GTI extension names
259 260 m_infiles.push_back("");
  261 + m_evtname.push_back("EVENTS");
  262 + m_gtiname.push_back("GTI");
260 263  
261 264 // Get CTA observation
262 265 GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]);
... ... @@ -287,6 +290,23 @@ void ctselect::run(void)
287 290 // Save event file name (for possible saving)
288 291 m_infiles[i] = obs->eventfile();
289 292  
  293 + // Extract event and GTI extension names from input FITS file
  294 + GFilename fname(m_infiles[i]);
  295 + if (fname.has_extname()) {
  296 + m_evtname[i] = fname.extname();
  297 + }
  298 + m_gtiname[i] = get_gtiname(fname.filename(), m_evtname[i]);
  299 +
  300 + // Log input file information
  301 + if (logTerse()) {
  302 + log << gammalib::parformat("Input filename");
  303 + log << m_infiles[i] << std::endl;
  304 + log << gammalib::parformat("Event extension name");
  305 + log << m_evtname[i] << std::endl;
  306 + log << gammalib::parformat("GTI extension name");
  307 + log << m_gtiname[i] << std::endl;
  308 + }
  309 +
290 310 // Fall through in case that the event file is empty
291 311 if (obs->events()->size() == 0) {
292 312 if (logTerse()) {
... ... @@ -297,6 +317,14 @@ void ctselect::run(void)
297 317 continue;
298 318 }
299 319  
  320 + // If we have an input file then check it
  321 + if (!m_infiles[i].empty()) {
  322 + std::string message = check_infile(m_infiles[i], m_evtname[i]);
  323 + if (message.length() > 0) {
  324 + throw GException::app_error(G_RUN, message);
  325 + }
  326 + }
  327 +
300 328 // Get temporary file name
301 329 #if G_USE_MKSTEMP
302 330 char tpl[] = "ctselectXXXXXX";
... ... @@ -306,10 +334,13 @@ void ctselect::run(void)
306 334 std::string filename = std::tmpnam(NULL);
307 335 #endif
308 336  
309   - // Save observation in temporary file
310   - obs->save(filename, true);
  337 + // Save observation in temporary file. We add here the events and
  338 + // GTI extension name so that the GCTAObservation::save method can
  339 + // use this information for writing the proper extension names into
  340 + // the temporary file
  341 + obs->save(filename+"["+m_evtname[i]+";"+ m_gtiname[i]+"]", true);
311 342  
312   - // Log saved FITS file
  343 + // Log saved FITS file.
313 344 if (logExplicit()) {
314 345 GFits tmpfile(filename);
315 346 log << std::endl;
... ... @@ -318,14 +349,16 @@ void ctselect::run(void)
318 349 tmpfile.close();
319 350 }
320 351  
321   - // Check temporary file
322   - std::string message = check_infile(filename);
323   - if (message.length() > 0) {
324   - throw GException::app_error(G_RUN, message);
  352 + // If we have a temporary file then check it
  353 + if (!filename.empty()) {
  354 + std::string message = check_infile(filename, m_evtname[i]);
  355 + if (message.length() > 0) {
  356 + throw GException::app_error(G_RUN, message);
  357 + }
325 358 }
326 359  
327 360 // Load observation from temporary file, including event selection
328   - select_events(obs, filename);
  361 + select_events(obs, filename, m_evtname[i], m_gtiname[i]);
329 362  
330 363 // Close temporary file
331 364 #if G_USE_MKSTEMP
... ... @@ -430,6 +463,8 @@ void ctselect::init_members(void)
430 463 // Initialise protected members
431 464 m_obs.clear();
432 465 m_infiles.clear();
  466 + m_evtname.clear();
  467 + m_gtiname.clear();
433 468 m_timemin.clear();
434 469 m_timemax.clear();
435 470 m_select_energy = true;
... ... @@ -449,7 +484,7 @@ void ctselect::init_members(void)
449 484 void ctselect::copy_members(const ctselect& app)
450 485 {
451 486 // Copy parameters
452   - m_outobs = app.m_outobs;
  487 + m_outobs = app.m_outobs;
453 488 m_prefix = app.m_prefix;
454 489 m_usepnt = app.m_usepnt;
455 490 m_ra = app.m_ra;
... ... @@ -465,6 +500,8 @@ void ctselect::copy_members(const ctselect&amp; app)
465 500 // Copy protected members
466 501 m_obs = app.m_obs;
467 502 m_infiles = app.m_infiles;
  503 + m_evtname = app.m_evtname;
  504 + m_gtiname = app.m_gtiname;
468 505 m_timemin = app.m_timemin;
469 506 m_timemax = app.m_timemax;
470 507 m_select_energy = app.m_select_energy;
... ... @@ -594,27 +631,29 @@ void ctselect::get_parameters(void)
594 631 /***********************************************************************//**
595 632 * @brief Select events
596 633 *
597   - * @param[in] obs CTA observation.
  634 + * @param[in,out] obs CTA observation.
598 635 * @param[in] filename File name.
  636 + * @param[in] evtname Event extension name.
  637 + * @param[in] gtiname GTI extension name.
599 638 *
600 639 * @exception GException::invalid_value
601   - * No EVENTS extension found in FITS file.
  640 + * No events extension found in FITS file.
602 641 *
603 642 * Select events from a FITS file by making use of the selection possibility
604 643 * of the cfitsio library on loading a file. A selection string is created
605 644 * from the specified criteria that is appended to the filename so that
606 645 * cfitsio will automatically filter the event data. This selection string
607   - * is then applied when opening the FITS file. The opened FITS file is then
608   - * saved into a temporary file which is the loaded into the actual CTA
609   - * observation, overwriting the old CTA observation. The ROI, GTI and Ebounds
610   - * of the CTA event list are then set accordingly to the specified selection.
611   - * Finally, the temporary file created during this process is removed.
  646 + * is then applied when opening the FITS file. The event list in the current
  647 + * observation is replaced by selected event list read from the FITS file.
612 648 *
613 649 * Good Time Intervals of the observation will be limited to the time
614 650 * interval [m_tmin, m_tmax]. If m_tmin=m_tmax=0, no time selection is
615 651 * performed.
616 652 ***************************************************************************/
617   -void ctselect::select_events(GCTAObservation* obs, const std::string& filename)
  653 +void ctselect::select_events(GCTAObservation* obs,
  654 + const std::string& filename,
  655 + const std::string& evtname,
  656 + const std::string& gtiname)
618 657 {
619 658 // Initialise selection string
620 659 std::string selection;
... ... @@ -642,7 +681,7 @@ void ctselect::select_events(GCTAObservation* obs, const std::string&amp; filename)
642 681 }
643 682  
644 683 // Analyse expression to see if a selection is required
645   - bool select_expr = (gammalib::strip_whitespace(m_expr).length() > 0);
  684 + bool select_expr = (gammalib::strip_whitespace(m_expr).length() > 0);
646 685  
647 686 // Set RA/DEC selection. If the "usepnt" parameter is set to true then
648 687 // use the pointing direction as the ROI centre.
... ... @@ -835,7 +874,7 @@ void ctselect::select_events(GCTAObservation* obs, const std::string&amp; filename)
835 874 // Build input filename including selection expression
836 875 std::string expression = filename;
837 876 if (selection.length() > 0) {
838   - expression += "[EVENTS]["+selection+"]";
  877 + expression += "["+evtname+"]["+selection+"]";
839 878 }
840 879  
841 880 // Dump FITS filename including selection expression
... ... @@ -854,15 +893,16 @@ void ctselect::select_events(GCTAObservation* obs, const std::string&amp; filename)
854 893 log << file << std::endl;
855 894 }
856 895  
857   - // Check if we have an EVENTS HDU
858   - if (!file.contains("EVENTS")) {
859   - std::string msg = "No \"EVENTS\" extension found in FITS file \""+
860   - expression+"\".";
  896 + // Check if we have an events HDU
  897 + if (!file.contains(evtname)) {
  898 + std::string msg = "No events extension \""+evtname+"\" found in "
  899 + "FITS file. The expression \""+expression+"\" "
  900 + "was used to open the FITS file.";
861 901 throw GException::invalid_value(G_SELECT_EVENTS, msg);
862 902 }
863 903  
864   - // Determine number of events in EVENTS HDU
865   - int nevents = file.table("EVENTS")->nrows();
  904 + // Determine number of events in the events HDU
  905 + int nevents = file.table(evtname)->nrows();
866 906  
867 907 // If the selected event list is empty or if removal of all events
868 908 // has been requested then append an empty event list to the observation.
... ... @@ -1060,23 +1100,30 @@ GEbounds ctselect::set_ebounds(GCTAObservation* obs, const GEbounds&amp; ebounds) co
1060 1100 * @brief Check input filename
1061 1101 *
1062 1102 * @param[in] filename File name.
  1103 + * @param[in] evtname Event extension name.
1063 1104 *
1064 1105 * This method checks if the input FITS file is correct.
1065 1106 ***************************************************************************/
1066   -std::string ctselect::check_infile(const std::string& filename) const
  1107 +std::string ctselect::check_infile(const std::string& filename,
  1108 + const std::string& evtname) const
1067 1109 {
1068 1110 // Initialise message string
1069 1111 std::string message = "";
1070 1112  
1071 1113 // Open FITS file
1072   - GFits file(filename);
  1114 + GFits fits(filename);
  1115 +
  1116 + // Check for existence of events extensions
  1117 + if (!fits.contains(evtname)) {
  1118 + message = "No \""+evtname+"\" extension found in input file \""+
  1119 + filename + "\".";
  1120 + }
1073 1121  
1074   - // Check for EVENTS HDU
1075   - GFitsTable* table = NULL;
1076   - try {
  1122 + // ... otherwise check column names
  1123 + else {
1077 1124  
1078 1125 // Get pointer to FITS table
1079   - table = file.table("EVENTS");
  1126 + GFitsTable* table = fits.table(evtname);
1080 1127  
1081 1128 // Initialise list of missing columns
1082 1129 std::vector<std::string> missing;
... ... @@ -1103,9 +1150,9 @@ std::string ctselect::check_infile(const std::string&amp; filename) const
1103 1150  
1104 1151 // Set error message for missing columns
1105 1152 if (!missing.empty()) {
1106   - message = "The following columns are missing in the"
1107   - " \"EVENTS\" extension of input file \""
1108   - + m_outobs + "\": ";
  1153 + message = "The following columns are missing in the "
  1154 + "\""+evtname+"\" extension of input file \""+
  1155 + filename + "\": ";
1109 1156 for (int i = 0; i < missing.size(); ++i) {
1110 1157 message += "\"" + missing[i] + "\"";
1111 1158 if (i < missing.size()-1) {
... ... @@ -1114,11 +1161,7 @@ std::string ctselect::check_infile(const std::string&amp; filename) const
1114 1161 }
1115 1162 }
1116 1163  
1117   - }
1118   - catch (GException::fits_hdu_not_found& e) {
1119   - message = "No \"EVENTS\" extension found in input file \""
1120   - + m_outobs + "\".";
1121   - }
  1164 + } // endelse: checked column names
1122 1165  
1123 1166 // Return
1124 1167 return message;
... ... @@ -1130,15 +1173,18 @@ std::string ctselect::check_infile(const std::string&amp; filename) const
1130 1173 *
1131 1174 * @param[in] filename Input file name.
1132 1175 *
1133   - * Converts an input filename into an output filename by prepending the
1134   - * prefix stored in the member m_prefix to the input filename. Any path will
1135   - * be stripped from the input filename. Also a trailing ".gz" will be
1136   - * stripped.
  1176 + * Converts an input file name into an output filename by prepending the
  1177 + * prefix stored in the member m_prefix to the input file name. Any path as
  1178 + * well as extension will be stripped from the input file name. Also a
  1179 + * trailing ".gz" will be stripped as one cannot write into gzipped files.
1137 1180 ***************************************************************************/
1138 1181 std::string ctselect::set_outfile_name(const std::string& filename) const
1139 1182 {
1140   - // Split input filename into path elements
1141   - std::vector<std::string> elements = gammalib::split(filename, "/");
  1183 + // Create filename
  1184 + GFilename fname(filename);
  1185 +
  1186 + // Split input filename without any extensions into path elements
  1187 + std::vector<std::string> elements = gammalib::split(fname.filename(), "/");
1142 1188  
1143 1189 // The last path element is the filename
1144 1190 std::string outname = m_prefix + elements[elements.size()-1];
... ... @@ -1152,10 +1198,43 @@ std::string ctselect::set_outfile_name(const std::string&amp; filename) const
1152 1198  
1153 1199  
1154 1200 /***********************************************************************//**
  1201 + * @brief Get Good Time Intervals extension name
  1202 + *
  1203 + * @param[in] filename Input file name.
  1204 + * @param[in] evtname Events extension name.
  1205 + *
  1206 + * Extracts the Good Time Intervals extension name from the event file. We
  1207 + * do this by loading the events and accessing the Good Time Intervals
  1208 + * extension name using the GCTAEventList::gtiname() method. If the file name
  1209 + * is empty, the method returns "GTI".
  1210 + ***************************************************************************/
  1211 +std::string ctselect::get_gtiname(const std::string& filename,
  1212 + const std::string& evtname) const
  1213 +{
  1214 + // Initialise GTI name
  1215 + std::string gtiname = "GTI";
  1216 +
  1217 + // Continue only if the filename is not empty
  1218 + if (!filename.empty()) {
  1219 +
  1220 + // Load events
  1221 + GCTAEventList events(filename+"["+evtname+"]");
  1222 +
  1223 + // Get GTI name
  1224 + gtiname = events.gtiname();
  1225 +
  1226 + }
  1227 +
  1228 + // Return GTI name
  1229 + return (gtiname);
  1230 +}
  1231 +
  1232 +
  1233 +/***********************************************************************//**
1155 1234 * @brief Save event list in FITS format.
1156 1235 *
1157   - * Save the event list as a FITS file. The filename of the FITS file is
1158   - * specified by the outfile parameter.
  1236 + * Save the event list as a FITS file. The file name of the FITS file is
  1237 + * specified by the "outobs" parameter.
1159 1238 ***************************************************************************/
1160 1239 void ctselect::save_fits(void)
1161 1240 {
... ... @@ -1168,16 +1247,32 @@ void ctselect::save_fits(void)
1168 1247 // Save only if it's a CTA observation
1169 1248 if (obs != NULL) {
1170 1249  
1171   - // Save only if filename is non-empty
  1250 + // Save only if file name is non-empty
1172 1251 if (m_infiles[0].length() > 0) {
1173 1252  
1174   - // Dump filename
  1253 + // Create file name object
  1254 + GFilename fname(m_outobs);
  1255 +
  1256 + // Extract filename and event extension name
  1257 + std::string outfile = fname.filename();
  1258 +
  1259 + // Append event extension name. We handle here the possibility
  1260 + // to write the events into a different extension.
  1261 + if (fname.has_extname()) {
  1262 + outfile += "["+fname.extname()+"]";
  1263 + }
  1264 + else {
  1265 + outfile += "["+m_evtname[0]+"]";
  1266 + }
  1267 +
  1268 + // Log filename
1175 1269 if (logTerse()) {
1176   - log << "Save \""+m_infiles[0]+"\"" << std::endl;
  1270 + log << "Save \""+outfile+"\"" << std::endl;
1177 1271 }
1178 1272  
1179 1273 // Save event list
1180   - save_event_list(obs, m_infiles[0], m_outobs);
  1274 + save_event_list(obs, m_infiles[0], m_evtname[0], m_gtiname[0],
  1275 + outfile);
1181 1276  
1182 1277 } // endif: filename was non empty
1183 1278  
... ... @@ -1235,7 +1330,10 @@ void ctselect::save_xml(void)
1235 1330 // Set event output file name
1236 1331 std::string outfile = set_outfile_name(m_infiles[i]);
1237 1332  
1238   - // Dump filename
  1333 + // Append event extension name
  1334 + outfile += "["+m_evtname[i]+"]";
  1335 +
  1336 + // Log filename
1239 1337 if (logTerse()) {
1240 1338 log << "Save \""+outfile+"\"" << std::endl;
1241 1339 }
... ... @@ -1244,7 +1342,8 @@ void ctselect::save_xml(void)
1244 1342 obs->eventfile(outfile);
1245 1343  
1246 1344 // Save event list
1247   - save_event_list(obs, m_infiles[i], outfile);
  1345 + save_event_list(obs, m_infiles[i], m_evtname[i], m_gtiname[i],
  1346 + outfile);
1248 1347  
1249 1348 } // endfor: looped over observations
1250 1349  
... ... @@ -1266,13 +1365,45 @@ void ctselect::save_xml(void)
1266 1365 *
1267 1366 * @param[in] obs Pointer to CTA observation.
1268 1367 * @param[in] infile Input file name.
  1368 + * @param[in] evtname Event extension name.
  1369 + * @param[in] gtiname GTI extension name.
1269 1370 * @param[in] outfile Output file name.
1270 1371 *
1271   - * Saves an event list into a FITS file and copy all others extensions from
1272   - * the input file to the output file.
  1372 + * Saves an event list and the corresponding Good Time Intervals into a FITS
  1373 + * file and copy all others extensions from the input file to the output
  1374 + * file.
  1375 + *
  1376 + * If an extension name is specified in the @p outfile argument, the events
  1377 + * and eventually also the Good Time Intervals will be extracted from the
  1378 + * argument and used for writing the events. The format is
  1379 + *
  1380 + * <filename>[<event extension name;GTI extension name>]
  1381 + *
  1382 + * where <filename> needs to be replaced by the name of the FITS file,
  1383 + * and <event extension name;GTI extension name> by the name of the events
  1384 + * and Good Time Intervals extensions. For example
  1385 + *
  1386 + * myfits.fits[EVENTS1;GTI1]
  1387 + *
  1388 + * will write the selected events into the "EVENTS1" extension and the
  1389 + * Good Time Intervals into the "GTI1" extension of the "myfits.fits" FITS
  1390 + * file. If the Good Time Intervals extension name is skipped, e.g.
  1391 + *
  1392 + * myfits.fits[EVENTS1]
  1393 + *
  1394 + * the original extension name for the Good Time Intervals will be kept.
  1395 + * Analogously, only the Good Time Intervals extension name can be changed
  1396 + * by specifying
  1397 + *
  1398 + * myfits.fits[;GTI1]
  1399 + *
  1400 + * In none of the cases will the original events and Good Time Intervals be
  1401 + * copied over to the output file.
1273 1402 ***************************************************************************/
1274 1403 void ctselect::save_event_list(const GCTAObservation* obs,
1275 1404 const std::string& infile,
  1405 + const std::string& evtname,
  1406 + const std::string& gtiname,
1276 1407 const std::string& outfile) const
1277 1408 {
1278 1409 // Save only if observation is valid
... ... @@ -1281,18 +1412,44 @@ void ctselect::save_event_list(const GCTAObservation* obs,
1281 1412 // Save only if we have an event list
1282 1413 if (obs->eventtype() == "EventList") {
1283 1414  
1284   - // Save observation into FITS file
1285   - obs->save(outfile, clobber());
  1415 + // Set output FITS file event extension names
  1416 + GFilename outname(outfile);
  1417 + std::string outevt = evtname;
  1418 + std::string outgti = gtiname;
  1419 + if (outname.has_extname()) {
  1420 + std::vector<std::string> extnames = gammalib::split(outname.extname(), ";");
  1421 + if (extnames.size() > 0) {
  1422 + std::string extname = gammalib::strip_whitespace(extnames[0]);
  1423 + if (!extname.empty()) {
  1424 + outevt = extname;
  1425 + }
  1426 + }
  1427 + if (extnames.size() > 1) {
  1428 + std::string extname = gammalib::strip_whitespace(extnames[1]);
  1429 + if (!extname.empty()) {
  1430 + outgti = extname;
  1431 + }
  1432 + }
  1433 + }
  1434 +
  1435 + // Create output FITS file
  1436 + GFits outfits;
  1437 +
  1438 + // Write observation into FITS file
  1439 + obs->write(outfits, outevt, outgti);
1286 1440  
1287   - // Copy all extensions other than EVENTS and GTI from the input to
1288   - // the output event list. The EVENTS and GTI extensions are written
1289   - // by the save method, all others that may eventually be present
1290   - // have to be copied by hand.
  1441 + // Copy all extensions other than evtname and gtiname extensions
  1442 + // from the input to the output event list. The evtname and
  1443 + // gtiname extensions are written by the save method, all others
  1444 + // that may eventually be present have to be copied over
  1445 + // explicitly.
1291 1446 GFits infits(infile);
1292   - GFits outfits(outfile);
1293 1447 for (int extno = 1; extno < infits.size(); ++extno) {
1294 1448 GFitsHDU* hdu = infits.at(extno);
1295   - if (hdu->extname() != "EVENTS" && hdu->extname() != "GTI") {
  1449 + if (hdu->extname() != evtname &&
  1450 + hdu->extname() != gtiname &&
  1451 + hdu->extname() != outevt &&
  1452 + hdu->extname() != outgti) {
1296 1453 outfits.append(*hdu);
1297 1454 }
1298 1455 }
... ... @@ -1301,7 +1458,7 @@ void ctselect::save_event_list(const GCTAObservation* obs,
1301 1458 infits.close();
1302 1459  
1303 1460 // Save file to disk and close it (we need both operations)
1304   - outfits.save(true);
  1461 + outfits.saveto(outname.filename(), clobber());
1305 1462 outfits.close();
1306 1463  
1307 1464 } // endif: observation was unbinned
... ...
src/ctselect/ctselect.hpp
1 1 /***************************************************************************
2 2 * ctselect - Data selection tool *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2010-2015 by Juergen Knoedlseder *
  4 + * copyright (C) 2010-2016 by Juergen Knoedlseder *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -70,15 +70,23 @@ protected:
70 70 void copy_members(const ctselect& app);
71 71 void free_members(void);
72 72 void get_parameters(void);
73   - void select_events(GCTAObservation* obs, const std::string& filename);
  73 + void select_events(GCTAObservation* obs,
  74 + const std::string& filename,
  75 + const std::string& evtname,
  76 + const std::string& gtiname);
74 77 GEbounds set_ebounds(GCTAObservation* obs,
75 78 const GEbounds& ebounds) const;
76   - std::string check_infile(const std::string& filename) const;
  79 + std::string check_infile(const std::string& filename,
  80 + const std::string& evtname) const;
77 81 std::string set_outfile_name(const std::string& filename) const;
  82 + std::string get_gtiname(const std::string& filename,
  83 + const std::string& evtname) const;
78 84 void save_fits(void);
79 85 void save_xml(void);
80 86 void save_event_list(const GCTAObservation* obs,
81 87 const std::string& infile,
  88 + const std::string& evtname,
  89 + const std::string& gtiname,
82 90 const std::string& outfile) const;
83 91  
84 92 // User parameters
... ... @@ -98,12 +106,13 @@ protected:
98 106 // Protected members
99 107 GObservations m_obs; //!< Observations container
100 108 std::vector<std::string> m_infiles; //!< Input event filenames
  109 + std::vector<std::string> m_evtname; //!< Event extension names
  110 + std::vector<std::string> m_gtiname; //!< GTI extension names
101 111 GTime m_timemin; //!< Earliest time
102 112 GTime m_timemax; //!< Latest time
103 113 bool m_select_energy; //!< Perform energy selection
104 114 bool m_select_roi; //!< Perform ROI selection
105 115 bool m_select_time; //!< Perform time selection
106   -
107 116 };
108 117  
109 118  
... ...
test/test_pipelines.py
... ... @@ -175,6 +175,7 @@ class Test(gammalib.GPythonTestSuite):
175 175 select["tmax"] = tstop
176 176 select["emin"] = emin
177 177 select["emax"] = emax
  178 + select.run()
178 179 self.test_try("Run ctselect")
179 180 try:
180 181 select.run()
... ...