Пример #1
0
/***********************************************************************//**
 * @brief Evaluate function
 *
 * @param[in] photon Incident photon.
 * @return Model value.
 *
 * Computes the spatial diffuse model as function of photon parameters.
 ***************************************************************************/
double GModelSpatialDiffuseCube::eval(const GPhoton& photon) const
{
    // Initialise value
    double value = 0.0;

    // Fetch cube
    fetch_cube();

    // Continue only if there is energy information for the map cube
    if (m_logE.size() > 0) {

        // Compute diffuse model value by interpolation in log10(energy)
        m_logE.set_value(photon.energy().log10MeV());
        double intensity = m_logE.wgt_left() *
                           m_cube(photon.dir(), m_logE.inx_left()) +
                           m_logE.wgt_right() *
                           m_cube(photon.dir(), m_logE.inx_right());

        // Set the intensity times the scaling factor as model value
        value = intensity * m_value.value();

        // Make sure that value is not negative
        if (value < 0.0) {
            value = 0.0;
        }

    } // endif: energy information was available

    // Return value
    return value;
}
Пример #2
0
/***********************************************************************//**
 * @brief Return exposure (in units of cm2 s)
 *
 * @param[in] dir Coordinate of the true photon position.
 * @param[in] energy Energy of the true photon.
 * @return Exposure (in units of cm2 s)
 ***************************************************************************/
double GCTACubeExposure::operator()(const GSkyDir& dir, const GEnergy& energy) const
{ 
    // Set indices and weighting factors for interpolation
    update(energy.log10TeV());

    // Perform interpolation
    double exposure = m_wgt_left  * m_cube(dir, m_inx_left) +
                      m_wgt_right * m_cube(dir, m_inx_right);

    // Make sure that exposure does not become negative
    if (exposure < 0.0) {
        exposure = 0.0;
    }

    // Return exposure
    return exposure;
}
Пример #3
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;
}
Пример #4
0
/***********************************************************************//**
 * @brief Evaluate function and gradients
 *
 * @param[in] photon Incident photon.
 * @return Model value.
 *
 * Computes the spatial diffuse model as function of photon parameters and
 * sets the value gradient.
 ***************************************************************************/
double GModelSpatialDiffuseCube::eval_gradients(const GPhoton& photon) const
{
    // Initialise intensity
    double intensity = 0.0;

    // Fetch cube
    fetch_cube();

    // Continue only if there is energy information for the map cube
    if (m_logE.size() > 0) {

        // Compute diffuse model value by interpolation in log10(energy)
        m_logE.set_value(photon.energy().log10MeV());
        intensity = m_logE.wgt_left() *
                    m_cube(photon.dir(), m_logE.inx_left()) +
                    m_logE.wgt_right() *
                    m_cube(photon.dir(), m_logE.inx_right());


    } // endif: energy information was available

    // Compute the model value
    double value = intensity * m_value.value();

	// Compute partial derivatives of the parameter value
	double g_value = (m_value.is_free()) ? intensity * m_value.scale() : 0.0;

    // Make sure that value is not negative
    if (value < 0.0) {
        value   = 0.0;
        g_value = 0.0;
    }

	// Set gradient to 0 (circumvent const correctness)
	const_cast<GModelSpatialDiffuseCube*>(this)->m_value.factor_gradient(g_value);

    // Return value
    return value;
}
Пример #5
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;
}
Пример #6
0
/***********************************************************************//**
 * @brief Set Monte Carlo simulation cone
 *
 * @param[in] centre Simulation cone centre.
 * @param[in] radius Simulation cone radius (degrees).
 *
 * Sets the simulation cone centre and radius that defines the directions
 * that will be simulated using the mc() method.
 ***************************************************************************/
void GModelSpatialDiffuseCube::set_mc_cone(const GSkyDir& centre,
                                           const double&  radius)
{
    // Initialise cache
    m_mc_cache.clear();
    m_mc_spectrum.clear();

    // Fetch cube
    fetch_cube();

    // Determine number of cube pixels and maps
    int npix  = pixels();
    int nmaps = maps();

    // Continue only if there are pixels and maps
    if (npix > 0 && nmaps > 0) {

        // Reserve space for all pixels in cache
        m_mc_cache.reserve((npix+1)*nmaps);

        // Loop over all maps
        for (int i = 0; i < nmaps; ++i) {

            // Compute pixel offset
            int offset = i * (npix+1);

            // Set first cache value to 0
            m_mc_cache.push_back(0.0);

            // Initialise cache with cumulative pixel fluxes and compute
            // total flux in skymap for normalization. Negative pixels are
            // excluded from the cumulative map.
            double total_flux = 0.0;
        	for (int k = 0; k < npix; ++k) {

                // Derive effective pixel radius from half opening angle
                // that corresponds to the pixel's solid angle. For security,
                // the radius is enhanced by 50%.
                double pixel_radius =
                       std::acos(1.0 - m_cube.solidangle(k)/gammalib::twopi) *
                       gammalib::rad2deg * 1.5;

                // Add up flux with simulation cone radius + effective pixel
                // radius. The effective pixel radius is added to make sure
                // that all pixels that overlap with the simulation cone are
                // taken into account. There is no problem of having even
                // pixels outside the simulation cone taken into account as
                // long as the mc() method has an explicit test of whether a
                // simulated event is contained in the simulation cone.
                double distance = centre.dist_deg(m_cube.pix2dir(k));
                if (distance <= radius+pixel_radius) {
                    double flux = m_cube(k,i) * m_cube.solidangle(k);
                    if (flux > 0.0) {
                        total_flux += flux;
                    }
                }

                // Push back flux
        		m_mc_cache.push_back(total_flux); // units: ph/cm2/s/MeV
        	}

            // Normalize cumulative pixel fluxes so that the values in the
            // cache run from 0 to 1
            if (total_flux > 0.0) {
        		for (int k = 0; k < npix; ++k) {
        			m_mc_cache[k+offset] /= total_flux;
        		}
        	}

            // Make sure that last pixel in the cache is >1
            m_mc_cache[npix+offset] = 1.0001;

            // Store centre flux in node array
            if (m_logE.size() == nmaps) {
                GEnergy energy;
                energy.log10MeV(m_logE[i]);
                
                // Only append node if flux > 0
                if (total_flux > 0.0) {
                	m_mc_spectrum.append(energy, total_flux);
                }

            }

        } // endfor: looped over all maps

        // Dump cache values for debugging
        #if defined(G_DEBUG_CACHE)
        for (int i = 0; i < m_mc_cache.size(); ++i) {
            std::cout << "i=" << i;
            std::cout << " c=" << m_mc_cache[i] << std::endl;
        }
        #endif

    } // endif: there were cube pixels and maps

    // Return
    return;
}