/***********************************************************************//**
 * @brief Returns MC sky direction
 *
 * @param[in] ran Random number generator.
 *
 * @exception GException::feature_not_implemented
 *            Method not yet implemented
 *
 * This method returns a random sky direction according to the intensity
 * distribution of the model sky map. It makes use of a cache array that
 * contains the normalized cumulative flux values of the skymap. Using a
 * uniform random number, this cache array is scanned using a bi-section
 * method to determine the skymap pixel for which the position should be
 * returned. To avoid binning problems, the exact position within the pixel
 * is set by a uniform random number generator (neglecting thus pixel
 * distortions). The fractional skymap pixel is then converted into a sky
 * direction.
 ***************************************************************************/
GSkyDir GModelSpatialMap::mc(GRan& ran) const
{
    // Allocate sky direction
    GSkyDir dir;

    // Determine number of skymap pixels
    int npix = m_map.npix();

    // Continue only if there are skymap pixels
    if (npix > 0) {

        // Get uniform random number
        double u = ran.uniform();

        // Get pixel index according to random number. We use a bi-section
        // method to find the corresponding skymap pixel
        int low  = 0;
        int high = npix;
        while ((high - low) > 1) {
            int mid = (low+high) / 2;
            if (u < m_mc_cache[mid]) {
                high = mid;
            }
            else if (m_mc_cache[mid] <= u) {
                low = mid;
            }
        }

        // Convert 1D pixel index to 2D pixel index
        GSkyPixel pixel = m_map.pix2xy(low);

        // Randomize pixel
        pixel.x(pixel.x() + ran.uniform() - 0.5);
        pixel.y(pixel.y() + ran.uniform() - 0.5);

        // Get sky direction
        dir = m_map.xy2dir(pixel);

    } // endif: there were pixels in sky map
    
    // Return sky direction
    return dir;
}
Exemple #2
0
/***********************************************************************//**
 * @brief Test GSkyPixel class
 *
 * Test GSkyPixel class.
 ***************************************************************************/
void TestGSky::test_GSkyPixel(void)
{
    // Test void constructor
    test_try("Test void constructor");
    try {
        GSkyPixel pixel;
        test_value(pixel.size(), 0);
        test_try_success();
    }
    catch (std::exception &e) {
        test_try_failure(e);
    }

    // Test 1D constructor
    test_try("Test 1D constructor (int version)");
    try {
        GSkyPixel pixel(41);
        test_assert(pixel.is_1D(), "Pixel is not 1D");
        test_assert(!pixel.is_2D(), "Pixel is 2D but it should be 1D");
        test_value(pixel.size(), 1);
        test_value(pixel.index(), 41.0);
        test_try_success();
    }
    catch (std::exception &e) {
        test_try_failure(e);
    }

    // Test 1D constructor
    test_try("Test 1D constructor (double version)");
    try {
        GSkyPixel pixel(41.001);
        test_assert(pixel.is_1D(), "Pixel is not 1D");
        test_assert(!pixel.is_2D(), "Pixel is 2D but it should be 1D");
        test_value(pixel.size(), 1);
        test_value(pixel.index(), 41.001);
        test_try_success();
    }
    catch (std::exception &e) {
        test_try_failure(e);
    }

    // Test 2D constructor
    test_try("Test 2D constructor (int version)");
    try {
        GSkyPixel pixel(41,14);
        test_assert(!pixel.is_1D(), "Pixel is 1D but it should be 2D");
        test_assert(pixel.is_2D(), "Pixel is not 2D");
        test_value(pixel.size(), 2);
        test_value(pixel.x(), 41.0);
        test_value(pixel.y(), 14.0);
        test_try_success();
    }
    catch (std::exception &e) {
        test_try_failure(e);
    }

    // Test 2D constructor
    test_try("Test 2D constructor (double version)");
    try {
        GSkyPixel pixel(41.001,14.003);
        test_assert(!pixel.is_1D(), "Pixel is 1D but it should be 2D");
        test_assert(pixel.is_2D(), "Pixel is not 2D");
        test_value(pixel.size(), 2);
        test_value(pixel.x(), 41.001);
        test_value(pixel.y(), 14.003);
        test_try_success();
    }
    catch (std::exception &e) {
        test_try_failure(e);
    }

    // Test 1D indexing
    test_try("Test 1D indexing");
    try {
        GSkyPixel pixel;
        test_value(pixel.size(), 0);
        pixel = 41;
        int index = pixel;
        test_value(index, 41);
        pixel = 41.001;
        index = pixel;
        test_value(index, 41);
        double dindex = pixel;
        test_value(dindex, 41.001);
        test_try_success();
    }
    catch (std::exception &e) {
        test_try_failure(e);
    }

    // Test cloning
    test_try("Test cloning");
    try {
        GSkyPixel pixel;
        test_value(pixel.size(), 0);
        GSkyPixel* clone = pixel.clone();
        test_value(clone->size(), 0);
        delete clone;
        pixel = 41;
        clone = pixel.clone();
        test_value(clone->size(), 1);
        int index = pixel;
        test_value(index, 41);
        delete clone;
        pixel.x(41.001);
        pixel.y(14.003);
        clone = pixel.clone();
        test_value(clone->size(), 2);
        test_value(clone->x(), 41.001);
        test_value(clone->y(), 14.003);
        delete clone;
        test_try_success();
    }
    catch (std::exception &e) {
        test_try_failure(e);
    }

    // Return
    return;
}
Exemple #3
0
/***********************************************************************//**
 * @brief Fill events into counts cube
 *
 * @param[in] obs CTA observation.
 *
 * @exception GException::invalid_value
 *            No event list found in observation.
 *
 * Fills the events from an event list in the counts cube setup by init_cube.
 ***************************************************************************/
