Commit 98c5cdc0aeb766e4269dafa77da4f527d5594d57

Authored by Jürgen Knödlseder
2 parents 34fcdde8 272721f9

Merge branch '1039-allow-energy-thresholds-in-ctselect' into integration

ChangeLog
1 -2014-10-30 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu> 1 +2014-11-08 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu>
2 2
3 * Version 0.8.0 released 3 * Version 0.8.0 released
4 ======================== 4 ========================
@@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
17 ctmodel now always creates a single model cube 17 ctmodel now always creates a single model cube
18 Support energy dispersion in ctobssim, ctlike and ctmodel 18 Support energy dispersion in ctobssim, ctlike and ctmodel
19 Correct ctobssim for thread safety 19 Correct ctobssim for thread safety
  20 + Support save and user energy thresholds in ctselect
20 Correctly apply time references in ctselect 21 Correctly apply time references in ctselect
21 Reduce memory usage 22 Reduce memory usage
22 Move obsutils to ctools namespace 23 Move obsutils to ctools namespace
@@ -2,7 +2,7 @@ New Features and Important Changes in ctools 00-08-00 @@ -2,7 +2,7 @@ New Features and Important Changes in ctools 00-08-00
2 2
3 Author(s) : Juergen Knoedlseder 3 Author(s) : Juergen Knoedlseder
4 4
5 -30 October 2014 5 +8 November 2014
6 6
7 7
8 1. Introduction 8 1. Introduction
@@ -65,6 +65,30 @@ tmin and tmax parameters are given in CTA reference time, they are @@ -65,6 +65,30 @@ tmin and tmax parameters are given in CTA reference time, they are
65 internally converted to the reference time of the GTI before event 65 internally converted to the reference time of the GTI before event
66 selection (#1329). 66 selection (#1329).
67 67
  68 +ctselect now supports save and user energy thresholds (#1039). There
  69 +are three different possibilities for specifying a threshold. They
  70 +are toggled using the hidden usethres parameter:
  71 +
  72 +NONE: Use the emin and emax parameters to select an energy range.
  73 + This is the default mode which is identical to the previous
  74 + workings. The only difference is now that if the emin and/or
  75 + emax parameter is set to 0.0, the threshold will be ignored.
  76 + This allows to select all events above or below a given
  77 + threshold.
  78 +
  79 +DEFAULT: Use the save threshold that is found in the effective
  80 + area FITS header keywords LO_THRES and HI_THRES. If the
  81 + emin and emax parameters are non-zero, they will provide
  82 + an additional energy constraint.
  83 +
  84 +USER: Use the user specified threshold that are found in the
  85 + XML observation definition file. If the emin and emax
  86 + parameters are non-zero, they will provide an additional
  87 + energy constraint.
  88 +
  89 +Note that any existing energy boundaries will be used as envelope,
  90 +i.e. a wider energy threshold specification will have no effect.
  91 +
68 92
69 7. ctbin - CTA event binning 93 7. ctbin - CTA event binning
70 ---------------------------- 94 ----------------------------
src/ctselect/ctselect.cpp
@@ -36,6 +36,8 @@ @@ -36,6 +36,8 @@
36 #define G_RUN "ctselect::run()" 36 #define G_RUN "ctselect::run()"
37 #define G_SELECT_EVENTS "ctselect::select_events(GCTAObservation*, "\ 37 #define G_SELECT_EVENTS "ctselect::select_events(GCTAObservation*, "\
38 "std::string&)" 38 "std::string&)"
  39 +#define G_SET_EBOUNDS "ctselect::set_ebounds(GCTAObservation*, GEbounds&)"
  40 +#define G_GET_PARAMETERS "ctselect::get_parameters()"
39 41
40 /* __ Debug definitions __________________________________________________ */ 42 /* __ Debug definitions __________________________________________________ */
41 43
@@ -397,13 +399,14 @@ void ctselect::init_members(void) @@ -397,13 +399,14 @@ void ctselect::init_members(void)
397 m_emin = 0.0; 399 m_emin = 0.0;
398 m_emax = 0.0; 400 m_emax = 0.0;
399 m_expr.clear(); 401 m_expr.clear();
  402 + m_usethres.clear();
400 403
401 // Initialise protected members 404 // Initialise protected members
402 m_obs.clear(); 405 m_obs.clear();
403 m_infiles.clear(); 406 m_infiles.clear();
404 m_timemin.clear(); 407 m_timemin.clear();
405 m_timemax.clear(); 408 m_timemax.clear();
406 - m_use_xml = false; 409 + m_use_xml = false;
407 410
408 // Set CTA time reference. G_CTA_MJDREF is the CTA reference MJD, 411 // Set CTA time reference. G_CTA_MJDREF is the CTA reference MJD,
409 // which is defined in GCTALib.hpp. This is somehow a kluge. We need 412 // which is defined in GCTALib.hpp. This is somehow a kluge. We need
@@ -423,18 +426,19 @@ void ctselect::init_members(void) @@ -423,18 +426,19 @@ void ctselect::init_members(void)
423 void ctselect::copy_members(const ctselect& app) 426 void ctselect::copy_members(const ctselect& app)
424 { 427 {
425 // Copy parameters 428 // Copy parameters
426 - m_infile = app.m_infile;  
427 - m_outfile = app.m_outfile;  
428 - m_prefix = app.m_prefix;  
429 - m_usepnt = app.m_usepnt;  
430 - m_ra = app.m_ra;  
431 - m_dec = app.m_dec;  
432 - m_rad = app.m_rad;  
433 - m_tmin = app.m_tmin;  
434 - m_tmax = app.m_tmax;  
435 - m_emin = app.m_emin;  
436 - m_emax = app.m_emax;  
437 - m_expr = app.m_expr; 429 + m_infile = app.m_infile;
  430 + m_outfile = app.m_outfile;
  431 + m_prefix = app.m_prefix;
  432 + m_usepnt = app.m_usepnt;
  433 + m_ra = app.m_ra;
  434 + m_dec = app.m_dec;
  435 + m_rad = app.m_rad;
  436 + m_tmin = app.m_tmin;
  437 + m_tmax = app.m_tmax;
  438 + m_emin = app.m_emin;
  439 + m_emax = app.m_emax;
  440 + m_expr = app.m_expr;
  441 + m_usethres = app.m_usethres;
438 442
439 // Copy protected members 443 // Copy protected members
440 m_obs = app.m_obs; 444 m_obs = app.m_obs;
@@ -514,12 +518,21 @@ void ctselect::get_parameters(void) @@ -514,12 +518,21 @@ void ctselect::get_parameters(void)
514 m_ra = (*this)["ra"].real(); 518 m_ra = (*this)["ra"].real();
515 m_dec = (*this)["dec"].real(); 519 m_dec = (*this)["dec"].real();
516 } 520 }
517 - m_rad = (*this)["rad"].real();  
518 - m_tmin = (*this)["tmin"].real();  
519 - m_tmax = (*this)["tmax"].real();  
520 - m_emin = (*this)["emin"].real();  
521 - m_emax = (*this)["emax"].real();  
522 - m_expr = (*this)["expr"].string(); 521 + m_rad = (*this)["rad"].real();
  522 + m_tmin = (*this)["tmin"].real();
  523 + m_tmax = (*this)["tmax"].real();
  524 + m_emin = (*this)["emin"].real();
  525 + m_emax = (*this)["emax"].real();
  526 + m_expr = (*this)["expr"].string();
  527 + m_usethres = (*this)["usethres"].string();
  528 +
  529 + // Check parameters (Kluge as the parfile interface does not yet check
  530 + // parameters; this can be removed once this is done properly)
  531 + if (m_usethres != "NONE" && m_usethres != "DEFAULT" && m_usethres != "USER") {
  532 + std::string msg = "Parameter \"usethres\" must be one of \"NONE\", "
  533 + "\"DEFAULT\" or \"USER\".";
  534 + throw GException::invalid_value(G_GET_PARAMETERS, msg);
  535 + }
523 536
524 // Optionally read ahead parameters so that they get correctly 537 // Optionally read ahead parameters so that they get correctly
525 // dumped into the log file 538 // dumped into the log file
@@ -569,16 +582,25 @@ void ctselect::select_events(GCTAObservation* obs, const std::string&amp; filename) @@ -569,16 +582,25 @@ void ctselect::select_events(GCTAObservation* obs, const std::string&amp; filename)
569 // Initialise selection flags 582 // Initialise selection flags
570 bool remove_all = false; 583 bool remove_all = false;
571 584
572 - // Analyse task parameters to see what selections are required 585 + // Get CTA event list pointer
  586 + GCTAEventList* list =
  587 + static_cast<GCTAEventList*>(const_cast<GEvents*>(obs->events()));
  588 +
  589 + // Get energy boundaries
  590 + double emin = 0.0;
  591 + double emax = 0.0;
  592 + GEbounds ebounds = set_ebounds(obs, list->ebounds());
  593 + if (ebounds.size() >= 1) {
  594 + emin = ebounds.emin(0).TeV();
  595 + emax = ebounds.emax(0).TeV();
  596 + }
  597 +
  598 + // Analyse parameters to see what selections are required
573 bool select_time = (m_tmin != 0.0 || m_tmax != 0.0); 599 bool select_time = (m_tmin != 0.0 || m_tmax != 0.0);
574 - bool select_energy = true; 600 + bool select_energy = (emin != 0.0 || emax != 0.0);
575 bool select_roi = ((m_dec != -1.0 && m_ra != -1.0 && m_rad != -1.0) || m_usepnt); 601 bool select_roi = ((m_dec != -1.0 && m_ra != -1.0 && m_rad != -1.0) || m_usepnt);
576 bool select_expr = (gammalib::strip_whitespace(m_expr).length() > 0); 602 bool select_expr = (gammalib::strip_whitespace(m_expr).length() > 0);
577 603
578 - // Set energy selection  
579 - double emin = m_emin;  
580 - double emax = m_emax;  
581 -  
582 // Set RA/DEC selection. If the "usepnt" parameter is set to true then 604 // Set RA/DEC selection. If the "usepnt" parameter is set to true then
583 // use the pointing direction as the ROI centre. 605 // use the pointing direction as the ROI centre.
584 double ra = m_ra; 606 double ra = m_ra;
@@ -589,10 +611,6 @@ void ctselect::select_events(GCTAObservation* obs, const std::string&amp; filename) @@ -589,10 +611,6 @@ void ctselect::select_events(GCTAObservation* obs, const std::string&amp; filename)
589 ra = pnt.dir().ra_deg(); 611 ra = pnt.dir().ra_deg();
590 dec = pnt.dir().dec_deg(); 612 dec = pnt.dir().dec_deg();
591 } 613 }
592 -  
593 - // Get CTA event list pointer  
594 - GCTAEventList* list =  
595 - static_cast<GCTAEventList*>(const_cast<GEvents*>(obs->events()));  
596 614
597 // Set time selection interval. We make sure here that the time selection 615 // Set time selection interval. We make sure here that the time selection
598 // interval cannot be wider than the GTIs covering the data. This is done 616 // interval cannot be wider than the GTIs covering the data. This is done
@@ -638,48 +656,58 @@ void ctselect::select_events(GCTAObservation* obs, const std::string&amp; filename) @@ -638,48 +656,58 @@ void ctselect::select_events(GCTAObservation* obs, const std::string&amp; filename)
638 selection += " && "; 656 selection += " && ";
639 } 657 }
640 658
641 - // Log the requested energy range 659 + // Log the requested energy selection
642 if (logTerse()) { 660 if (logTerse()) {
643 - log << gammalib::parformat("Requested energy range");  
644 - log << m_emin << " - " << m_emax << " TeV" << std::endl;  
645 - }  
646 -  
647 - // Set the energy boundaries. Make sure that they overlap with any  
648 - // existing energy boundaries  
649 - const GEbounds& ebounds = list->ebounds();  
650 - if (ebounds.size() >= 1) {  
651 - if (logTerse()) {  
652 - log << gammalib::parformat("Energy range of data");  
653 - log << ebounds.emin(0).TeV() << " - ";  
654 - log << ebounds.emax(0).TeV() << " TeV" << std::endl; 661 + log << gammalib::parformat("Selected energy range");
  662 + if (emin > 0.0 && emax > 0.0) {
  663 + if (emin >= emax) {
  664 + log << "None. There is no overlap between existing ";
  665 + log << "and requested energy range." << std::endl;
  666 + }
  667 + else {
  668 + log << emin << " - " << emax << " TeV" << std::endl;
  669 + }
  670 + }
  671 + else if (emin > 0.0) {
  672 + log << "> " << emin << " TeV" << std::endl;
655 } 673 }
656 - if (emin < ebounds.emin(0).TeV()) {  
657 - emin = ebounds.emin(0).TeV(); 674 + else if (emax > 0.0) {
  675 + log << "< " << emax << " TeV" << std::endl;
658 } 676 }
659 - if (emax > ebounds.emax(0).TeV()) {  
660 - emax = ebounds.emax(0).TeV(); 677 + else {
  678 + log << "None" << std::endl;
661 } 679 }
662 } 680 }
663 681
664 - // Log the selected energy range  
665 - if (logTerse()) {  
666 - log << gammalib::parformat("Selected energy range"); 682 + // Apply the requested energy selection
  683 + if (emin > 0.0 && emax > 0.0) {
667 if (emin >= emax) { 684 if (emin >= emax) {
668 - log << "None. There is no overlap between existing ";  
669 - log << "and requested energy range." << std::endl; 685 + remove_all = true;
670 } 686 }
671 else { 687 else {
672 - log << emin << " - " << emax << " TeV" << std::endl; 688 + char cmin[80];
  689 + char cmax[80];
  690 + sprintf(cmin, "%.8f", emin);
  691 + sprintf(cmax, "%.8f", emax);
  692 + selection += "ENERGY >= "+std::string(cmin)+" && ENERGY <= "+
  693 + std::string(cmax);
673 } 694 }
674 } 695 }
  696 + else if (emin > 0.0) {
  697 + char cmin[80];
  698 + sprintf(cmin, "%.8f", emin);
  699 + selection += "ENERGY >= "+std::string(cmin);
  700 + }
  701 + else if (emax > 0.0) {
  702 + char cmax[80];
  703 + sprintf(cmax, "%.8f", emax);
  704 + selection += "ENERGY <= "+std::string(cmax);
  705 + }
  706 + else {
  707 + log << "None" << std::endl;
  708 + remove_all = true;
  709 + }
