25 LOG_TRACE_L1(
m_logger,
"Constructing species index map for adaptive engine view...");
26 std::unordered_map<Species, size_t> fullSpeciesReverseMap;
27 const auto& fullSpeciesList =
m_baseEngine.getNetworkSpecies();
29 fullSpeciesReverseMap.reserve(fullSpeciesList.size());
31 for (
size_t i = 0; i < fullSpeciesList.size(); ++i) {
32 fullSpeciesReverseMap[fullSpeciesList[i]] = i;
35 std::vector<size_t> speciesIndexMap;
39 auto it = fullSpeciesReverseMap.find(active_species);
40 if (it != fullSpeciesReverseMap.end()) {
41 speciesIndexMap.push_back(it->second);
43 LOG_ERROR(
m_logger,
"Species '{}' not found in full species map.", active_species.name());
45 throw std::runtime_error(
"Species not found in full species map: " + std::string(active_species.name()));
48 LOG_TRACE_L1(
m_logger,
"Species index map constructed with {} entries.", speciesIndexMap.size());
49 return speciesIndexMap;
54 LOG_TRACE_L1(
m_logger,
"Constructing reaction index map for adaptive engine view...");
57 std::unordered_map<std::string_view, size_t> fullReactionReverseMap;
58 const auto& fullReactionSet =
m_baseEngine.getNetworkReactions();
59 fullReactionReverseMap.reserve(fullReactionSet.size());
61 for (
size_t i_full = 0; i_full < fullReactionSet.size(); ++i_full) {
62 fullReactionReverseMap[fullReactionSet[i_full].id()] = i_full;
66 std::vector<size_t> reactionIndexMap;
70 auto it = fullReactionReverseMap.find(active_reaction_ptr.id());
72 if (it != fullReactionReverseMap.end()) {
73 reactionIndexMap.push_back(it->second);
75 LOG_ERROR(
m_logger,
"Active reaction '{}' not found in base engine during reaction index map construction.", active_reaction_ptr.id());
77 throw std::runtime_error(
"Mismatch between active reactions and base engine.");
81 LOG_TRACE_L1(
m_logger,
"Reaction index map constructed with {} entries.", reactionIndexMap.size());
82 return reactionIndexMap;
86 LOG_TRACE_L1(
m_logger,
"Updating adaptive engine view...");
88 const auto& fullSpeciesList =
m_baseEngine.getNetworkSpecies();
89 std::vector<double>Y_full;
90 Y_full.reserve(fullSpeciesList.size());
92 for (
const auto& species : fullSpeciesList) {
94 Y_full.push_back(netIn.
composition.getMolarAbundance(std::string(species.name())));
96 LOG_TRACE_L2(
m_logger,
"Species '{}' not found in composition. Setting abundance to 0.0.", species.name());
97 Y_full.push_back(0.0);
102 const double rho = netIn.
density;
105 std::vector<ReactionFlow> reactionFlows;
106 const auto& fullReactionSet =
m_baseEngine.getNetworkReactions();
107 reactionFlows.reserve(fullReactionSet.size());
109 for (
const auto& reactionPtr : fullReactionSet) {
110 const double flow =
m_baseEngine.calculateMolarReactionFlow(reactionPtr, Y_full, T9, rho);
111 reactionFlows.push_back({&reactionPtr, flow});
114 double max_flow = 0.0;
115 double min_flow = std::numeric_limits<double>::max();
116 double flowSum = 0.0;
117 for (
const auto&[reactionPtr, flowRate] : reactionFlows) {
118 if (flowRate > max_flow) {
120 }
else if (flowRate < min_flow) {
124 LOG_TRACE_L2(
m_logger,
"Reaction '{}' has flow rate: {:0.3E} [mol/s]", reactionPtr->id(), flowRate);
126 flowSum /= reactionFlows.size();
128 LOG_DEBUG(
m_logger,
"Maximum reaction flow rate in adaptive engine view: {:0.3E} [mol/s]", max_flow);
129 LOG_DEBUG(
m_logger,
"Minimum reaction flow rate in adaptive engine view: {:0.3E} [mol/s]", min_flow);
130 LOG_DEBUG(
m_logger,
"Average reaction flow rate in adaptive engine view: {:0.3E} [mol/s]", flowSum);
132 const double relative_culling_threshold =
m_config.get<
double>(
"gridfire:AdaptiveEngineView:RelativeCullingThreshold", 1e-75);
134 double absoluteCullingThreshold = relative_culling_threshold * max_flow;
135 LOG_DEBUG(
m_logger,
"Relative culling threshold: {:0.3E} ({})", relative_culling_threshold, absoluteCullingThreshold);
138 LOG_TRACE_L1(
m_logger,
"Culling reactions based on reaction flow rates...");
139 std::vector<const reaction::Reaction*> flowCulledReactions;
140 for (
const auto&[reactionPtr, flowRate] : reactionFlows) {
141 if (flowRate > absoluteCullingThreshold) {
142 LOG_TRACE_L2(
m_logger,
"Maintaining reaction '{}' with relative (abs) flow rate: {:0.3E} ({:0.3E} [mol/s])", reactionPtr->id(), flowRate/max_flow, flowRate);
143 flowCulledReactions.push_back(reactionPtr);
146 LOG_DEBUG(
m_logger,
"Selected {} (total: {}, culled: {}) reactions based on flow rates.", flowCulledReactions.size(), fullReactionSet.size(), fullReactionSet.size() - flowCulledReactions.size());
149 std::queue<Species> species_to_visit;
150 std::unordered_set<Species> reachable_species;
152 constexpr double ABUNDANCE_FLOOR = 1e-12;
153 for (
const auto& species : fullSpeciesList) {
154 if (netIn.
composition.contains(species) && netIn.
composition.getMassFraction(std::string(species.name())) > ABUNDANCE_FLOOR) {
155 species_to_visit.push(species);
156 reachable_species.insert(species);
157 LOG_TRACE_L2(
m_logger,
"Species '{}' is part of the initial fuel.", species.name());
160 std::unordered_map<Species, std::vector<const reaction::Reaction*>> reactant_to_reactions_map;
161 for (
const auto* reaction_ptr : flowCulledReactions) {
162 for (
const auto& reactant : reaction_ptr->reactants()) {
163 reactant_to_reactions_map[reactant].push_back(reaction_ptr);
167 while (!species_to_visit.empty()) {
168 Species currentSpecies = species_to_visit.front();
169 species_to_visit.pop();
171 auto it = reactant_to_reactions_map.find(currentSpecies);
172 if (it == reactant_to_reactions_map.end()) {
176 const auto& reactions = it->second;
177 for (
const auto* reaction_ptr : reactions) {
178 for (
const auto& product : reaction_ptr->products()) {
179 if (!reachable_species.contains(product)) {
180 reachable_species.insert(product);
181 species_to_visit.push(product);
182 LOG_TRACE_L2(
m_logger,
"Species '{}' is reachable via reaction '{}'.", product.name(), reaction_ptr->id());
187 LOG_DEBUG(
m_logger,
"Reachable species count: {}", reachable_species.size());
189 m_activeSpecies.assign(reachable_species.begin(), reachable_species.end());
191 [](
const Species &a,
const Species &b) {
return a.mass() < b.mass(); });
194 for (
const auto* reaction_ptr : flowCulledReactions) {
195 bool all_reactants_present =
true;
196 for (
const auto& reactant : reaction_ptr->reactants()) {
197 if (!reachable_species.contains(reactant)) {
198 all_reactants_present =
false;
203 if (all_reactants_present) {
205 LOG_TRACE_L2(
m_logger,
"Maintaining reaction '{}' with all reactants present.", reaction_ptr->id());
207 LOG_TRACE_L1(
m_logger,
"Culling reaction '{}' due to missing reactants.", reaction_ptr->id());
210 LOG_DEBUG(
m_logger,
"Active reactions count: {} (total: {}, culled: {}, culled due to connectivity: {})",
m_activeReactions.size(),