void ctbin::fill_cube(GCTAObservation* obs)
{
    // Continue only if observation pointer is valid
    if (obs != NULL) {

        // Make sure that the observation holds a CTA event list. If this
        // is not the case then throw an exception.
        const GCTAEventList* events = dynamic_cast<const GCTAEventList*>(obs->events());
        if (events == NULL) {
            std::string msg = "CTA Observation does not contain an event "
                              "list. Event list information is needed to "
                              "fill the counts map.";
            throw GException::invalid_value(G_FILL_CUBE, msg);
        }

        // Get the RoI
        const GCTARoi& roi = events->roi();

        // Initialise binning statistics
        int num_outside_roi  = 0;
        int num_outside_map  = 0;
        int num_outside_ebds = 0;
        int num_in_map       = 0;

        // Fill sky map
        for (int i = 0; i < events->size(); ++i) {

            // Get event
            const GCTAEventAtom* event = (*events)[i];

            // Determine sky pixel
            GCTAInstDir* inst  = (GCTAInstDir*)&(event->dir());
            GSkyDir      dir   = inst->dir();
            GSkyPixel    pixel = m_cube.dir2pix(dir);

            // Skip if pixel is outside RoI
            if (roi.centre().dir().dist_deg(dir) > roi.radius()) {
                num_outside_roi++;
                continue;
            }

            // Skip if pixel is out of range
            if (pixel.x() < -0.5 || pixel.x() > (m_cube.nx()-0.5) ||
                    pixel.y() < -0.5 || pixel.y() > (m_cube.ny()-0.5)) {
                num_outside_map++;
                continue;
            }

            // Determine energy bin. Skip if we are outside the energy range
            int index = m_ebounds.index(event->energy());
            if (index == -1) {
                num_outside_ebds++;
                continue;
            }

            // Fill event in skymap
            m_cube(pixel, index) += 1.0;
            num_in_map++;

        } // endfor: looped over all events

        // Append GTIs
        m_gti.extend(events->gti());

        // Update ontime and livetime
        m_ontime   += obs->ontime();
        m_livetime += obs->livetime();

        // Log filling results
        if (logTerse()) {
            log << gammalib::parformat("Events in list");
            log << obs->events()->size() << std::endl;
            log << gammalib::parformat("Events in cube");
            log << num_in_map << std::endl;
            log << gammalib::parformat("Event bins outside RoI");
            log << num_outside_roi << std::endl;
            log << gammalib::parformat("Events outside cube area");
            log << num_outside_map << std::endl;
            log << gammalib::parformat("Events outside energy bins");
            log << num_outside_ebds << std::endl;
        }

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

    } // endif: observation was valid

    // Return
    return;
}
/***********************************************************************//**
 * @brief Returns MC sky direction
 *
 * @param[in] energy Photon energy.
 * @param[in] time Photon arrival time.
 * @param[in,out] ran Random number generator.
 * @return Sky direction.
 *
 * @exception GException::invalid_value
 *            No energy boundaries specified, or energy boundaries do not
 *            cover the specified @p energy.
 *
 * Returns a random sky direction according to the intensity distribution of
 * the model sky map and the specified energy. The method makes use of a
 * cache array that contains the normalised cumulative flux values for each
 * of the sky maps in the cube. The specified energy is used to select the
 * appropriate cache array from the cube. Using a uniform random number, the
 * selected cache array is scanned using a bi-section method to determine
 * the skymap pixel for which the position should be returned. To avoid
 * binning problems, the exact position within the pixel is set by a uniform
 * random number generator (neglecting thus pixel distortions). The
 * fractional skymap pixel is then converted into a sky direction.
 ***************************************************************************/
