/***********************************************************************//**
 * @brief Returns map cube energies
 *
 * @return Map cube energies.
 *
 * Returns the energies for the map cube in a vector.
 ***************************************************************************/
GEnergies GModelSpatialDiffuseCube::energies(void)
{
    // Initialise energies container
    GEnergies energies;

    // Fetch cube
    fetch_cube();

    // Get number of map energies
    int num = m_logE.size();

    // Continue only if there are maps in the cube
    if (num > 0) {

        // Reserve space for all energies
        energies.reserve(num);

        // Set log10(energy) nodes, where energy is in units of MeV
        for (int i = 0; i < num; ++i) {
            GEnergy energy;
            energy.log10MeV(m_logE[i]);
            energies.append(energy);
        }

    } // endif: there were maps in the cube

    // Return energies
    return energies;
}
/***********************************************************************//**
 * @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 Test GEnergies
 ***************************************************************************/
void TestGObservation::test_energies(void)
{
    // Test void constructor
    test_try("Void constructor");
    try {
        GEnergies energies;
        test_try_success();
    }
    catch (std::exception &e) {
        test_try_failure(e);
    }

    // Manipulate GEnergies starting from an empty object
    GEnergies energies;
    test_value(energies.size(), 0, "GEnergies should have zero size.");
    test_assert(energies.is_empty(), "GEnergies should be empty.");

    // Add an energy
    energies.append(GEnergy());
    test_value(energies.size(), 1, "GEnergies should have 1 energy.");
    test_assert(!energies.is_empty(), "GEnergies should not be empty.");

    // Remove energy
    energies.remove(0);
    test_value(energies.size(), 0, "GEnergies should have zero size.");
    test_assert(energies.is_empty(), "GEnergies should be empty.");

    // Append two energies
    energies.append(GEnergy());
    energies.append(GEnergy());
    test_value(energies.size(), 2, "GEnergies should have 2 energies.");
    test_assert(!energies.is_empty(), "GEnergies should not be empty.");

    // Clear object
    energies.clear();
    test_value(energies.size(), 0, "GEnergies should have zero size.");
    test_assert(energies.is_empty(), "GEnergies should be empty.");

    // Insert two energies
    energies.insert(0, GEnergy());
    energies.insert(0, GEnergy());
    test_value(energies.size(), 2, "GEnergies should have 2 energies.");
    test_assert(!energies.is_empty(), "GEnergies should not be empty.");

    // Extend energies
    energies.extend(energies);
    test_value(energies.size(), 4, "GEnergies should have 4 energies.");
    test_assert(!energies.is_empty(), "GEnergies should not be empty.");

    // Create 4 energies
    energies.clear();
    for (int i = 0; i < 4; ++i) {
        energies.append(GEnergy(double(i), "MeV"));
    }
    for (int i = 0; i < 4; ++i) {
        test_value(energies[i].MeV(), double(i));
    }

    // Save and reload energies
    test_try("Saving and loading");
    try {
        energies.save("test_energies.fits", true);
        energies.clear();
        energies.load("test_energies.fits");
        test_try_success();
    }
    catch (std::exception &e) {
        test_try_failure(e);
    }
    for (int i = 0; i < 4; ++i) {
        test_value(energies[i].MeV(), double(i));
    }

    // Test load constructor
    test_try("Load constructor");
    try {
        GEnergies energies2("test_energies.fits");
        for (int i = 0; i < 4; ++i) {
            test_value(energies[i].MeV(), double(i));
        }
        test_try_success();
    }
    catch (std::exception &e) {
        test_try_failure(e);
    }

    // Return
    return;
}