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; } } }
unsigned int AtomicCompositionTable::CheckStoichiometry(std::ostream& fOut, const Reaction& reaction, const double epsilon) { 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]; Eigen::VectorXd relative_errors(element_weights_list_.size()); for(int i=0;i<reactant_side.size();i++) relative_errors(i) = std::fabs(reactant_side(i)-product_side(i))/std::max((reactant_side(i)+product_side(i))*0.5, 1.e-32); for(int i=0;i<reactant_side.size();i++) if (relative_errors(i)>epsilon) { fOut << "Error in reaction stoichiometry" << std::endl; fOut << "Atom Reactants Products Rel. error(%)" << std::endl; for(int k=0;k<reactant_side.size();k++) { if (relative_errors(k)*100. > epsilon) { fOut << std::left << std::setw(10) << element_names_list_[k]; fOut << std::left << std::setw(16) << reactant_side(k); fOut << std::left << std::setw(16) << product_side(k); fOut << std::left << std::setw(16) << relative_errors(k)*100.; fOut << std::endl; } } return 1; } double max_relative_errors = relative_errors.maxCoeff(); if (max_relative_errors>1.e-12) { fOut << "Warning: the reaction is not perfectly balanced!" << std::endl; fOut << "Atom Reactants Products Rel. error(%)" << std::endl; for(int k=0;k<reactant_side.size();k++) { if (relative_errors(k)*100. > 1e-10) { fOut << std::left << std::setw(10) << element_names_list_[k]; fOut << std::left << std::setw(16) << reactant_side(k); fOut << std::left << std::setw(16) << product_side(k); fOut << std::left << std::setw(16) << relative_errors(k)*100.; fOut << std::endl; } } return 2; } return 0; }