/***********************************************************************//**
 * @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.
 *
 * Draws an arbitrary sky position from the 2D disk distribution.
 *
 * @todo Test function
 ***************************************************************************/
GSkyDir GModelSpatialEllipticalDisk::mc(const GEnergy& energy,
                                        const GTime&   time,
                                        GRan&          ran) const
{
    // Update precomputation cache
	update();

	// Initialise photon
    GPhoton photon;
    photon.energy(energy);
    photon.time(time);

	// Draw randomly from the radial disk
	// and reject the value if its outside the ellipse
	do {

        // Simulate offset from photon arrival direction
        double cosrad = std::cos(semimajor() * gammalib::deg2rad);
        double theta  = std::acos(1.0 - ran.uniform() * (1.0 - cosrad)) *
                        gammalib::rad2deg;
        double phi    = 360.0 * ran.uniform();

        // Rotate sky direction by offset
        GSkyDir sky_dir = dir();
        sky_dir.rotate_deg(phi, theta);

        // Set photon sky direction
        photon.dir(sky_dir);

	} while(GModelSpatialElliptical::eval(photon) <= 0.0);

	// Return photon direction
	return (photon.dir());

}
/***********************************************************************//**
 * @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;
}
/***********************************************************************//**
 * @brief Return model value and set analytical gradients
 *
 * @param[in] photon Incident Photon.
 *
 * Evaluates the radial spatial model value and analytical model parameter
 * gradients for a specific incident @p photon.
 ***************************************************************************/
double GModelSpatialRadial::eval_gradients(const GPhoton& photon) const
{
    // Compute distance from source (in radians)
    double theta = photon.dir().dist(dir());

    // Evaluate model and set gradients
    double value = eval_gradients(theta, photon.energy(), photon.time());

    // Return result
    return value;
}
Beispiel #4
0
/***********************************************************************//**
 * @brief Return model value
 *
 * @param[in] photon Incident Photon.
 * @param[in] gradients Compute gradients?
 * @return Value of spatial elliptical model.
 *
 * Evaluates the elliptical spatial model value for a specific incident
 * @p photon.
 *
 * If the @p gradients flag is true the method will also compute the
 * parameter gradients for all model parameters.
 ***************************************************************************/
double GModelSpatialElliptical::eval(const GPhoton& photon,
                                     const bool&    gradients) const
{
    // Compute distance from source and position angle (in radians)
    const GSkyDir& srcDir = photon.dir();
    double         theta  = dir().dist(srcDir);
    double         posang = dir().posang(srcDir);

    // Evaluate model
    double value = eval(theta, posang, photon.energy(), photon.time(), gradients);

    // Return result
    return value;
}
Beispiel #5
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.
 *
 * Draws an arbitrary sky direction from the elliptical Gaussian model.
 *
 * @warning
 * For numerical reasons the elliptical Gaussian will be truncated for
 * \f$\theta\f$ angles that correspond to 3.0 times the effective ellipse
 * radius.
 ***************************************************************************/
GSkyDir GModelSpatialEllipticalGauss::mc(const GEnergy& energy,
                                         const GTime&   time,
                                         GRan&          ran) const
{
    // Update precomputation cache
    update();

    // Initialise photon
    GPhoton photon;
    photon.energy(energy);
    photon.time(time);

    // Draw gaussian offset from each axis
    double ran_major;
    double ran_minor;
    do {
        ran_major = ran.normal();
    } while (ran_major > c_theta_max);
    do {
        ran_minor = ran.normal();
    } while (ran_minor > c_theta_max);
    double theta1 = semimajor() * ran_major;
    double theta2 = semiminor() * ran_minor;

    // Compute total offset from model centre in small angle approximation
    double theta = std::sqrt(theta1 * theta1 + theta2 * theta2);

    // Compute rotation angle, taking into account given position angle
    double phi = gammalib::atan2d(theta2, theta1) + posangle();

    // Rotate sky direction by offset
    GSkyDir sky_dir = dir();
    sky_dir.rotate_deg(phi , theta);

    // Set photon sky direction
    photon.dir(sky_dir);

    // Return photon direction
    return (photon.dir());
}
/***********************************************************************//**
 * @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;
}
Beispiel #7
0
/***********************************************************************//**
 * @brief Return simulated list of photons
 *
 * @param[in] area Simulation surface area (cm2).
 * @param[in] dir Centre of simulation cone.
 * @param[in] radius Radius of simulation cone (deg).
 * @param[in] emin Minimum photon energy.
 * @param[in] emax Maximum photon energy.
 * @param[in] tmin Minimum photon arrival time.
 * @param[in] tmax Maximum photon arrival time.
 * @param[in] ran Random number generator.
 *
 * This method returns a list of photons that has been derived by Monte Carlo
 * simulation from the model. A simulation region is define by specification
 * of a simulation cone (a circular region on the sky),
 * of an energy range [emin, emax], and
 * of a time interval [tmin, tmax].
 * The simulation cone may eventually cover the entire sky (by setting
 * the radius to 180 degrees), yet simulations will be more efficient if
 * only the sky region will be simulated that is actually observed by the
 * telescope.
 *
 * @todo Check usage for diffuse models
 * @todo Implement photon arrival direction simulation for diffuse models
 * @todo Implement unique model ID to assign as Monte Carlo ID
 ***************************************************************************/
