fix(MultiscalePartitioningEngineView): made qse partitioning much more robust
This commit is contained in:
@@ -4,11 +4,11 @@
|
|||||||
#include "gridfire/engine/views/engine_view_abstract.h"
|
#include "gridfire/engine/views/engine_view_abstract.h"
|
||||||
#include "gridfire/engine/engine_graph.h"
|
#include "gridfire/engine/engine_graph.h"
|
||||||
|
|
||||||
#include "Eigen/Dense"
|
|
||||||
#include "unsupported/Eigen/NonLinearOptimization"
|
#include "unsupported/Eigen/NonLinearOptimization"
|
||||||
|
|
||||||
namespace gridfire {
|
namespace gridfire {
|
||||||
class MultiscalePartitioningEngineView final: public DynamicEngine, public EngineView<DynamicEngine> {
|
class MultiscalePartitioningEngineView final: public DynamicEngine, public EngineView<DynamicEngine> {
|
||||||
|
typedef std::tuple<std::vector<fourdst::atomic::Species>, std::vector<size_t>, std::vector<fourdst::atomic::Species>, std::vector<size_t>> QSEPartition;
|
||||||
public:
|
public:
|
||||||
explicit MultiscalePartitioningEngineView(GraphEngine& baseEngine);
|
explicit MultiscalePartitioningEngineView(GraphEngine& baseEngine);
|
||||||
|
|
||||||
@@ -68,16 +68,19 @@ namespace gridfire {
|
|||||||
void partitionNetwork(
|
void partitionNetwork(
|
||||||
const std::vector<double>& Y,
|
const std::vector<double>& Y,
|
||||||
double T9,
|
double T9,
|
||||||
double rho,
|
double rho
|
||||||
double dt_control
|
|
||||||
);
|
);
|
||||||
|
|
||||||
void partitionNetwork(
|
void partitionNetwork(
|
||||||
const NetIn& netIn,
|
const NetIn& netIn
|
||||||
double dt_control
|
|
||||||
);
|
);
|
||||||
|
|
||||||
void exportToDot(const std::string& filename) const;
|
void exportToDot(
|
||||||
|
const std::string& filename,
|
||||||
|
const std::vector<double>& Y,
|
||||||
|
const double T9,
|
||||||
|
const double rho
|
||||||
|
) const;
|
||||||
|
|
||||||
[[nodiscard]] int getSpeciesIndex(const fourdst::atomic::Species &species) const override;
|
[[nodiscard]] int getSpeciesIndex(const fourdst::atomic::Species &species) const override;
|
||||||
|
|
||||||
@@ -91,21 +94,53 @@ namespace gridfire {
|
|||||||
fourdst::composition::Composition equilibrateNetwork(
|
fourdst::composition::Composition equilibrateNetwork(
|
||||||
const std::vector<double> &Y,
|
const std::vector<double> &Y,
|
||||||
double T9,
|
double T9,
|
||||||
double rho,
|
double rho
|
||||||
double dt_control
|
|
||||||
);
|
);
|
||||||
|
|
||||||
fourdst::composition::Composition equilibrateNetwork(
|
fourdst::composition::Composition equilibrateNetwork(
|
||||||
const NetIn &netIn,
|
const NetIn &netIn
|
||||||
const double dt_control
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct QSEGroup {
|
struct QSEGroup {
|
||||||
std::vector<size_t> species_indices; ///< Indices of all species in this group.
|
std::set<size_t> species_indices; ///< Indices of all species in this group.
|
||||||
size_t seed_nucleus_index; ///< Index of the one species that will be evolved dynamically.
|
|
||||||
bool is_in_equilibrium = false; ///< Flag set by flux analysis.
|
bool is_in_equilibrium = false; ///< Flag set by flux analysis.
|
||||||
|
std::set<size_t> algebraic_indices; ///< Indices of algebraic species in this group.
|
||||||
|
std::set<size_t> seed_indices; ///< Indices of dynamic species in this group.
|
||||||
|
|
||||||
|
friend std::ostream& operator<<(std::ostream& os, const QSEGroup& group) {
|
||||||
|
os << "QSEGroup(species_indices: [";
|
||||||
|
int count = 0;
|
||||||
|
for (const auto& idx : group.species_indices) {
|
||||||
|
os << idx;
|
||||||
|
if (count < group.species_indices.size() - 1) {
|
||||||
|
os << ", ";
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
count = 0;
|
||||||
|
os << "], is_in_equilibrium: " << group.is_in_equilibrium
|
||||||
|
<< ", algebraic_indices: [";
|
||||||
|
for (const auto& idx : group.algebraic_indices) {
|
||||||
|
os << idx;
|
||||||
|
if (count < group.algebraic_indices.size() - 1) {
|
||||||
|
os << ", ";
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
count = 0;
|
||||||
|
os << "], seed_indices: [";
|
||||||
|
for (const auto& idx : group.seed_indices) {
|
||||||
|
os << idx;
|
||||||
|
if (count < group.seed_indices.size() - 1) {
|
||||||
|
os << ", ";
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
os << "])";
|
||||||
|
return os;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EigenFunctor {
|
struct EigenFunctor {
|
||||||
@@ -147,38 +182,31 @@ namespace gridfire {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
quill::Logger* m_logger = fourdst::logging::LogManager::getInstance().getLogger("log");
|
quill::Logger* m_logger = LogManager::getInstance().getLogger("log");
|
||||||
GraphEngine& m_baseEngine; ///< The base engine to which this view delegates calculations.
|
GraphEngine& m_baseEngine; ///< The base engine to which this view delegates calculations.
|
||||||
std::vector<QSEGroup> m_qse_groups; ///< The list of identified equilibrium groups.
|
std::vector<QSEGroup> m_qse_groups; ///< The list of identified equilibrium groups.
|
||||||
std::vector<fourdst::atomic::Species> m_dynamic_species; ///< The simplified set of species presented to the solver.
|
std::vector<fourdst::atomic::Species> m_dynamic_species; ///< The simplified set of species presented to the solver.
|
||||||
std::vector<size_t> m_dynamic_species_indices; ///< Indices mapping the dynamic species back to the master engine's list.
|
std::vector<size_t> m_dynamic_species_indices; ///< Indices mapping the dynamic species back to the master engine's list.
|
||||||
|
std::vector<fourdst::atomic::Species> m_algebraic_species; ///< Species that are algebraic in the QSE groups.
|
||||||
|
std::vector<size_t> m_algebraic_species_indices; ///< Indices of algebraic species in the full network.
|
||||||
std::unordered_map<size_t, std::vector<size_t>> m_connectivity_graph;
|
std::unordered_map<size_t, std::vector<size_t>> m_connectivity_graph;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_set<size_t> identifyFastReactions(
|
std::vector<std::vector<size_t>> partitionByTimescale(
|
||||||
const std::vector<double> &Y_full,
|
const std::vector<double> &Y_full,
|
||||||
double T9,
|
double T9,
|
||||||
double rho,
|
double rho
|
||||||
double dt_control
|
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
void buildConnectivityGraph(
|
std::unordered_map<size_t, std::vector<size_t>> buildConnectivityGraph(
|
||||||
const std::unordered_set<size_t> &fast_reaction_indices
|
const std::unordered_set<size_t> &fast_reaction_indices
|
||||||
);
|
) const;
|
||||||
|
|
||||||
void findConnectedComponents();
|
std::vector<QSEGroup> validateGroupsWithFluxAnalysis(
|
||||||
|
const std::vector<QSEGroup> &candidate_groups,
|
||||||
void validateGroupsWithFluxAnalysis(
|
|
||||||
const std::vector<double>& Y,
|
const std::vector<double>& Y,
|
||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
);
|
|
||||||
|
|
||||||
std::pair<std::vector<fourdst::atomic::Species>, std::vector<size_t>> identifyDynamicSpecies(
|
|
||||||
const std::vector<double>& Y,
|
|
||||||
const std::vector<QSEGroup>& qse_groups,
|
|
||||||
double T9,
|
|
||||||
double rho
|
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
std::vector<double> solveQSEAbundances(
|
std::vector<double> solveQSEAbundances(
|
||||||
@@ -186,5 +214,19 @@ namespace gridfire {
|
|||||||
double T9,
|
double T9,
|
||||||
double rho
|
double rho
|
||||||
);
|
);
|
||||||
|
|
||||||
|
size_t identifyMeanSlowestPool(
|
||||||
|
const std::vector<std::vector<size_t>>& pools,
|
||||||
|
const std::vector<double> &Y,
|
||||||
|
double T9,
|
||||||
|
double rho
|
||||||
|
) const;
|
||||||
|
|
||||||
|
std::vector<QSEGroup> constructCandidateGroups(
|
||||||
|
const std::vector<std::vector<size_t>>& timescale_pools,
|
||||||
|
const std::vector<double>& Y,
|
||||||
|
double T9,
|
||||||
|
double rho
|
||||||
|
) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -690,23 +690,23 @@ namespace gridfire {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG_DEBUG(
|
// LOG_DEBUG(
|
||||||
m_logger,
|
// m_logger,
|
||||||
"Final Jacobian is:\n{}",
|
// "Final Jacobian is:\n{}",
|
||||||
[&]() -> std::string {
|
// [&]() -> std::string {
|
||||||
std::stringstream ss;
|
// std::stringstream ss;
|
||||||
ss << std::scientific << std::setprecision(5);
|
// ss << std::scientific << std::setprecision(5);
|
||||||
for (size_t i = 0; i < m_jacobianMatrix.size1(); ++i) {
|
// for (size_t i = 0; i < m_jacobianMatrix.size1(); ++i) {
|
||||||
for (size_t j = 0; j < m_jacobianMatrix.size2(); ++j) {
|
// for (size_t j = 0; j < m_jacobianMatrix.size2(); ++j) {
|
||||||
ss << m_jacobianMatrix(i, j);
|
// ss << m_jacobianMatrix(i, j);
|
||||||
if (j < m_jacobianMatrix.size2() - 1) {
|
// if (j < m_jacobianMatrix.size2() - 1) {
|
||||||
ss << ", ";
|
// ss << ", ";
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
ss << "\n";
|
// ss << "\n";
|
||||||
}
|
// }
|
||||||
return ss.str();
|
// return ss.str();
|
||||||
}());
|
// }());
|
||||||
LOG_TRACE_L1(m_logger, "Jacobian matrix generated with dimensions: {} rows x {} columns.", m_jacobianMatrix.size1(), m_jacobianMatrix.size2());
|
LOG_TRACE_L1(m_logger, "Jacobian matrix generated with dimensions: {} rows x {} columns.", m_jacobianMatrix.size1(), m_jacobianMatrix.size2());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -110,6 +110,10 @@ namespace gridfire {
|
|||||||
if (destructionRateConstant > 1e-99) {
|
if (destructionRateConstant > 1e-99) {
|
||||||
const double creationRate = calculateCreationRate(primer, primingSpecies, Y, T9, rho);
|
const double creationRate = calculateCreationRate(primer, primingSpecies, Y, T9, rho);
|
||||||
equilibriumMassFraction = (creationRate / destructionRateConstant) * primingSpecies.mass();
|
equilibriumMassFraction = (creationRate / destructionRateConstant) * primingSpecies.mass();
|
||||||
|
if (std::isnan(equilibriumMassFraction)) {
|
||||||
|
LOG_WARNING(logger, "Equilibrium mass fraction for {} is NaN. Setting to 0.0. This is likely not an issue. It probably originates from all reactions leading to creation and destruction being frozen out. In that case 0.0 should be a good approximation. Hint: This happens often when the network temperature is very the low. ", primingSpecies.name());
|
||||||
|
equilibriumMassFraction = 0.0;
|
||||||
|
}
|
||||||
LOG_INFO(logger, "Found equilibrium for {}: X_eq = {:.4e}", primingSpecies.name(), equilibriumMassFraction);
|
LOG_INFO(logger, "Found equilibrium for {}: X_eq = {:.4e}", primingSpecies.name(), equilibriumMassFraction);
|
||||||
|
|
||||||
const reaction::Reaction* dominantChannel = findDominantCreationChannel(primer, primingSpecies, Y, T9, rho);
|
const reaction::Reaction* dominantChannel = findDominantCreationChannel(primer, primingSpecies, Y, T9, rho);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -71,22 +71,27 @@ int main() {
|
|||||||
|
|
||||||
NetIn netIn;
|
NetIn netIn;
|
||||||
netIn.composition = composition;
|
netIn.composition = composition;
|
||||||
netIn.temperature = 1.5e6;
|
netIn.temperature = 1.5e7;
|
||||||
netIn.density = 1.5e3;
|
netIn.density = 1.5e3;
|
||||||
netIn.energy = 0;
|
netIn.energy = 0;
|
||||||
netIn.tMax = 3e17;
|
netIn.tMax = 3e17;
|
||||||
netIn.dt0 = 1e-12;
|
netIn.dt0 = 1e-12;
|
||||||
|
|
||||||
GraphEngine ReaclibEngine(composition, partitionFunction, NetworkBuildDepth::SecondOrder);
|
GraphEngine ReaclibEngine(composition, partitionFunction, NetworkBuildDepth::SecondOrder);
|
||||||
|
ReaclibEngine.exportToDot("GraphEngine.dot");
|
||||||
auto primedReport = ReaclibEngine.primeEngine(netIn);
|
auto primedReport = ReaclibEngine.primeEngine(netIn);
|
||||||
std::cout << primedReport << std::endl;
|
if (!primedReport.success) {
|
||||||
std::cout << "Initial Composition\n";
|
LOG_CRITICAL(logger, "Failed to prime the network!");
|
||||||
for (const auto& [symbol, entry] : netIn.composition) {
|
return 1;
|
||||||
std::cout << "\t" << symbol << ": " << entry.mass_fraction() << "\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "\nPrimed Composition\n";
|
NetIn primedNetIn = netIn;
|
||||||
for (const auto& [symbol, entry] : primedReport.primedComposition) {
|
primedNetIn.composition = primedReport.primedComposition;
|
||||||
std::cout << "\t" << symbol << ": " << entry.mass_fraction() << "\n";
|
|
||||||
}
|
std::cout << primedReport.primedComposition << std::endl;
|
||||||
|
|
||||||
|
MultiscalePartitioningEngineView partitioningView(ReaclibEngine);
|
||||||
|
fourdst::composition::Composition qseComp = partitioningView.equilibrateNetwork(primedNetIn);
|
||||||
|
std::cout << qseComp.getMolarAbundance("H-2") / qseComp.getMolarAbundance("H-1") << std::endl;
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user