fix(MultiscalePartitioningEngineView): began work to call the QSE solver every timestep

one major issue was that QSE solving was only running at each partition. This was creating effectivley infinite sources of partitioned species. Now we partition when engine updates are triggered, however, solveQSEAbundance is called every timestep. This has major performance implications and so has required a lot of optimization to make it even somewhat viable. For now construction is much slower. Time per iteration is still slower than it was before; however, it is tractable. There is also currently too much stiffness in the network. This is likeley a bug that was introduced in this refactoring which will be addressed soon.
This commit is contained in:
2025-11-12 16:54:12 -05:00
parent 741a11d256
commit 81cca35130
20 changed files with 446 additions and 697 deletions

View File

@@ -17,34 +17,11 @@
#include "quill/LogMacros.h"
#include "quill/Logger.h"
#include "xxhash64.h"
#include "fourdst/composition/utils/composition_hash.h"
namespace {
using namespace fourdst::atomic;
//TODO: Replace all calls to this function with composition.getMolarAbundanceVector() so that
// we don't have to keep this function around. (Cant do this right now because there is not a
// guarantee that this function will return the same ordering as the canonical vector representation)
std::vector<double> packCompositionToVector(
const fourdst::composition::Composition& composition,
const gridfire::DynamicEngine& engine
) {
std::vector<double> Y(engine.getNetworkSpecies().size(), 0.0);
const auto& allSpecies = engine.getNetworkSpecies();
for (size_t i = 0; i < allSpecies.size(); ++i) {
const auto& species = allSpecies[i];
if (!composition.contains(species)) {
Y[i] = 0.0; // Species not in the composition, set to zero
} else {
Y[i] = composition.getMolarAbundance(species);
}
}
return Y;
}
template <class T>
void hash_combine(std::size_t& seed, const T& v) {
std::hash<T> hashed;
seed ^= hashed(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
std::vector<std::vector<Species>> findConnectedComponentsBFS(
const std::unordered_map<Species, std::vector<Species>>& graph,
const std::vector<Species>& nodes
@@ -186,11 +163,14 @@ namespace gridfire {
const double T9,
const double rho
) const {
// Check the cache to see if the network needs to be repartitioned. Note that the QSECacheKey manages binning of T9, rho, and Y_full to ensure that small changes (which would likely not result in a repartitioning) do not trigger a cache miss.
const auto result = m_baseEngine.calculateRHSAndEnergy(comp, T9, rho);
const fourdst::composition::Composition qseComposition = getNormalizedEquilibratedComposition(comp, T9, rho);
const auto result = m_baseEngine.calculateRHSAndEnergy(qseComposition, T9, rho);
if (!result) {
return std::unexpected{result.error()};
}
auto deriv = result.value();
for (const auto& species : m_algebraic_species) {
@@ -204,7 +184,8 @@ namespace gridfire {
const double T9,
const double rho
) const {
return m_baseEngine.calculateEpsDerivatives(comp, T9, rho);
const fourdst::composition::Composition qseComposition = getNormalizedEquilibratedComposition(comp, T9, rho);
return m_baseEngine.calculateEpsDerivatives(qseComposition, T9, rho);
}
void MultiscalePartitioningEngineView::generateJacobianMatrix(
@@ -212,8 +193,8 @@ namespace gridfire {
const double T9,
const double rho
) const {
// We do not need to generate the jacobian for QSE species since those entries are by definition 0
m_baseEngine.generateJacobianMatrix(comp, T9, rho, m_dynamic_species);
const fourdst::composition::Composition qseComposition = getNormalizedEquilibratedComposition(comp, T9, rho);
m_baseEngine.generateJacobianMatrix(qseComposition, T9, rho, m_dynamic_species);
}
void MultiscalePartitioningEngineView::generateJacobianMatrix(
@@ -249,7 +230,9 @@ namespace gridfire {
}
}
m_baseEngine.generateJacobianMatrix(comp, T9, rho, dynamicActiveSpeciesIntersection);
const fourdst::composition::Composition qseComposition = getNormalizedEquilibratedComposition(comp, T9, rho);
m_baseEngine.generateJacobianMatrix(qseComposition, T9, rho, dynamicActiveSpeciesIntersection);
}
void MultiscalePartitioningEngineView::generateJacobianMatrix(
@@ -258,7 +241,8 @@ namespace gridfire {
const double rho,
const SparsityPattern &sparsityPattern
) const {
return m_baseEngine.generateJacobianMatrix(comp, T9, rho, sparsityPattern);
const fourdst::composition::Composition qseComposition = getNormalizedEquilibratedComposition(comp, T9, rho);
return m_baseEngine.generateJacobianMatrix(qseComposition, T9, rho, sparsityPattern);
}
double MultiscalePartitioningEngineView::getJacobianMatrixEntry(
@@ -292,19 +276,9 @@ namespace gridfire {
const double T9,
const double rho
) const {
// Fix the algebraic species to the equilibrium abundances we calculate.
fourdst::composition::Composition comp_mutable;
for (const auto& species : comp.getRegisteredSpecies()) {
comp_mutable.registerSpecies(species);
comp_mutable.setMolarAbundance(species, comp.getMolarAbundance(species));
}
const fourdst::composition::Composition qseComposition = getNormalizedEquilibratedComposition(comp, T9, rho);
for (const auto& species : m_algebraic_species) {
const double Yi = m_algebraic_abundances.at(species);
comp_mutable.setMolarAbundance(species, Yi);
}
return m_baseEngine.calculateMolarReactionFlow(reaction, comp_mutable, T9, rho);
return m_baseEngine.calculateMolarReactionFlow(reaction, qseComposition, T9, rho);
}
const reaction::ReactionSet & MultiscalePartitioningEngineView::getNetworkReactions() const {
@@ -321,7 +295,8 @@ namespace gridfire {
const double T9,
const double rho
) const {
const auto result = m_baseEngine.getSpeciesTimescales(comp, T9, rho);
const fourdst::composition::Composition qseComposition = getNormalizedEquilibratedComposition(comp, T9, rho);
const auto result = m_baseEngine.getSpeciesTimescales(qseComposition, T9, rho);
if (!result) {
return std::unexpected{result.error()};
}
@@ -338,7 +313,8 @@ namespace gridfire {
const double T9,
const double rho
) const {
const auto result = m_baseEngine.getSpeciesDestructionTimescales(comp, T9, rho);
const fourdst::composition::Composition qseComposition = getNormalizedEquilibratedComposition(comp, T9, rho);
const auto result = m_baseEngine.getSpeciesDestructionTimescales(qseComposition, T9, rho);
if (!result) {
return std::unexpected{result.error()};
}
@@ -354,27 +330,13 @@ namespace gridfire {
NetIn baseUpdatedNetIn = netIn;
baseUpdatedNetIn.composition = baseUpdatedComposition;
const fourdst::composition::Composition equilibratedComposition = equilibrateNetwork(baseUpdatedNetIn);
std::unordered_map<Species, double> algebraicAbundances;
for (const auto& species : m_algebraic_species) {
algebraicAbundances.emplace(species, equilibratedComposition.getMolarAbundance(species));
}
m_algebraic_abundances = std::move(algebraicAbundances);
fourdst::composition::Composition equilibratedComposition = partitionNetwork(baseUpdatedNetIn);
return equilibratedComposition;
}
bool MultiscalePartitioningEngineView::isStale(const NetIn &netIn) {
const auto key = QSECacheKey(
netIn.temperature,
netIn.density,
packCompositionToVector(netIn.composition, m_baseEngine)
);
if (m_qse_abundance_cache.contains(key)) {
return m_baseEngine.isStale(netIn); // The cache hit indicates the engine is not stale for the given conditions.
}
return true;
return m_baseEngine.isStale(netIn);
}
void MultiscalePartitioningEngineView::setScreeningModel(
@@ -392,10 +354,7 @@ namespace gridfire {
}
std::vector<std::vector<Species>> MultiscalePartitioningEngineView::analyzeTimescalePoolConnectivity(
const std::vector<std::vector<Species>> &timescale_pools,
const fourdst::composition::Composition &comp,
double T9,
double rho
const std::vector<std::vector<Species>> &timescale_pools
) const {
std::vector<std::vector<Species>> final_connected_pools;
@@ -413,17 +372,22 @@ namespace gridfire {
}
void MultiscalePartitioningEngineView::partitionNetwork(
const fourdst::composition::Composition &comp,
const double T9,
const double rho
fourdst::composition::Composition MultiscalePartitioningEngineView::partitionNetwork(
const NetIn &netIn
) {
// --- Step 0. Clear previous state ---
// --- Step 0. Prime the network ---
const PrimingReport primingReport = m_baseEngine.primeEngine(netIn);
const fourdst::composition::Composition& comp = primingReport.primedComposition;
const double T9 = netIn.temperature / 1e9;
const double rho = netIn.density;
// --- Step 0.5 Clear previous state ---
LOG_TRACE_L1(m_logger, "Partitioning network...");
LOG_TRACE_L1(m_logger, "Clearing previous state...");
m_qse_groups.clear();
m_dynamic_species.clear();
m_algebraic_species.clear();
m_composition_cache.clear(); // We need to clear the cache now cause the same comp, temp, and density may result in a different value
// --- Step 1. Identify distinct timescale regions ---
LOG_TRACE_L1(m_logger, "Identifying fast reactions...");
@@ -449,7 +413,7 @@ namespace gridfire {
}
LOG_TRACE_L1(m_logger, "Preforming connectivity analysis on timescale pools...");
const std::vector<std::vector<Species>> connected_pools = analyzeTimescalePoolConnectivity(candidate_pools, comp, T9, rho);
const std::vector<std::vector<Species>> connected_pools = analyzeTimescalePoolConnectivity(candidate_pools);
LOG_TRACE_L1(m_logger, "Found {} connected pools (compared to {} timescale pools) for QSE analysis.", connected_pools.size(), timescale_pools.size());
@@ -555,15 +519,12 @@ namespace gridfire {
m_qse_groups.size(),
m_qse_groups.size() == 1 ? "" : "s"
);
}
void MultiscalePartitioningEngineView::partitionNetwork(
const NetIn &netIn
) {
const double T9 = netIn.temperature / 1e9; // Convert temperature from Kelvin to T9 (T9 = T / 1e9)
const double rho = netIn.density; // Density in g/cm^3
partitionNetwork(netIn.composition, T9, rho);
// Sort the QSE groups by mean timescale so that fastest groups get equilibrated first (as these may feed slower groups)
std::ranges::sort(m_qse_groups, [](const QSEGroup& a, const QSEGroup& b) {
return a.mean_timescale < b.mean_timescale;
});
return getNormalizedEquilibratedComposition(comp, T9, rho);
}
void MultiscalePartitioningEngineView::exportToDot(
@@ -593,6 +554,7 @@ namespace gridfire {
}
}
const fourdst::composition::Composition qseComposition = getNormalizedEquilibratedComposition(comp, T9, rho);
// Calculate reaction flows and find min/max for logarithmic scaling of transparency
std::vector<double> reaction_flows;
reaction_flows.reserve(all_reactions.size());
@@ -600,7 +562,7 @@ namespace gridfire {
double max_log_flow = std::numeric_limits<double>::lowest();
for (const auto& reaction : all_reactions) {
double flow = std::abs(m_baseEngine.calculateMolarReactionFlow(*reaction, comp, T9, rho));
double flow = std::abs(m_baseEngine.calculateMolarReactionFlow(*reaction, qseComposition, T9, rho));
reaction_flows.push_back(flow);
if (flow > 1e-99) { // Avoid log(0)
double log_flow = std::log10(flow);
@@ -776,7 +738,7 @@ namespace gridfire {
std::vector<double> MultiscalePartitioningEngineView::mapNetInToMolarAbundanceVector(const NetIn &netIn) const {
std::vector<double> Y(m_dynamic_species.size(), 0.0); // Initialize with zeros
std::vector<double> Y(netIn.composition.size(), 0.0); // Initialize with zeros
for (const auto& [sp, y] : netIn.composition) {
Y[getSpeciesIndex(sp)] = y; // Map species to their molar abundance
}
@@ -804,33 +766,6 @@ namespace gridfire {
return m_baseEngine.primeEngine(netIn);
}
fourdst::composition::Composition MultiscalePartitioningEngineView::equilibrateNetwork(
const fourdst::composition::Composition &comp,
const double T9,
const double rho
) {
partitionNetwork(comp, T9, rho);
fourdst::composition::Composition qseComposition = solveQSEAbundances(comp, T9, rho);
for (const auto &[sp, y]: qseComposition) {
if (y < 0.0 && std::abs(y) < 1e-20) {
qseComposition.setMolarAbundance(sp, 0.0); // Avoid negative mass fractions
}
}
return qseComposition;
}
fourdst::composition::Composition MultiscalePartitioningEngineView::equilibrateNetwork(
const NetIn &netIn
) {
const PrimingReport primingReport = m_baseEngine.primeEngine(netIn);
const double T9 = netIn.temperature / 1e9; // Convert temperature from Kelvin to T9 (T9 = T / 1e9)
const double rho = netIn.density; // Density in g/cm^3
return equilibrateNetwork(primingReport.primedComposition, T9, rho);
}
bool MultiscalePartitioningEngineView::involvesSpecies(
const Species &species
@@ -852,30 +787,43 @@ namespace gridfire {
return std::ranges::find(m_dynamic_species, species) != m_dynamic_species.end();
}
fourdst::composition::Composition MultiscalePartitioningEngineView::collectComposition(
fourdst::composition::CompositionAbstract &comp
fourdst::composition::Composition MultiscalePartitioningEngineView::getNormalizedEquilibratedComposition(
const fourdst::composition::CompositionAbstract& comp,
const double T9,
const double rho
) const {
fourdst::composition::Composition result = m_baseEngine.collectComposition(comp);
std::map<Species, double> Ym; // Use an ordered map here so that this is ordered by atomic mass (which is the </> comparator for Species)
for (const auto& [sp, y] : result) {
Ym.emplace(sp, y);
const std::array<uint64_t, 3> hashes = {
fourdst::composition::utils::CompositionHash::hash_exact(comp),
std::hash<double>()(T9),
std::hash<double>()(rho)
};
const uint64_t composite_hash = XXHash64::hash(hashes.begin(), sizeof(uint64_t) * 3, 0);
if (m_composition_cache.contains(composite_hash)) {
LOG_TRACE_L1(m_logger, "Cache Hit in Multiscale Partitioning Engine View for composition at T9 = {}, rho = {}.", T9, rho);
return m_composition_cache.at(composite_hash);
}
for (const auto& [species, Yi] : m_algebraic_abundances) {
if (!Ym.contains(species)) {
throw exceptions::BadCollectionError("MuiltiscalePartitioningEngineView failed to collect composition for species " + std::string(species.name()) + " as the base engine did not report that species present in its composition!");
fourdst::composition::Composition qseComposition = solveQSEAbundances(comp, T9, rho);
for (const auto &[sp, y]: qseComposition) {
if (y < 0.0 && std::abs(y) < 1e-20) {
qseComposition.setMolarAbundance(sp, 0.0); // normalize small negative abundances to zero
}
Ym.at(species) = Yi;
}
std::vector<double> Y;
std::vector<std::string> speciesNames;
Y.reserve(Ym.size());
m_composition_cache[composite_hash] = qseComposition;
for (const auto& [species, Yi] : Ym) {
Y.emplace_back(Yi);
speciesNames.emplace_back(species.name());
}
return qseComposition;
}
return {speciesNames, Y};
fourdst::composition::Composition MultiscalePartitioningEngineView::collectComposition(
const fourdst::composition::CompositionAbstract &comp,
const double T9,
const double rho
) const {
const fourdst::composition::Composition result = m_baseEngine.collectComposition(comp, T9, rho);
fourdst::composition::Composition qseComposition = solveQSEAbundances(result, T9, rho);
return qseComposition;
}
size_t MultiscalePartitioningEngineView::getSpeciesIndex(const Species &species) const {
@@ -1201,33 +1149,21 @@ namespace gridfire {
}
fourdst::composition::Composition MultiscalePartitioningEngineView::solveQSEAbundances(
const fourdst::composition::Composition &comp,
const fourdst::composition::CompositionAbstract &comp,
const double T9,
const double rho
) {
) const {
LOG_TRACE_L1(m_logger, "Solving for QSE abundances...");
// Sort by timescale to solve fastest QSE groups first (these can seed slower groups)
std::ranges::sort(m_qse_groups, [](const QSEGroup& a, const QSEGroup& b) {
return a.mean_timescale < b.mean_timescale;
});
fourdst::composition::Composition outputComposition = comp;
fourdst::composition::Composition outputComposition(comp.getRegisteredSpecies());
for (const auto& [sp, y]: comp) {
outputComposition.setMolarAbundance(sp, y);
}
for (const auto&[is_in_equilibrium, algebraic_species, seed_species, mean_timescale] : m_qse_groups) {
if (!is_in_equilibrium || (algebraic_species.empty() && seed_species.empty())) {
continue;
}
fourdst::composition::Composition normalized_composition = comp;
for (const auto& species: algebraic_species) {
if (!normalized_composition.contains(species)) {
normalized_composition.registerSpecies(species);
}
}
for (const auto& species: seed_species) {
if (!normalized_composition.contains(species)) {
normalized_composition.registerSpecies(species);
}
}
Eigen::VectorXd Y_scale(algebraic_species.size());
Eigen::VectorXd v_initial(algebraic_species.size());
@@ -1235,14 +1171,14 @@ namespace gridfire {
std::unordered_map<Species, size_t> species_to_index_map;
for (const auto& species : algebraic_species) {
constexpr double abundance_floor = 1.0e-100;
const double initial_abundance = normalized_composition.getMolarAbundance(species);
const double initial_abundance = comp.getMolarAbundance(species);
const double Y = std::max(initial_abundance, abundance_floor);
v_initial(i) = std::log(Y);
species_to_index_map.emplace(species, i);
i++;
}
EigenFunctor functor(*this, algebraic_species, normalized_composition, T9, rho, Y_scale, species_to_index_map);
EigenFunctor functor(*this, algebraic_species, comp, T9, rho, Y_scale, species_to_index_map);
Eigen::LevenbergMarquardt lm(functor);
lm.parameters.ftol = 1.0e-10;
lm.parameters.xtol = 1.0e-10;
@@ -1275,7 +1211,7 @@ namespace gridfire {
m_logger,
"During QSE solving species {} started with a molar abundance of {} and ended with an abundance of {}.",
species.name(),
normalized_composition.getMolarAbundance(species),
comp.getMolarAbundance(species),
Y_final_qse(i)
);
// double Xi = Y_final_qse(i) * species.mass(); // Convert from molar abundance to mass fraction
@@ -1488,23 +1424,28 @@ namespace gridfire {
}
//////////////////////////////////////
/// Eigen Functor Member Functions ///
/////////////////////////////////////
int MultiscalePartitioningEngineView::EigenFunctor::operator()(const InputType &v_qse, OutputType &f_qse) const {
fourdst::composition::Composition comp_trial = m_initial_comp;
fourdst::composition::Composition comp_trial(m_initial_comp.getRegisteredSpecies());
for (const auto& [sp, y] : m_initial_comp) {
comp_trial.setMolarAbundance(sp, y);
}
Eigen::VectorXd y_qse = v_qse.array().exp(); // Convert to physical abundances using exponential scaling
for (const auto& species: m_qse_solve_species) {
if (!comp_trial.contains(std::string(species.name()))) {
comp_trial.registerSpecies(species);
}
auto index = static_cast<long>(m_qse_solve_species_index_map.at(species));
comp_trial.setMolarAbundance(species, y_qse[index]);
}
const auto result = m_view->getBaseEngine().calculateRHSAndEnergy(comp_trial, m_T9, m_rho);
const auto result = m_view.getBaseEngine().calculateRHSAndEnergy(comp_trial, m_T9, m_rho);
if (!result) {
throw exceptions::StaleEngineError("Failed to calculate RHS and energy due to stale engine state");
}
const auto&[dydt, nuclearEnergyGenerationRate] = result.value();
const auto&[dydt, nuclearEnergyGenerationRate, _] = result.value();
f_qse.resize(static_cast<long>(m_qse_solve_species.size()));
long i = 0;
// TODO: make sure that just counting up i is a valid approach, this is a possible place an indexing bug may have crept in
@@ -1514,7 +1455,7 @@ namespace gridfire {
i++;
}
LOG_TRACE_L2(
m_view->m_logger,
m_view.m_logger,
"Functor evaluation at T9 = {}, rho = {}, y_qse = <{}> complete. ||f|| = {}",
m_T9,
m_rho,
@@ -1531,7 +1472,7 @@ namespace gridfire {
f_qse.norm()
);
LOG_TRACE_L3(
m_view->m_logger,
m_view.m_logger,
"{}",
[&]() -> std::string {
std::stringstream ss;
@@ -1546,24 +1487,24 @@ namespace gridfire {
}
int MultiscalePartitioningEngineView::EigenFunctor::df(const InputType &v_qse, JacobianType &J_qse) const {
fourdst::composition::Composition comp_trial = m_initial_comp;
fourdst::composition::Composition comp_trial(m_initial_comp.getRegisteredSpecies());
for (const auto& [sp, y] : m_initial_comp) {
comp_trial.setMolarAbundance(sp, y);
}
Eigen::VectorXd y_qse = v_qse.array().exp(); // Convert to physical abundances using exponential scaling
for (const auto& species: m_qse_solve_species) {
if (!comp_trial.contains(std::string(species.name()))) {
comp_trial.registerSpecies(species);
}
const double molarAbundance = y_qse[static_cast<long>(m_qse_solve_species_index_map.at(species))];
comp_trial.setMolarAbundance(species, molarAbundance);
}
std::vector<Species> qse_species_vector(m_qse_solve_species.begin(), m_qse_solve_species.end());
m_view->getBaseEngine().generateJacobianMatrix(comp_trial, m_T9, m_rho, qse_species_vector);
const auto result = m_view->getBaseEngine().calculateRHSAndEnergy(comp_trial, m_T9, m_rho);
m_view.getBaseEngine().generateJacobianMatrix(comp_trial, m_T9, m_rho, qse_species_vector);
const auto result = m_view.getBaseEngine().calculateRHSAndEnergy(comp_trial, m_T9, m_rho);
if (!result) {
throw exceptions::StaleEngineError("Failed to calculate RHS and energy due to stale engine state");
}
const auto&[dydt, nuclearEnergyGenerationRate] = result.value();
const auto&[dydt, nuclearEnergyGenerationRate, _] = result.value();
const long N = static_cast<long>(m_qse_solve_species.size());
J_qse.resize(N, N);
@@ -1571,12 +1512,12 @@ namespace gridfire {
for (const auto& rowSpecies : m_qse_solve_species) {
long colID = 0;
for (const auto& colSpecies: m_qse_solve_species) {
J_qse(rowID, colID) = m_view->getBaseEngine().getJacobianMatrixEntry(
J_qse(rowID, colID) = m_view.getBaseEngine().getJacobianMatrixEntry(
rowSpecies,
colSpecies
);
colID += 1;
LOG_TRACE_L3(m_view->m_logger, "Jacobian[{}, {}] (d(dY({}))/dY({})) = {}", rowID, colID - 1, rowSpecies.name(), colSpecies.name(), J_qse(rowID, colID - 1));
LOG_TRACE_L3(m_view.m_logger, "Jacobian[{}, {}] (d(dY({}))/dY({})) = {}", rowID, colID - 1, rowSpecies.name(), colSpecies.name(), J_qse(rowID, colID - 1));
}
rowID += 1;
}
@@ -1597,46 +1538,12 @@ namespace gridfire {
}
QSECacheKey::QSECacheKey(
const double T9,
const double rho,
const std::vector<double> &Y
) :
m_T9(T9),
m_rho(rho),
m_Y(Y) {
m_hash = hash();
}
size_t QSECacheKey::hash() const {
std::size_t seed = 0;
/////////////////////////////////
/// QSEGroup Member Functions ///
////////////////////////////////
hash_combine(seed, m_Y.size());
hash_combine(seed, bin(m_T9, m_cacheConfig.T9_tol));
hash_combine(seed, bin(m_rho, m_cacheConfig.rho_tol));
double negThresh = 1e-10; // Threshold for considering a value as negative.
for (double Yi : m_Y) {
if (Yi < 0.0 && std::abs(Yi) < negThresh) {
Yi = 0.0; // Avoid negative abundances
} else if (Yi < 0.0 && std::abs(Yi) >= negThresh) {
throw std::invalid_argument("Yi should be positive for valid hashing (expected Yi > 0, received " + std::to_string(Yi) + ")");
}
hash_combine(seed, bin(Yi, m_cacheConfig.Yi_tol));
}
return seed;
}
long QSECacheKey::bin(const double value, const double tol) {
return static_cast<long>(std::floor(value / tol));
}
bool QSECacheKey::operator==(const QSECacheKey &other) const {
return m_hash == other.m_hash;
}
bool MultiscalePartitioningEngineView::QSEGroup::operator==(const QSEGroup &other) const {
return mean_timescale == other.mean_timescale;
@@ -1707,36 +1614,4 @@ namespace gridfire {
return ss.str();
}
void MultiscalePartitioningEngineView::CacheStats::hit(const operators op) {
if (op == operators::All) {
throw std::invalid_argument("Cannot use 'ALL' as an operator for a hit");
}
m_hit ++;
m_operatorHits[op]++;
}
void MultiscalePartitioningEngineView::CacheStats::miss(const operators op) {
if (op == operators::All) {
throw std::invalid_argument("Cannot use 'ALL' as an operator for a miss");
}
m_miss ++;
m_operatorMisses[op]++;
}
size_t MultiscalePartitioningEngineView::CacheStats::hits(const operators op) const {
if (op == operators::All) {
return m_hit;
}
return m_operatorHits.at(op);
}
size_t MultiscalePartitioningEngineView::CacheStats::misses(const operators op) const {
if (op == operators::All) {
return m_miss;
}
return m_operatorMisses.at(op);
}
}