/***********************************************************************//** * @brief Set energies for map cube * * @param[in] energies Sky map energies. * * @exception GException::invalid_argument * Specified sky map energies incompatible with map cube. * * Sets the energies for the map cube. ***************************************************************************/ void GModelSpatialDiffuseCube::energies(const GEnergies& energies) { // Initialise energies m_logE.clear(); // Fetch cube fetch_cube(); // Extract number of energies in vector int num = energies.size(); // Check if energy binning is consistent with number of maps in the cube if (num != m_cube.nmaps() ) { std::string msg = "Number of specified energies ("+gammalib::str(num)+")" " does not match the number of maps (" ""+gammalib::str(m_cube.nmaps())+" in the map cube.\n" "The energies argument shall provide a vector of length" " "+gammalib::str(m_cube.nmaps())+"."; throw GException::invalid_argument(G_ENERGIES, msg); } // Set log10(energy) nodes, where energy is in units of MeV for (int i = 0; i < num; ++i) { m_logE.append(energies[i].log10MeV()); } // Set energy boundaries set_energy_boundaries(); // Update MC cache update_mc_cache(); // Return return; }
/***********************************************************************//** * @brief Load cube into the model class * * @param[in] filename cube file. * * @exception GException::invalid_value * Number of maps in cube mismatches number of energy bins. * * Loads cube into the model class. ***************************************************************************/ void GModelSpatialDiffuseCube::load(const std::string& filename) { // Initialise skymap m_cube.clear(); m_logE.clear(); // Store filename of cube (for XML writing). Note that we do not // expand any environment variable at this level, so that if we write // back the XML element we write the filepath with the environment // variables m_filename = filename; // Get expanded filename std::string fname = gammalib::expand_env(filename); // Load cube m_cube.load(fname); // Load energies GEnergies energies(fname); // Extract number of energy bins int num = energies.size(); // Check if energy binning is consistent with primary image hdu if (num != m_cube.nmaps() ) { std::string msg = "Number of energies in \"ENERGIES\" extension" " ("+gammalib::str(num)+") does not match the" " number of maps ("+gammalib::str(m_cube.nmaps())+"" " in the map cube.\n" "The \"ENERGIES\" extension table shall provide" " one enegy value for each map in the cube."; throw GException::invalid_value(G_LOAD, msg); } // Set log10(energy) nodes, where energy is in units of MeV for (int i = 0; i < num; ++i) { m_logE.append(energies[i].log10MeV()); } // Signal that cube has been loaded m_loaded = true; // Set energy boundaries set_energy_boundaries(); // Update Monte Carlo cache update_mc_cache(); // Return return; }
/***********************************************************************//** * @brief Returns Monte Carlo energy between [emin, emax] * * @param[in] emin Minimum photon energy. * @param[in] emax Maximum photon energy. * @param[in] time True photon arrival time. * @param[in,out] ran Random number generator. * @return Energy. * * @exception GException::erange_invalid * Energy range is invalid (emin < emax required). * * Returns Monte Carlo energy by randomly drawing from a power law. ***************************************************************************/ GEnergy GModelSpectralPlaw::mc(const GEnergy& emin, const GEnergy& emax, const GTime& time, GRan& ran) const { // Throw an exception if energy range is invalid if (emin >= emax) { throw GException::erange_invalid(G_MC, emin.MeV(), emax.MeV(), "Minimum energy < maximum energy required."); } // Update cache update_mc_cache(emin, emax); // Get uniform random number double u = ran.uniform(); // Initialise energy double eng; // Case A: Index is not -1 if (index() != -1.0) { if (u > 0.0) { eng = std::exp(std::log(u * m_mc_pow_ewidth + m_mc_pow_emin) / m_mc_exponent); } else { eng = 0.0; } } // Case B: Index is -1 else { eng = std::exp(u * m_mc_pow_ewidth + m_mc_pow_emin); } // Set energy GEnergy energy; energy.MeV(eng); // Return energy return energy; }
/***********************************************************************//** * @brief Returns Monte Carlo energy between [emin, emax] * * @param[in] emin Minimum photon energy. * @param[in] emax Maximum photon energy. * @param[in] time True photon arrival time. * @param[in,out] ran Random number generator. * @return Energy. * * @exception GException::erange_invalid * Energy range is invalid (emin < emax required). * * Returns Monte Carlo energy by randomly drawing from a smoothly broken * power law. ***************************************************************************/ GEnergy GModelSpectralSmoothBrokenPlaw::mc(const GEnergy& emin, const GEnergy& emax, const GTime& time, GRan& ran) const { // Throw exception if energy range is not valid if (emin >= emax) { throw GException::erange_invalid(G_MC, emin.MeV(), emax.MeV(), "Minimum energy < maximum energy required."); } // Allocate energy GEnergy energy; // Update Monte Carlo cache update_mc_cache(); // Initialse acceptance fraction double acceptance_fraction(0.0); // Use rejection method to draw a random energy. We first draw // analytically from a broken power law, and then compare the power law // at the drawn energy to the curved function. This gives an acceptance // fraction, and we accept the energy only if a uniform random number // is <= the acceptance fraction. do { // Generate an energy from the broken power law distribution energy = m_mc_brokenplaw.mc(emin, emax, time, ran); // Compute acceptance fraction acceptance_fraction = eval(energy) / m_mc_brokenplaw.eval(energy); } while (ran.uniform() > acceptance_fraction); // Return energy return energy; }
/***********************************************************************//** * @brief Returns MC energy between [emin, emax] * * @param[in] emin Minimum photon energy. * @param[in] emax Maximum photon energy. * @param[in] time True photon arrival time. * @param[in,out] ran Random number generator. * @return Energy. * * @exception GException::erange_invalid * Energy range is invalid (emin < emax required). * * Simulates a random energy in the interval [emin, emax] for an * exponentially cut off power law. The simulation is done using a rejection * method. First, a random energy within [emin, emax] is drawn from an * power law distribution. Then the energy is accepted or rejected based * on an acceptance fraction that is computed from the exponential cut off. ***************************************************************************/ GEnergy GModelSpectralExpPlaw::mc(const GEnergy& emin, const GEnergy& emax, const GTime& time, GRan& ran) const { // Throw an exception if energy range is invalid if (emin >= emax) { throw GException::erange_invalid(G_MC, emin.MeV(), emax.MeV(), "Minimum energy < maximum energy required."); } // Allocate energy GEnergy energy; // Update cache update_mc_cache(emin, emax); // Initialise energy double eng; // Initialse acceptance fraction double acceptance_fraction; double inv_ecut = 1.0 / m_ecut.value(); // Use rejection method to draw a random energy. We first draw // analytically from a power law, and then compare the power law // at the drawn energy to the exponentially cut off function. This // gives an acceptance fraction, and we accept the energy only if // a uniform random number is <= the acceptance fraction. do { // Get uniform random number double u = ran.uniform(); // Case A: Index is not -1 if (index() != -1.0) { if (u > 0.0) { eng = std::exp(std::log(u * m_mc_pow_ewidth + m_mc_pow_emin) / m_mc_exponent); } else { eng = 0.0; } } // Case B: Index is -1 else { eng = std::exp(u * m_mc_pow_ewidth + m_mc_pow_emin); } // Compute acceptance fraction acceptance_fraction = std::exp(-eng * inv_ecut); } while (ran.uniform() > acceptance_fraction); // Set energy energy.MeV(eng); // Return energy return energy; }