Beispiel #1
0
/***********************************************************************//**
 * @brief Test CTA Npred computation
 *
 * Tests the Npred computation for the diffuse source model. This is done
 * by loading the model from the XML file and by calling the
 * GCTAObservation::npred method which in turn calls the
 * GCTAResponse::npred_diffuse method. The test takes a few seconds.
 ***************************************************************************/
void TestGCTAResponse::test_response_npred_diffuse(void)
{
    // Set reference value
    double ref = 11212.26274;

    // Set parameters
    double src_ra  = 201.3651;
    double src_dec = -43.0191;
    double roi_rad =   4.0;

    // Setup ROI centred on Cen A with a radius of 4 deg
    GCTARoi     roi;
    GCTAInstDir instDir;
    instDir.radec_deg(src_ra, src_dec);
    roi.centre(instDir);
    roi.radius(roi_rad);

    // Setup pointing on Cen A
    GSkyDir skyDir;
    skyDir.radec_deg(src_ra, src_dec);
    GCTAPointing pnt;
    pnt.dir(skyDir);

    // Setup dummy event list
    GGti     gti;
    GEbounds ebounds;
    GTime    tstart(0.0);
    GTime    tstop(1800.0);
    GEnergy  emin;
    GEnergy  emax;
    emin.TeV(0.1);
    emax.TeV(100.0);
    gti.append(tstart, tstop);
    ebounds.append(emin, emax);
    GCTAEventList events;
    events.roi(roi);
    events.gti(gti);
    events.ebounds(ebounds);

    // Setup dummy CTA observation
    GCTAObservation obs;
    obs.ontime(1800.0);
    obs.livetime(1600.0);
    obs.deadc(1600.0/1800.0);
    obs.response(cta_irf, cta_caldb);
    obs.events(&events);
    obs.pointing(pnt);

    // Load models for Npred computation
    GModels models(cta_rsp_xml);

    // Perform Npred computation
    double npred = obs.npred(models, NULL);

    // Test Npred
    test_value(npred, ref, 1.0e-5, "Diffuse Npred computation");

    // Return
    return;
}
Beispiel #2
0
/***********************************************************************//**
 * @brief Set exposure cube from one CTA observation
 *
 * @param[in] obs CTA observation.
 *
 * Set the exposure cube from a single CTA observations. The cube pixel
 * values are computed as product of the effective area and the livetime.
 *
 * @todo: Throw an exception if response is not valid
 ***************************************************************************/
void GCTACubeExposure::set(const GCTAObservation& obs)
{
    // Clear GTIs, reset livetime and exposure cube pixels
    m_gti.clear();
    m_livetime = 0.0;
    m_cube     = 0.0;

    // Extract region of interest from CTA observation
    GCTARoi roi = obs.roi();

    // Get references on CTA response and pointing direction
    const GCTAResponseIrf* rsp = dynamic_cast<const GCTAResponseIrf*>(obs.response());
    const GSkyDir&         pnt = obs.pointing().dir();

    // Continue only if response is valid
    if (rsp != NULL) {

        // Loop over all pixels in sky map
        for (int pixel = 0; pixel < m_cube.npix(); ++pixel) {

            // Get pixel sky direction
            GSkyDir dir = m_cube.inx2dir(pixel);
            
            // Continue only if pixel is within RoI
            if (roi.centre().dir().dist_deg(dir) <= roi.radius()) {

                // Compute theta angle with respect to pointing direction
                // in radians
                double theta = pnt.dist(dir);
    
                // Loop over all exposure cube energy bins
                for (int iebin = 0; iebin < m_ebounds.size(); ++iebin){

                    // Get logE/TeV
                    double logE = m_ebounds.elogmean(iebin).log10TeV();

                    // Set exposure cube (effective area * lifetime)
                    m_cube(pixel, iebin) = rsp->aeff(theta, 0.0, 0.0, 0.0, logE) *
                                           obs.livetime();

                } // endfor: looped over energy bins

            } // endif: pixel was within RoI

        } // endfor: looped over all pixels

        // Append GTIs and increment livetime
        m_gti.extend(obs.gti());
        m_livetime += obs.livetime();
    
    } // endif: response was valid

    // Return
    return;
}
Beispiel #3
0
/***********************************************************************//**
 * @brief Extract ROI from data sub-space keywords
 *
 * @param[in] hdu FITS HDU
 *
 * @exception GException::invalid_value
 *            Invalid ROI data sub-space encountered
 *
 * Reads the ROI data sub-space keywords by searching for a DSTYPx keyword
 * named "POS(RA,DEC)". The data sub-space information is expected to be in
 * the format "CIRCLE(267.0208,-24.78,4.5)", where the 3 arguments are Right
 * Ascension, Declination and radius in units of degrees. No detailed syntax
 * checking is performed.
 *
 * If no ROI information has been found, an GCTARoi object with initial
 * values will be returned. 
 ***************************************************************************/
