Test rate calculations in various monod scenarios.
1569{
1573 std::vector<Real> promoting_indices(5 + 7, 0.0);
1574 std::vector<Real> promoting_monod(5 + 7, 0.0);
1575 std::vector<Real> half_saturation(5 + 7, 0.0);
1576 const std::vector<std::string> basis_name = {"H2O", "H+", "HCO3-", "O2(aq)", "Ca++"};
1577 const std::vector<bool> basis_species_gas = {false, false, false, true, false};
1578 const std::vector<Real> basis_molality = {1.5, 2.0, 3.0, 4.0, 5.0};
1579 const std::vector<Real> basis_activity = {0.1, 0.2, 0.3, 0.4, 0.5};
1580 const std::vector<bool> basis_activity_known = {false, false, false, true, true};
1581 const std::vector<std::string> eqm_name = {"OH-", "n2", "n3", "n4", "n5", "n6", "n7"};
1582 const std::vector<bool> eqm_species_gas = {false, false, false, true, false, false, false};
1583 std::vector<Real> eqm_molality = {1.5, 2.5, 2.3, 2.1, 1.9, 1.7, 1.3};
1584 std::vector<Real> eqm_activity = {1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7};
1585 DenseMatrix<Real> eqm_stoichiometry(7, 5);
1586 DenseMatrix<Real> kin_stoichiometry(2, 5);
1587
1590 std::vector<Real> drate_dmol(5, 1.0);
1591
1592
1594 std::vector<Real>(12, 0),
1595 std::vector<Real>(12, 0),
1597 basis_name,
1598 basis_species_gas,
1599 basis_molality,
1600 basis_activity,
1601 basis_activity_known,
1602 eqm_name,
1603 eqm_species_gas,
1604 eqm_molality,
1605 eqm_activity,
1606 eqm_stoichiometry,
1607 1.25,
1608 2.25,
1609 3.5,
1610 4.0,
1611 kin_stoichiometry,
1612 0,
1613 50.0,
1614 rate,
1615 drate_dkin,
1616 drate_dmol);
1617 EXPECT_NEAR(rate,
1618 -1.5 * 2.0 * 1.25 * 2.25 * std::pow(1.25 / 1.5, 1.75) /
1619 std::pow(std::pow(1.25 / 1.5, 1.75) + std::pow(0.875, 1.75), 2.125) *
1620 std::pow(std::abs(1 - std::pow(std::pow(10.0, 4.0 - 3.5), 0.8)), 2.5) *
1623 1.0E-6);
1624 EXPECT_NEAR(drate_dkin,
1625 -1.5 * 2.0 * 2.25 *
1626 (std::pow(1.25 / 1.5, 1.75) /
1627 std::pow(std::pow(1.25 / 1.5, 1.75) + std::pow(0.875, 1.75), 2.125) +
1628 1.25 * 1.75 * std::pow(1.25 / 1.5, 1.75 - 1.0) / 1.5 /
1629 std::pow(std::pow(1.25 / 1.5, 1.75) + std::pow(0.875, 1.75), 2.125) +
1630 1.25 * std::pow(1.25 / 1.5, 1.75) * (-2.125) /
1631 std::pow(std::pow(1.25 / 1.5, 1.75) + std::pow(0.875, 1.75), 2.125 + 1.0) *
1632 1.75 * std::pow(1.25 / 1.5, 1.75 - 1.0) / 1.5) *
1633 std::pow(std::abs(1 - std::pow(std::pow(10.0, 4.0 - 3.5), 0.8)), 2.5) *
1636 1.0E-6);
1637 EXPECT_NEAR(drate_dmol[0],
1638 -1.5 * 2.0 * 1.25 * 2.25 *
1639 (1.75 * std::pow(1.25 / 1.5, 1.75 - 1.0) * (-1.25 / 1.5 / 1.5) /
1640 std::pow(std::pow(1.25 / 1.5, 1.75) + std::pow(0.875, 1.75), 2.125) +
1641 std::pow(1.25 / 1.5, 1.75) * (-2.125) /
1642 std::pow(std::pow(1.25 / 1.5, 1.75) + std::pow(0.875, 1.75), 2.125 + 1.0) *
1643 1.75 * std::pow(1.25 / 1.5, 1.75 - 1.0) * (-1.25 / 1.5 / 1.5)) *
1644 std::pow(std::abs(1 - std::pow(std::pow(10.0, 4.0 - 3.5), 0.8)), 2.5) *
1647 1.0E-6);
1648 for (unsigned i = 1; i < 5; ++i)
1649 ASSERT_EQ(drate_dmol[i], 0.0);
1650
1651
1652 for (unsigned i = 0; i < 5; ++i)
1653 {
1654 promoting_indices[i] = 0.5 * (i + 1);
1655 promoting_monod[i] = 0.25 * i;
1656 half_saturation[i] = 0.125 * i;
1657 }
1659 promoting_monod,
1660 half_saturation,
1662 basis_name,
1663 basis_species_gas,
1664 basis_molality,
1665 basis_activity,
1666 basis_activity_known,
1667 eqm_name,
1668 eqm_species_gas,
1669 eqm_molality,
1670 eqm_activity,
1671 eqm_stoichiometry,
1672 1.25,
1673 2.25,
1674 3.5,
1675 4.0,
1676 kin_stoichiometry,
1677 0,
1678 40.0,
1679 rate,
1680 drate_dkin,
1681 drate_dmol);
1682 EXPECT_NEAR(rate,
1683 -7.0 * 6.0 *
1684 (std::pow(1.5, 0.5) / std::pow(std::pow(1.5, 0.5) + std::pow(0.0, 0.5), 0.0)) *
1685 (std::pow(0.2, 1.0) / std::pow(std::pow(0.2, 1.0) + std::pow(0.125, 1.0), 0.25)) *
1686 (std::pow(3.0, 1.5) / std::pow(std::pow(3.0, 1.5) + std::pow(0.25, 1.5), 0.5)) *
1687 (std::pow(0.4, 2.0) / std::pow(std::pow(0.4, 2.0) + std::pow(0.375, 2.0), 0.75)) *
1688 (std::pow(5.0, 2.5) / std::pow(std::pow(5.0, 2.5) + std::pow(0.5, 2.5), 1.0)) *
1689 std::pow(std::abs(1 - std::pow(std::pow(10.0, 4.0 - 3.5), 2.5)), 0.8) *
1692 1.0E-6);
1693 EXPECT_EQ(drate_dkin, 0.0);
1694 EXPECT_NEAR(drate_dmol[0], 0.5 * rate / 1.5, 1.0E-6);
1695 EXPECT_NEAR(drate_dmol[1],
1696 1.0 * rate / 2.0 + (-0.25) / (std::pow(0.2, 1.0) + std::pow(0.125, 1.0)) * rate *
1697 1.0 * std::pow(0.2, 1.0 - 1.0) * 0.2 / 2.0,
1698 1.0E-6);
1699 EXPECT_NEAR(drate_dmol[2],
1700 1.5 * rate / 3.0 + (-0.5) / (std::pow(3.0, 1.5) + std::pow(0.25, 1.5)) * rate * 1.5 *
1701 std::pow(3.0, 1.5 - 1.0),
1702 1.0E-6);
1703 EXPECT_EQ(drate_dmol[3], 0.0);
1704 EXPECT_NEAR(drate_dmol[4],
1705 2.5 * rate / 5.0 + (-1.0) / (std::pow(5.0, 2.5) + std::pow(0.5, 2.5)) * rate * 2.5 *
1706 std::pow(5.0, 2.5 - 1.0),
1707 1.0E-6);
1708
1709
1710 for (unsigned i = 5; i < 12; ++i)
1711 {
1712 promoting_indices[i] = -0.1 * (i + 1);
1713 promoting_monod[i] = 0.25 * i;
1714 half_saturation[i] = 0.125 * i;
1715 }
1717 promoting_monod,
1718 half_saturation,
1720 basis_name,
1721 basis_species_gas,
1722 basis_molality,
1723 basis_activity,
1724 basis_activity_known,
1725 eqm_name,
1726 eqm_species_gas,
1727 eqm_molality,
1728 eqm_activity,
1729 eqm_stoichiometry,
1730 1.25,
1731 2.25,
1732 3.5,
1733 4.0,
1734 kin_stoichiometry,
1735 0,
1736 40.0,
1737 rate,
1738 drate_dkin,
1739 drate_dmol);
1740 EXPECT_NEAR(
1741 rate,
1742 -7.0 * 6.0 * (std::pow(1.5, 0.5) / std::pow(std::pow(1.5, 0.5) + std::pow(0.0, 0.5), 0.0)) *
1743 (std::pow(0.2, 1.0) / std::pow(std::pow(0.2, 1.0) + std::pow(0.125, 1.0), 0.25)) *
1744 (std::pow(3.0, 1.5) / std::pow(std::pow(3.0, 1.5) + std::pow(0.25, 1.5), 0.5)) *
1745 (std::pow(0.4, 2.0) / std::pow(std::pow(0.4, 2.0) + std::pow(0.375, 2.0), 0.75)) *
1746 (std::pow(5.0, 2.5) / std::pow(std::pow(5.0, 2.5) + std::pow(0.5, 2.5), 1.0)) *
1747 (std::pow(1.1, -0.6) / std::pow(std::pow(1.1, -0.6) + std::pow(0.625, -0.6), 1.25)) *
1748 (std::pow(2.5, -0.7) / std::pow(std::pow(2.5, -0.7) + std::pow(0.75, -0.7), 1.5)) *
1749 (std::pow(2.3, -0.8) / std::pow(std::pow(2.3, -0.8) + std::pow(0.875, -0.8), 1.75)) *
1750 (std::pow(1.4, -0.9) / std::pow(std::pow(1.4, -0.9) + std::pow(1.0, -0.9), 2.0)) *
1751 (std::pow(1.9, -1.0) / std::pow(std::pow(1.9, -1.0) + std::pow(1.125, -1.0), 2.25)) *
1752 (std::pow(1.7, -1.1) / std::pow(std::pow(1.7, -1.1) + std::pow(1.25, -1.1), 2.5)) *
1753 (std::pow(1.3, -1.2) / std::pow(std::pow(1.3, -1.2) + std::pow(1.375, -1.2), 2.75)) *
1754 std::pow(std::abs(1 - std::pow(std::pow(10.0, 4.0 - 3.5), 2.5)), 0.8) *
1757 1.0E-6);
1758 EXPECT_EQ(drate_dkin, 0.0);
1759 EXPECT_NEAR(drate_dmol[0], 0.5 * rate / 1.5, 1.0E-6);
1760 EXPECT_NEAR(drate_dmol[1],
1761 1.0 * rate / 2.0 + (-0.25) / (std::pow(0.2, 1.0) + std::pow(0.125, 1.0)) * rate *
1762 1.0 * std::pow(0.2, 1.0 - 1.0) * 0.2 / 2.0,
1763 1.0E-6);
1764 EXPECT_NEAR(drate_dmol[2],
1765 1.5 * rate / 3.0 + (-0.5) / (std::pow(3.0, 1.5) + std::pow(0.25, 1.5)) * rate * 1.5 *
1766 std::pow(3.0, 1.5 - 1.0),
1767 1.0E-6);
1768 EXPECT_EQ(drate_dmol[3], 0.0);
1769 EXPECT_NEAR(drate_dmol[4],
1770 2.5 * rate / 5.0 + (-1.0) / (std::pow(5.0, 2.5) + std::pow(0.5, 2.5)) * rate * 2.5 *
1771 std::pow(5.0, 2.5 - 1.0),
1772 1.0E-6);
1773
1774
1775
1776
1777 for (unsigned i = 0; i < 5; ++i)
1778 {
1781 if (basis_species_gas[i])
1782 continue;
1783
1784
1785 std::vector<Real> fd_basis_molality = basis_molality;
1786 std::vector<Real> fd_basis_activity =
1787 fd_basis_molality;
1789 promoting_monod,
1790 half_saturation,
1792 basis_name,
1793 basis_species_gas,
1794 fd_basis_molality,
1795 fd_basis_activity,
1796 basis_activity_known,
1797 eqm_name,
1798 eqm_species_gas,
1799 eqm_molality,
1800 eqm_activity,
1801 eqm_stoichiometry,
1802 1.25,
1803 2.25,
1804 3.5,
1805 4.0,
1806 kin_stoichiometry,
1807 0,
1808 40.0,
1809 rate,
1810 drate_dkin,
1811 drate_dmol);
1812
1813 fd_basis_molality[i] +=
eps;
1814 fd_basis_activity = fd_basis_molality;
1816 promoting_monod,
1817 half_saturation,
1819 basis_name,
1820 basis_species_gas,
1821 fd_basis_molality,
1822 fd_basis_activity,
1823 basis_activity_known,
1824 eqm_name,
1825 eqm_species_gas,
1826 eqm_molality,
1827 eqm_activity,
1828 eqm_stoichiometry,
1829 1.25,
1830 2.25,
1831 3.5,
1832 4.0,
1833 kin_stoichiometry,
1834 0,
1835 40.0,
1836 rate_new,
1837 drate_dkin,
1838 drate_dmol);
1839 const Real fd = (rate_new - rate) /
eps;
1840 EXPECT_TRUE(std::abs(drate_dmol[i] / fd - 1.0) < 1E-4);
1841 }
1842
1843
1844 eqm_stoichiometry(0, 0) = 1.0;
1845 eqm_stoichiometry(0, 1) = -1.25;
1846 eqm_stoichiometry(0, 2) = 1.5;
1847 eqm_stoichiometry(0, 3) = 3.5;
1848 eqm_stoichiometry(1, 0) = 1.25;
1849 eqm_stoichiometry(1, 1) = 2.75;
1850 eqm_stoichiometry(1, 2) = 0.75;
1851 eqm_stoichiometry(1, 3) = -1.5;
1852 eqm_stoichiometry(3, 0) = 2.0;
1853 eqm_stoichiometry(3, 1) = -2.25;
1854 eqm_stoichiometry(3, 2) = -2.5;
1855 eqm_stoichiometry(3, 3) = -33.5;
1857 promoting_monod,
1858 half_saturation,
1860 basis_name,
1861 basis_species_gas,
1862 basis_molality,
1863 basis_activity,
1864 basis_activity_known,
1865 eqm_name,
1866 eqm_species_gas,
1867 eqm_molality,
1868 eqm_activity,
1869 eqm_stoichiometry,
1870 1.25,
1871 2.25,
1872 3.5,
1873 4.0,
1874 kin_stoichiometry,
1875 0,
1876 40.0,
1877 rate,
1878 drate_dkin,
1879 drate_dmol);
1880 EXPECT_NEAR(
1881 rate,
1882 -7.0 * 6.0 * (std::pow(1.5, 0.5) / std::pow(std::pow(1.5, 0.5) + std::pow(0.0, 0.5), 0.0)) *
1883 (std::pow(0.2, 1.0) / std::pow(std::pow(0.2, 1.0) + std::pow(0.125, 1.0), 0.25)) *
1884 (std::pow(3.0, 1.5) / std::pow(std::pow(3.0, 1.5) + std::pow(0.25, 1.5), 0.5)) *
1885 (std::pow(0.4, 2.0) / std::pow(std::pow(0.4, 2.0) + std::pow(0.375, 2.0), 0.75)) *
1886 (std::pow(5.0, 2.5) / std::pow(std::pow(5.0, 2.5) + std::pow(0.5, 2.5), 1.0)) *
1887 (std::pow(1.1, -0.6) / std::pow(std::pow(1.1, -0.6) + std::pow(0.625, -0.6), 1.25)) *
1888 (std::pow(2.5, -0.7) / std::pow(std::pow(2.5, -0.7) + std::pow(0.75, -0.7), 1.5)) *
1889 (std::pow(2.3, -0.8) / std::pow(std::pow(2.3, -0.8) + std::pow(0.875, -0.8), 1.75)) *
1890 (std::pow(1.4, -0.9) / std::pow(std::pow(1.4, -0.9) + std::pow(1.0, -0.9), 2.0)) *
1891 (std::pow(1.9, -1.0) / std::pow(std::pow(1.9, -1.0) + std::pow(1.125, -1.0), 2.25)) *
1892 (std::pow(1.7, -1.1) / std::pow(std::pow(1.7, -1.1) + std::pow(1.25, -1.1), 2.5)) *
1893 (std::pow(1.3, -1.2) / std::pow(std::pow(1.3, -1.2) + std::pow(1.375, -1.2), 2.75)) *
1894 std::pow(std::abs(1 - std::pow(std::pow(10.0, 4.0 - 3.5), 2.5)), 0.8) *
1897 1.0E-6);
1898 EXPECT_EQ(drate_dkin, 0.0);
1899 EXPECT_NEAR(drate_dmol[0], 0.5 * rate / 1.5, 1.0E-6);
1900 EXPECT_NEAR(
1901 drate_dmol[1],
1902 (1.0 * rate / 2.0 + (-0.25) / (std::pow(0.2, 1.0) + std::pow(0.125, 1.0)) * rate * 1.0 *
1903 std::pow(0.2, 1.0 - 1.0) * 0.2 / 2.0) +
1904 (-1.25 *
1905 (-0.6 * rate / 2.0 + (-1.25) / (std::pow(1.1, -0.6) + std::pow(0.625, -0.6)) * rate *
1906 (-0.6) * std::pow(1.1, -0.6 - 1.0) * 1.1 / 2.0)) +
1907 (2.75 * (-0.7 * rate / 2.0 + (-1.5) / (std::pow(2.5, -0.7) + std::pow(0.75, -0.7)) *
1908 rate * (-0.7) * std::pow(2.5, -0.7 - 1.0) * 2.5 / 2.0)) +
1909 (-2.25 * (-0.9 * rate / 2.0 + (-2.0) / (std::pow(1.4, -0.9) + std::pow(1.0, -0.9)) *
1910 rate * (-0.9) * std::pow(1.4, -0.9 - 1.0) * 1.4 / 2.0)),
1911 1.0E-6);
1912 EXPECT_NEAR(
1913 drate_dmol[2],
1914 (1.5 * rate / 3.0 + (-0.5) / (std::pow(3.0, 1.5) + std::pow(0.25, 1.5)) * rate * 1.5 *
1915 std::pow(3.0, 1.5 - 1.0)) +
1916 (1.5 *
1917 (-0.6 * rate / 1.1 * 1.1 / 1.5 +
1918 (-1.25) / (std::pow(1.1, -0.6) + std::pow(0.625, -0.6)) * rate * (-0.6) *
1919 std::pow(1.1, -0.6 - 1.0) * 1.1 / 1.5) *
1920 1.5 / 3.0) +
1921 (0.75 * (-0.7 * rate / 3.0 + (-1.5) / (std::pow(2.5, -0.7) + std::pow(0.75, -0.7)) *
1922 rate * (-0.7) * std::pow(2.5, -0.7 - 1.0) * 2.5 / 3.0)) +
1923 (-2.5 *
1924 (-0.9 * rate / 1.4 + (-2.0) / (std::pow(1.4, -0.9) + std::pow(1.0, -0.9)) * rate *
1925 (-0.9) * std::pow(1.4, -0.9 - 1.0)) *
1926 1.4 / 3.0),
1927 1.0E-6);
1928
1929 EXPECT_EQ(drate_dmol[3], 0.0);
1930 EXPECT_NEAR(drate_dmol[4],
1931 2.5 * rate / 5.0 + (-1.0) / (std::pow(5.0, 2.5) + std::pow(0.5, 2.5)) * rate * 2.5 *
1932 std::pow(5.0, 2.5 - 1.0),
1933 1.0E-6);
1934
1935
1936
1937
1938 for (unsigned i = 0; i < 5; ++i)
1939 {
1942 if (basis_species_gas[i])
1943 continue;
1944
1945
1946 std::vector<Real> fd_basis_molality = basis_molality;
1947 std::vector<Real> fd_basis_activity =
1948 fd_basis_molality;
1949 for (unsigned j = 0; j < 7; ++j)
1950 {
1951 eqm_molality[j] = std::pow(fd_basis_activity[0], eqm_stoichiometry(j, 0));
1952 for (unsigned basis = 1; basis < 5; ++basis)
1953 {
1954 if (basis_species_gas[basis])
1955 continue;
1956 eqm_molality[j] *= std::pow(fd_basis_molality[basis], eqm_stoichiometry(j, basis));
1957 }
1958 }
1959 eqm_activity = eqm_molality;
1961 promoting_monod,
1962 half_saturation,
1964 basis_name,
1965 basis_species_gas,
1966 fd_basis_molality,
1967 fd_basis_activity,
1968 basis_activity_known,
1969 eqm_name,
1970 eqm_species_gas,
1971 eqm_molality,
1972 eqm_activity,
1973 eqm_stoichiometry,
1974 1.25,
1975 2.25,
1976 3.5,
1977 4.0,
1978 kin_stoichiometry,
1979 0,
1980 40.0,
1981 rate,
1982 drate_dkin,
1983 drate_dmol);
1984
1985 fd_basis_molality[i] +=
eps;
1986 for (unsigned basis = 1; basis < 5; ++basis)
1987 fd_basis_activity[basis] =
1988 fd_basis_molality[basis];
1989
1990 for (unsigned j = 0; j < 7; ++j)
1991 {
1992 eqm_molality[j] = std::pow(fd_basis_activity[0], eqm_stoichiometry(j, 0));
1993 for (unsigned basis = 1; basis < 5; ++basis)
1994 {
1995 if (basis_species_gas[basis])
1996 continue;
1997 eqm_molality[j] *= std::pow(fd_basis_molality[basis], eqm_stoichiometry(j, basis));
1998 }
1999 }
2000 eqm_activity = eqm_molality;
2002 promoting_monod,
2003 half_saturation,
2005 basis_name,
2006 basis_species_gas,
2007 fd_basis_molality,
2008 fd_basis_activity,
2009 basis_activity_known,
2010 eqm_name,
2011 eqm_species_gas,
2012 eqm_molality,
2013 eqm_activity,
2014 eqm_stoichiometry,
2015 1.25,
2016 2.25,
2017 3.5,
2018 4.0,
2019 kin_stoichiometry,
2020 0,
2021 40.0,
2022 rate_new,
2023 drate_dkin,
2024 drate_dmol);
2025 const Real fd = (rate_new - rate) /
eps;
2026 EXPECT_TRUE(std::abs(drate_dmol[i] / fd - 1.0) < 1E-4);
2027 }
2028}
KineticRateUserDescription rate_ch4_kin_mon("CH4(aq)", 1.5, 2.0, true, 1.75, 2.125, 0.875, {"H2O", "OH-", "O2(aq)", "CO2(aq)", "CaCO3"}, {3.0, 3.1, 3.2, 3.3, 3.4}, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, 0.8, 2.5, 66.0, 0.003, DirectionChoiceEnum::BOTH, "H2O", 0.0, -1.0, 0.0)