GSkyDir GModelSpatialDiffuseCube::mc(const GEnergy& energy,
                                     const GTime&   time,
                                     GRan&          ran) const
{
    // Allocate sky direction
    GSkyDir dir;

    // Fetch cube
    fetch_cube();

    // Determine number of skymap pixels
    int npix = pixels();

    // Continue only if there are skymap pixels
    if (npix > 0) {

        // If no energy boundaries are defined, throw an exception
        if (m_ebounds.size() < 1) {
            std::string msg = "The energy boundaries of the maps in the cube"
                              " have not been defined. Maybe the map cube file"
                              " is missing the \"ENERGIES\" extension which"
                              " defines the energy of each map in the cube.\n"
                              "Please provide the energy information."; 
            throw GException::invalid_value(G_MC, msg);
        }

        // Determine the map that corresponds best to the specified energy.
        // This is not 100% clean, as ideally some map interpolation should
        // be done to the exact energy specified. However, as long as the map
        // does not change drastically with energy, taking the closest map
        // seems to be fine.
        int i = m_ebounds.index(energy);
        if (i < 0) {
            if (energy <= m_ebounds.emin()) {
                i = 0;
            }
            else if (energy >= m_ebounds.emax()) {
                i = m_ebounds.size()-1;
            }
            else {
                std::string msg = "The specified energy "+energy.print()+" does"
                                  " not fall in any of the energy boundaries of"
                                  " the map cube.\n"
                                  "Please make sure that the map cube energies"
                                  " are properly defined.";
                throw GException::invalid_value(G_MC, msg);
            }
        }
        
        // Get uniform random number
        double u = ran.uniform();

        // Get pixel index according to random number. We use a bi-section
        // method to find the corresponding skymap pixel
        int offset = i * (npix+1);
        int low    = offset;
        int high   = offset + npix;
        while ((high - low) > 1) {
            int mid = (low+high) / 2;
            if (u < m_mc_cache[mid]) {
                high = mid;
            }
            else if (m_mc_cache[mid] <= u) {
                low = mid;
            }
        }

        // Convert sky map index to sky map pixel
        GSkyPixel pixel = m_cube.inx2pix(low-offset);

        // Randomize pixel
        pixel.x(pixel.x() + ran.uniform() - 0.5);
        pixel.y(pixel.y() + ran.uniform() - 0.5);

        // Get sky direction
        dir = m_cube.pix2dir(pixel);
    
    } // endif: there were pixels in sky map

    // Return sky direction
    return dir;
}
Exemple #5
0
/***********************************************************************//**
 * @brief Bin events into a counts map
 *
 * @param[in] obs CTA observation.
 *
 * @exception GException::no_list
 *            No event list found in observation.
 * @exception GCTAException::no_pointing
 *            No valid CTA pointing found.
 *
 * This method bins the events found in a CTA events list into a counts map
 * and replaces the event list by the counts map in the observation. The
 * energy boundaries of the counts map are also stored in the observation's
 * energy boundary member.
 *
 * If the reference values for the map centre (m_xref, m_yref) are 9999.0,
 * the pointing direction of the observation is taken as the map centre.
 * Otherwise, the specified reference value is used.
 ***************************************************************************/