GCTARoi gammalib::read_ds_roi(const GFitsHDU& hdu)
{
    // Initialise ROI
    GCTARoi roi;

    // Get number of data sub-space keywords (default to 0 if keyword is
    // not found)
    int ndskeys = (hdu.has_card("NDSKEYS")) ? hdu.integer("NDSKEYS") : 0;

    // Loop over all data selection keys
    for (int i = 1; i <= ndskeys; ++i) {

        // Set data sub-space key strings
        std::string type_key  = "DSTYP"+gammalib::str(i);
        //std::string unit_key  = "DSUNI"+gammalib::str(i);
        std::string value_key = "DSVAL"+gammalib::str(i);

        // Continue only if type_key is found and if this key is POS(RA,DEC)
        if (hdu.has_card(type_key) && hdu.string(type_key) == "POS(RA,DEC)") {

            // ...
            //std::string unit              = gammalib::toupper(hdu.string(unit_key));
            std::string value             = hdu.string(value_key);
            std::string value_proc        = gammalib::strip_chars(value, "CIRCLE(");
            value_proc                    = gammalib::strip_chars(value_proc, ")");
            std::vector<std::string> args = gammalib::split(value_proc, ",");
            if (args.size() == 3) {
                double ra  = gammalib::todouble(args[0]);
                double dec = gammalib::todouble(args[1]);
                double rad = gammalib::todouble(args[2]);
                GCTAInstDir dir;
                dir.dir().radec_deg(ra, dec);
                roi.centre(dir);
                roi.radius(rad);
            }
            else {
                std::string msg = "Invalid acceptance cone value \""+value+
                                  "\" encountered in data sub-space "
                                  "key \""+value_key+"\".";
                throw GException::invalid_value(G_READ_DS_ROI, msg);
            }

        } // endif: POS(RA,DEC) type found

    } // endfor: looped over data sub-space keys

    // Return roi
    return roi;
}
Beispiel #4
0
/***********************************************************************//**
 * @brief Test CTA npsf computation
 ***************************************************************************/
void TestGCTAResponse::test_response_npsf(void)
{
    // Setup CTA response
    GCTAResponse rsp;
    rsp.caldb(cta_caldb);
    rsp.load(cta_irf);

    // Setup npsf computation
    GSkyDir      srcDir;
    GEnergy      srcEng;
    GTime        srcTime;
    GCTAPointing pnt;
    GCTARoi      roi;
    GCTAInstDir  instDir;
    instDir.radec_deg(0.0, 0.0);
    roi.centre(instDir);
    roi.radius(2.0);
    srcEng.TeV(0.1);

    // Test PSF centred on ROI
    srcDir.radec_deg(0.0, 0.0);
    double npsf = rsp.npsf(srcDir, srcEng.log10TeV(), srcTime, pnt, roi);
    test_value(npsf, 1.0, 1.0e-3, "PSF(0,0) integration");

    // Test PSF offset but inside ROI
    srcDir.radec_deg(1.0, 1.0);
    npsf = rsp.npsf(srcDir, srcEng.log10TeV(), srcTime, pnt, roi);
    test_value(npsf, 1.0, 1.0e-3, "PSF(1,1) integration");

    // Test PSF outside and overlapping ROI
    srcDir.radec_deg(0.0, 2.0);
    npsf = rsp.npsf(srcDir, srcEng.log10TeV(), srcTime, pnt, roi);
    test_value(npsf, 0.492373, 1.0e-3, "PSF(0,2) integration");

    // Test PSF outside ROI
    srcDir.radec_deg(2.0, 2.0);
    npsf = rsp.npsf(srcDir, srcEng.log10TeV(), srcTime, pnt, roi);
    test_value(npsf, 0.0, 1.0e-3, "PSF(2,2) integration");

    // Return
    return;
}
Beispiel #5
0
/***********************************************************************//**
 * @brief Fill model into model cube
 *
 * @param[in] obs CTA observation.
 *
 * Adds the expected number of events for a given observation to the events
 * that are already found in the model cube. The method also updates the
 * GTI of the model cube so that cube GTI is a list of the GTIs of all
 * observations that were used to generate the model cube.
 ***************************************************************************/
