/***********************************************************************//**
 * @brief Return maximum model radius (in radians)
 *
 * @return Returns maximum model radians.
 ***************************************************************************/
double GModelSpatialEllipticalDisk::theta_max(void) const
{
    // Set maximum model radius
    double theta_max = (semimajor() > semiminor())
                       ? semimajor() * gammalib::deg2rad
                       : semiminor() * gammalib::deg2rad;

    // Return value
    return theta_max;
}
/***********************************************************************//**
 * @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 Update precomputation cache
 *
 * Computes the normalization
 * \f[
 *    {\tt m\_norm} = \frac{1}{2 \pi (1 - \cos a) (1 - \cos b)}
 * \f]
 *
 * @todo check this formula
 ***************************************************************************/
void GModelSpatialEllipticalDisk::update() const
{
    // Update if one axis has changed has changed
    if (m_last_semiminor != semiminor() || m_last_semimajor != semimajor()) {

        // Store last values
        m_last_semiminor = semiminor();
        m_last_semimajor = semimajor();

        // Compute axes in radians
        m_semiminor_rad = semiminor() * gammalib::deg2rad;
        m_semimajor_rad = semimajor() * gammalib::deg2rad;

        // Perform precomputations
        double denom = gammalib::twopi *
                       std::sqrt((1.0 - std::cos(m_semiminor_rad)) *
                                 (1.0 - std::cos(m_semimajor_rad)));
        m_norm       = (denom > 0.0) ? 1.0 / denom : 0.0;

    } // endif: update required

    // Return
    return;
}
示例#4
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());
}
示例#5
0
/***********************************************************************//**
 * @brief Update precomputation cache
 *
 * Computes the normalization
 * \f[
 *    {\tt m\_norm} = \frac{1}{2 \pi \times a \times b}
 * \f]
 * where 
 * \f$a\f$ is the semi-major axis and
 * \f$b\f$ is the semi-minor axis of the ellipse.
 *
 * @warning
 * The normalization of the elliptical Gaussian is only valid in the small
 * angle approximation.
 ***************************************************************************/
void GModelSpatialEllipticalGauss::update() const
{
    // Initialise flag if something has changed
    bool changed = false;

    // Update if one axis has changed
    if (m_last_minor != semiminor() || m_last_major != semimajor()) {

        // Signal parameter changes
        changed = true;

        // Store last values
        m_last_minor = semiminor();
        m_last_major = semimajor();

        // Compute axes in radians
        m_minor_rad = m_last_minor * gammalib::deg2rad;
        m_major_rad = m_last_major * gammalib::deg2rad;

        // Perform precomputations. Note that I verified the normalization
        // by numerical integration of the resulting Gaussian. Note also
        // also that the normalization is only correct in the small angle
        // approximation.
        m_minor2     = m_minor_rad * m_minor_rad;
        m_major2     = m_major_rad * m_major_rad;
        double denom = gammalib::twopi * m_minor_rad * m_major_rad *
                       c_fraction;
        m_norm       = (denom > 0.0) ? 1.0 / denom : 0.0;

    } // endif: update required

    // Update chache if position angle changed
    #if !defined(G_SMALL_ANGLE_APPROXIMATION)
    if (m_last_posangle != posangle()) {

        // Signal parameter changes
        changed = true;

        // Store last value
        m_last_posangle = posangle();

        // Compute angle in radians
        double posangle_rad = m_last_posangle * gammalib::deg2rad;

        // Compute sine and cosine
        double cospos = std::cos(posangle_rad);
        double sinpos = std::sin(posangle_rad);

        // Cache important values for further computations
        m_cospos2 = cospos * cospos;
        m_sinpos2 = sinpos * sinpos;
        m_sin2pos = std::sin(2.0 * posangle_rad);

    } // endif: position angle update required

    // Perform precomputations in case anything has changed
    if (changed) {

        // Compute help terms
        m_term1 = 0.5 * (m_cospos2 / m_minor2 + m_sinpos2 / m_major2);
        m_term2 = 0.5 * (m_cospos2 / m_major2 + m_sinpos2 / m_minor2);
        m_term3 = 0.5 * (m_sin2pos / m_major2 - m_sin2pos / m_minor2);

    } // endif: something has changed
    #endif

    // Return
    return;
}