GPhotons GModelSky::mc(const double& area,
                       const GSkyDir& dir,  const double&  radius,
                       const GEnergy& emin, const GEnergy& emax,
                       const GTime&   tmin, const GTime&   tmax,
                       GRan& ran) const
{
    // Allocate photons
    GPhotons photons;

    // Continue only if model is valid)
    if (valid_model()) {

        // Get point source pointer
        GModelSpatialPtsrc* ptsrc = dynamic_cast<GModelSpatialPtsrc*>(m_spatial);

        // Check if model will produce any photons in the specified
        // simulation region. If the model is a point source we check if the
        // source is located within the simulation code. If the model is a
        // diffuse source we check if the source overlaps with the simulation
        // code
        bool use_model = true;
        if (ptsrc != NULL) {
            if (dir.dist(ptsrc->dir()) > radius) {
                use_model = false;
            }
        }
        else {
            //TODO
        }

        // Continue only if model overlaps with simulation region
        if (use_model) {

            // Compute flux within [emin, emax] in model from spectral
            // component (units: ph/cm2/s)
            double flux = m_spectral->flux(emin, emax);

            // Derive expecting counting rate within simulation surface
            // (units: ph/s)
            double rate = flux * area;

            // Debug option: dump rate
#if G_DUMP_MC
            std::cout << "GModelSky::mc(\"" << name() << "\": ";
            std::cout << "flux=" << flux << " ph/cm2/s, ";
            std::cout << "rate=" << rate << " ph/s)" << std::endl;
#endif

            // Get photon arrival times from temporal model
            GTimes times = m_temporal->mc(rate, tmin, tmax, ran);

            // Reserve space for photons
            if (times.size() > 0) {
                photons.reserve(times.size());
            }

            // Loop over photons
            for (int i = 0; i < times.size(); ++i) {

                // Allocate photon
                GPhoton photon;

                // Set photon arrival time
                photon.time(times[i]);

                // Set incident photon direction
                photon.dir(m_spatial->mc(ran));

                // Set photon energy
                photon.energy(m_spectral->mc(emin, emax, ran));

                // Append photon
                photons.append(photon);

            } // endfor: looped over photons

        } // endif: model was used
    } // endif: model was valid

    // Return photon list
    return photons;
}
Beispiel #8
0
/***********************************************************************//**
 * @brief Return instrument response
 *
 * @param[in] event Observed event.
 * @param[in] photon Incident photon.
 * @param[in] obs Observation (not used).
 * @return Instrument response.
 ***************************************************************************/
double GCTAResponseCube::irf(const GEvent&       event,
                             const GPhoton&      photon,
                             const GObservation& obs) const
{
    // Retrieve event instrument direction
    const GCTAInstDir& dir = retrieve_dir(G_IRF, event);

    // Get event attributes
    const GSkyDir& obsDir = dir.dir();
    //const GEnergy& obsEng = event.energy();

    // Get photon attributes
    const GSkyDir& srcDir  = photon.dir();
    const GEnergy& srcEng  = photon.energy();
    //const GTime&   srcTime = photon.time();

    // Determine angular separation between true and measured photon
    // direction in radians
    double delta = obsDir.dist(srcDir);

    // Get maximum angular separation for PSF (in radians)
    double delta_max = psf().delta_max();

    // Initialise IRF value
    double irf = 0.0;

    // Get livetime (in seconds)
    double livetime = exposure().livetime();

    // Continue only if livetime is >0 and if we're sufficiently close
    // to the PSF
    if ((livetime > 0.0) && (delta <= delta_max)) {

        // Get exposure
        irf = exposure()(srcDir, srcEng);

        // Multiply-in PSF
        if (irf > 0.0) {

            // Get PSF component
            irf *= psf()(srcDir, delta, srcEng);

            // Divide by livetime
            irf /= livetime;

            // Apply deadtime correction
            irf *= exposure().deadc();

        } // endif: Aeff was non-zero

    } // endif: we were sufficiently close to PSF and livetime was >0

    // Compile option: Check for NaN/Inf
    #if defined(G_NAN_CHECK)
    if (gammalib::is_notanumber(irf) || gammalib::is_infinite(irf)) {
        std::cout << "*** ERROR: GCTAResponseCube::irf:";
        std::cout << " NaN/Inf encountered";
        std::cout << " irf=" << irf;
        std::cout << std::endl;
    }
    #endif

    // Return IRF value
    return irf;
}
Beispiel #9
0
/***********************************************************************//**
 * @brief Return value of instrument response function
 *
 * @param[in] event Observed event.
 * @param[in] photon Incident photon.
 * @param[in] obs Observation.
 * @return Instrument response function (cm2 sr-1)
 *
 * @exception GException::invalid_argument
 *            Observation is not a COMPTEL observation.
 *            Event is not a COMPTEL event bin.
 *
 * Returns the instrument response function for a given observed photon
 * direction as function of the assumed true photon direction. The result
 * is given by
 * \f[IRF = \frac{IAQ \times DRG \times DRX}{ontime \times ewidth}\f]
 * where
 * \f$IRF\f$ is the instrument response function,
 * \f$IAQ\f$ is the COMPTEL response matrix (sr-1),
 * \f$DRG\f$ is the geometry factor (cm2),
 * \f$DRX\f$ is the exposure (s),
 * \f$ontime\f$ is the ontime (s), and
 * \f$ewidth\f$ is the energy width (MeV).
 *
 * The observed photon direction is spanned by the 3 values (Chi,Psi,Phibar).
 * (Chi,Psi) is the scatter direction of the event, given in sky coordinates.
 * Phibar is the Compton scatter angle, computed from the energy deposits.
 ***************************************************************************/