void ctmodel::fill_cube(const GCTAObservation* obs)
{
    // Continue only if observation pointer is valid
    if (obs != NULL) {

        // Get GTI and energy boundaries references for observation
        const GGti&     gti         = obs->events()->gti();
        const GEbounds& obs_ebounds = obs->ebounds();

        // Get cube energy boundaries
        const GEbounds& cube_ebounds = m_cube.ebounds();

        // Initialise empty, invalid RoI
        GCTARoi roi;

        // Retrieve RoI in case we have an unbinned observation
        if (obs->eventtype() == "EventList") {
            roi = obs->roi();
        }

        // Initialise statistics
        double sum              = 0.0;
        int    num_outside_ebds = 0;
        int    num_outside_roi  = 0;

        // Setup cube GTIs for this observation
        m_cube.gti(obs->events()->gti());

        // Loop over all cube bins
        for (int i = 0; i < m_cube.size(); ++i) {

            // Get cube bin
            GCTAEventBin* bin = m_cube[i];

            // Skip bin if it is outside the energy range of the observation
            int index = cube_ebounds.index(bin->energy());
            if (index == -1 ||
                !obs_ebounds.contains(cube_ebounds.emin(index)+g_energy_margin,
                                      cube_ebounds.emax(index)-g_energy_margin)) {
                num_outside_ebds++;
                continue;
            }

            // Check if RoI is valid, i.e. check if we have an unbinned
            // observation
            if (roi.is_valid()) {

                // Skip bin if it is outside the RoI of the observation
                if (!roi.contains(*bin)) {
                    num_outside_roi++;
                    continue;
                }

            } // endif: RoI was not valid

            // Get actual bin value
            double value = bin->counts();
            
            // Compute model value for cube bin
            double model = m_obs.models().eval(*bin, *obs) * bin->size();

            // Add model to actual value
            value += model;
            sum   += model;

            // Store value
            bin->counts(value);

        } // endfor: looped over all cube bins

        // Append GTIs of observation to list of GTIs
        m_gti.extend(gti);

        // Update GTIs
        m_cube.gti(m_gti);

        // Log results
        if (logTerse()) {
            log << gammalib::parformat("Model events in cube");
            log << sum << std::endl;
            log << gammalib::parformat("Bins outside energy range");
            log << num_outside_ebds << std::endl;
            log << gammalib::parformat("Bins outside RoI");
            log << num_outside_roi << std::endl;
        }

        // Log cube
        if (logExplicit()) {
            log.header2("Model cube");
            log << m_cube << std::endl;
        }

    } // endif: observation was valid

    // Return
    return;
}
Beispiel #6
0
/***********************************************************************//**
 * @brief Select events
 *
 * @param[in] obs CTA observation.
 * @param[in] filename File name.
 *
 * Select events from a FITS file by making use of the selection possibility
 * of the cfitsio library on loading a file. A selection string is created
 * from the specified criteria that is appended to the filename so that
 * cfitsio will automatically filter the event data. This selection string
 * is then applied when opening the FITS file. The opened FITS file is then
 * saved into a temporary file which is the loaded into the actual CTA
 * observation, overwriting the old CTA observation. The ROI, GTI and EBounds
 * of the CTA event list are then set accordingly to the specified selection.
 * Finally, the temporary file created during this process is removed.
 *
 * Good Time Intervals of the observation will be limited to the time
 * interval [m_tmin, m_tmax]. If m_tmin=m_tmax=0, no time selection is
 * performed.
 *
 * @todo Use INDEF instead of 0.0 for pointing as RA/DEC selection
 ***************************************************************************/