675 710
676 - // Format energy selection  
677 - char cmin[80];  
678 - char cmax[80];  
679 - sprintf(cmin, "%.8f", emin);  
680 - sprintf(cmax, "%.8f", emax);  
681 - selection += "ENERGY >= "+std::string(cmin)+" && ENERGY <= "+std::string(cmax);  
682 -  
683 } // endif: made energy selection 711 } // endif: made energy selection
684 712
685 // Make ROI selection 713 // Make ROI selection
@@ -841,6 +869,137 @@ void ctselect::select_events(GCTAObservation* obs, const std::string&amp; filename) @@ -841,6 +869,137 @@ void ctselect::select_events(GCTAObservation* obs, const std::string&amp; filename)
841 869
842 870
843 /***********************************************************************//** 871 /***********************************************************************//**
  872 + * @brief Return energy boundaries for a given observation
  873 + *
  874 + * @param[in] obs Pointer to CTA observation.
  875 + * @param[in] ebounds Current energy boundaries.
  876 + * @return Energy boundaries.
  877 + *
  878 + * Returns the energy boundaries for a given observation. Depending on the
  879 + * value of the usethres parameter, the following values will be
  880 + * returned:
  881 + *
  882 + * NONE: [max(emin,emin_exist),min(emax,emax_exist)]
  883 + * DEFAULT: [max(emin,emin_exist,emin_save),min(emax,emax_exist,emax_save)]
  884 + * USER: [max(emin,emin_exist,emin_user),min(emax,emax_exist,emax_user)]
  885 + *
  886 + * where
  887 + *
  888 + * emin is the value of the emin parameter
  889 + * emax is the value of the emax parameter
  890 + * emin_exist is the value of any existing minimum boundary
  891 + * emax_exist is the value of any existing maximum boundary
  892 + * emin_save is the lower save threshold
  893 + * emax_save is the upper save threshold
  894 + * emin_user is the lower user threshold
  895 + * emax_user is the upper user threshold
  896 + *
  897 + * Any threshold value of 0 will be ignored.
  898 + ***************************************************************************/
  899 +GEbounds ctselect::set_ebounds(GCTAObservation* obs, const GEbounds& ebounds) const
  900 +{
  901 + // Set emin and emax values from user parameters
  902 + double emin = m_emin;
  903 + double emax = m_emax;
  904 +
  905 + // Check if we have already energy boundaries
  906 + if (ebounds.size() > 0) {
  907 +
  908 + // Raise minimum energy to lower boundary
  909 + if ((emin == 0.0) ||
  910 + ((ebounds.emin(0).TeV() > 0.0) && (emin < ebounds.emin(0).TeV()))) {
  911 + emin = ebounds.emin(0).TeV();
  912 + }
  913 +
  914 + // Lower maximum energy to upper boundary
  915 + if ((emax == 0.0) ||
  916 + ((ebounds.emax(0).TeV() > 0.0) && (emax > ebounds.emax(0).TeV()))) {
  917 + emax = ebounds.emax(0).TeV();
  918 + }
  919 +
  920 + } // endif: there were already energy boundaries
  921 +
  922 + // Check if default threshold (the one from the IRF, also known as save
  923 + // threshold) should be applied
  924 + if (m_usethres == "DEFAULT") {
  925 +
  926 + // Get CTA IRF respsonse pointer and throw exception if we don't
  927 + // find IRF
  928 + const GCTAResponseIrf* rsp = dynamic_cast<const GCTAResponseIrf*>(obs->response());
  929 + if (rsp == NULL) {
  930 + std::string msg = "No IRF response attached to given observation.";
  931 + throw GException::invalid_value(G_SET_EBOUNDS, msg);
  932 + }
  933 +
  934 + // Retrieve energy range from response information
  935 + double lo_save_thres = rsp->lo_save_thres();
  936 + double hi_save_thres = rsp->hi_save_thres();
  937 +
  938 + // Check threshold information for validity
  939 + if ((lo_save_thres > 0.0) &&
  940 + (hi_save_thres > 0.0) &&
  941 + (lo_save_thres >= hi_save_thres)) {
  942 + std::string msg = "IRF \""+obs->name()+"\" contains an invalid "
  943 + "energy range ["+gammalib::str(lo_save_thres)+","+
  944 + gammalib::str(hi_save_thres)+"] TeV.";
  945 + throw GException::invalid_value(G_SET_EBOUNDS, msg);
  946 + }
  947 +
  948 + // Raise minimum energy to lower threshold (if lower threshold exists)
  949 + if ((emin == 0.0) ||
  950 + ((lo_save_thres > 0.0) && (emin < lo_save_thres))) {
  951 + emin = lo_save_thres;
  952 + }
  953 +
  954 + // Lower maximum energy to upper threshold (if upper threshold exists)
  955 + if ((emax == 0.0) ||
  956 + ((hi_save_thres > 0.0) && (emax > hi_save_thres))) {
  957 + emax = hi_save_thres;
  958 + }
  959 +
  960 + } //endif: usethres was "DEFAULT"
  961 +
  962 + // ... otherwise check if a user specified threshold should be applied
  963 + else if (m_usethres == "USER") {
  964 +
  965 + // Retrieve thresholds from observation
  966 + double lo_user_thres = obs->lo_user_thres();
  967 + double hi_user_thres = obs->hi_user_thres();
  968 +
  969 + // Check threshold information for validity
  970 + if ((lo_user_thres > 0.0) &&
  971 + (hi_user_thres > 0.0) &&
  972 + (lo_user_thres >= hi_user_thres)) {
  973 + std::string msg = "User energy range ["+gammalib::str(lo_user_thres)+
  974 + ","+gammalib::str(hi_user_thres)+"] TeV is invalid.";
  975 + throw GException::invalid_value(G_SET_EBOUNDS, msg);
  976 + }
  977 +
  978 + // Raise minimum energy to lower threshold (if lower threshold exists)
  979 + if ((emin == 0.0) ||
  980 + ((lo_user_thres > 0.0) && (emin < lo_user_thres))) {
  981 + emin = lo_user_thres;
  982 + }
  983 +
  984 + // Lower maximum energy to upper threshold (if upper threshold exists)
  985 + if ((emax == 0.0) ||
  986 + ((hi_user_thres > 0.0) && (emax > hi_user_thres))) {
  987 + emax = hi_user_thres;
  988 + }
  989 +
  990 + } // endif: usethres was "USER
  991 +
  992 + // Set selection energy boundaries
  993 + GEbounds result;
  994 + result.append(GEnergy(emin, "TeV"), GEnergy(emax, "TeV"));
  995 +
  996 + // Return result
  997 + return result;
  998 +
  999 +}
  1000 +
  1001 +
  1002 +/***********************************************************************//**
844 * @brief Check input filename 1003 * @brief Check input filename
845 * 1004 *
846 * @param[in] filename File name. 1005 * @param[in] filename File name.
@@ -1060,4 +1219,3 @@ void ctselect::save_event_list(const GCTAObservation* obs, @@ -1060,4 +1219,3 @@ void ctselect::save_event_list(const GCTAObservation* obs,
1060 // Return 1219 // Return
1061 return; 1220 return;
1062 } 1221 }
1063 -  
src/ctselect/ctselect.hpp
@@ -71,6 +71,8 @@ protected: @@ -71,6 +71,8 @@ protected:
71 void free_members(void); 71 void free_members(void);
72 void get_parameters(void); 72 void get_parameters(void);
73 void select_events(GCTAObservation* obs, const std::string& filename); 73 void select_events(GCTAObservation* obs, const std::string& filename);
  74 + GEbounds set_ebounds(GCTAObservation* obs,
  75 + const GEbounds& ebounds) const;
74 std::string check_infile(const std::string& filename) const; 76 std::string check_infile(const std::string& filename) const;
75 std::string set_outfile_name(const std::string& filename) const; 77 std::string set_outfile_name(const std::string& filename) const;
76 void save_fits(void); 78 void save_fits(void);
@@ -92,6 +94,7 @@ protected: @@ -92,6 +94,7 @@ protected:
92 double m_emin; //!< Lower energy 94 double m_emin; //!< Lower energy
93 double m_emax; //!< Upper energy 95 double m_emax; //!< Upper energy
94 std::string m_expr; //!< Selection expression 96 std::string m_expr; //!< Selection expression
  97 + std::string m_usethres; //!< Energy threshold type
95 98
96 // Protected members 99 // Protected members
97 GObservations m_obs; //!< Observations container 100 GObservations m_obs; //!< Observations container
src/ctselect/ctselect.par
@@ -23,15 +23,16 @@ prefix, s, h, &quot;selected_&quot;,,,&quot;Prefix for event lists in observation definition fi @@ -23,15 +23,16 @@ prefix, s, h, &quot;selected_&quot;,,,&quot;Prefix for event lists in observation definition fi
23 # 23 #
24 # Selection parameters 24 # Selection parameters
25 #===================== 25 #=====================
26 -usepnt, b, h, no,,, "Use pointing instead of RA/DEC parameters?"  
27 -ra, r, a, 83.63, 0,360, "RA for ROI centre (degrees)"  
28 -dec, r, a, 22.01, -90, 90, "Dec for ROI centre (degrees)"  
29 -rad, r, a, 3.0, 0,180, "Radius of ROI (degrees)"  
30 -tmin, r, a, 0.0, 0, , "Start time (CTA MET in seconds)"  
31 -tmax, r, a, 0.0, 0, , "End time (CTA MET in seconds)"  
32 -emin, r, a, 0.1, 0, , "Lower energy limit (TeV)"  
33 -emax, r, a, 100.0, 0, , "Upper energy limit (TeV)"  
34 -expr, s, h, "", , , "Additional selection expression" 26 +usepnt, b, h, no,,, "Use pointing instead of RA/DEC parameters?"
  27 +ra, r, a, 83.63, 0,360, "RA for ROI centre (degrees)"
  28 +dec, r, a, 22.01, -90, 90, "Dec for ROI centre (degrees)"
  29 +rad, r, a, 3.0, 0,180, "Radius of ROI (degrees)"
  30 +tmin, r, a, 0.0, 0, , "Start time (CTA MET in seconds)"
  31 +tmax, r, a, 0.0, 0, , "End time (CTA MET in seconds)"
  32 +emin, r, a, 0.1, 0, , "Lower energy limit (TeV)"
  33 +emax, r, a, 100.0, 0, , "Upper energy limit (TeV)"
  34 +expr, s, h, "", , , "Additional selection expression"
  35 +usethres,s, h,"NONE",NONE|DEFAULT|USER,,"Energy threshold type (NONE|DEFAULT|USER)"
35 # 36 #
36 # Standard parameters 37 # Standard parameters
37 #==================== 38 #====================