double GCOMResponse::irf(const GEvent&       event,
                         const GPhoton&      photon,
                         const GObservation& obs) const
{
    // Extract COMPTEL observation
    const GCOMObservation* observation = dynamic_cast<const GCOMObservation*>(&obs);
    if (observation == NULL) {
        std::string cls = std::string(typeid(&obs).name());
        std::string msg = "Observation of type \""+cls+"\" is not a COMPTEL "
                          "observations. Please specify a COMPTEL observation "
                          "as argument.";
        throw GException::invalid_argument(G_IRF, msg);
    }

    // Extract COMPTEL event bin
    const GCOMEventBin* bin = dynamic_cast<const GCOMEventBin*>(&event);
    if (bin == NULL) {
        std::string cls = std::string(typeid(&event).name());
        std::string msg = "Event of type \""+cls+"\" is  not a COMPTEL event. "
                          "Please specify a COMPTEL event as argument.";
        throw GException::invalid_argument(G_IRF, msg);
    }

    // Extract event parameters
    const GCOMInstDir& obsDir = bin->dir();

    // Extract photon parameters
    const GSkyDir& srcDir  = photon.dir();
    const GTime&   srcTime = photon.time();

    // Compute angle between true photon arrival direction and scatter
    // direction (Chi,Psi)
    double phigeo = srcDir.dist_deg(obsDir.dir());

    // Compute scatter angle index
    int iphibar = int(obsDir.phibar() / m_phibar_bin_size);

    // Extract IAQ value by linear inter/extrapolation in Phigeo
    double iaq = 0.0;
    if (iphibar < m_phibar_bins) {
        double phirat  = phigeo / m_phigeo_bin_size; // 0.5 at bin centre
        int    iphigeo = int(phirat);                // index into which Phigeo falls
        double eps     = phirat - iphigeo - 0.5;     // 0.0 at bin centre
        if (iphigeo < m_phigeo_bins) {
            int i = iphibar * m_phigeo_bins + iphigeo;
            if (eps < 0.0) { // interpolate towards left
                if (iphigeo > 0) {
                    iaq = (1.0 + eps) * m_iaq[i] - eps * m_iaq[i-1];
                }
                else {
                    iaq = (1.0 - eps) * m_iaq[i] + eps * m_iaq[i+1];
                }
            }
            else {           // interpolate towards right
                if (iphigeo < m_phigeo_bins-1) {
                    iaq = (1.0 - eps) * m_iaq[i] + eps * m_iaq[i+1];
                }
                else {
                    iaq = (1.0 + eps) * m_iaq[i] - eps * m_iaq[i-1];
                }
            }
        }
    }

    // Get DRG value (units: cm2)
    double drg = observation->drg()(obsDir.dir(), iphibar);

    // Get DRX value (units: sec)
    double drx = observation->drx()(srcDir);

    // Get ontime
    double ontime = observation->ontime(); // sec

    // Compute IRF value
    double irf = iaq * drg * drx / ontime;

    // Apply deadtime correction
    irf *= obs.deadc(srcTime);

    // Compile option: Check for NaN/Inf
    #if defined(G_NAN_CHECK)
    if (gammalib::is_notanumber(irf) || gammalib::is_infinite(irf)) {
        std::cout << "*** ERROR: GCOMResponse::irf:";
        std::cout << " NaN/Inf encountered";
        std::cout << " (irf=" << irf;
        std::cout << ", iaq=" << iaq;
        std::cout << ", drg=" << drg;
        std::cout << ", drx=" << drx;
        std::cout << ")";
        std::cout << std::endl;
    }
    #endif

    // Return IRF value
    return irf;
}