void ctselect::select_events(GCTAObservation* obs, const std::string& filename)
{
    // Allocate selection string
    std::string selection;
    char        cmin[80];
    char        cmax[80];
    char        cra[80];
    char        cdec[80];
    char        crad[80];

    // Set requested selections
    bool select_time = (m_tmin != 0.0 || m_tmax != 0.0);

    // Set RA/DEC selection
    double ra  = m_ra;
    double dec = m_dec;
    if (m_usepnt) {
        const GCTAPointing *pnt = obs->pointing();
        ra = pnt->dir().ra_deg();
        dec = pnt->dir().dec_deg();
    }

    // Set time selection interval. We make sure here that the time selection
    // interval cannot be wider than the GTIs covering the data. This is done
    // using GGti's reduce() method.
    if (select_time) {

        // Reduce GTIs to specified time interval. The complicated cast is
        // necessary here because the gti() method is declared const, so
        // we're not officially allowed to modify the GTIs.
        ((GGti*)(&obs->events()->gti()))->reduce(m_timemin, m_timemax);

    } // endif: time selection was required

    // Save GTI for later usage
    GGti gti = obs->events()->gti();

    // Make time selection
    if (select_time) {
    
        // Extract effective time interval in CTA reference time. We need
        // this reference for filtering.
        double tmin = gti.tstart().convert(m_cta_ref);
        double tmax = gti.tstop().convert(m_cta_ref);

        // Format time with sufficient accuracy and add to selection string
        sprintf(cmin, "%.8f", tmin);
        sprintf(cmax, "%.8f", tmax);
        selection = "TIME >= "+std::string(cmin)+" && TIME <= "+std::string(cmax);
        if (logTerse()) {
            log << parformat("Time range");
            log << tmin << " - " << tmax << " s" << std::endl;
        }
        if (selection.length() > 0) {
            selection += " && ";
        }
    }

    // Make energy selection
    sprintf(cmin, "%.8f", m_emin);
    sprintf(cmax, "%.8f", m_emax);
    selection += "ENERGY >= "+std::string(cmin)+" && ENERGY <= "+std::string(cmax);
    if (logTerse()) {
        log << parformat("Energy range");
        log << m_emin << " - " << m_emax << " TeV" << std::endl;
    }
    if (selection.length() > 0) {
        selection += " && ";
    }

    // Make ROI selection
    sprintf(cra,  "%.6f", ra);
    sprintf(cdec, "%.6f", dec);
    sprintf(crad, "%.6f", m_rad);
    selection += "ANGSEP("+std::string(cra)+"," +
                 std::string(cdec)+",RA,DEC) <= " +
                 std::string(crad);
    if (logTerse()) {
        log << parformat("Acceptance cone centre");
        log << "RA=" << ra << ", DEC=" << dec << " deg" << std::endl;
        log << parformat("Acceptance cone radius");
        log << m_rad << " deg" << std::endl;
    }
    if (logTerse()) {
        log << parformat("cfitsio selection");
        log << selection << std::endl;
    }

    // Add additional expression
    if (strip_whitespace(m_expr).length() > 0) {
        if (selection.length() > 0) {
            selection += " && ";
        }
        selection += "("+strip_whitespace(m_expr)+")";
    }

    // Build input filename including selection expression
    std::string expression = filename;
    if (selection.length() > 0)
        expression += "[EVENTS]["+selection+"]";
    if (logTerse()) {
        log << parformat("FITS filename");
        log << expression << std::endl;
    }

    // Open FITS file
    GFits file(expression);

    // Log selected FITS file
    if (logExplicit()) {
        log << std::endl;
        log.header1("FITS file content after selection");
        log << file << std::endl;
    }

    // Check if we have an EVENTS HDU
    if (!file.hashdu("EVENTS")) {
        std::string message = "No \"EVENTS\" extension found in FITS file "+
                              expression+".";
        throw GException::app_error(G_SELECT_EVENTS, message);
    }

    // Determine number of events in EVENTS HDU
    int nevents = file.table("EVENTS")->nrows();

    // If the selected event list is empty then append an empty event list
    // to the observation. Otherwise load the data from the temporary file.
    if (nevents < 1) {

        // Create empty event list
        GCTAEventList eventlist;

        // Append list to observation
        obs->events(&eventlist);

    }
    else {

        // Get temporary file name
        std::string tmpname = std::tmpnam(NULL);

        // Save FITS file to temporary file
        file.saveto(tmpname, true);

        // Load observation from temporary file
        obs->load_unbinned(tmpname);

        // Remove temporary file
        std::remove(tmpname.c_str());

    }

    // Get CTA event list pointer
    GCTAEventList* list =
        static_cast<GCTAEventList*>(const_cast<GEvents*>(obs->events()));

    // Set ROI
    GCTARoi     roi;
    GCTAInstDir instdir;
    instdir.radec_deg(ra, dec);
    roi.centre(instdir);
    roi.radius(m_rad);
    list->roi(roi);

    // Set GTI
    list->gti(gti);

    // Set energy boundaries
    GEbounds ebounds;
    GEnergy  emin;
    GEnergy  emax;
    emin.TeV(m_emin);
    emax.TeV(m_emax);
    ebounds.append(emin, emax);
    list->ebounds(ebounds);

    // Recompute ontime and livetime.
    GTime meantime = 0.5 * (gti.tstart() + gti.tstop());
    obs->ontime(gti.ontime());
    obs->livetime(gti.ontime() * obs->deadc(meantime));

    // Return
    return;
}