/*----------------------------------------------------------------*/ NOMAD::Point NOMAD::SMesh::get_delta_max ( ) const { NOMAD::Point delta_max ( _n ); // power_of_tau = tau^{ max{0,l0} - max{0,lk} }: NOMAD::Double power_of_tau = pow ( _update_basis.value() , ( (_initial_mesh_index > 0) ? _initial_mesh_index : 0) - ( (_min_mesh_index > 0) ? _min_mesh_index : 0) ); // delta^k = power_of_tau * delta^0: for ( int i = 0 ; i < _n ; ++i ) delta_max[i] = _delta_0[i] * power_of_tau; return delta_max; }
/***********************************************************************//** * @brief Return the radius that contains a fraction of the events (radians) * * @param[in] fraction of events (0.0<fraction<1.0) * @param[in] logE Log10 of the true photon energy (TeV). * @param[in] theta Offset angle in camera system (rad). Not used. * @param[in] phi Azimuth angle in camera system (rad). Not used. * @param[in] zenith Zenith angle in Earth system (rad). Not used. * @param[in] azimuth Azimuth angle in Earth system (rad). Not used. * @param[in] etrue Use true energy (true/false). Not used. * @return Containment radius (radians). * * @exception GException::invalid_argument * Invalid fraction specified. * * Uses the Newton-Raphson method to find which 'a' solves the equation: * * \f[ * * fraction = \pi * m\_norm * \left( * \frac{ 1 }{m\_width1} e^{m\_width1 * a^2} + * \frac{m\_norm2}{m\_width2} e^{m\_width2 * a^2} + * \frac{m\_norm3}{m\_width3} e^{m\_width3 * a^2} \right) * * \f] * * Calculate the radius from the center that contains 'fraction' percent * of the events. fraction * 100. = Containment % . Fraction must be * 0.0 < fraction < 1.0 . ***************************************************************************/ double GCTAPsf2D::containment_radius(const double& fraction, const double& logE, const double& theta, const double& phi, const double& zenith, const double& azimuth, const bool& etrue) const { // Check input argument if (fraction <= 0.0 || fraction >= 1.0) { std::string message = "Containment fraction "+ gammalib::str(fraction)+" must be between " + "0.0 and 1.0, not inclusive."; throw GException::invalid_argument(G_CONTAINMENT_RADIUS, message); } // Update the parameter cache update(logE, theta); // Required accuracy const double convergence = 1.0e-6; // Initial radius to start Newton's method with guess fraction * delta_max double a = fraction * delta_max(logE, theta, phi, zenith, azimuth, etrue); // Maximum number of newton-raphson loops before giving up const int iterlimit = 10000; // Do the newton-raphson loops int iter(0); for (; iter < iterlimit; ++iter) { // ... double a2 = a*a; // Calculate f(a) double fa(0.0); fa += m_norm * (std::exp( m_width1 * a2) - 1.0) / m_width1; fa += m_norm2 * (std::exp( m_width2 * a2) - 1.0) / m_width2; fa += m_norm3 * (std::exp( m_width3 * a2) - 1.0) / m_width3; fa *= gammalib::pi; fa -= fraction; // Check if we've met the desired accuracy if (std::abs(fa) < convergence) { break; } // Calculate f'(a) double fp(0.0); fp += m_norm * std::exp(m_width1 * a2); fp += m_norm2 * std::exp(m_width2 * a2); fp += m_norm3 * std::exp(m_width3 * a2); fp *= gammalib::twopi * a; // Calculate next point via x+1 = x - f(a) / f'(a) a = a - fa / fp; } // endfor: Newton-Raphson loops // Warn the user if we didn't converge if (iter == iterlimit-1) { std::string message = "Unable to converge within " + gammalib::str(convergence) + " of the root in less than " + gammalib::str(iterlimit) + " iterations." ; gammalib::warning(G_CONTAINMENT_RADIUS, message); } // Return containment radius return a; }