/***********************************************************************//** * @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 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; }
/***********************************************************************//** * @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 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; }