unsigned int AtomicCompositionTable::CorrectStoichiometry(Reaction& reaction) { Eigen::VectorXd reactant_side(element_weights_list_.size()); Eigen::VectorXd product_side(element_weights_list_.size()); reactant_side.setZero(); product_side.setZero(); for (unsigned int i = 0; i<reaction.reactant_nu_indices().size(); i++) for (int j = 0; j<reactant_side.size(); j++) reactant_side(j) += element_coefficients_list_(reaction.reactant_nu_indices()[i], j)*reaction.reactant_nu()[i]; for (unsigned int i = 0; i<reaction.product_nu_indices().size(); i++) for (int j = 0; j<product_side.size(); j++) product_side(j) += element_coefficients_list_(reaction.product_nu_indices()[i], j)*reaction.product_nu()[i]; // Propose correction { // List of available elements std::vector<unsigned int> indices_available_elements; for (int k = 0; k<reactant_side.size(); k++) if (reactant_side(k) > 0.) indices_available_elements.push_back(k); unsigned int m = indices_available_elements.size(); unsigned int n = reaction.product_nu_indices().size(); if (m <= n) { Eigen::VectorXd beta(m); for (unsigned int k = 0; k < m; k++) { unsigned int j = indices_available_elements[k]; beta(k) = reactant_side(j) - product_side(j); } Eigen::MatrixXd nu(m, n); for (unsigned int i = 0; i<reaction.product_nu_indices().size(); i++) for (unsigned int k = 0; k < m; k++) { unsigned int j = indices_available_elements[k]; nu(k, i) = element_coefficients_list_(reaction.product_nu_indices()[i], j); } Eigen::VectorXd delta(n); if (m == n) delta = nu.fullPivLu().solve(beta); else delta = nu.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(beta); for (unsigned int i = 0; i < reaction.product_nu_indices().size(); i++) { const double new_coefficient = reaction.product_nu()[i] + delta(i); reaction.set_product_nu(i, new_coefficient); } return 1; } else { return 0; } } }