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;
	}
	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;
			}
		}
	}