/***********************************************************************//** * @brief Return normalization of radial source for Monte Carlo simulations * * @param[in] dir Centre of simulation cone. * @param[in] radius Radius of simulation cone (degrees). * @return Normalization. * * Returns the normalization for a radial source within a circular region. * The normalization is 1 if the radial source falls within the circle * defined by @p dir and @p radius, 0 otherwise. ***************************************************************************/ inline double GModelSpatialRadial::mc_norm(const GSkyDir& dir, const double& radius) const { double norm = (dir.dist_deg(this->dir()) <= radius+theta_max()) ? 1.0 : 0.0; return (norm); }
/***********************************************************************//** * @brief Checks where model contains specified sky direction * * @param[in] dir Sky direction. * @param[in] margin Margin to be added to sky direction (degrees) * @return True if the model contains the sky direction. * * Signals whether a sky direction is contained in the radial gauss model. ***************************************************************************/ bool GModelSpatialRadialGauss::contains(const GSkyDir& dir, const double& margin) const { // Compute distance to centre (radians) double distance = dir.dist(this->dir()); // Return flag return (distance <= theta_max() + margin*gammalib::deg2rad); }
/***********************************************************************//** * @brief Evaluate function (in units of sr^-1) * * @param[in] theta Angular distance from disk centre (radians). * @param[in] posangle Position angle (counterclockwise from North) (radians). * @param[in] energy Photon energy. * @param[in] time Photon arrival time. * @return Model value. * * Evaluates the spatial component for an elliptical disk source model. The * disk source model is an elliptical function * \f$S_{\rm p}(\theta, \phi | E, t)\f$, where * \f$\theta\f$ is the angular separation between elliptical disk centre and * the actual location and \f$\phi\f$ the position angle with respect to the * ellipse centre, counted counterclockwise from North. * * The function \f$f(\theta, \phi)\f$ is given by * * \f[ * S_{\rm p}(\theta, \phi | E, t) = \left \{ * \begin{array}{l l} * {\tt m\_norm} * & \mbox{if} \, \, \theta \le \theta_0 \\ * \\ * 0 & \mbox{else} * \end{array} * \right . * \f] * * where \f$\theta_0\f$ is the effective radius of the ellipse on the sphere * given by * * \f[\theta_0\ = * \frac{ab}{\sqrt{b^2 \cos^2(\phi-\phi_0) + a^2 \sin^2(\phi-\phi_0)}}\f] * * and * \f$a\f$ is the semi-major axis of the ellipse, * \f$b\f$ is the semi-minor axis, and * \f$\phi_0\f$ is the position angle of the ellipse, counted * counterclockwise from North. * * The normalisation constant \f${\tt m\_norm}\f$ which is the inverse of the * solid angle subtended by an ellipse is given by * * @todo Quote formula for ellipse solid angle * * (see the update() method). ***************************************************************************/ double GModelSpatialEllipticalDisk::eval(const double& theta, const double& posangle, const GEnergy& energy, const GTime& time) const { // Initialise value double value = 0.0; // Continue only if we're inside circle enclosing the ellipse if (theta <= theta_max()) { // Update precomputation cache update(); // Perform computations double diff_angle = posangle - m_posangle.value() * gammalib::deg2rad; double cosinus = std::cos(diff_angle); double sinus = std::sin(diff_angle); double arg1 = m_semiminor_rad * cosinus; double arg2 = m_semimajor_rad * sinus; double r_ell = m_semiminor_rad * m_semimajor_rad / std::sqrt(arg1*arg1 + arg2*arg2); // Set value value = (theta <= r_ell) ? m_norm : 0.0; // Compile option: Check for NaN/Inf #if defined(G_NAN_CHECK) if (gammalib::is_notanumber(value) || gammalib::is_infinite(value)) { std::cout << "*** ERROR: GModelSpatialEllipticalDisk::eval"; std::cout << "(theta=" << theta << "): NaN/Inf encountered"; std::cout << "(posangle=" << posangle << "): NaN/Inf encountered"; std::cout << " (value=" << value; std::cout << ", R_ellipse=" << r_ell; std::cout << ", diff_angle=" << diff_angle; std::cout << ", m_norm=" << m_norm; std::cout << ")" << std::endl; } #endif } // endif: position was inside enclosing circle // Return value return value; }
/***********************************************************************//** * @brief Evaluate function (in units of sr^-1) * * @param[in] theta Angular distance from disk centre (radians). * @param[in] posangle Position angle (counterclockwise from North) (radians). * @param[in] energy Photon energy. * @param[in] time Photon arrival time. * @return Model value. * * Evaluates the spatial component for an elliptical Gaussian source model. * * The elliptical Gaussian function is defined by * \f$S_{\rm p}(\theta, \phi | E, t)\f$, where * \f$\theta\f$ is the angular separation between elliptical Gaussian centre * and the actual location and \f$\phi\f$ the position angle with respect to * the model centre, counted counterclockwise from North. * * The function \f$S_{\rm p}(\theta, \phi | E, t)\f$ is given by * * \f[ * S_{\rm p}(\theta, \phi | E, t) = {\tt m\_norm} \times * \exp \left( -\frac{\theta^2}{2 r_{\rm eff}^2} \right) * \f] * * where the effective ellipse radius \f$r_{\rm eff}\f$ towards a given * position angle is given by * * \f[ * r_{\rm eff} = \frac{ab} * {\sqrt{\left( a \sin (\phi - \phi_0) \right)^2} + * \sqrt{\left( b \cos (\phi - \phi_0) \right)^2}} * \f] * and * \f$a\f$ is the semi-major axis of the ellipse, * \f$b\f$ is the semi-minor axis, and * \f$\phi_0\f$ is the position angle of the ellipse, counted * counterclockwise from North. * \f${\tt m\_norm}\f$ is a normalization constant given by * * \f[ * {\tt m\_norm} = \frac{1}{2 \pi \times a \times b} * \f] * * @warning * The above formula for an elliptical Gaussian are accurate for small * angles, with semimajor and semiminor axes below a few degrees. This * should be fine for most use cases, but you should be aware that the * ellipse will get distorted for larger angles. * * @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. ***************************************************************************/ double GModelSpatialEllipticalGauss::eval(const double& theta, const double& posangle, const GEnergy& energy, const GTime& time) const { // Initialise value double value = 0.0; // Continue only if we're inside circle enclosing the ellipse if (theta <= theta_max()) { // Update precomputation cache update(); // Perform computations to compute exponent #if defined(G_SMALL_ANGLE_APPROXIMATION) double rel_posangle = posangle - this->posangle() * gammalib::deg2rad; double cosinus = std::cos(rel_posangle); double sinus = std::sin(rel_posangle); double arg1 = m_minor_rad * cosinus; double arg2 = m_major_rad * sinus; double r_ellipse = m_minor_rad * m_major_rad / std::sqrt(arg1*arg1 + arg2*arg2); //!< small angle double r_relative = theta/r_ellipse; double exponent = 0.5*r_relative*r_relative; #else // Perform computations double sinphi = std::sin(posangle); double cosphi = std::cos(posangle); // Compute help term double term1 = m_term1 * cosphi * cosphi; double term2 = m_term2 * sinphi * sinphi; double term3 = m_term3 * sinphi * cosphi; // Compute exponent double exponent = theta * theta * (term1 + term2 + term3); #endif // Set value if the exponent is within the truncation region if (exponent <= c_max_exponent) { value = m_norm * std::exp(-exponent); } // Compile option: Check for NaN/Inf #if defined(G_NAN_CHECK) if (gammalib::is_notanumber(value) || gammalib::is_infinite(value)) { std::cout << "*** ERROR: GModelSpatialEllipticalGauss::eval"; std::cout << "(theta=" << theta << "): NaN/Inf encountered"; std::cout << "(posangle=" << posangle << "): NaN/Inf encountered"; std::cout << " (value=" << value; std::cout << ", MinorAxis^2=" << m_minor2; std::cout << ", MaxjorAxis^2=" << m_major2; std::cout << ", m_norm=" << m_norm; std::cout << ")" << std::endl; } #endif } // endif: position was inside enclosing circle // Return value return value; }