Ejemplo n.º 1
0
/***********************************************************************//**
 * @brief Insert energy interval
 *
 * @param[in] index Index after with interval is inserted.
 * @param[in] emin Minimum energy of interval.
 * @param[in] emax Maximum energy of interval.
 *
 * @exception GException::invalid_argument
 *            Minimum energy larger than maximum energy
 *
 * Inserts an energy interval after the specified @p index in the energy
 * boundaries. The method does not reorder the intervals by energy, instead
 * the client needs to determine the approriate @p index.
 *
 * Invalid parameters do not produce any exception, but are handled
 * transparently. If the interval is invalid (i.e. @p emin > @p emax) an
 * exception is thrown. If the @p index is out of the valid range, the
 * index will be adjusted to either the first or the last element.
 ***************************************************************************/
void GEbounds::insert_eng(const int&     index,
                          const GEnergy& emin,
                          const GEnergy& emax)
{
    // Throw an exception if energy interval is invalid
    if (emin > emax) {
        std::string msg = "Invalid energy interval specified. Minimum"
                          " energy "+emin.print(NORMAL)+" can not be"
                          " larger than maximum energy "+
                          emax.print(NORMAL)+".";
        throw GException::invalid_argument(G_INSERT_ENG, msg);
    }

    // Set index
    int inx = index;

    // If inx is out of range then adjust it
    if (inx < 0)     inx = 0;
    if (inx > m_num) inx = m_num;

    // Allocate new intervals
    int      num = m_num+1;
    GEnergy* min = new GEnergy[num];
    GEnergy* max = new GEnergy[num];

    // Copy intervals before index to be inserted
    for (int i = 0; i < inx; ++i) {
        min[i] = m_min[i];
        max[i] = m_max[i];
    }

    // Insert interval
    min[inx] = emin;
    max[inx] = emax;

    // Copy intervals after index to be inserted
    for (int i = inx+1; i < num; ++i) {
        min[i] = m_min[i-1];
        max[i] = m_max[i-1];
    }

    // Free memory
    if (m_min != NULL) delete [] m_min;
    if (m_max != NULL) delete [] m_max;

    // Set new memory
    m_min = min;
    m_max = max;

    // Set number of elements
    m_num = num;

    // Set attributes
    set_attributes();

    // Return
    return;
}
Ejemplo n.º 2
0
/***********************************************************************//**
 * @brief Test CTA psf computation
 *
 * The Psf computation is tested by integrating numerically the Psf
 * function. Integration is done in a rather simplistic way, by stepping
 * radially away from the centre. The integration is done for a set of
 * energies from 0.1-10 TeV.
 ***************************************************************************/
void TestGCTAResponse::test_response_psf(void)
{
    // Load response
    GCTAResponse rsp;
    rsp.caldb(cta_caldb);
    rsp.load(cta_irf);

    // Integrate Psf
    GEnergy eng;
    for (double e = 0.1; e < 10.0; e *= 2.0) {
        eng.TeV(e);
        double r     = 0.0;
        double dr    = 0.001;
        int    steps = int(1.0/dr);
        double sum   = 0.0;
        for (int i = 0; i < steps; ++i) {
            r   += dr;
            sum += rsp.psf(r*deg2rad, 0.0, 0.0, 0.0, 0.0, eng.log10TeV()) *
                   twopi * std::sin(r*deg2rad) * dr*deg2rad;
        }
        test_value(sum, 1.0, 0.001, "PSF integration for "+eng.print());
    }

    // Return
    return;
}
Ejemplo n.º 3
0
/***********************************************************************//**
 * @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;
}