void ctbin::bin_events(GCTAObservation* obs)
{
    // Continue only if observation pointer is valid
    if (obs != NULL) {

        // Make sure that the observation holds a CTA event list. If this
        // is not the case then throw an exception.
        if (dynamic_cast<const GCTAEventList*>(obs->events()) == NULL) {
            throw GException::no_list(G_BIN_EVENTS);
        }

        // Setup energy range covered by data
        GEnergy  emin;
        GEnergy  emax;
        GEbounds ebds;
        emin.TeV(m_emin);
        emax.TeV(m_emax);
        ebds.setlog(emin, emax, m_enumbins);

        // Get Good Time intervals
        GGti gti = obs->events()->gti();
        
        // Get map centre
        double xref;
        double yref;
        if (m_xref != 9999.0 && m_yref != 9999.0) {
            xref = m_xref;
            yref = m_yref;
        }
        else {
            
            // Get pointer on CTA pointing
            const GCTAPointing *pnt = obs->pointing();
            if (pnt == NULL) {
                throw GCTAException::no_pointing(G_BIN_EVENTS);
            }
            
            // Set reference point to pointing
            if (toupper(m_coordsys) == "GAL") {
                xref = pnt->dir().l_deg();
                yref = pnt->dir().b_deg();
            }
            else {
                xref = pnt->dir().ra_deg();
                yref = pnt->dir().dec_deg();
            }

        } // endelse: map centre set to pointing

        // Create skymap
        GSkymap map = GSkymap(m_proj, m_coordsys,
                              xref, yref, m_binsz, m_binsz,
                              m_nxpix, m_nypix, m_enumbins);

        // Initialise binning statistics
        int num_outside_map  = 0;
        int num_outside_ebds = 0;
        int num_in_map       = 0;

        // Fill sky map
        GCTAEventList* events = static_cast<GCTAEventList*>(const_cast<GEvents*>(obs->events()));
        for (GCTAEventList::iterator event = events->begin(); event != events->end(); ++event) {

            // Determine sky pixel
            GCTAInstDir* inst  = (GCTAInstDir*)&(event->dir());
            GSkyDir      dir   = inst->dir();
            GSkyPixel    pixel = map.dir2xy(dir);

            // Skip if pixel is out of range
            if (pixel.x() < -0.5 || pixel.x() > (m_nxpix-0.5) ||
                pixel.y() < -0.5 || pixel.y() > (m_nypix-0.5)) {
                num_outside_map++;
                continue;
            }

            // Determine energy bin. Skip if we are outside the energy range
            int index = ebds.index(event->energy());
            if (index == -1) {
                num_outside_ebds++;
                continue;
            }

            // Fill event in skymap
            map(pixel, index) += 1.0;
            num_in_map++;

        } // endfor: looped over all events

        // Log binning results
        if (logTerse()) {
            log << std::endl;
            log.header1("Binning");
            log << parformat("Events in list");
            log << obs->events()->size() << std::endl;
            log << parformat("Events in map");
            log << num_in_map << std::endl;
            log << parformat("Events outside map area");
            log << num_outside_map << std::endl;
            log << parformat("Events outside energy bins");
            log << num_outside_ebds << std::endl;
        }

        // Log map
        if (logTerse()) {
            log << std::endl;
            log.header1("Counts map");
            log << map << std::endl;
        }

        // Create events cube from sky map
        GCTAEventCube cube(map, ebds, gti);

        // Replace event list by event cube in observation
        obs->events(&cube);

    } // endif: observation was valid

    // Return
    return;
}